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