[BACK]Return to window-customize.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/window-customize.c, Revision 1.13

1.13    ! nicm        1: /* $OpenBSD: window-customize.c,v 1.12 2021/08/21 17:25:32 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <ctype.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24:
                     25: #include "tmux.h"
                     26:
                     27: static struct screen   *window_customize_init(struct window_mode_entry *,
                     28:                             struct cmd_find_state *, struct args *);
                     29: static void             window_customize_free(struct window_mode_entry *);
                     30: static void             window_customize_resize(struct window_mode_entry *,
                     31:                              u_int, u_int);
                     32: static void             window_customize_key(struct window_mode_entry *,
                     33:                             struct client *, struct session *,
                     34:                             struct winlink *, key_code, struct mouse_event *);
                     35:
                     36: #define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \
                     37:        "#{?is_option," \
                     38:                "#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \
                     39:                "#[ignore]" \
                     40:                "#{option_value}#{?option_unit, #{option_unit},}" \
                     41:        "," \
                     42:                "#{key}" \
                     43:        "}"
                     44:
                     45: static const struct menu_item window_customize_menu_items[] = {
                     46:        { "Select", '\r', NULL },
                     47:        { "Expand", KEYC_RIGHT, NULL },
                     48:        { "", KEYC_NONE, NULL },
                     49:        { "Tag", 't', NULL },
                     50:        { "Tag All", '\024', NULL },
                     51:        { "Tag None", 'T', NULL },
                     52:        { "", KEYC_NONE, NULL },
                     53:        { "Cancel", 'q', NULL },
                     54:
                     55:        { NULL, KEYC_NONE, NULL }
                     56: };
                     57:
                     58: const struct window_mode window_customize_mode = {
                     59:        .name = "options-mode",
                     60:        .default_format = WINDOW_CUSTOMIZE_DEFAULT_FORMAT,
                     61:
                     62:        .init = window_customize_init,
                     63:        .free = window_customize_free,
                     64:        .resize = window_customize_resize,
                     65:        .key = window_customize_key,
                     66: };
                     67:
                     68: enum window_customize_scope {
                     69:        WINDOW_CUSTOMIZE_NONE,
                     70:        WINDOW_CUSTOMIZE_KEY,
                     71:        WINDOW_CUSTOMIZE_SERVER,
                     72:        WINDOW_CUSTOMIZE_GLOBAL_SESSION,
                     73:        WINDOW_CUSTOMIZE_SESSION,
                     74:        WINDOW_CUSTOMIZE_GLOBAL_WINDOW,
                     75:        WINDOW_CUSTOMIZE_WINDOW,
                     76:        WINDOW_CUSTOMIZE_PANE
                     77: };
                     78:
1.4       nicm       79: enum window_customize_change {
                     80:        WINDOW_CUSTOMIZE_UNSET,
                     81:        WINDOW_CUSTOMIZE_RESET,
                     82: };
                     83:
1.1       nicm       84: struct window_customize_itemdata {
                     85:        struct window_customize_modedata        *data;
                     86:        enum window_customize_scope              scope;
                     87:
                     88:        char                                    *table;
                     89:        key_code                                 key;
                     90:
                     91:        struct options                          *oo;
                     92:        char                                    *name;
                     93:        int                                      idx;
                     94: };
                     95:
                     96: struct window_customize_modedata {
                     97:        struct window_pane                       *wp;
                     98:        int                                       dead;
                     99:        int                                       references;
                    100:
                    101:        struct mode_tree_data                    *data;
                    102:        char                                     *format;
                    103:        int                                       hide_global;
                    104:
                    105:        struct window_customize_itemdata        **item_list;
                    106:        u_int                                     item_size;
                    107:
                    108:        struct cmd_find_state                     fs;
1.4       nicm      109:        enum window_customize_change              change;
1.1       nicm      110: };
                    111:
                    112: static uint64_t
                    113: window_customize_get_tag(struct options_entry *o, int idx,
                    114:     const struct options_table_entry *oe)
                    115: {
                    116:        uint64_t        offset;
                    117:
                    118:        if (oe == NULL)
                    119:                return ((uint64_t)o);
                    120:        offset = ((char *)oe - (char *)options_table) / sizeof *options_table;
                    121:        return ((2ULL << 62)|(offset << 32)|((idx + 1) << 1)|1);
                    122: }
                    123:
                    124: static struct options *
                    125: window_customize_get_tree(enum window_customize_scope scope,
                    126:     struct cmd_find_state *fs)
                    127: {
                    128:        switch (scope) {
                    129:        case WINDOW_CUSTOMIZE_NONE:
                    130:        case WINDOW_CUSTOMIZE_KEY:
                    131:                return (NULL);
                    132:        case WINDOW_CUSTOMIZE_SERVER:
                    133:                return (global_options);
                    134:        case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
                    135:                return (global_s_options);
                    136:        case WINDOW_CUSTOMIZE_SESSION:
                    137:                return (fs->s->options);
                    138:        case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
                    139:                return (global_w_options);
                    140:        case WINDOW_CUSTOMIZE_WINDOW:
                    141:                return (fs->w->options);
                    142:        case WINDOW_CUSTOMIZE_PANE:
                    143:                return (fs->wp->options);
                    144:        }
                    145:        return (NULL);
                    146: }
                    147:
                    148: static int
                    149: window_customize_check_item(struct window_customize_modedata *data,
                    150:     struct window_customize_itemdata *item, struct cmd_find_state *fsp)
                    151: {
                    152:        struct cmd_find_state   fs;
                    153:
                    154:        if (fsp == NULL)
                    155:                fsp = &fs;
                    156:
                    157:        if (cmd_find_valid_state(&data->fs))
                    158:                cmd_find_copy_state(fsp, &data->fs);
                    159:        else
                    160:                cmd_find_from_pane(fsp, data->wp, 0);
                    161:        return (item->oo == window_customize_get_tree(item->scope, fsp));
                    162: }
                    163:
                    164: static int
                    165: window_customize_get_key(struct window_customize_itemdata *item,
                    166:     struct key_table **ktp, struct key_binding **bdp)
                    167: {
                    168:        struct key_table        *kt;
                    169:        struct key_binding      *bd;
                    170:
                    171:        kt = key_bindings_get_table(item->table, 0);
                    172:        if (kt == NULL)
                    173:                return (0);
                    174:        bd = key_bindings_get(kt, item->key);
                    175:        if (bd == NULL)
                    176:                return (0);
                    177:
                    178:        if (ktp != NULL)
                    179:                *ktp = kt;
                    180:        if (bdp != NULL)
                    181:                *bdp = bd;
                    182:        return (1);
                    183: }
                    184:
                    185: static char *
                    186: window_customize_scope_text(enum window_customize_scope scope,
                    187:     struct cmd_find_state *fs)
                    188: {
                    189:        char    *s;
                    190:        u_int    idx;
                    191:
                    192:        switch (scope) {
                    193:        case WINDOW_CUSTOMIZE_PANE:
                    194:                window_pane_index(fs->wp, &idx);
                    195:                xasprintf(&s, "pane %u", idx);
                    196:                break;
                    197:        case WINDOW_CUSTOMIZE_SESSION:
                    198:                xasprintf(&s, "session %s", fs->s->name);
                    199:                break;
                    200:        case WINDOW_CUSTOMIZE_WINDOW:
                    201:                xasprintf(&s, "window %u", fs->wl->idx);
1.8       nicm      202:                break;
                    203:        default:
                    204:                s = xstrdup("");
1.1       nicm      205:                break;
                    206:        }
                    207:        return (s);
                    208: }
                    209:
                    210: static struct window_customize_itemdata *
                    211: window_customize_add_item(struct window_customize_modedata *data)
                    212: {
                    213:        struct window_customize_itemdata        *item;
                    214:
                    215:        data->item_list = xreallocarray(data->item_list, data->item_size + 1,
                    216:            sizeof *data->item_list);
                    217:        item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
                    218:        return (item);
                    219: }
                    220:
                    221: static void
                    222: window_customize_free_item(struct window_customize_itemdata *item)
                    223: {
                    224:        free(item->table);
                    225:        free(item->name);
                    226:        free(item);
                    227: }
                    228:
                    229: static void
                    230: window_customize_build_array(struct window_customize_modedata *data,
                    231:     struct mode_tree_item *top, enum window_customize_scope scope,
                    232:     struct options_entry *o, struct format_tree *ft)
                    233: {
                    234:        const struct options_table_entry        *oe = options_table_entry(o);
                    235:        struct options                          *oo = options_owner(o);
                    236:        struct window_customize_itemdata        *item;
                    237:        struct options_array_item               *ai;
                    238:        char                                    *name, *value, *text;
                    239:        u_int                                    idx;
                    240:        uint64_t                                 tag;
                    241:
                    242:        ai = options_array_first(o);
                    243:        while (ai != NULL) {
                    244:                idx = options_array_item_index(ai);
                    245:
                    246:                xasprintf(&name, "%s[%u]", options_name(o), idx);
                    247:                format_add(ft, "option_name", "%s", name);
                    248:                value = options_to_string(o, idx, 0);
                    249:                format_add(ft, "option_value", "%s", value);
                    250:
                    251:                item = window_customize_add_item(data);
                    252:                item->scope = scope;
                    253:                item->oo = oo;
                    254:                item->name = xstrdup(options_name(o));
                    255:                item->idx = idx;
                    256:
                    257:                text = format_expand(ft, data->format);
                    258:                tag = window_customize_get_tag(o, idx, oe);
                    259:                mode_tree_add(data->data, top, item, tag, name, text, -1);
                    260:                free(text);
                    261:
                    262:                free(name);
                    263:                free(value);
                    264:
                    265:                ai = options_array_next(ai);
                    266:        }
                    267: }
                    268:
                    269: static void
                    270: window_customize_build_option(struct window_customize_modedata *data,
                    271:     struct mode_tree_item *top, enum window_customize_scope scope,
                    272:     struct options_entry *o, struct format_tree *ft,
                    273:     const char *filter, struct cmd_find_state *fs)
                    274: {
                    275:        const struct options_table_entry        *oe = options_table_entry(o);
                    276:        struct options                          *oo = options_owner(o);
                    277:        const char                              *name = options_name(o);
                    278:        struct window_customize_itemdata        *item;
                    279:        char                                    *text, *expanded, *value;
                    280:        int                                      global = 0, array = 0;
                    281:        uint64_t                                 tag;
                    282:
                    283:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
                    284:                return;
                    285:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY))
                    286:                array = 1;
                    287:
                    288:        if (scope == WINDOW_CUSTOMIZE_SERVER ||
                    289:            scope == WINDOW_CUSTOMIZE_GLOBAL_SESSION ||
                    290:            scope == WINDOW_CUSTOMIZE_GLOBAL_WINDOW)
                    291:                global = 1;
                    292:        if (data->hide_global && global)
                    293:                return;
                    294:
                    295:        format_add(ft, "option_name", "%s", name);
                    296:        format_add(ft, "option_is_global", "%d", global);
                    297:        format_add(ft, "option_is_array", "%d", array);
                    298:
                    299:        text = window_customize_scope_text(scope, fs);
                    300:        format_add(ft, "option_scope", "%s", text);
                    301:        free(text);
                    302:
                    303:        if (oe != NULL && oe->unit != NULL)
                    304:                format_add(ft, "option_unit", "%s", oe->unit);
                    305:        else
                    306:                format_add(ft, "option_unit", "%s", "");
                    307:
                    308:        if (!array) {
                    309:                value = options_to_string(o, -1, 0);
                    310:                format_add(ft, "option_value", "%s", value);
                    311:                free(value);
                    312:        }
                    313:
                    314:        if (filter != NULL) {
                    315:                expanded = format_expand(ft, filter);
                    316:                if (!format_true(expanded)) {
                    317:                        free(expanded);
                    318:                        return;
                    319:                }
                    320:                free(expanded);
                    321:        }
                    322:        item = window_customize_add_item(data);
                    323:        item->oo = oo;
                    324:        item->scope = scope;
                    325:        item->name = xstrdup(name);
                    326:        item->idx = -1;
                    327:
                    328:        if (array)
                    329:                text = NULL;
                    330:        else
                    331:                text = format_expand(ft, data->format);
                    332:        tag = window_customize_get_tag(o, -1, oe);
                    333:        top = mode_tree_add(data->data, top, item, tag, name, text, 0);
                    334:        free(text);
                    335:
                    336:        if (array)
                    337:                window_customize_build_array(data, top, scope, o, ft);
                    338: }
                    339:
                    340: static void
                    341: window_customize_find_user_options(struct options *oo, const char ***list,
                    342:     u_int *size)
                    343: {
                    344:        struct options_entry    *o;
                    345:        const char              *name;
                    346:        u_int                    i;
                    347:
                    348:        o = options_first(oo);
                    349:        while (o != NULL) {
                    350:                name = options_name(o);
                    351:                if (*name != '@') {
                    352:                        o = options_next(o);
                    353:                        continue;
                    354:                }
                    355:                for (i = 0; i < *size; i++) {
                    356:                        if (strcmp((*list)[i], name) == 0)
                    357:                                break;
                    358:                }
                    359:                if (i != *size) {
                    360:                        o = options_next(o);
                    361:                        continue;
                    362:                }
                    363:                *list = xreallocarray(*list, (*size) + 1, sizeof **list);
                    364:                (*list)[(*size)++] = name;
                    365:
                    366:                o = options_next(o);
                    367:        }
                    368: }
                    369:
                    370: static void
                    371: window_customize_build_options(struct window_customize_modedata *data,
                    372:     const char *title, uint64_t tag,
                    373:     enum window_customize_scope scope0, struct options *oo0,
                    374:     enum window_customize_scope scope1, struct options *oo1,
                    375:     enum window_customize_scope scope2, struct options *oo2,
                    376:     struct format_tree *ft, const char *filter, struct cmd_find_state *fs)
                    377: {
                    378:        struct mode_tree_item            *top;
1.7       nicm      379:        struct options_entry             *o = NULL, *loop;
1.1       nicm      380:        const char                      **list = NULL, *name;
                    381:        u_int                             size = 0, i;
                    382:        enum window_customize_scope       scope;
                    383:
                    384:        top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
1.4       nicm      385:        mode_tree_no_tag(top);
1.1       nicm      386:
                    387:        /*
                    388:         * We get the options from the first tree, but build it using the
                    389:         * values from the other two. Any tree can have user options so we need
                    390:         * to build a separate list of them.
                    391:         */
                    392:
                    393:        window_customize_find_user_options(oo0, &list, &size);
                    394:        if (oo1 != NULL)
                    395:                window_customize_find_user_options(oo1, &list, &size);
                    396:        if (oo2 != NULL)
                    397:                window_customize_find_user_options(oo2, &list, &size);
                    398:
                    399:        for (i = 0; i < size; i++) {
                    400:                if (oo2 != NULL)
1.13    ! nicm      401:                        o = options_get(oo2, list[i]);
1.5       nicm      402:                if (o == NULL && oo1 != NULL)
1.1       nicm      403:                        o = options_get(oo1, list[i]);
1.5       nicm      404:                if (o == NULL)
1.13    ! nicm      405:                        o = options_get(oo0, list[i]);
1.1       nicm      406:                if (options_owner(o) == oo2)
                    407:                        scope = scope2;
                    408:                else if (options_owner(o) == oo1)
                    409:                        scope = scope1;
                    410:                else
                    411:                        scope = scope0;
                    412:                window_customize_build_option(data, top, scope, o, ft, filter,
                    413:                    fs);
                    414:        }
                    415:        free(list);
                    416:
                    417:        loop = options_first(oo0);
                    418:        while (loop != NULL) {
                    419:                name = options_name(loop);
                    420:                if (*name == '@') {
                    421:                        loop = options_next(loop);
                    422:                        continue;
                    423:                }
                    424:                if (oo2 != NULL)
                    425:                        o = options_get(oo2, name);
                    426:                else if (oo1 != NULL)
                    427:                        o = options_get(oo1, name);
                    428:                else
                    429:                        o = loop;
                    430:                if (options_owner(o) == oo2)
                    431:                        scope = scope2;
                    432:                else if (options_owner(o) == oo1)
                    433:                        scope = scope1;
                    434:                else
                    435:                        scope = scope0;
                    436:                window_customize_build_option(data, top, scope, o, ft, filter,
                    437:                    fs);
                    438:                loop = options_next(loop);
                    439:        }
                    440: }
                    441:
                    442: static void
                    443: window_customize_build_keys(struct window_customize_modedata *data,
                    444:     struct key_table *kt, struct format_tree *ft, const char *filter,
                    445:     struct cmd_find_state *fs, u_int number)
                    446: {
                    447:        struct mode_tree_item                   *top, *child, *mti;
                    448:        struct window_customize_itemdata        *item;
                    449:        struct key_binding                      *bd;
                    450:        char                                    *title, *text, *tmp, *expanded;
                    451:        const char                              *flag;
                    452:        uint64_t                                 tag;
                    453:
                    454:        tag = (1ULL << 62)|((uint64_t)number << 54)|1;
                    455:
                    456:        xasprintf(&title, "Key Table - %s", kt->name);
                    457:        top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
1.4       nicm      458:        mode_tree_no_tag(top);
1.1       nicm      459:        free(title);
                    460:
                    461:        ft = format_create_from_state(NULL, NULL, fs);
                    462:        format_add(ft, "is_option", "0");
                    463:        format_add(ft, "is_key", "1");
                    464:
                    465:        bd = key_bindings_first(kt);
                    466:        while (bd != NULL) {
1.3       nicm      467:                format_add(ft, "key", "%s", key_string_lookup_key(bd->key, 0));
1.1       nicm      468:                if (bd->note != NULL)
                    469:                        format_add(ft, "key_note", "%s", bd->note);
                    470:                if (filter != NULL) {
                    471:                        expanded = format_expand(ft, filter);
                    472:                        if (!format_true(expanded)) {
                    473:                                free(expanded);
                    474:                                continue;
                    475:                        }
                    476:                        free(expanded);
                    477:                }
                    478:
                    479:                item = window_customize_add_item(data);
                    480:                item->scope = WINDOW_CUSTOMIZE_KEY;
                    481:                item->table = xstrdup(kt->name);
                    482:                item->key = bd->key;
1.4       nicm      483:                item->name = xstrdup(key_string_lookup_key(item->key, 0));
                    484:                item->idx = -1;
1.1       nicm      485:
                    486:                expanded = format_expand(ft, data->format);
                    487:                child = mode_tree_add(data->data, top, item, (uint64_t)bd,
                    488:                    expanded, NULL, 0);
                    489:                free(expanded);
                    490:
                    491:                tmp = cmd_list_print(bd->cmdlist, 0);
                    492:                xasprintf(&text, "#[ignore]%s", tmp);
                    493:                free(tmp);
                    494:                mti = mode_tree_add(data->data, child, item,
                    495:                    tag|(bd->key << 3)|(0 << 1)|1, "Command", text, -1);
                    496:                mode_tree_draw_as_parent(mti);
1.4       nicm      497:                mode_tree_no_tag(mti);
1.1       nicm      498:                free(text);
                    499:
                    500:                if (bd->note != NULL)
                    501:                        xasprintf(&text, "#[ignore]%s", bd->note);
                    502:                else
                    503:                        text = xstrdup("");
                    504:                mti = mode_tree_add(data->data, child, item,
                    505:                    tag|(bd->key << 3)|(1 << 1)|1, "Note", text, -1);
                    506:                mode_tree_draw_as_parent(mti);
1.4       nicm      507:                mode_tree_no_tag(mti);
1.1       nicm      508:                free(text);
                    509:
                    510:                if (bd->flags & KEY_BINDING_REPEAT)
                    511:                        flag = "on";
                    512:                else
                    513:                        flag = "off";
                    514:                mti = mode_tree_add(data->data, child, item,
                    515:                    tag|(bd->key << 3)|(2 << 1)|1, "Repeat", flag, -1);
                    516:                mode_tree_draw_as_parent(mti);
1.4       nicm      517:                mode_tree_no_tag(mti);
1.1       nicm      518:
                    519:                bd = key_bindings_next(kt, bd);
                    520:        }
                    521:
                    522:        format_free(ft);
                    523: }
                    524:
                    525: static void
                    526: window_customize_build(void *modedata,
                    527:     __unused struct mode_tree_sort_criteria *sort_crit, __unused uint64_t *tag,
                    528:     const char *filter)
                    529: {
                    530:        struct window_customize_modedata        *data = modedata;
                    531:        struct cmd_find_state                    fs;
                    532:        struct format_tree                      *ft;
                    533:        u_int                                    i;
                    534:        struct key_table                        *kt;
                    535:
                    536:        for (i = 0; i < data->item_size; i++)
                    537:                window_customize_free_item(data->item_list[i]);
                    538:        free(data->item_list);
                    539:        data->item_list = NULL;
                    540:        data->item_size = 0;
                    541:
                    542:        if (cmd_find_valid_state(&data->fs))
                    543:                cmd_find_copy_state(&fs, &data->fs);
                    544:        else
                    545:                cmd_find_from_pane(&fs, data->wp, 0);
                    546:
                    547:        ft = format_create_from_state(NULL, NULL, &fs);
                    548:        format_add(ft, "is_option", "1");
                    549:        format_add(ft, "is_key", "0");
                    550:
                    551:        window_customize_build_options(data, "Server Options",
                    552:            (3ULL << 62)|(OPTIONS_TABLE_SERVER << 1)|1,
                    553:            WINDOW_CUSTOMIZE_SERVER, global_options,
                    554:            WINDOW_CUSTOMIZE_NONE, NULL,
                    555:            WINDOW_CUSTOMIZE_NONE, NULL,
                    556:            ft, filter, &fs);
                    557:        window_customize_build_options(data, "Session Options",
                    558:            (3ULL << 62)|(OPTIONS_TABLE_SESSION << 1)|1,
                    559:            WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options,
                    560:            WINDOW_CUSTOMIZE_SESSION, fs.s->options,
                    561:            WINDOW_CUSTOMIZE_NONE, NULL,
                    562:            ft, filter, &fs);
                    563:        window_customize_build_options(data, "Window & Pane Options",
                    564:            (3ULL << 62)|(OPTIONS_TABLE_WINDOW << 1)|1,
                    565:            WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options,
                    566:            WINDOW_CUSTOMIZE_WINDOW, fs.w->options,
                    567:            WINDOW_CUSTOMIZE_PANE, fs.wp->options,
                    568:            ft, filter, &fs);
                    569:
                    570:        format_free(ft);
                    571:        ft = format_create_from_state(NULL, NULL, &fs);
                    572:
                    573:        i = 0;
                    574:        kt = key_bindings_first_table();
                    575:        while (kt != NULL) {
                    576:                if (!RB_EMPTY(&kt->key_bindings)) {
                    577:                        window_customize_build_keys(data, kt, ft, filter, &fs,
                    578:                            i);
                    579:                        if (++i == 256)
                    580:                                break;
                    581:                }
                    582:                kt = key_bindings_next_table(kt);
                    583:        }
                    584:
                    585:        format_free(ft);
                    586: }
                    587:
                    588: static void
                    589: window_customize_draw_key(__unused struct window_customize_modedata *data,
                    590:     struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
                    591:     u_int sx, u_int sy)
                    592: {
                    593:        struct screen           *s = ctx->s;
                    594:        u_int                    cx = s->cx, cy = s->cy;
                    595:        struct key_table        *kt;
                    596:        struct key_binding      *bd, *default_bd;
                    597:        const char              *note, *period = "";
                    598:        char                    *cmd, *default_cmd;
                    599:
                    600:        if (item == NULL || !window_customize_get_key(item, &kt, &bd))
                    601:                return;
                    602:
                    603:        note = bd->note;
                    604:        if (note == NULL)
                    605:                note = "There is no note for this key.";
                    606:        if (*note != '\0' && note[strlen (note) - 1] != '.')
                    607:                period = ".";
                    608:        if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s%s",
                    609:            note, period))
                    610:                return;
                    611:        screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
                    612:        if (s->cy >= cy + sy - 1)
                    613:                return;
                    614:
                    615:        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    616:            &grid_default_cell, "This key is in the %s table.", kt->name))
                    617:                return;
                    618:        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    619:            &grid_default_cell, "This key %s repeat.",
                    620:            (bd->flags & KEY_BINDING_REPEAT) ? "does" : "does not"))
                    621:                return;
                    622:        screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
                    623:        if (s->cy >= cy + sy - 1)
                    624:                return;
                    625:
                    626:        cmd = cmd_list_print(bd->cmdlist, 0);
                    627:        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    628:            &grid_default_cell, "Command: %s", cmd)) {
                    629:                free(cmd);
                    630:                return;
                    631:        }
                    632:        default_bd = key_bindings_get_default(kt, bd->key);
                    633:        if (default_bd != NULL) {
                    634:                default_cmd = cmd_list_print(default_bd->cmdlist, 0);
                    635:                if (strcmp(cmd, default_cmd) != 0 &&
                    636:                    !screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    637:                    &grid_default_cell, "The default is: %s", default_cmd)) {
                    638:                        free(default_cmd);
                    639:                        free(cmd);
                    640:                        return;
                    641:                }
                    642:                free(default_cmd);
                    643:        }
                    644:        free(cmd);
                    645: }
                    646:
                    647: static void
                    648: window_customize_draw_option(struct window_customize_modedata *data,
                    649:     struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
                    650:     u_int sx, u_int sy)
                    651: {
                    652:        struct screen                            *s = ctx->s;
                    653:        u_int                                     cx = s->cx, cy = s->cy;
                    654:        int                                       idx;
                    655:        struct options_entry                     *o, *parent;
                    656:        struct options                           *go, *wo;
                    657:        const struct options_table_entry         *oe;
                    658:        struct grid_cell                          gc;
                    659:        const char                              **choice, *text, *name;
                    660:        const char                               *space = "", *unit = "";
                    661:        char                                     *value = NULL, *expanded;
                    662:        char                                     *default_value = NULL;
                    663:        char                                      choices[256] = "";
                    664:        struct cmd_find_state                     fs;
                    665:        struct format_tree                       *ft;
                    666:
                    667:        if (!window_customize_check_item(data, item, &fs))
                    668:                return;
                    669:        name = item->name;
                    670:        idx = item->idx;
                    671:
                    672:        o = options_get(item->oo, name);
                    673:        if (o == NULL)
                    674:                return;
                    675:        oe = options_table_entry(o);
                    676:
                    677:        if (oe != NULL && oe->unit != NULL) {
                    678:                space = " ";
                    679:                unit = oe->unit;
                    680:        }
                    681:        ft = format_create_from_state(NULL, NULL, &fs);
                    682:
                    683:        if (oe == NULL)
                    684:                text = "This is a user option.";
                    685:        else if (oe->text == NULL)
                    686:                text = "This option doesn't have a description.";
                    687:        else
                    688:                text = oe->text;
                    689:        if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s",
                    690:            text))
                    691:                goto out;
                    692:        screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
                    693:        if (s->cy >= cy + sy - 1)
                    694:                goto out;
                    695:
                    696:        if (oe == NULL)
                    697:                text = "user";
                    698:        else if ((oe->scope & (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) ==
                    699:            (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE))
                    700:                text = "window and pane";
                    701:        else if (oe->scope & OPTIONS_TABLE_WINDOW)
                    702:                text = "window";
                    703:        else if (oe->scope & OPTIONS_TABLE_SESSION)
                    704:                text = "session";
                    705:        else
                    706:                text = "server";
                    707:        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    708:            &grid_default_cell, "This is a %s option.", text))
                    709:                goto out;
                    710:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
                    711:                if (idx != -1) {
                    712:                        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
                    713:                            0, &grid_default_cell,
                    714:                            "This is an array option, index %u.", idx))
                    715:                                goto out;
                    716:                } else {
                    717:                        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
                    718:                            0, &grid_default_cell, "This is an array option."))
                    719:                                goto out;
                    720:                }
                    721:                if (idx == -1)
                    722:                        goto out;
                    723:        }
                    724:        screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
                    725:        if (s->cy >= cy + sy - 1)
                    726:                goto out;
                    727:
                    728:        value = options_to_string(o, idx, 0);
                    729:        if (oe != NULL && idx == -1) {
                    730:                default_value = options_default_to_string(oe);
                    731:                if (strcmp(default_value, value) == 0) {
                    732:                        free(default_value);
                    733:                        default_value = NULL;
                    734:                }
                    735:        }
                    736:        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    737:            &grid_default_cell, "Option value: %s%s%s", value, space, unit))
                    738:                goto out;
                    739:        if (oe == NULL || oe->type == OPTIONS_TABLE_STRING) {
                    740:                expanded = format_expand(ft, value);
                    741:                if (strcmp(expanded, value) != 0) {
                    742:                        if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
                    743:                            0, &grid_default_cell, "This expands to: %s",
                    744:                            expanded))
                    745:                                goto out;
                    746:                }
                    747:                free(expanded);
                    748:        }
                    749:        if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) {
                    750:                for (choice = oe->choices; *choice != NULL; choice++) {
                    751:                        strlcat(choices, *choice, sizeof choices);
                    752:                        strlcat(choices, ", ", sizeof choices);
                    753:                }
                    754:                choices[strlen(choices) - 2] = '\0';
                    755:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    756:                    &grid_default_cell, "Available values are: %s",
                    757:                    choices))
                    758:                        goto out;
                    759:        }
                    760:        if (oe != NULL && oe->type == OPTIONS_TABLE_COLOUR) {
                    761:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
                    762:                    &grid_default_cell, "This is a colour option: "))
                    763:                        goto out;
                    764:                memcpy(&gc, &grid_default_cell, sizeof gc);
                    765:                gc.fg = options_get_number(item->oo, name);
                    766:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
                    767:                    "EXAMPLE"))
                    768:                        goto out;
                    769:        }
                    770:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_STYLE)) {
                    771:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
                    772:                    &grid_default_cell, "This is a style option: "))
                    773:                        goto out;
                    774:                style_apply(&gc, item->oo, name, ft);
                    775:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
                    776:                    "EXAMPLE"))
                    777:                        goto out;
                    778:        }
                    779:        if (default_value != NULL) {
                    780:                if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
                    781:                    &grid_default_cell, "The default is: %s%s%s", default_value,
                    782:                    space, unit))
                    783:                        goto out;
                    784:        }
                    785:
                    786:        screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
                    787:        if (s->cy > cy + sy - 1)
                    788:                goto out;
                    789:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
                    790:                wo = NULL;
                    791:                go = NULL;
                    792:        } else {
                    793:                switch (item->scope) {
                    794:                case WINDOW_CUSTOMIZE_PANE:
                    795:                        wo = options_get_parent(item->oo);
                    796:                        go = options_get_parent(wo);
                    797:                        break;
                    798:                case WINDOW_CUSTOMIZE_WINDOW:
                    799:                case WINDOW_CUSTOMIZE_SESSION:
                    800:                        wo = NULL;
                    801:                        go = options_get_parent(item->oo);
                    802:                        break;
                    803:                default:
                    804:                        wo = NULL;
                    805:                        go = NULL;
                    806:                        break;
                    807:                }
                    808:        }
                    809:        if (wo != NULL && options_owner(o) != wo) {
                    810:                parent = options_get_only(wo, name);
                    811:                if (parent != NULL) {
                    812:                        value = options_to_string(parent, -1 , 0);
                    813:                        if (!screen_write_text(ctx, s->cx, sx,
                    814:                            sy - (s->cy - cy), 0, &grid_default_cell,
                    815:                            "Window value (from window %u): %s%s%s", fs.wl->idx,
                    816:                            value, space, unit))
                    817:                                goto out;
                    818:                }
                    819:        }
                    820:        if (go != NULL && options_owner(o) != go) {
                    821:                parent = options_get_only(go, name);
                    822:                if (parent != NULL) {
                    823:                        value = options_to_string(parent, -1 , 0);
                    824:                        if (!screen_write_text(ctx, s->cx, sx,
                    825:                            sy - (s->cy - cy), 0, &grid_default_cell,
                    826:                            "Global value: %s%s%s", value, space, unit))
                    827:                                goto out;
                    828:                }
                    829:        }
                    830:
                    831: out:
                    832:        free(value);
                    833:        free(default_value);
                    834:        format_free(ft);
                    835: }
                    836:
                    837: static void
                    838: window_customize_draw(void *modedata, void *itemdata,
                    839:     struct screen_write_ctx *ctx, u_int sx, u_int sy)
                    840: {
                    841:        struct window_customize_modedata        *data = modedata;
                    842:        struct window_customize_itemdata        *item = itemdata;
                    843:
                    844:        if (item == NULL)
                    845:                return;
                    846:
                    847:        if (item->scope == WINDOW_CUSTOMIZE_KEY)
                    848:                window_customize_draw_key(data, item, ctx, sx, sy);
                    849:        else
                    850:                window_customize_draw_option(data, item, ctx, sx, sy);
                    851: }
                    852:
                    853: static void
                    854: window_customize_menu(void *modedata, struct client *c, key_code key)
                    855: {
                    856:        struct window_customize_modedata        *data = modedata;
                    857:        struct window_pane                      *wp = data->wp;
                    858:        struct window_mode_entry                *wme;
                    859:
                    860:        wme = TAILQ_FIRST(&wp->modes);
                    861:        if (wme == NULL || wme->data != modedata)
                    862:                return;
                    863:        window_customize_key(wme, c, NULL, NULL, key, NULL);
                    864: }
                    865:
                    866: static u_int
                    867: window_customize_height(__unused void *modedata, __unused u_int height)
                    868: {
                    869:        return (12);
                    870: }
                    871:
                    872: static struct screen *
                    873: window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
                    874:     struct args *args)
                    875: {
                    876:        struct window_pane                      *wp = wme->wp;
                    877:        struct window_customize_modedata        *data;
                    878:        struct screen                           *s;
                    879:
                    880:        wme->data = data = xcalloc(1, sizeof *data);
                    881:        data->wp = wp;
                    882:        data->references = 1;
                    883:
                    884:        memcpy(&data->fs, fs, sizeof data->fs);
                    885:
                    886:        if (args == NULL || !args_has(args, 'F'))
                    887:                data->format = xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT);
                    888:        else
                    889:                data->format = xstrdup(args_get(args, 'F'));
                    890:
                    891:        data->data = mode_tree_start(wp, args, window_customize_build,
                    892:            window_customize_draw, NULL, window_customize_menu,
1.9       nicm      893:            window_customize_height, NULL, data, window_customize_menu_items,
                    894:            NULL, 0, &s);
1.1       nicm      895:        mode_tree_zoom(data->data, args);
                    896:
                    897:        mode_tree_build(data->data);
                    898:        mode_tree_draw(data->data);
                    899:
                    900:        return (s);
                    901: }
                    902:
                    903: static void
                    904: window_customize_destroy(struct window_customize_modedata *data)
                    905: {
                    906:        u_int   i;
                    907:
                    908:        if (--data->references != 0)
                    909:                return;
                    910:
                    911:        for (i = 0; i < data->item_size; i++)
                    912:                window_customize_free_item(data->item_list[i]);
                    913:        free(data->item_list);
                    914:
                    915:        free(data->format);
                    916:
                    917:        free(data);
                    918: }
                    919:
                    920: static void
                    921: window_customize_free(struct window_mode_entry *wme)
                    922: {
                    923:        struct window_customize_modedata *data = wme->data;
                    924:
                    925:        if (data == NULL)
                    926:                return;
                    927:
                    928:        data->dead = 1;
                    929:        mode_tree_free(data->data);
                    930:        window_customize_destroy(data);
                    931: }
                    932:
                    933: static void
                    934: window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
                    935: {
                    936:        struct window_customize_modedata        *data = wme->data;
                    937:
                    938:        mode_tree_resize(data->data, sx, sy);
                    939: }
                    940:
                    941: static void
                    942: window_customize_free_callback(void *modedata)
                    943: {
                    944:        window_customize_destroy(modedata);
                    945: }
                    946:
                    947: static void
                    948: window_customize_free_item_callback(void *itemdata)
                    949: {
                    950:        struct window_customize_itemdata        *item = itemdata;
                    951:        struct window_customize_modedata        *data = item->data;
                    952:
                    953:        window_customize_free_item(item);
                    954:        window_customize_destroy(data);
                    955: }
                    956:
                    957: static int
                    958: window_customize_set_option_callback(struct client *c, void *itemdata,
                    959:     const char *s, __unused int done)
                    960: {
                    961:        struct window_customize_itemdata        *item = itemdata;
                    962:        struct window_customize_modedata        *data = item->data;
                    963:        struct options_entry                    *o;
                    964:        const struct options_table_entry        *oe;
                    965:        struct options                          *oo = item->oo;
                    966:        const char                              *name = item->name;
                    967:        char                                    *cause;
                    968:        int                                      idx = item->idx;
                    969:
                    970:        if (s == NULL || *s == '\0' || data->dead)
                    971:                return (0);
                    972:        if (item == NULL || !window_customize_check_item(data, item, NULL))
                    973:                return (0);
                    974:        o = options_get(oo, name);
                    975:        if (o == NULL)
                    976:                return (0);
                    977:        oe = options_table_entry(o);
                    978:
                    979:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
                    980:                if (idx == -1) {
                    981:                        for (idx = 0; idx < INT_MAX; idx++) {
                    982:                                if (options_array_get(o, idx) == NULL)
                    983:                                        break;
                    984:                        }
                    985:                }
                    986:                if (options_array_set(o, idx, s, 0, &cause) != 0)
                    987:                        goto fail;
                    988:        } else {
                    989:                if (options_from_string(oo, oe, name, s, 0, &cause) != 0)
                    990:                        goto fail;
                    991:        }
                    992:
                    993:        options_push_changes(item->name);
                    994:        mode_tree_build(data->data);
                    995:        mode_tree_draw(data->data);
                    996:        data->wp->flags |= PANE_REDRAW;
                    997:
                    998:        return (0);
                    999:
                   1000: fail:
                   1001:        *cause = toupper((u_char)*cause);
1.10      nicm     1002:        status_message_set(c, -1, 1, 0, "%s", cause);
1.1       nicm     1003:        free(cause);
                   1004:        return (0);
                   1005: }
                   1006:
                   1007: static void
                   1008: window_customize_set_option(struct client *c,
                   1009:     struct window_customize_modedata *data,
                   1010:     struct window_customize_itemdata *item, int global, int pane)
                   1011: {
                   1012:        struct options_entry                    *o;
                   1013:        const struct options_table_entry        *oe;
                   1014:        struct options                          *oo;
                   1015:        struct window_customize_itemdata        *new_item;
                   1016:        int                                      flag, idx = item->idx;
1.7       nicm     1017:        enum window_customize_scope              scope = WINDOW_CUSTOMIZE_NONE;
1.1       nicm     1018:        u_int                                    choice;
                   1019:        const char                              *name = item->name, *space = "";
                   1020:        char                                    *prompt, *value, *text;
                   1021:        struct cmd_find_state                    fs;
                   1022:
                   1023:        if (item == NULL || !window_customize_check_item(data, item, &fs))
                   1024:                return;
                   1025:        o = options_get(item->oo, name);
                   1026:        if (o == NULL)
                   1027:                return;
                   1028:
                   1029:        oe = options_table_entry(o);
1.7       nicm     1030:        if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE)
1.1       nicm     1031:                pane = 0;
                   1032:        if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
                   1033:                scope = item->scope;
                   1034:                oo = item->oo;
                   1035:        } else {
                   1036:                if (global) {
                   1037:                        switch (item->scope) {
                   1038:                        case WINDOW_CUSTOMIZE_NONE:
                   1039:                        case WINDOW_CUSTOMIZE_KEY:
                   1040:                        case WINDOW_CUSTOMIZE_SERVER:
                   1041:                        case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
                   1042:                        case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
                   1043:                                scope = item->scope;
                   1044:                                break;
                   1045:                        case WINDOW_CUSTOMIZE_SESSION:
                   1046:                                scope = WINDOW_CUSTOMIZE_GLOBAL_SESSION;
                   1047:                                break;
                   1048:                        case WINDOW_CUSTOMIZE_WINDOW:
                   1049:                        case WINDOW_CUSTOMIZE_PANE:
                   1050:                                scope = WINDOW_CUSTOMIZE_GLOBAL_WINDOW;
                   1051:                                break;
                   1052:                        }
                   1053:                } else {
                   1054:                        switch (item->scope) {
                   1055:                        case WINDOW_CUSTOMIZE_NONE:
                   1056:                        case WINDOW_CUSTOMIZE_KEY:
                   1057:                        case WINDOW_CUSTOMIZE_SERVER:
                   1058:                        case WINDOW_CUSTOMIZE_SESSION:
                   1059:                                scope = item->scope;
                   1060:                                break;
                   1061:                        case WINDOW_CUSTOMIZE_WINDOW:
                   1062:                        case WINDOW_CUSTOMIZE_PANE:
                   1063:                                if (pane)
                   1064:                                        scope = WINDOW_CUSTOMIZE_PANE;
                   1065:                                else
                   1066:                                        scope = WINDOW_CUSTOMIZE_WINDOW;
                   1067:                                break;
                   1068:                        case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
                   1069:                                scope = WINDOW_CUSTOMIZE_SESSION;
                   1070:                                break;
                   1071:                        case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
                   1072:                                if (pane)
                   1073:                                        scope = WINDOW_CUSTOMIZE_PANE;
                   1074:                                else
                   1075:                                        scope = WINDOW_CUSTOMIZE_WINDOW;
                   1076:                                break;
                   1077:                        }
                   1078:                }
                   1079:                if (scope == item->scope)
                   1080:                        oo = item->oo;
                   1081:                else
                   1082:                        oo = window_customize_get_tree(scope, &fs);
                   1083:        }
                   1084:
                   1085:        if (oe != NULL && oe->type == OPTIONS_TABLE_FLAG) {
                   1086:                flag = options_get_number(oo, name);
                   1087:                options_set_number(oo, name, !flag);
                   1088:        } else if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) {
                   1089:                choice = options_get_number(oo, name);
                   1090:                if (oe->choices[choice + 1] == NULL)
                   1091:                        choice = 0;
                   1092:                else
                   1093:                        choice++;
                   1094:                options_set_number(oo, name, choice);
                   1095:        } else {
                   1096:                text = window_customize_scope_text(scope, &fs);
                   1097:                if (*text != '\0')
                   1098:                        space = ", for ";
                   1099:                else if (scope != WINDOW_CUSTOMIZE_SERVER)
                   1100:                        space = ", global";
                   1101:                if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
                   1102:                        if (idx == -1) {
                   1103:                                xasprintf(&prompt, "(%s[+]%s%s) ", name, space,
                   1104:                                    text);
                   1105:                        } else {
                   1106:                                xasprintf(&prompt, "(%s[%d]%s%s) ", name, idx,
                   1107:                                    space, text);
                   1108:                        }
                   1109:                } else
                   1110:                        xasprintf(&prompt, "(%s%s%s) ", name, space, text);
                   1111:                free(text);
                   1112:
                   1113:                value = options_to_string(o, idx, 0);
                   1114:
                   1115:                new_item = xcalloc(1, sizeof *new_item);
                   1116:                new_item->data = data;
                   1117:                new_item->scope = scope;
                   1118:                new_item->oo = oo;
                   1119:                new_item->name = xstrdup(name);
                   1120:                new_item->idx = idx;
                   1121:
                   1122:                data->references++;
1.2       nicm     1123:                status_prompt_set(c, NULL, prompt, value,
1.1       nicm     1124:                    window_customize_set_option_callback,
                   1125:                    window_customize_free_item_callback, new_item,
1.11      nicm     1126:                    PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.1       nicm     1127:
                   1128:                free(prompt);
                   1129:                free(value);
                   1130:        }
                   1131: }
                   1132:
                   1133: static void
                   1134: window_customize_unset_option(struct window_customize_modedata *data,
                   1135:     struct window_customize_itemdata *item)
                   1136: {
1.4       nicm     1137:        struct options_entry    *o;
1.1       nicm     1138:
                   1139:        if (item == NULL || !window_customize_check_item(data, item, NULL))
                   1140:                return;
                   1141:
                   1142:        o = options_get(item->oo, item->name);
                   1143:        if (o == NULL)
                   1144:                return;
1.4       nicm     1145:        if (item->idx != -1 && item == mode_tree_get_current(data->data))
                   1146:                mode_tree_up(data->data, 0);
                   1147:        options_remove_or_default(o, item->idx, NULL);
                   1148: }
                   1149:
                   1150: static void
                   1151: window_customize_reset_option(struct window_customize_modedata *data,
                   1152:     struct window_customize_itemdata *item)
                   1153: {
                   1154:        struct options          *oo;
                   1155:        struct options_entry    *o;
                   1156:
                   1157:        if (item == NULL || !window_customize_check_item(data, item, NULL))
                   1158:                return;
                   1159:        if (item->idx != -1)
1.1       nicm     1160:                return;
1.4       nicm     1161:
                   1162:        oo = item->oo;
                   1163:        while (oo != NULL) {
                   1164:                o = options_get_only(item->oo, item->name);
                   1165:                if (o != NULL)
                   1166:                        options_remove_or_default(o, -1, NULL);
                   1167:                oo = options_get_parent(oo);
1.1       nicm     1168:        }
                   1169: }
                   1170:
                   1171: static int
                   1172: window_customize_set_command_callback(struct client *c, void *itemdata,
                   1173:     const char *s, __unused int done)
                   1174: {
                   1175:        struct window_customize_itemdata        *item = itemdata;
                   1176:        struct window_customize_modedata        *data = item->data;
                   1177:        struct key_binding                      *bd;
                   1178:        struct cmd_parse_result                 *pr;
                   1179:        char                                    *error;
                   1180:
                   1181:        if (s == NULL || *s == '\0' || data->dead)
                   1182:                return (0);
                   1183:        if (item == NULL || !window_customize_get_key(item, NULL, &bd))
                   1184:                return (0);
                   1185:
                   1186:        pr = cmd_parse_from_string(s, NULL);
                   1187:        switch (pr->status) {
                   1188:        case CMD_PARSE_ERROR:
                   1189:                error = pr->error;
                   1190:                goto fail;
                   1191:        case CMD_PARSE_SUCCESS:
                   1192:                break;
                   1193:        }
                   1194:        cmd_list_free(bd->cmdlist);
                   1195:        bd->cmdlist = pr->cmdlist;
                   1196:
                   1197:        mode_tree_build(data->data);
                   1198:        mode_tree_draw(data->data);
                   1199:        data->wp->flags |= PANE_REDRAW;
                   1200:
                   1201:        return (0);
                   1202:
                   1203: fail:
                   1204:        *error = toupper((u_char)*error);
1.10      nicm     1205:        status_message_set(c, -1, 1, 0, "%s", error);
1.1       nicm     1206:        free(error);
                   1207:        return (0);
                   1208: }
                   1209:
                   1210: static int
                   1211: window_customize_set_note_callback(__unused struct client *c, void *itemdata,
                   1212:     const char *s, __unused int done)
                   1213: {
                   1214:        struct window_customize_itemdata        *item = itemdata;
                   1215:        struct window_customize_modedata        *data = item->data;
                   1216:        struct key_binding                      *bd;
                   1217:
                   1218:        if (s == NULL || *s == '\0' || data->dead)
                   1219:                return (0);
                   1220:        if (item == NULL || !window_customize_get_key(item, NULL, &bd))
                   1221:                return (0);
                   1222:
                   1223:        free((void *)bd->note);
                   1224:        bd->note = xstrdup(s);
                   1225:
                   1226:        mode_tree_build(data->data);
                   1227:        mode_tree_draw(data->data);
                   1228:        data->wp->flags |= PANE_REDRAW;
                   1229:
                   1230:        return (0);
                   1231: }
                   1232:
                   1233: static void
                   1234: window_customize_set_key(struct client *c,
                   1235:     struct window_customize_modedata *data,
                   1236:     struct window_customize_itemdata *item)
                   1237: {
                   1238:        key_code                                 key = item->key;
                   1239:        struct key_binding                      *bd;
                   1240:        const char                              *s;
                   1241:        char                                    *prompt, *value;
                   1242:        struct window_customize_itemdata        *new_item;
                   1243:
                   1244:        if (item == NULL || !window_customize_get_key(item, NULL, &bd))
                   1245:                return;
                   1246:
                   1247:        s = mode_tree_get_current_name(data->data);
                   1248:        if (strcmp(s, "Repeat") == 0)
                   1249:                bd->flags ^= KEY_BINDING_REPEAT;
                   1250:        else if (strcmp(s, "Command") == 0) {
1.3       nicm     1251:                xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0));
1.1       nicm     1252:                value = cmd_list_print(bd->cmdlist, 0);
                   1253:
                   1254:                new_item = xcalloc(1, sizeof *new_item);
                   1255:                new_item->data = data;
                   1256:                new_item->scope = item->scope;
                   1257:                new_item->table = xstrdup(item->table);
                   1258:                new_item->key = key;
                   1259:
                   1260:                data->references++;
1.2       nicm     1261:                status_prompt_set(c, NULL, prompt, value,
1.1       nicm     1262:                    window_customize_set_command_callback,
                   1263:                    window_customize_free_item_callback, new_item,
1.11      nicm     1264:                    PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.1       nicm     1265:                free(prompt);
                   1266:                free(value);
                   1267:        } else if (strcmp(s, "Note") == 0) {
1.3       nicm     1268:                xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0));
1.1       nicm     1269:
                   1270:                new_item = xcalloc(1, sizeof *new_item);
                   1271:                new_item->data = data;
                   1272:                new_item->scope = item->scope;
                   1273:                new_item->table = xstrdup(item->table);
                   1274:                new_item->key = key;
                   1275:
                   1276:                data->references++;
1.2       nicm     1277:                status_prompt_set(c, NULL, prompt,
                   1278:                    (bd->note == NULL ? "" : bd->note),
1.1       nicm     1279:                    window_customize_set_note_callback,
                   1280:                    window_customize_free_item_callback, new_item,
1.11      nicm     1281:                    PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.1       nicm     1282:                free(prompt);
                   1283:        }
                   1284: }
                   1285:
                   1286: static void
                   1287: window_customize_unset_key(struct window_customize_modedata *data,
                   1288:     struct window_customize_itemdata *item)
                   1289: {
                   1290:        struct key_table        *kt;
                   1291:        struct key_binding      *bd;
                   1292:
                   1293:        if (item == NULL || !window_customize_get_key(item, &kt, &bd))
                   1294:                return;
                   1295:
                   1296:        if (item == mode_tree_get_current(data->data)) {
                   1297:                mode_tree_collapse_current(data->data);
                   1298:                mode_tree_up(data->data, 0);
                   1299:        }
                   1300:        key_bindings_remove(kt->name, bd->key);
                   1301: }
                   1302:
                   1303: static void
1.4       nicm     1304: window_customize_reset_key(struct window_customize_modedata *data,
                   1305:     struct window_customize_itemdata *item)
                   1306: {
                   1307:        struct key_table        *kt;
                   1308:        struct key_binding      *dd, *bd;
                   1309:
                   1310:        if (item == NULL || !window_customize_get_key(item, &kt, &bd))
                   1311:                return;
                   1312:
                   1313:        dd = key_bindings_get_default(kt, bd->key);
                   1314:        if (dd != NULL && bd->cmdlist == dd->cmdlist)
                   1315:                return;
                   1316:        if (dd == NULL && item == mode_tree_get_current(data->data)) {
                   1317:                mode_tree_collapse_current(data->data);
                   1318:                mode_tree_up(data->data, 0);
                   1319:        }
                   1320:        key_bindings_reset(kt->name, bd->key);
                   1321: }
                   1322:
                   1323: static void
                   1324: window_customize_change_each(void *modedata, void *itemdata,
1.1       nicm     1325:     __unused struct client *c, __unused key_code key)
                   1326: {
1.4       nicm     1327:        struct window_customize_modedata        *data = modedata;
1.1       nicm     1328:        struct window_customize_itemdata        *item = itemdata;
                   1329:
1.4       nicm     1330:        switch (data->change) {
                   1331:        case WINDOW_CUSTOMIZE_UNSET:
                   1332:                if (item->scope == WINDOW_CUSTOMIZE_KEY)
                   1333:                        window_customize_unset_key(data, item);
                   1334:                else
                   1335:                        window_customize_unset_option(data, item);
                   1336:                break;
                   1337:        case WINDOW_CUSTOMIZE_RESET:
                   1338:                if (item->scope == WINDOW_CUSTOMIZE_KEY)
                   1339:                        window_customize_reset_key(data, item);
                   1340:                else
                   1341:                        window_customize_reset_option(data, item);
                   1342:                break;
                   1343:        }
                   1344:        if (item->scope != WINDOW_CUSTOMIZE_KEY)
1.1       nicm     1345:                options_push_changes(item->name);
                   1346: }
                   1347:
                   1348: static int
1.4       nicm     1349: window_customize_change_current_callback(__unused struct client *c,
1.1       nicm     1350:     void *modedata, const char *s, __unused int done)
                   1351: {
                   1352:        struct window_customize_modedata        *data = modedata;
                   1353:        struct window_customize_itemdata        *item;
                   1354:
                   1355:        if (s == NULL || *s == '\0' || data->dead)
                   1356:                return (0);
                   1357:        if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
                   1358:                return (0);
                   1359:
                   1360:        item = mode_tree_get_current(data->data);
1.4       nicm     1361:        switch (data->change) {
                   1362:        case WINDOW_CUSTOMIZE_UNSET:
                   1363:                if (item->scope == WINDOW_CUSTOMIZE_KEY)
                   1364:                        window_customize_unset_key(data, item);
                   1365:                else
                   1366:                        window_customize_unset_option(data, item);
                   1367:                break;
                   1368:        case WINDOW_CUSTOMIZE_RESET:
                   1369:                if (item->scope == WINDOW_CUSTOMIZE_KEY)
                   1370:                        window_customize_reset_key(data, item);
                   1371:                else
                   1372:                        window_customize_reset_option(data, item);
                   1373:                break;
                   1374:        }
                   1375:        if (item->scope != WINDOW_CUSTOMIZE_KEY)
1.1       nicm     1376:                options_push_changes(item->name);
                   1377:        mode_tree_build(data->data);
                   1378:        mode_tree_draw(data->data);
                   1379:        data->wp->flags |= PANE_REDRAW;
                   1380:
                   1381:        return (0);
                   1382: }
                   1383:
                   1384: static int
1.4       nicm     1385: window_customize_change_tagged_callback(struct client *c, void *modedata,
1.1       nicm     1386:     const char *s, __unused int done)
                   1387: {
                   1388:        struct window_customize_modedata        *data = modedata;
                   1389:
                   1390:        if (s == NULL || *s == '\0' || data->dead)
                   1391:                return (0);
                   1392:        if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
                   1393:                return (0);
                   1394:
1.4       nicm     1395:        mode_tree_each_tagged(data->data, window_customize_change_each, c,
1.1       nicm     1396:            KEYC_NONE, 0);
                   1397:        mode_tree_build(data->data);
                   1398:        mode_tree_draw(data->data);
                   1399:        data->wp->flags |= PANE_REDRAW;
                   1400:
                   1401:        return (0);
                   1402: }
                   1403:
                   1404: static void
                   1405: window_customize_key(struct window_mode_entry *wme, struct client *c,
                   1406:     __unused struct session *s, __unused struct winlink *wl, key_code key,
                   1407:     struct mouse_event *m)
                   1408: {
                   1409:        struct window_pane                      *wp = wme->wp;
                   1410:        struct window_customize_modedata        *data = wme->data;
                   1411:        struct window_customize_itemdata        *item, *new_item;
1.4       nicm     1412:        int                                      finished, idx;
1.1       nicm     1413:        char                                    *prompt;
                   1414:        u_int                                    tagged;
                   1415:
                   1416:        item = mode_tree_get_current(data->data);
                   1417:        finished = mode_tree_key(data->data, c, &key, m, NULL, NULL);
                   1418:        if (item != (new_item = mode_tree_get_current(data->data)))
                   1419:                item = new_item;
                   1420:
                   1421:        switch (key) {
                   1422:        case '\r':
                   1423:        case 's':
                   1424:                if (item == NULL)
                   1425:                        break;
                   1426:                if (item->scope == WINDOW_CUSTOMIZE_KEY)
                   1427:                        window_customize_set_key(c, data, item);
                   1428:                else {
                   1429:                        window_customize_set_option(c, data, item, 0, 1);
                   1430:                        options_push_changes(item->name);
                   1431:                }
                   1432:                mode_tree_build(data->data);
                   1433:                break;
                   1434:        case 'w':
                   1435:                if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY)
                   1436:                        break;
                   1437:                window_customize_set_option(c, data, item, 0, 0);
                   1438:                options_push_changes(item->name);
                   1439:                mode_tree_build(data->data);
                   1440:                break;
                   1441:        case 'S':
                   1442:        case 'W':
                   1443:                if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY)
                   1444:                        break;
                   1445:                window_customize_set_option(c, data, item, 1, 0);
                   1446:                options_push_changes(item->name);
                   1447:                mode_tree_build(data->data);
                   1448:                break;
1.4       nicm     1449:        case 'd':
                   1450:                if (item == NULL || item->idx != -1)
                   1451:                        break;
                   1452:                xasprintf(&prompt, "Reset %s to default? ", item->name);
                   1453:                data->references++;
                   1454:                data->change = WINDOW_CUSTOMIZE_RESET;
                   1455:                status_prompt_set(c, NULL, prompt, "",
                   1456:                    window_customize_change_current_callback,
                   1457:                    window_customize_free_callback, data,
1.11      nicm     1458:                    PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.4       nicm     1459:                free(prompt);
                   1460:                break;
                   1461:        case 'D':
                   1462:                tagged = mode_tree_count_tagged(data->data);
                   1463:                if (tagged == 0)
                   1464:                        break;
                   1465:                xasprintf(&prompt, "Reset %u tagged to default? ", tagged);
                   1466:                data->references++;
                   1467:                data->change = WINDOW_CUSTOMIZE_RESET;
                   1468:                status_prompt_set(c, NULL, prompt, "",
                   1469:                    window_customize_change_tagged_callback,
                   1470:                    window_customize_free_callback, data,
1.11      nicm     1471:                    PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.4       nicm     1472:                free(prompt);
                   1473:                break;
1.1       nicm     1474:        case 'u':
                   1475:                if (item == NULL)
                   1476:                        break;
1.4       nicm     1477:                idx = item->idx;
                   1478:                if (idx != -1)
                   1479:                        xasprintf(&prompt, "Unset %s[%d]? ", item->name, idx);
                   1480:                else
                   1481:                        xasprintf(&prompt, "Unset %s? ", item->name);
1.1       nicm     1482:                data->references++;
1.4       nicm     1483:                data->change = WINDOW_CUSTOMIZE_UNSET;
1.2       nicm     1484:                status_prompt_set(c, NULL, prompt, "",
1.4       nicm     1485:                    window_customize_change_current_callback,
1.1       nicm     1486:                    window_customize_free_callback, data,
1.11      nicm     1487:                    PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.1       nicm     1488:                free(prompt);
                   1489:                break;
                   1490:        case 'U':
                   1491:                tagged = mode_tree_count_tagged(data->data);
                   1492:                if (tagged == 0)
                   1493:                        break;
1.4       nicm     1494:                xasprintf(&prompt, "Unset %u tagged? ", tagged);
1.1       nicm     1495:                data->references++;
1.4       nicm     1496:                data->change = WINDOW_CUSTOMIZE_UNSET;
1.2       nicm     1497:                status_prompt_set(c, NULL, prompt, "",
1.4       nicm     1498:                    window_customize_change_tagged_callback,
1.1       nicm     1499:                    window_customize_free_callback, data,
1.11      nicm     1500:                    PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1.1       nicm     1501:                free(prompt);
                   1502:                break;
                   1503:        case 'H':
                   1504:                data->hide_global = !data->hide_global;
                   1505:                mode_tree_build(data->data);
                   1506:                break;
                   1507:        }
                   1508:        if (finished)
                   1509:                window_pane_reset_mode(wp);
                   1510:        else {
                   1511:                mode_tree_draw(data->data);
                   1512:                wp->flags |= PANE_REDRAW;
                   1513:        }
                   1514: }