1 /* $OpenBSD: window-customize.c,v 1.14 2022/03/24 12:07:25 nicm Exp $ */ 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 enum window_customize_change { 80 WINDOW_CUSTOMIZE_UNSET, 81 WINDOW_CUSTOMIZE_RESET, 82 }; 83 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; 109 enum window_customize_change change; 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); 202 break; 203 default: 204 s = xstrdup(""); 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; 379 struct options_entry *o = NULL, *loop; 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); 385 mode_tree_no_tag(top); 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) 401 o = options_get(oo2, list[i]); 402 if (o == NULL && oo1 != NULL) 403 o = options_get(oo1, list[i]); 404 if (o == NULL) 405 o = options_get(oo0, list[i]); 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); 458 mode_tree_no_tag(top); 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) { 467 format_add(ft, "key", "%s", key_string_lookup_key(bd->key, 0)); 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; 483 item->name = xstrdup(key_string_lookup_key(item->key, 0)); 484 item->idx = -1; 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); 497 mode_tree_no_tag(mti); 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); 507 mode_tree_no_tag(mti); 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); 517 mode_tree_no_tag(mti); 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 || oe->text == NULL) 684 text = "This option doesn't have a description."; 685 else 686 text = oe->text; 687 if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s", 688 text)) 689 goto out; 690 screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 691 if (s->cy >= cy + sy - 1) 692 goto out; 693 694 if (oe == NULL) 695 text = "user"; 696 else if ((oe->scope & (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) == 697 (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) 698 text = "window and pane"; 699 else if (oe->scope & OPTIONS_TABLE_WINDOW) 700 text = "window"; 701 else if (oe->scope & OPTIONS_TABLE_SESSION) 702 text = "session"; 703 else 704 text = "server"; 705 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 706 &grid_default_cell, "This is a %s option.", text)) 707 goto out; 708 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 709 if (idx != -1) { 710 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 711 0, &grid_default_cell, 712 "This is an array option, index %u.", idx)) 713 goto out; 714 } else { 715 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 716 0, &grid_default_cell, "This is an array option.")) 717 goto out; 718 } 719 if (idx == -1) 720 goto out; 721 } 722 screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 723 if (s->cy >= cy + sy - 1) 724 goto out; 725 726 value = options_to_string(o, idx, 0); 727 if (oe != NULL && idx == -1) { 728 default_value = options_default_to_string(oe); 729 if (strcmp(default_value, value) == 0) { 730 free(default_value); 731 default_value = NULL; 732 } 733 } 734 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 735 &grid_default_cell, "Option value: %s%s%s", value, space, unit)) 736 goto out; 737 if (oe == NULL || oe->type == OPTIONS_TABLE_STRING) { 738 expanded = format_expand(ft, value); 739 if (strcmp(expanded, value) != 0) { 740 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 741 0, &grid_default_cell, "This expands to: %s", 742 expanded)) 743 goto out; 744 } 745 free(expanded); 746 } 747 if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) { 748 for (choice = oe->choices; *choice != NULL; choice++) { 749 strlcat(choices, *choice, sizeof choices); 750 strlcat(choices, ", ", sizeof choices); 751 } 752 choices[strlen(choices) - 2] = '\0'; 753 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 754 &grid_default_cell, "Available values are: %s", 755 choices)) 756 goto out; 757 } 758 if (oe != NULL && oe->type == OPTIONS_TABLE_COLOUR) { 759 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1, 760 &grid_default_cell, "This is a colour option: ")) 761 goto out; 762 memcpy(&gc, &grid_default_cell, sizeof gc); 763 gc.fg = options_get_number(item->oo, name); 764 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc, 765 "EXAMPLE")) 766 goto out; 767 } 768 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_STYLE)) { 769 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1, 770 &grid_default_cell, "This is a style option: ")) 771 goto out; 772 style_apply(&gc, item->oo, name, ft); 773 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc, 774 "EXAMPLE")) 775 goto out; 776 } 777 if (default_value != NULL) { 778 if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 779 &grid_default_cell, "The default is: %s%s%s", default_value, 780 space, unit)) 781 goto out; 782 } 783 784 screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 785 if (s->cy > cy + sy - 1) 786 goto out; 787 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 788 wo = NULL; 789 go = NULL; 790 } else { 791 switch (item->scope) { 792 case WINDOW_CUSTOMIZE_PANE: 793 wo = options_get_parent(item->oo); 794 go = options_get_parent(wo); 795 break; 796 case WINDOW_CUSTOMIZE_WINDOW: 797 case WINDOW_CUSTOMIZE_SESSION: 798 wo = NULL; 799 go = options_get_parent(item->oo); 800 break; 801 default: 802 wo = NULL; 803 go = NULL; 804 break; 805 } 806 } 807 if (wo != NULL && options_owner(o) != wo) { 808 parent = options_get_only(wo, name); 809 if (parent != NULL) { 810 value = options_to_string(parent, -1 , 0); 811 if (!screen_write_text(ctx, s->cx, sx, 812 sy - (s->cy - cy), 0, &grid_default_cell, 813 "Window value (from window %u): %s%s%s", fs.wl->idx, 814 value, space, unit)) 815 goto out; 816 } 817 } 818 if (go != NULL && options_owner(o) != go) { 819 parent = options_get_only(go, name); 820 if (parent != NULL) { 821 value = options_to_string(parent, -1 , 0); 822 if (!screen_write_text(ctx, s->cx, sx, 823 sy - (s->cy - cy), 0, &grid_default_cell, 824 "Global value: %s%s%s", value, space, unit)) 825 goto out; 826 } 827 } 828 829 out: 830 free(value); 831 free(default_value); 832 format_free(ft); 833 } 834 835 static void 836 window_customize_draw(void *modedata, void *itemdata, 837 struct screen_write_ctx *ctx, u_int sx, u_int sy) 838 { 839 struct window_customize_modedata *data = modedata; 840 struct window_customize_itemdata *item = itemdata; 841 842 if (item == NULL) 843 return; 844 845 if (item->scope == WINDOW_CUSTOMIZE_KEY) 846 window_customize_draw_key(data, item, ctx, sx, sy); 847 else 848 window_customize_draw_option(data, item, ctx, sx, sy); 849 } 850 851 static void 852 window_customize_menu(void *modedata, struct client *c, key_code key) 853 { 854 struct window_customize_modedata *data = modedata; 855 struct window_pane *wp = data->wp; 856 struct window_mode_entry *wme; 857 858 wme = TAILQ_FIRST(&wp->modes); 859 if (wme == NULL || wme->data != modedata) 860 return; 861 window_customize_key(wme, c, NULL, NULL, key, NULL); 862 } 863 864 static u_int 865 window_customize_height(__unused void *modedata, __unused u_int height) 866 { 867 return (12); 868 } 869 870 static struct screen * 871 window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs, 872 struct args *args) 873 { 874 struct window_pane *wp = wme->wp; 875 struct window_customize_modedata *data; 876 struct screen *s; 877 878 wme->data = data = xcalloc(1, sizeof *data); 879 data->wp = wp; 880 data->references = 1; 881 882 memcpy(&data->fs, fs, sizeof data->fs); 883 884 if (args == NULL || !args_has(args, 'F')) 885 data->format = xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT); 886 else 887 data->format = xstrdup(args_get(args, 'F')); 888 889 data->data = mode_tree_start(wp, args, window_customize_build, 890 window_customize_draw, NULL, window_customize_menu, 891 window_customize_height, NULL, data, window_customize_menu_items, 892 NULL, 0, &s); 893 mode_tree_zoom(data->data, args); 894 895 mode_tree_build(data->data); 896 mode_tree_draw(data->data); 897 898 return (s); 899 } 900 901 static void 902 window_customize_destroy(struct window_customize_modedata *data) 903 { 904 u_int i; 905 906 if (--data->references != 0) 907 return; 908 909 for (i = 0; i < data->item_size; i++) 910 window_customize_free_item(data->item_list[i]); 911 free(data->item_list); 912 913 free(data->format); 914 915 free(data); 916 } 917 918 static void 919 window_customize_free(struct window_mode_entry *wme) 920 { 921 struct window_customize_modedata *data = wme->data; 922 923 if (data == NULL) 924 return; 925 926 data->dead = 1; 927 mode_tree_free(data->data); 928 window_customize_destroy(data); 929 } 930 931 static void 932 window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy) 933 { 934 struct window_customize_modedata *data = wme->data; 935 936 mode_tree_resize(data->data, sx, sy); 937 } 938 939 static void 940 window_customize_free_callback(void *modedata) 941 { 942 window_customize_destroy(modedata); 943 } 944 945 static void 946 window_customize_free_item_callback(void *itemdata) 947 { 948 struct window_customize_itemdata *item = itemdata; 949 struct window_customize_modedata *data = item->data; 950 951 window_customize_free_item(item); 952 window_customize_destroy(data); 953 } 954 955 static int 956 window_customize_set_option_callback(struct client *c, void *itemdata, 957 const char *s, __unused int done) 958 { 959 struct window_customize_itemdata *item = itemdata; 960 struct window_customize_modedata *data = item->data; 961 struct options_entry *o; 962 const struct options_table_entry *oe; 963 struct options *oo = item->oo; 964 const char *name = item->name; 965 char *cause; 966 int idx = item->idx; 967 968 if (s == NULL || *s == '\0' || data->dead) 969 return (0); 970 if (item == NULL || !window_customize_check_item(data, item, NULL)) 971 return (0); 972 o = options_get(oo, name); 973 if (o == NULL) 974 return (0); 975 oe = options_table_entry(o); 976 977 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 978 if (idx == -1) { 979 for (idx = 0; idx < INT_MAX; idx++) { 980 if (options_array_get(o, idx) == NULL) 981 break; 982 } 983 } 984 if (options_array_set(o, idx, s, 0, &cause) != 0) 985 goto fail; 986 } else { 987 if (options_from_string(oo, oe, name, s, 0, &cause) != 0) 988 goto fail; 989 } 990 991 options_push_changes(item->name); 992 mode_tree_build(data->data); 993 mode_tree_draw(data->data); 994 data->wp->flags |= PANE_REDRAW; 995 996 return (0); 997 998 fail: 999 *cause = toupper((u_char)*cause); 1000 status_message_set(c, -1, 1, 0, "%s", cause); 1001 free(cause); 1002 return (0); 1003 } 1004 1005 static void 1006 window_customize_set_option(struct client *c, 1007 struct window_customize_modedata *data, 1008 struct window_customize_itemdata *item, int global, int pane) 1009 { 1010 struct options_entry *o; 1011 const struct options_table_entry *oe; 1012 struct options *oo; 1013 struct window_customize_itemdata *new_item; 1014 int flag, idx = item->idx; 1015 enum window_customize_scope scope = WINDOW_CUSTOMIZE_NONE; 1016 u_int choice; 1017 const char *name = item->name, *space = ""; 1018 char *prompt, *value, *text; 1019 struct cmd_find_state fs; 1020 1021 if (item == NULL || !window_customize_check_item(data, item, &fs)) 1022 return; 1023 o = options_get(item->oo, name); 1024 if (o == NULL) 1025 return; 1026 1027 oe = options_table_entry(o); 1028 if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE) 1029 pane = 0; 1030 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 1031 scope = item->scope; 1032 oo = item->oo; 1033 } else { 1034 if (global) { 1035 switch (item->scope) { 1036 case WINDOW_CUSTOMIZE_NONE: 1037 case WINDOW_CUSTOMIZE_KEY: 1038 case WINDOW_CUSTOMIZE_SERVER: 1039 case WINDOW_CUSTOMIZE_GLOBAL_SESSION: 1040 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: 1041 scope = item->scope; 1042 break; 1043 case WINDOW_CUSTOMIZE_SESSION: 1044 scope = WINDOW_CUSTOMIZE_GLOBAL_SESSION; 1045 break; 1046 case WINDOW_CUSTOMIZE_WINDOW: 1047 case WINDOW_CUSTOMIZE_PANE: 1048 scope = WINDOW_CUSTOMIZE_GLOBAL_WINDOW; 1049 break; 1050 } 1051 } else { 1052 switch (item->scope) { 1053 case WINDOW_CUSTOMIZE_NONE: 1054 case WINDOW_CUSTOMIZE_KEY: 1055 case WINDOW_CUSTOMIZE_SERVER: 1056 case WINDOW_CUSTOMIZE_SESSION: 1057 scope = item->scope; 1058 break; 1059 case WINDOW_CUSTOMIZE_WINDOW: 1060 case WINDOW_CUSTOMIZE_PANE: 1061 if (pane) 1062 scope = WINDOW_CUSTOMIZE_PANE; 1063 else 1064 scope = WINDOW_CUSTOMIZE_WINDOW; 1065 break; 1066 case WINDOW_CUSTOMIZE_GLOBAL_SESSION: 1067 scope = WINDOW_CUSTOMIZE_SESSION; 1068 break; 1069 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: 1070 if (pane) 1071 scope = WINDOW_CUSTOMIZE_PANE; 1072 else 1073 scope = WINDOW_CUSTOMIZE_WINDOW; 1074 break; 1075 } 1076 } 1077 if (scope == item->scope) 1078 oo = item->oo; 1079 else 1080 oo = window_customize_get_tree(scope, &fs); 1081 } 1082 1083 if (oe != NULL && oe->type == OPTIONS_TABLE_FLAG) { 1084 flag = options_get_number(oo, name); 1085 options_set_number(oo, name, !flag); 1086 } else if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) { 1087 choice = options_get_number(oo, name); 1088 if (oe->choices[choice + 1] == NULL) 1089 choice = 0; 1090 else 1091 choice++; 1092 options_set_number(oo, name, choice); 1093 } else { 1094 text = window_customize_scope_text(scope, &fs); 1095 if (*text != '\0') 1096 space = ", for "; 1097 else if (scope != WINDOW_CUSTOMIZE_SERVER) 1098 space = ", global"; 1099 if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 1100 if (idx == -1) { 1101 xasprintf(&prompt, "(%s[+]%s%s) ", name, space, 1102 text); 1103 } else { 1104 xasprintf(&prompt, "(%s[%d]%s%s) ", name, idx, 1105 space, text); 1106 } 1107 } else 1108 xasprintf(&prompt, "(%s%s%s) ", name, space, text); 1109 free(text); 1110 1111 value = options_to_string(o, idx, 0); 1112 1113 new_item = xcalloc(1, sizeof *new_item); 1114 new_item->data = data; 1115 new_item->scope = scope; 1116 new_item->oo = oo; 1117 new_item->name = xstrdup(name); 1118 new_item->idx = idx; 1119 1120 data->references++; 1121 status_prompt_set(c, NULL, prompt, value, 1122 window_customize_set_option_callback, 1123 window_customize_free_item_callback, new_item, 1124 PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1125 1126 free(prompt); 1127 free(value); 1128 } 1129 } 1130 1131 static void 1132 window_customize_unset_option(struct window_customize_modedata *data, 1133 struct window_customize_itemdata *item) 1134 { 1135 struct options_entry *o; 1136 1137 if (item == NULL || !window_customize_check_item(data, item, NULL)) 1138 return; 1139 1140 o = options_get(item->oo, item->name); 1141 if (o == NULL) 1142 return; 1143 if (item->idx != -1 && item == mode_tree_get_current(data->data)) 1144 mode_tree_up(data->data, 0); 1145 options_remove_or_default(o, item->idx, NULL); 1146 } 1147 1148 static void 1149 window_customize_reset_option(struct window_customize_modedata *data, 1150 struct window_customize_itemdata *item) 1151 { 1152 struct options *oo; 1153 struct options_entry *o; 1154 1155 if (item == NULL || !window_customize_check_item(data, item, NULL)) 1156 return; 1157 if (item->idx != -1) 1158 return; 1159 1160 oo = item->oo; 1161 while (oo != NULL) { 1162 o = options_get_only(item->oo, item->name); 1163 if (o != NULL) 1164 options_remove_or_default(o, -1, NULL); 1165 oo = options_get_parent(oo); 1166 } 1167 } 1168 1169 static int 1170 window_customize_set_command_callback(struct client *c, void *itemdata, 1171 const char *s, __unused int done) 1172 { 1173 struct window_customize_itemdata *item = itemdata; 1174 struct window_customize_modedata *data = item->data; 1175 struct key_binding *bd; 1176 struct cmd_parse_result *pr; 1177 char *error; 1178 1179 if (s == NULL || *s == '\0' || data->dead) 1180 return (0); 1181 if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 1182 return (0); 1183 1184 pr = cmd_parse_from_string(s, NULL); 1185 switch (pr->status) { 1186 case CMD_PARSE_ERROR: 1187 error = pr->error; 1188 goto fail; 1189 case CMD_PARSE_SUCCESS: 1190 break; 1191 } 1192 cmd_list_free(bd->cmdlist); 1193 bd->cmdlist = pr->cmdlist; 1194 1195 mode_tree_build(data->data); 1196 mode_tree_draw(data->data); 1197 data->wp->flags |= PANE_REDRAW; 1198 1199 return (0); 1200 1201 fail: 1202 *error = toupper((u_char)*error); 1203 status_message_set(c, -1, 1, 0, "%s", error); 1204 free(error); 1205 return (0); 1206 } 1207 1208 static int 1209 window_customize_set_note_callback(__unused struct client *c, void *itemdata, 1210 const char *s, __unused int done) 1211 { 1212 struct window_customize_itemdata *item = itemdata; 1213 struct window_customize_modedata *data = item->data; 1214 struct key_binding *bd; 1215 1216 if (s == NULL || *s == '\0' || data->dead) 1217 return (0); 1218 if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 1219 return (0); 1220 1221 free((void *)bd->note); 1222 bd->note = xstrdup(s); 1223 1224 mode_tree_build(data->data); 1225 mode_tree_draw(data->data); 1226 data->wp->flags |= PANE_REDRAW; 1227 1228 return (0); 1229 } 1230 1231 static void 1232 window_customize_set_key(struct client *c, 1233 struct window_customize_modedata *data, 1234 struct window_customize_itemdata *item) 1235 { 1236 key_code key = item->key; 1237 struct key_binding *bd; 1238 const char *s; 1239 char *prompt, *value; 1240 struct window_customize_itemdata *new_item; 1241 1242 if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 1243 return; 1244 1245 s = mode_tree_get_current_name(data->data); 1246 if (strcmp(s, "Repeat") == 0) 1247 bd->flags ^= KEY_BINDING_REPEAT; 1248 else if (strcmp(s, "Command") == 0) { 1249 xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 1250 value = cmd_list_print(bd->cmdlist, 0); 1251 1252 new_item = xcalloc(1, sizeof *new_item); 1253 new_item->data = data; 1254 new_item->scope = item->scope; 1255 new_item->table = xstrdup(item->table); 1256 new_item->key = key; 1257 1258 data->references++; 1259 status_prompt_set(c, NULL, prompt, value, 1260 window_customize_set_command_callback, 1261 window_customize_free_item_callback, new_item, 1262 PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1263 free(prompt); 1264 free(value); 1265 } else if (strcmp(s, "Note") == 0) { 1266 xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 1267 1268 new_item = xcalloc(1, sizeof *new_item); 1269 new_item->data = data; 1270 new_item->scope = item->scope; 1271 new_item->table = xstrdup(item->table); 1272 new_item->key = key; 1273 1274 data->references++; 1275 status_prompt_set(c, NULL, prompt, 1276 (bd->note == NULL ? "" : bd->note), 1277 window_customize_set_note_callback, 1278 window_customize_free_item_callback, new_item, 1279 PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1280 free(prompt); 1281 } 1282 } 1283 1284 static void 1285 window_customize_unset_key(struct window_customize_modedata *data, 1286 struct window_customize_itemdata *item) 1287 { 1288 struct key_table *kt; 1289 struct key_binding *bd; 1290 1291 if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 1292 return; 1293 1294 if (item == mode_tree_get_current(data->data)) { 1295 mode_tree_collapse_current(data->data); 1296 mode_tree_up(data->data, 0); 1297 } 1298 key_bindings_remove(kt->name, bd->key); 1299 } 1300 1301 static void 1302 window_customize_reset_key(struct window_customize_modedata *data, 1303 struct window_customize_itemdata *item) 1304 { 1305 struct key_table *kt; 1306 struct key_binding *dd, *bd; 1307 1308 if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 1309 return; 1310 1311 dd = key_bindings_get_default(kt, bd->key); 1312 if (dd != NULL && bd->cmdlist == dd->cmdlist) 1313 return; 1314 if (dd == NULL && item == mode_tree_get_current(data->data)) { 1315 mode_tree_collapse_current(data->data); 1316 mode_tree_up(data->data, 0); 1317 } 1318 key_bindings_reset(kt->name, bd->key); 1319 } 1320 1321 static void 1322 window_customize_change_each(void *modedata, void *itemdata, 1323 __unused struct client *c, __unused key_code key) 1324 { 1325 struct window_customize_modedata *data = modedata; 1326 struct window_customize_itemdata *item = itemdata; 1327 1328 switch (data->change) { 1329 case WINDOW_CUSTOMIZE_UNSET: 1330 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1331 window_customize_unset_key(data, item); 1332 else 1333 window_customize_unset_option(data, item); 1334 break; 1335 case WINDOW_CUSTOMIZE_RESET: 1336 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1337 window_customize_reset_key(data, item); 1338 else 1339 window_customize_reset_option(data, item); 1340 break; 1341 } 1342 if (item->scope != WINDOW_CUSTOMIZE_KEY) 1343 options_push_changes(item->name); 1344 } 1345 1346 static int 1347 window_customize_change_current_callback(__unused struct client *c, 1348 void *modedata, const char *s, __unused int done) 1349 { 1350 struct window_customize_modedata *data = modedata; 1351 struct window_customize_itemdata *item; 1352 1353 if (s == NULL || *s == '\0' || data->dead) 1354 return (0); 1355 if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 1356 return (0); 1357 1358 item = mode_tree_get_current(data->data); 1359 switch (data->change) { 1360 case WINDOW_CUSTOMIZE_UNSET: 1361 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1362 window_customize_unset_key(data, item); 1363 else 1364 window_customize_unset_option(data, item); 1365 break; 1366 case WINDOW_CUSTOMIZE_RESET: 1367 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1368 window_customize_reset_key(data, item); 1369 else 1370 window_customize_reset_option(data, item); 1371 break; 1372 } 1373 if (item->scope != WINDOW_CUSTOMIZE_KEY) 1374 options_push_changes(item->name); 1375 mode_tree_build(data->data); 1376 mode_tree_draw(data->data); 1377 data->wp->flags |= PANE_REDRAW; 1378 1379 return (0); 1380 } 1381 1382 static int 1383 window_customize_change_tagged_callback(struct client *c, void *modedata, 1384 const char *s, __unused int done) 1385 { 1386 struct window_customize_modedata *data = modedata; 1387 1388 if (s == NULL || *s == '\0' || data->dead) 1389 return (0); 1390 if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 1391 return (0); 1392 1393 mode_tree_each_tagged(data->data, window_customize_change_each, c, 1394 KEYC_NONE, 0); 1395 mode_tree_build(data->data); 1396 mode_tree_draw(data->data); 1397 data->wp->flags |= PANE_REDRAW; 1398 1399 return (0); 1400 } 1401 1402 static void 1403 window_customize_key(struct window_mode_entry *wme, struct client *c, 1404 __unused struct session *s, __unused struct winlink *wl, key_code key, 1405 struct mouse_event *m) 1406 { 1407 struct window_pane *wp = wme->wp; 1408 struct window_customize_modedata *data = wme->data; 1409 struct window_customize_itemdata *item, *new_item; 1410 int finished, idx; 1411 char *prompt; 1412 u_int tagged; 1413 1414 item = mode_tree_get_current(data->data); 1415 finished = mode_tree_key(data->data, c, &key, m, NULL, NULL); 1416 if (item != (new_item = mode_tree_get_current(data->data))) 1417 item = new_item; 1418 1419 switch (key) { 1420 case '\r': 1421 case 's': 1422 if (item == NULL) 1423 break; 1424 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1425 window_customize_set_key(c, data, item); 1426 else { 1427 window_customize_set_option(c, data, item, 0, 1); 1428 options_push_changes(item->name); 1429 } 1430 mode_tree_build(data->data); 1431 break; 1432 case 'w': 1433 if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 1434 break; 1435 window_customize_set_option(c, data, item, 0, 0); 1436 options_push_changes(item->name); 1437 mode_tree_build(data->data); 1438 break; 1439 case 'S': 1440 case 'W': 1441 if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 1442 break; 1443 window_customize_set_option(c, data, item, 1, 0); 1444 options_push_changes(item->name); 1445 mode_tree_build(data->data); 1446 break; 1447 case 'd': 1448 if (item == NULL || item->idx != -1) 1449 break; 1450 xasprintf(&prompt, "Reset %s to default? ", item->name); 1451 data->references++; 1452 data->change = WINDOW_CUSTOMIZE_RESET; 1453 status_prompt_set(c, NULL, prompt, "", 1454 window_customize_change_current_callback, 1455 window_customize_free_callback, data, 1456 PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1457 free(prompt); 1458 break; 1459 case 'D': 1460 tagged = mode_tree_count_tagged(data->data); 1461 if (tagged == 0) 1462 break; 1463 xasprintf(&prompt, "Reset %u tagged to default? ", tagged); 1464 data->references++; 1465 data->change = WINDOW_CUSTOMIZE_RESET; 1466 status_prompt_set(c, NULL, prompt, "", 1467 window_customize_change_tagged_callback, 1468 window_customize_free_callback, data, 1469 PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1470 free(prompt); 1471 break; 1472 case 'u': 1473 if (item == NULL) 1474 break; 1475 idx = item->idx; 1476 if (idx != -1) 1477 xasprintf(&prompt, "Unset %s[%d]? ", item->name, idx); 1478 else 1479 xasprintf(&prompt, "Unset %s? ", item->name); 1480 data->references++; 1481 data->change = WINDOW_CUSTOMIZE_UNSET; 1482 status_prompt_set(c, NULL, prompt, "", 1483 window_customize_change_current_callback, 1484 window_customize_free_callback, data, 1485 PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1486 free(prompt); 1487 break; 1488 case 'U': 1489 tagged = mode_tree_count_tagged(data->data); 1490 if (tagged == 0) 1491 break; 1492 xasprintf(&prompt, "Unset %u tagged? ", tagged); 1493 data->references++; 1494 data->change = WINDOW_CUSTOMIZE_UNSET; 1495 status_prompt_set(c, NULL, prompt, "", 1496 window_customize_change_tagged_callback, 1497 window_customize_free_callback, data, 1498 PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 1499 free(prompt); 1500 break; 1501 case 'H': 1502 data->hide_global = !data->hide_global; 1503 mode_tree_build(data->data); 1504 break; 1505 } 1506 if (finished) 1507 window_pane_reset_mode(wp); 1508 else { 1509 mode_tree_draw(data->data); 1510 wp->flags |= PANE_REDRAW; 1511 } 1512 } 1513