1 /* $OpenBSD: window-customize.c,v 1.8 2021/01/18 11:14:24 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(oo0, list[i]); 402 if (o == NULL && oo1 != NULL) 403 o = options_get(oo1, list[i]); 404 if (o == NULL) 405 o = options_get(oo2, 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) 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, 893 window_customize_height, data, window_customize_menu_items, NULL, 0, 894 &s); 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); 1002 status_message_set(c, -1, 1, "%s", cause); 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; 1017 enum window_customize_scope scope = WINDOW_CUSTOMIZE_NONE; 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); 1030 if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE) 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++; 1123 status_prompt_set(c, NULL, prompt, value, 1124 window_customize_set_option_callback, 1125 window_customize_free_item_callback, new_item, 1126 PROMPT_NOFORMAT); 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 { 1137 struct options_entry *o; 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; 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) 1160 return; 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); 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_EMPTY: 1189 error = xstrdup("empty command"); 1190 goto fail; 1191 case CMD_PARSE_ERROR: 1192 error = pr->error; 1193 goto fail; 1194 case CMD_PARSE_SUCCESS: 1195 break; 1196 } 1197 cmd_list_free(bd->cmdlist); 1198 bd->cmdlist = pr->cmdlist; 1199 1200 mode_tree_build(data->data); 1201 mode_tree_draw(data->data); 1202 data->wp->flags |= PANE_REDRAW; 1203 1204 return (0); 1205 1206 fail: 1207 *error = toupper((u_char)*error); 1208 status_message_set(c, -1, 1, "%s", error); 1209 free(error); 1210 return (0); 1211 } 1212 1213 static int 1214 window_customize_set_note_callback(__unused struct client *c, void *itemdata, 1215 const char *s, __unused int done) 1216 { 1217 struct window_customize_itemdata *item = itemdata; 1218 struct window_customize_modedata *data = item->data; 1219 struct key_binding *bd; 1220 1221 if (s == NULL || *s == '\0' || data->dead) 1222 return (0); 1223 if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 1224 return (0); 1225 1226 free((void *)bd->note); 1227 bd->note = xstrdup(s); 1228 1229 mode_tree_build(data->data); 1230 mode_tree_draw(data->data); 1231 data->wp->flags |= PANE_REDRAW; 1232 1233 return (0); 1234 } 1235 1236 static void 1237 window_customize_set_key(struct client *c, 1238 struct window_customize_modedata *data, 1239 struct window_customize_itemdata *item) 1240 { 1241 key_code key = item->key; 1242 struct key_binding *bd; 1243 const char *s; 1244 char *prompt, *value; 1245 struct window_customize_itemdata *new_item; 1246 1247 if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 1248 return; 1249 1250 s = mode_tree_get_current_name(data->data); 1251 if (strcmp(s, "Repeat") == 0) 1252 bd->flags ^= KEY_BINDING_REPEAT; 1253 else if (strcmp(s, "Command") == 0) { 1254 xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 1255 value = cmd_list_print(bd->cmdlist, 0); 1256 1257 new_item = xcalloc(1, sizeof *new_item); 1258 new_item->data = data; 1259 new_item->scope = item->scope; 1260 new_item->table = xstrdup(item->table); 1261 new_item->key = key; 1262 1263 data->references++; 1264 status_prompt_set(c, NULL, prompt, value, 1265 window_customize_set_command_callback, 1266 window_customize_free_item_callback, new_item, 1267 PROMPT_NOFORMAT); 1268 free(prompt); 1269 free(value); 1270 } else if (strcmp(s, "Note") == 0) { 1271 xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 1272 1273 new_item = xcalloc(1, sizeof *new_item); 1274 new_item->data = data; 1275 new_item->scope = item->scope; 1276 new_item->table = xstrdup(item->table); 1277 new_item->key = key; 1278 1279 data->references++; 1280 status_prompt_set(c, NULL, prompt, 1281 (bd->note == NULL ? "" : bd->note), 1282 window_customize_set_note_callback, 1283 window_customize_free_item_callback, new_item, 1284 PROMPT_NOFORMAT); 1285 free(prompt); 1286 } 1287 } 1288 1289 static void 1290 window_customize_unset_key(struct window_customize_modedata *data, 1291 struct window_customize_itemdata *item) 1292 { 1293 struct key_table *kt; 1294 struct key_binding *bd; 1295 1296 if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 1297 return; 1298 1299 if (item == mode_tree_get_current(data->data)) { 1300 mode_tree_collapse_current(data->data); 1301 mode_tree_up(data->data, 0); 1302 } 1303 key_bindings_remove(kt->name, bd->key); 1304 } 1305 1306 static void 1307 window_customize_reset_key(struct window_customize_modedata *data, 1308 struct window_customize_itemdata *item) 1309 { 1310 struct key_table *kt; 1311 struct key_binding *dd, *bd; 1312 1313 if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 1314 return; 1315 1316 dd = key_bindings_get_default(kt, bd->key); 1317 if (dd != NULL && bd->cmdlist == dd->cmdlist) 1318 return; 1319 if (dd == NULL && item == mode_tree_get_current(data->data)) { 1320 mode_tree_collapse_current(data->data); 1321 mode_tree_up(data->data, 0); 1322 } 1323 key_bindings_reset(kt->name, bd->key); 1324 } 1325 1326 static void 1327 window_customize_change_each(void *modedata, void *itemdata, 1328 __unused struct client *c, __unused key_code key) 1329 { 1330 struct window_customize_modedata *data = modedata; 1331 struct window_customize_itemdata *item = itemdata; 1332 1333 switch (data->change) { 1334 case WINDOW_CUSTOMIZE_UNSET: 1335 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1336 window_customize_unset_key(data, item); 1337 else 1338 window_customize_unset_option(data, item); 1339 break; 1340 case WINDOW_CUSTOMIZE_RESET: 1341 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1342 window_customize_reset_key(data, item); 1343 else 1344 window_customize_reset_option(data, item); 1345 break; 1346 } 1347 if (item->scope != WINDOW_CUSTOMIZE_KEY) 1348 options_push_changes(item->name); 1349 } 1350 1351 static int 1352 window_customize_change_current_callback(__unused struct client *c, 1353 void *modedata, const char *s, __unused int done) 1354 { 1355 struct window_customize_modedata *data = modedata; 1356 struct window_customize_itemdata *item; 1357 1358 if (s == NULL || *s == '\0' || data->dead) 1359 return (0); 1360 if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 1361 return (0); 1362 1363 item = mode_tree_get_current(data->data); 1364 switch (data->change) { 1365 case WINDOW_CUSTOMIZE_UNSET: 1366 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1367 window_customize_unset_key(data, item); 1368 else 1369 window_customize_unset_option(data, item); 1370 break; 1371 case WINDOW_CUSTOMIZE_RESET: 1372 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1373 window_customize_reset_key(data, item); 1374 else 1375 window_customize_reset_option(data, item); 1376 break; 1377 } 1378 if (item->scope != WINDOW_CUSTOMIZE_KEY) 1379 options_push_changes(item->name); 1380 mode_tree_build(data->data); 1381 mode_tree_draw(data->data); 1382 data->wp->flags |= PANE_REDRAW; 1383 1384 return (0); 1385 } 1386 1387 static int 1388 window_customize_change_tagged_callback(struct client *c, void *modedata, 1389 const char *s, __unused int done) 1390 { 1391 struct window_customize_modedata *data = modedata; 1392 1393 if (s == NULL || *s == '\0' || data->dead) 1394 return (0); 1395 if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 1396 return (0); 1397 1398 mode_tree_each_tagged(data->data, window_customize_change_each, c, 1399 KEYC_NONE, 0); 1400 mode_tree_build(data->data); 1401 mode_tree_draw(data->data); 1402 data->wp->flags |= PANE_REDRAW; 1403 1404 return (0); 1405 } 1406 1407 static void 1408 window_customize_key(struct window_mode_entry *wme, struct client *c, 1409 __unused struct session *s, __unused struct winlink *wl, key_code key, 1410 struct mouse_event *m) 1411 { 1412 struct window_pane *wp = wme->wp; 1413 struct window_customize_modedata *data = wme->data; 1414 struct window_customize_itemdata *item, *new_item; 1415 int finished, idx; 1416 char *prompt; 1417 u_int tagged; 1418 1419 item = mode_tree_get_current(data->data); 1420 finished = mode_tree_key(data->data, c, &key, m, NULL, NULL); 1421 if (item != (new_item = mode_tree_get_current(data->data))) 1422 item = new_item; 1423 1424 switch (key) { 1425 case '\r': 1426 case 's': 1427 if (item == NULL) 1428 break; 1429 if (item->scope == WINDOW_CUSTOMIZE_KEY) 1430 window_customize_set_key(c, data, item); 1431 else { 1432 window_customize_set_option(c, data, item, 0, 1); 1433 options_push_changes(item->name); 1434 } 1435 mode_tree_build(data->data); 1436 break; 1437 case 'w': 1438 if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 1439 break; 1440 window_customize_set_option(c, data, item, 0, 0); 1441 options_push_changes(item->name); 1442 mode_tree_build(data->data); 1443 break; 1444 case 'S': 1445 case 'W': 1446 if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 1447 break; 1448 window_customize_set_option(c, data, item, 1, 0); 1449 options_push_changes(item->name); 1450 mode_tree_build(data->data); 1451 break; 1452 case 'd': 1453 if (item == NULL || item->idx != -1) 1454 break; 1455 xasprintf(&prompt, "Reset %s to default? ", item->name); 1456 data->references++; 1457 data->change = WINDOW_CUSTOMIZE_RESET; 1458 status_prompt_set(c, NULL, prompt, "", 1459 window_customize_change_current_callback, 1460 window_customize_free_callback, data, 1461 PROMPT_SINGLE|PROMPT_NOFORMAT); 1462 free(prompt); 1463 break; 1464 case 'D': 1465 tagged = mode_tree_count_tagged(data->data); 1466 if (tagged == 0) 1467 break; 1468 xasprintf(&prompt, "Reset %u tagged to default? ", tagged); 1469 data->references++; 1470 data->change = WINDOW_CUSTOMIZE_RESET; 1471 status_prompt_set(c, NULL, prompt, "", 1472 window_customize_change_tagged_callback, 1473 window_customize_free_callback, data, 1474 PROMPT_SINGLE|PROMPT_NOFORMAT); 1475 free(prompt); 1476 break; 1477 case 'u': 1478 if (item == NULL) 1479 break; 1480 idx = item->idx; 1481 if (idx != -1) 1482 xasprintf(&prompt, "Unset %s[%d]? ", item->name, idx); 1483 else 1484 xasprintf(&prompt, "Unset %s? ", item->name); 1485 data->references++; 1486 data->change = WINDOW_CUSTOMIZE_UNSET; 1487 status_prompt_set(c, NULL, prompt, "", 1488 window_customize_change_current_callback, 1489 window_customize_free_callback, data, 1490 PROMPT_SINGLE|PROMPT_NOFORMAT); 1491 free(prompt); 1492 break; 1493 case 'U': 1494 tagged = mode_tree_count_tagged(data->data); 1495 if (tagged == 0) 1496 break; 1497 xasprintf(&prompt, "Unset %u tagged? ", tagged); 1498 data->references++; 1499 data->change = WINDOW_CUSTOMIZE_UNSET; 1500 status_prompt_set(c, NULL, prompt, "", 1501 window_customize_change_tagged_callback, 1502 window_customize_free_callback, data, 1503 PROMPT_SINGLE|PROMPT_NOFORMAT); 1504 free(prompt); 1505 break; 1506 case 'H': 1507 data->hide_global = !data->hide_global; 1508 mode_tree_build(data->data); 1509 break; 1510 } 1511 if (finished) 1512 window_pane_reset_mode(wp); 1513 else { 1514 mode_tree_draw(data->data); 1515 wp->flags |= PANE_REDRAW; 1516 } 1517 } 1518