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