Merge branch 'obsd-master'
[tmux.git] / window-customize.c
blob387254e0ca965ea8664481bc25f5e97c1addf0c5
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "tmux.h"
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 *);
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 "}"
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 },
55 { NULL, KEYC_NONE, NULL }
58 const struct window_mode window_customize_mode = {
59 .name = "options-mode",
60 .default_format = WINDOW_CUSTOMIZE_DEFAULT_FORMAT,
62 .init = window_customize_init,
63 .free = window_customize_free,
64 .resize = window_customize_resize,
65 .key = window_customize_key,
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
79 enum window_customize_change {
80 WINDOW_CUSTOMIZE_UNSET,
81 WINDOW_CUSTOMIZE_RESET,
84 struct window_customize_itemdata {
85 struct window_customize_modedata *data;
86 enum window_customize_scope scope;
88 char *table;
89 key_code key;
91 struct options *oo;
92 char *name;
93 int idx;
96 struct window_customize_modedata {
97 struct window_pane *wp;
98 int dead;
99 int references;
101 struct mode_tree_data *data;
102 char *format;
103 int hide_global;
104 int prompt_flags;
106 struct window_customize_itemdata **item_list;
107 u_int item_size;
109 struct cmd_find_state fs;
110 enum window_customize_change change;
113 static uint64_t
114 window_customize_get_tag(struct options_entry *o, int idx,
115 const struct options_table_entry *oe)
117 uint64_t offset;
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);
125 static struct options *
126 window_customize_get_tree(enum window_customize_scope scope,
127 struct cmd_find_state *fs)
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);
146 return (NULL);
149 static int
150 window_customize_check_item(struct window_customize_modedata *data,
151 struct window_customize_itemdata *item, struct cmd_find_state *fsp)
153 struct cmd_find_state fs;
155 if (fsp == NULL)
156 fsp = &fs;
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));
165 static int
166 window_customize_get_key(struct window_customize_itemdata *item,
167 struct key_table **ktp, struct key_binding **bdp)
169 struct key_table *kt;
170 struct key_binding *bd;
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);
179 if (ktp != NULL)
180 *ktp = kt;
181 if (bdp != NULL)
182 *bdp = bd;
183 return (1);
186 static char *
187 window_customize_scope_text(enum window_customize_scope scope,
188 struct cmd_find_state *fs)
190 char *s;
191 u_int idx;
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;
208 return (s);
211 static struct window_customize_itemdata *
212 window_customize_add_item(struct window_customize_modedata *data)
214 struct window_customize_itemdata *item;
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);
222 static void
223 window_customize_free_item(struct window_customize_itemdata *item)
225 free(item->table);
226 free(item->name);
227 free(item);
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)
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;
243 ai = options_array_first(o);
244 while (ai != NULL) {
245 idx = options_array_item_index(ai);
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);
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;
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);
263 free(name);
264 free(value);
266 ai = options_array_next(ai);
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)
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;
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;
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;
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);
300 text = window_customize_scope_text(scope, fs);
301 format_add(ft, "option_scope", "%s", text);
302 free(text);
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", "");
309 if (!array) {
310 value = options_to_string(o, -1, 0);
311 format_add(ft, "option_value", "%s", value);
312 free(value);
315 if (filter != NULL) {
316 expanded = format_expand(ft, filter);
317 if (!format_true(expanded)) {
318 free(expanded);
319 return;
321 free(expanded);
323 item = window_customize_add_item(data);
324 item->oo = oo;
325 item->scope = scope;
326 item->name = xstrdup(name);
327 item->idx = -1;
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);
337 if (array)
338 window_customize_build_array(data, top, scope, o, ft);
341 static void
342 window_customize_find_user_options(struct options *oo, const char ***list,
343 u_int *size)
345 struct options_entry *o;
346 const char *name;
347 u_int i;
349 o = options_first(oo);
350 while (o != NULL) {
351 name = options_name(o);
352 if (*name != '@') {
353 o = options_next(o);
354 continue;
356 for (i = 0; i < *size; i++) {
357 if (strcmp((*list)[i], name) == 0)
358 break;
360 if (i != *size) {
361 o = options_next(o);
362 continue;
364 *list = xreallocarray(*list, (*size) + 1, sizeof **list);
365 (*list)[(*size)++] = name;
367 o = options_next(o);
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)
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;
385 top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
386 mode_tree_no_tag(top);
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.
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);
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);
416 free(list);
418 loop = options_first(oo0);
419 while (loop != NULL) {
420 name = options_name(loop);
421 if (*name == '@') {
422 loop = options_next(loop);
423 continue;
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);
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)
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;
455 tag = (1ULL << 62)|((uint64_t)number << 54)|1;
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);
462 ft = format_create_from_state(NULL, NULL, fs);
463 format_add(ft, "is_option", "0");
464 format_add(ft, "is_key", "1");
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;
477 free(expanded);
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;
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);
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);
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);
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);
520 bd = key_bindings_next(kt, bd);
523 format_free(ft);
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)
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;
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;
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);
548 ft = format_create_from_state(NULL, NULL, &fs);
549 format_add(ft, "is_option", "1");
550 format_add(ft, "is_key", "0");
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);
571 format_free(ft);
572 ft = format_create_from_state(NULL, NULL, &fs);
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,
580 if (++i == 256)
581 break;
583 kt = key_bindings_next_table(kt);
586 format_free(ft);
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)
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;
601 if (item == NULL || !window_customize_get_key(item, &kt, &bd))
602 return;
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;
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;
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;
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;
643 free(default_cmd);
645 free(cmd);
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)
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;
668 if (!window_customize_check_item(data, item, &fs))
669 return;
670 name = item->name;
671 idx = item->idx;
673 o = options_get(item->oo, name);
674 if (o == NULL)
675 return;
676 oe = options_table_entry(o);
678 if (oe != NULL && oe->unit != NULL) {
679 space = " ";
680 unit = oe->unit;
682 ft = format_create_from_state(NULL, NULL, &fs);
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;
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;
720 if (idx == -1)
721 goto out;
723 screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
724 if (s->cy >= cy + sy - 1)
725 goto out;
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;
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;
746 free(expanded);
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);
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;
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;
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;
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;
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;
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;
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;
830 out:
831 free(value);
832 free(default_value);
833 format_free(ft);
836 static void
837 window_customize_draw(void *modedata, void *itemdata,
838 struct screen_write_ctx *ctx, u_int sx, u_int sy)
840 struct window_customize_modedata *data = modedata;
841 struct window_customize_itemdata *item = itemdata;
843 if (item == NULL)
844 return;
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);
852 static void
853 window_customize_menu(void *modedata, struct client *c, key_code key)
855 struct window_customize_modedata *data = modedata;
856 struct window_pane *wp = data->wp;
857 struct window_mode_entry *wme;
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);
865 static u_int
866 window_customize_height(__unused void *modedata, __unused u_int height)
868 return (12);
871 static struct screen *
872 window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
873 struct args *args)
875 struct window_pane *wp = wme->wp;
876 struct window_customize_modedata *data;
877 struct screen *s;
879 wme->data = data = xcalloc(1, sizeof *data);
880 data->wp = wp;
881 data->references = 1;
883 memcpy(&data->fs, fs, sizeof data->fs);
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;
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);
898 mode_tree_build(data->data);
899 mode_tree_draw(data->data);
901 return (s);
904 static void
905 window_customize_destroy(struct window_customize_modedata *data)
907 u_int i;
909 if (--data->references != 0)
910 return;
912 for (i = 0; i < data->item_size; i++)
913 window_customize_free_item(data->item_list[i]);
914 free(data->item_list);
916 free(data->format);
918 free(data);
921 static void
922 window_customize_free(struct window_mode_entry *wme)
924 struct window_customize_modedata *data = wme->data;
926 if (data == NULL)
927 return;
929 data->dead = 1;
930 mode_tree_free(data->data);
931 window_customize_destroy(data);
934 static void
935 window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
937 struct window_customize_modedata *data = wme->data;
939 mode_tree_resize(data->data, sx, sy);
942 static void
943 window_customize_free_callback(void *modedata)
945 window_customize_destroy(modedata);
948 static void
949 window_customize_free_item_callback(void *itemdata)
951 struct window_customize_itemdata *item = itemdata;
952 struct window_customize_modedata *data = item->data;
954 window_customize_free_item(item);
955 window_customize_destroy(data);
958 static int
959 window_customize_set_option_callback(struct client *c, void *itemdata,
960 const char *s, __unused int done)
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;
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);
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;
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;
994 options_push_changes(item->name);
995 mode_tree_build(data->data);
996 mode_tree_draw(data->data);
997 data->wp->flags |= PANE_REDRAW;
999 return (0);
1001 fail:
1002 *cause = toupper((u_char)*cause);
1003 status_message_set(c, -1, 1, 0, "%s", cause);
1004 free(cause);
1005 return (0);
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)
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;
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;
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;
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;
1080 if (scope == item->scope)
1081 oo = item->oo;
1082 else
1083 oo = window_customize_get_tree(scope, &fs);
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);
1110 } else
1111 xasprintf(&prompt, "(%s%s%s) ", name, space, text);
1112 free(text);
1114 value = options_to_string(o, idx, 0);
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;
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);
1129 free(prompt);
1130 free(value);
1134 static void
1135 window_customize_unset_option(struct window_customize_modedata *data,
1136 struct window_customize_itemdata *item)
1138 struct options_entry *o;
1140 if (item == NULL || !window_customize_check_item(data, item, NULL))
1141 return;
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);
1151 static void
1152 window_customize_reset_option(struct window_customize_modedata *data,
1153 struct window_customize_itemdata *item)
1155 struct options *oo;
1156 struct options_entry *o;
1158 if (item == NULL || !window_customize_check_item(data, item, NULL))
1159 return;
1160 if (item->idx != -1)
1161 return;
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);
1172 static int
1173 window_customize_set_command_callback(struct client *c, void *itemdata,
1174 const char *s, __unused int done)
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;
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);
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;
1195 cmd_list_free(bd->cmdlist);
1196 bd->cmdlist = pr->cmdlist;
1198 mode_tree_build(data->data);
1199 mode_tree_draw(data->data);
1200 data->wp->flags |= PANE_REDRAW;
1202 return (0);
1204 fail:
1205 *error = toupper((u_char)*error);
1206 status_message_set(c, -1, 1, 0, "%s", error);
1207 free(error);
1208 return (0);
1211 static int
1212 window_customize_set_note_callback(__unused struct client *c, void *itemdata,
1213 const char *s, __unused int done)
1215 struct window_customize_itemdata *item = itemdata;
1216 struct window_customize_modedata *data = item->data;
1217 struct key_binding *bd;
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);
1224 free((void *)bd->note);
1225 bd->note = xstrdup(s);
1227 mode_tree_build(data->data);
1228 mode_tree_draw(data->data);
1229 data->wp->flags |= PANE_REDRAW;
1231 return (0);
1234 static void
1235 window_customize_set_key(struct client *c,
1236 struct window_customize_modedata *data,
1237 struct window_customize_itemdata *item)
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;
1245 if (item == NULL || !window_customize_get_key(item, NULL, &bd))
1246 return;
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);
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;
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));
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;
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);
1287 static void
1288 window_customize_unset_key(struct window_customize_modedata *data,
1289 struct window_customize_itemdata *item)
1291 struct key_table *kt;
1292 struct key_binding *bd;
1294 if (item == NULL || !window_customize_get_key(item, &kt, &bd))
1295 return;
1297 if (item == mode_tree_get_current(data->data)) {
1298 mode_tree_collapse_current(data->data);
1299 mode_tree_up(data->data, 0);
1301 key_bindings_remove(kt->name, bd->key);
1304 static void
1305 window_customize_reset_key(struct window_customize_modedata *data,
1306 struct window_customize_itemdata *item)
1308 struct key_table *kt;
1309 struct key_binding *dd, *bd;
1311 if (item == NULL || !window_customize_get_key(item, &kt, &bd))
1312 return;
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);
1321 key_bindings_reset(kt->name, bd->key);
1324 static void
1325 window_customize_change_each(void *modedata, void *itemdata,
1326 __unused struct client *c, __unused key_code key)
1328 struct window_customize_modedata *data = modedata;
1329 struct window_customize_itemdata *item = itemdata;
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;
1345 if (item->scope != WINDOW_CUSTOMIZE_KEY)
1346 options_push_changes(item->name);
1349 static int
1350 window_customize_change_current_callback(__unused struct client *c,
1351 void *modedata, const char *s, __unused int done)
1353 struct window_customize_modedata *data = modedata;
1354 struct window_customize_itemdata *item;
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);
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;
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;
1382 return (0);
1385 static int
1386 window_customize_change_tagged_callback(struct client *c, void *modedata,
1387 const char *s, __unused int done)
1389 struct window_customize_modedata *data = modedata;
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);
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;
1402 return (0);
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)
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;
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;
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);
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;
1513 if (finished)
1514 window_pane_reset_mode(wp);
1515 else {
1516 mode_tree_draw(data->data);
1517 wp->flags |= PANE_REDRAW;