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