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