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>
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
*,
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 \
38 "#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \
40 "#{option_value}#{?option_unit, #{option_unit},}" \
45 static const struct menu_item window_customize_menu_items
[] = {
46 { "Select", '\r', NULL
},
47 { "Expand", KEYC_RIGHT
, NULL
},
48 { "", KEYC_NONE
, 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
,
71 WINDOW_CUSTOMIZE_SERVER
,
72 WINDOW_CUSTOMIZE_GLOBAL_SESSION
,
73 WINDOW_CUSTOMIZE_SESSION
,
74 WINDOW_CUSTOMIZE_GLOBAL_WINDOW
,
75 WINDOW_CUSTOMIZE_WINDOW
,
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
;
96 struct window_customize_modedata
{
97 struct window_pane
*wp
;
101 struct mode_tree_data
*data
;
105 struct window_customize_itemdata
**item_list
;
108 struct cmd_find_state fs
;
109 enum window_customize_change change
;
113 window_customize_get_tag(struct options_entry
*o
, int idx
,
114 const struct options_table_entry
*oe
)
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);
124 static struct options
*
125 window_customize_get_tree(enum window_customize_scope scope
,
126 struct cmd_find_state
*fs
)
129 case WINDOW_CUSTOMIZE_NONE
:
130 case WINDOW_CUSTOMIZE_KEY
:
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
);
149 window_customize_check_item(struct window_customize_modedata
*data
,
150 struct window_customize_itemdata
*item
, struct cmd_find_state
*fsp
)
152 struct cmd_find_state fs
;
157 if (cmd_find_valid_state(&data
->fs
))
158 cmd_find_copy_state(fsp
, &data
->fs
);
160 cmd_find_from_pane(fsp
, data
->wp
, 0);
161 return (item
->oo
== window_customize_get_tree(item
->scope
, fsp
));
165 window_customize_get_key(struct window_customize_itemdata
*item
,
166 struct key_table
**ktp
, struct key_binding
**bdp
)
168 struct key_table
*kt
;
169 struct key_binding
*bd
;
171 kt
= key_bindings_get_table(item
->table
, 0);
174 bd
= key_bindings_get(kt
, item
->key
);
186 window_customize_scope_text(enum window_customize_scope scope
,
187 struct cmd_find_state
*fs
)
193 case WINDOW_CUSTOMIZE_PANE
:
194 window_pane_index(fs
->wp
, &idx
);
195 xasprintf(&s
, "pane %u", idx
);
197 case WINDOW_CUSTOMIZE_SESSION
:
198 xasprintf(&s
, "session %s", fs
->s
->name
);
200 case WINDOW_CUSTOMIZE_WINDOW
:
201 xasprintf(&s
, "window %u", fs
->wl
->idx
);
210 static struct window_customize_itemdata
*
211 window_customize_add_item(struct window_customize_modedata
*data
)
213 struct window_customize_itemdata
*item
;
215 data
->item_list
= xreallocarray(data
->item_list
, data
->item_size
+ 1,
216 sizeof *data
->item_list
);
217 item
= data
->item_list
[data
->item_size
++] = xcalloc(1, sizeof *item
);
222 window_customize_free_item(struct window_customize_itemdata
*item
)
230 window_customize_build_array(struct window_customize_modedata
*data
,
231 struct mode_tree_item
*top
, enum window_customize_scope scope
,
232 struct options_entry
*o
, struct format_tree
*ft
)
234 const struct options_table_entry
*oe
= options_table_entry(o
);
235 struct options
*oo
= options_owner(o
);
236 struct window_customize_itemdata
*item
;
237 struct options_array_item
*ai
;
238 char *name
, *value
, *text
;
242 ai
= options_array_first(o
);
244 idx
= options_array_item_index(ai
);
246 xasprintf(&name
, "%s[%u]", options_name(o
), idx
);
247 format_add(ft
, "option_name", "%s", name
);
248 value
= options_to_string(o
, idx
, 0);
249 format_add(ft
, "option_value", "%s", value
);
251 item
= window_customize_add_item(data
);
254 item
->name
= xstrdup(options_name(o
));
257 text
= format_expand(ft
, data
->format
);
258 tag
= window_customize_get_tag(o
, idx
, oe
);
259 mode_tree_add(data
->data
, top
, item
, tag
, name
, text
, -1);
265 ai
= options_array_next(ai
);
270 window_customize_build_option(struct window_customize_modedata
*data
,
271 struct mode_tree_item
*top
, enum window_customize_scope scope
,
272 struct options_entry
*o
, struct format_tree
*ft
,
273 const char *filter
, struct cmd_find_state
*fs
)
275 const struct options_table_entry
*oe
= options_table_entry(o
);
276 struct options
*oo
= options_owner(o
);
277 const char *name
= options_name(o
);
278 struct window_customize_itemdata
*item
;
279 char *text
, *expanded
, *value
;
280 int global
= 0, array
= 0;
283 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_HOOK
))
285 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
))
288 if (scope
== WINDOW_CUSTOMIZE_SERVER
||
289 scope
== WINDOW_CUSTOMIZE_GLOBAL_SESSION
||
290 scope
== WINDOW_CUSTOMIZE_GLOBAL_WINDOW
)
292 if (data
->hide_global
&& global
)
295 format_add(ft
, "option_name", "%s", name
);
296 format_add(ft
, "option_is_global", "%d", global
);
297 format_add(ft
, "option_is_array", "%d", array
);
299 text
= window_customize_scope_text(scope
, fs
);
300 format_add(ft
, "option_scope", "%s", text
);
303 if (oe
!= NULL
&& oe
->unit
!= NULL
)
304 format_add(ft
, "option_unit", "%s", oe
->unit
);
306 format_add(ft
, "option_unit", "%s", "");
309 value
= options_to_string(o
, -1, 0);
310 format_add(ft
, "option_value", "%s", value
);
314 if (filter
!= NULL
) {
315 expanded
= format_expand(ft
, filter
);
316 if (!format_true(expanded
)) {
322 item
= window_customize_add_item(data
);
325 item
->name
= xstrdup(name
);
331 text
= format_expand(ft
, data
->format
);
332 tag
= window_customize_get_tag(o
, -1, oe
);
333 top
= mode_tree_add(data
->data
, top
, item
, tag
, name
, text
, 0);
337 window_customize_build_array(data
, top
, scope
, o
, ft
);
341 window_customize_find_user_options(struct options
*oo
, const char ***list
,
344 struct options_entry
*o
;
348 o
= options_first(oo
);
350 name
= options_name(o
);
355 for (i
= 0; i
< *size
; i
++) {
356 if (strcmp((*list
)[i
], name
) == 0)
363 *list
= xreallocarray(*list
, (*size
) + 1, sizeof **list
);
364 (*list
)[(*size
)++] = name
;
371 window_customize_build_options(struct window_customize_modedata
*data
,
372 const char *title
, uint64_t tag
,
373 enum window_customize_scope scope0
, struct options
*oo0
,
374 enum window_customize_scope scope1
, struct options
*oo1
,
375 enum window_customize_scope scope2
, struct options
*oo2
,
376 struct format_tree
*ft
, const char *filter
, struct cmd_find_state
*fs
)
378 struct mode_tree_item
*top
;
379 struct options_entry
*o
= NULL
, *loop
;
380 const char **list
= NULL
, *name
;
382 enum window_customize_scope scope
;
384 top
= mode_tree_add(data
->data
, NULL
, NULL
, tag
, title
, NULL
, 0);
385 mode_tree_no_tag(top
);
388 * We get the options from the first tree, but build it using the
389 * values from the other two. Any tree can have user options so we need
390 * to build a separate list of them.
393 window_customize_find_user_options(oo0
, &list
, &size
);
395 window_customize_find_user_options(oo1
, &list
, &size
);
397 window_customize_find_user_options(oo2
, &list
, &size
);
399 for (i
= 0; i
< size
; i
++) {
401 o
= options_get(oo2
, list
[i
]);
402 if (o
== NULL
&& oo1
!= NULL
)
403 o
= options_get(oo1
, list
[i
]);
405 o
= options_get(oo0
, list
[i
]);
406 if (options_owner(o
) == oo2
)
408 else if (options_owner(o
) == oo1
)
412 window_customize_build_option(data
, top
, scope
, o
, ft
, filter
,
417 loop
= options_first(oo0
);
418 while (loop
!= NULL
) {
419 name
= options_name(loop
);
421 loop
= options_next(loop
);
425 o
= options_get(oo2
, name
);
426 else if (oo1
!= NULL
)
427 o
= options_get(oo1
, name
);
430 if (options_owner(o
) == oo2
)
432 else if (options_owner(o
) == oo1
)
436 window_customize_build_option(data
, top
, scope
, o
, ft
, filter
,
438 loop
= options_next(loop
);
443 window_customize_build_keys(struct window_customize_modedata
*data
,
444 struct key_table
*kt
, struct format_tree
*ft
, const char *filter
,
445 struct cmd_find_state
*fs
, u_int number
)
447 struct mode_tree_item
*top
, *child
, *mti
;
448 struct window_customize_itemdata
*item
;
449 struct key_binding
*bd
;
450 char *title
, *text
, *tmp
, *expanded
;
454 tag
= (1ULL << 62)|((uint64_t)number
<< 54)|1;
456 xasprintf(&title
, "Key Table - %s", kt
->name
);
457 top
= mode_tree_add(data
->data
, NULL
, NULL
, tag
, title
, NULL
, 0);
458 mode_tree_no_tag(top
);
461 ft
= format_create_from_state(NULL
, NULL
, fs
);
462 format_add(ft
, "is_option", "0");
463 format_add(ft
, "is_key", "1");
465 bd
= key_bindings_first(kt
);
467 format_add(ft
, "key", "%s", key_string_lookup_key(bd
->key
, 0));
468 if (bd
->note
!= NULL
)
469 format_add(ft
, "key_note", "%s", bd
->note
);
470 if (filter
!= NULL
) {
471 expanded
= format_expand(ft
, filter
);
472 if (!format_true(expanded
)) {
479 item
= window_customize_add_item(data
);
480 item
->scope
= WINDOW_CUSTOMIZE_KEY
;
481 item
->table
= xstrdup(kt
->name
);
483 item
->name
= xstrdup(key_string_lookup_key(item
->key
, 0));
486 expanded
= format_expand(ft
, data
->format
);
487 child
= mode_tree_add(data
->data
, top
, item
, (uint64_t)bd
,
491 tmp
= cmd_list_print(bd
->cmdlist
, 0);
492 xasprintf(&text
, "#[ignore]%s", tmp
);
494 mti
= mode_tree_add(data
->data
, child
, item
,
495 tag
|(bd
->key
<< 3)|(0 << 1)|1, "Command", text
, -1);
496 mode_tree_draw_as_parent(mti
);
497 mode_tree_no_tag(mti
);
500 if (bd
->note
!= NULL
)
501 xasprintf(&text
, "#[ignore]%s", bd
->note
);
504 mti
= mode_tree_add(data
->data
, child
, item
,
505 tag
|(bd
->key
<< 3)|(1 << 1)|1, "Note", text
, -1);
506 mode_tree_draw_as_parent(mti
);
507 mode_tree_no_tag(mti
);
510 if (bd
->flags
& KEY_BINDING_REPEAT
)
514 mti
= mode_tree_add(data
->data
, child
, item
,
515 tag
|(bd
->key
<< 3)|(2 << 1)|1, "Repeat", flag
, -1);
516 mode_tree_draw_as_parent(mti
);
517 mode_tree_no_tag(mti
);
519 bd
= key_bindings_next(kt
, bd
);
526 window_customize_build(void *modedata
,
527 __unused
struct mode_tree_sort_criteria
*sort_crit
, __unused
uint64_t *tag
,
530 struct window_customize_modedata
*data
= modedata
;
531 struct cmd_find_state fs
;
532 struct format_tree
*ft
;
534 struct key_table
*kt
;
536 for (i
= 0; i
< data
->item_size
; i
++)
537 window_customize_free_item(data
->item_list
[i
]);
538 free(data
->item_list
);
539 data
->item_list
= NULL
;
542 if (cmd_find_valid_state(&data
->fs
))
543 cmd_find_copy_state(&fs
, &data
->fs
);
545 cmd_find_from_pane(&fs
, data
->wp
, 0);
547 ft
= format_create_from_state(NULL
, NULL
, &fs
);
548 format_add(ft
, "is_option", "1");
549 format_add(ft
, "is_key", "0");
551 window_customize_build_options(data
, "Server Options",
552 (3ULL << 62)|(OPTIONS_TABLE_SERVER
<< 1)|1,
553 WINDOW_CUSTOMIZE_SERVER
, global_options
,
554 WINDOW_CUSTOMIZE_NONE
, NULL
,
555 WINDOW_CUSTOMIZE_NONE
, NULL
,
557 window_customize_build_options(data
, "Session Options",
558 (3ULL << 62)|(OPTIONS_TABLE_SESSION
<< 1)|1,
559 WINDOW_CUSTOMIZE_GLOBAL_SESSION
, global_s_options
,
560 WINDOW_CUSTOMIZE_SESSION
, fs
.s
->options
,
561 WINDOW_CUSTOMIZE_NONE
, NULL
,
563 window_customize_build_options(data
, "Window & Pane Options",
564 (3ULL << 62)|(OPTIONS_TABLE_WINDOW
<< 1)|1,
565 WINDOW_CUSTOMIZE_GLOBAL_WINDOW
, global_w_options
,
566 WINDOW_CUSTOMIZE_WINDOW
, fs
.w
->options
,
567 WINDOW_CUSTOMIZE_PANE
, fs
.wp
->options
,
571 ft
= format_create_from_state(NULL
, NULL
, &fs
);
574 kt
= key_bindings_first_table();
576 if (!RB_EMPTY(&kt
->key_bindings
)) {
577 window_customize_build_keys(data
, kt
, ft
, filter
, &fs
,
582 kt
= key_bindings_next_table(kt
);
589 window_customize_draw_key(__unused
struct window_customize_modedata
*data
,
590 struct window_customize_itemdata
*item
, struct screen_write_ctx
*ctx
,
593 struct screen
*s
= ctx
->s
;
594 u_int cx
= s
->cx
, cy
= s
->cy
;
595 struct key_table
*kt
;
596 struct key_binding
*bd
, *default_bd
;
597 const char *note
, *period
= "";
598 char *cmd
, *default_cmd
;
600 if (item
== NULL
|| !window_customize_get_key(item
, &kt
, &bd
))
605 note
= "There is no note for this key.";
606 if (*note
!= '\0' && note
[strlen (note
) - 1] != '.')
608 if (!screen_write_text(ctx
, cx
, sx
, sy
, 0, &grid_default_cell
, "%s%s",
611 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
612 if (s
->cy
>= cy
+ sy
- 1)
615 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
616 &grid_default_cell
, "This key is in the %s table.", kt
->name
))
618 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
619 &grid_default_cell
, "This key %s repeat.",
620 (bd
->flags
& KEY_BINDING_REPEAT
) ? "does" : "does not"))
622 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
623 if (s
->cy
>= cy
+ sy
- 1)
626 cmd
= cmd_list_print(bd
->cmdlist
, 0);
627 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
628 &grid_default_cell
, "Command: %s", cmd
)) {
632 default_bd
= key_bindings_get_default(kt
, bd
->key
);
633 if (default_bd
!= NULL
) {
634 default_cmd
= cmd_list_print(default_bd
->cmdlist
, 0);
635 if (strcmp(cmd
, default_cmd
) != 0 &&
636 !screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
637 &grid_default_cell
, "The default is: %s", default_cmd
)) {
648 window_customize_draw_option(struct window_customize_modedata
*data
,
649 struct window_customize_itemdata
*item
, struct screen_write_ctx
*ctx
,
652 struct screen
*s
= ctx
->s
;
653 u_int cx
= s
->cx
, cy
= s
->cy
;
655 struct options_entry
*o
, *parent
;
656 struct options
*go
, *wo
;
657 const struct options_table_entry
*oe
;
659 const char **choice
, *text
, *name
;
660 const char *space
= "", *unit
= "";
661 char *value
= NULL
, *expanded
;
662 char *default_value
= NULL
;
663 char choices
[256] = "";
664 struct cmd_find_state fs
;
665 struct format_tree
*ft
;
667 if (!window_customize_check_item(data
, item
, &fs
))
672 o
= options_get(item
->oo
, name
);
675 oe
= options_table_entry(o
);
677 if (oe
!= NULL
&& oe
->unit
!= NULL
) {
681 ft
= format_create_from_state(NULL
, NULL
, &fs
);
683 if (oe
== NULL
|| oe
->text
== NULL
)
684 text
= "This option doesn't have a description.";
687 if (!screen_write_text(ctx
, cx
, sx
, sy
, 0, &grid_default_cell
, "%s",
690 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
691 if (s
->cy
>= cy
+ sy
- 1)
696 else if ((oe
->scope
& (OPTIONS_TABLE_WINDOW
|OPTIONS_TABLE_PANE
)) ==
697 (OPTIONS_TABLE_WINDOW
|OPTIONS_TABLE_PANE
))
698 text
= "window and pane";
699 else if (oe
->scope
& OPTIONS_TABLE_WINDOW
)
701 else if (oe
->scope
& OPTIONS_TABLE_SESSION
)
705 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
706 &grid_default_cell
, "This is a %s option.", text
))
708 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
710 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
711 0, &grid_default_cell
,
712 "This is an array option, index %u.", idx
))
715 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
716 0, &grid_default_cell
, "This is an array option."))
722 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
723 if (s
->cy
>= cy
+ sy
- 1)
726 value
= options_to_string(o
, idx
, 0);
727 if (oe
!= NULL
&& idx
== -1) {
728 default_value
= options_default_to_string(oe
);
729 if (strcmp(default_value
, value
) == 0) {
731 default_value
= NULL
;
734 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
735 &grid_default_cell
, "Option value: %s%s%s", value
, space
, unit
))
737 if (oe
== NULL
|| oe
->type
== OPTIONS_TABLE_STRING
) {
738 expanded
= format_expand(ft
, value
);
739 if (strcmp(expanded
, value
) != 0) {
740 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
741 0, &grid_default_cell
, "This expands to: %s",
747 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_CHOICE
) {
748 for (choice
= oe
->choices
; *choice
!= NULL
; choice
++) {
749 strlcat(choices
, *choice
, sizeof choices
);
750 strlcat(choices
, ", ", sizeof choices
);
752 choices
[strlen(choices
) - 2] = '\0';
753 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
754 &grid_default_cell
, "Available values are: %s",
758 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_COLOUR
) {
759 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 1,
760 &grid_default_cell
, "This is a colour option: "))
762 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
763 gc
.fg
= options_get_number(item
->oo
, name
);
764 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0, &gc
,
768 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_STYLE
)) {
769 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 1,
770 &grid_default_cell
, "This is a style option: "))
772 style_apply(&gc
, item
->oo
, name
, ft
);
773 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0, &gc
,
777 if (default_value
!= NULL
) {
778 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
779 &grid_default_cell
, "The default is: %s%s%s", default_value
,
784 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
785 if (s
->cy
> cy
+ sy
- 1)
787 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
791 switch (item
->scope
) {
792 case WINDOW_CUSTOMIZE_PANE
:
793 wo
= options_get_parent(item
->oo
);
794 go
= options_get_parent(wo
);
796 case WINDOW_CUSTOMIZE_WINDOW
:
797 case WINDOW_CUSTOMIZE_SESSION
:
799 go
= options_get_parent(item
->oo
);
807 if (wo
!= NULL
&& options_owner(o
) != wo
) {
808 parent
= options_get_only(wo
, name
);
809 if (parent
!= NULL
) {
810 value
= options_to_string(parent
, -1 , 0);
811 if (!screen_write_text(ctx
, s
->cx
, sx
,
812 sy
- (s
->cy
- cy
), 0, &grid_default_cell
,
813 "Window value (from window %u): %s%s%s", fs
.wl
->idx
,
818 if (go
!= NULL
&& options_owner(o
) != go
) {
819 parent
= options_get_only(go
, name
);
820 if (parent
!= NULL
) {
821 value
= options_to_string(parent
, -1 , 0);
822 if (!screen_write_text(ctx
, s
->cx
, sx
,
823 sy
- (s
->cy
- cy
), 0, &grid_default_cell
,
824 "Global value: %s%s%s", value
, space
, unit
))
836 window_customize_draw(void *modedata
, void *itemdata
,
837 struct screen_write_ctx
*ctx
, u_int sx
, u_int sy
)
839 struct window_customize_modedata
*data
= modedata
;
840 struct window_customize_itemdata
*item
= itemdata
;
845 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
846 window_customize_draw_key(data
, item
, ctx
, sx
, sy
);
848 window_customize_draw_option(data
, item
, ctx
, sx
, sy
);
852 window_customize_menu(void *modedata
, struct client
*c
, key_code key
)
854 struct window_customize_modedata
*data
= modedata
;
855 struct window_pane
*wp
= data
->wp
;
856 struct window_mode_entry
*wme
;
858 wme
= TAILQ_FIRST(&wp
->modes
);
859 if (wme
== NULL
|| wme
->data
!= modedata
)
861 window_customize_key(wme
, c
, NULL
, NULL
, key
, NULL
);
865 window_customize_height(__unused
void *modedata
, __unused u_int height
)
870 static struct screen
*
871 window_customize_init(struct window_mode_entry
*wme
, struct cmd_find_state
*fs
,
874 struct window_pane
*wp
= wme
->wp
;
875 struct window_customize_modedata
*data
;
878 wme
->data
= data
= xcalloc(1, sizeof *data
);
880 data
->references
= 1;
882 memcpy(&data
->fs
, fs
, sizeof data
->fs
);
884 if (args
== NULL
|| !args_has(args
, 'F'))
885 data
->format
= xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT
);
887 data
->format
= xstrdup(args_get(args
, 'F'));
889 data
->data
= mode_tree_start(wp
, args
, window_customize_build
,
890 window_customize_draw
, NULL
, window_customize_menu
,
891 window_customize_height
, NULL
, data
, window_customize_menu_items
,
893 mode_tree_zoom(data
->data
, args
);
895 mode_tree_build(data
->data
);
896 mode_tree_draw(data
->data
);
902 window_customize_destroy(struct window_customize_modedata
*data
)
906 if (--data
->references
!= 0)
909 for (i
= 0; i
< data
->item_size
; i
++)
910 window_customize_free_item(data
->item_list
[i
]);
911 free(data
->item_list
);
919 window_customize_free(struct window_mode_entry
*wme
)
921 struct window_customize_modedata
*data
= wme
->data
;
927 mode_tree_free(data
->data
);
928 window_customize_destroy(data
);
932 window_customize_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
934 struct window_customize_modedata
*data
= wme
->data
;
936 mode_tree_resize(data
->data
, sx
, sy
);
940 window_customize_free_callback(void *modedata
)
942 window_customize_destroy(modedata
);
946 window_customize_free_item_callback(void *itemdata
)
948 struct window_customize_itemdata
*item
= itemdata
;
949 struct window_customize_modedata
*data
= item
->data
;
951 window_customize_free_item(item
);
952 window_customize_destroy(data
);
956 window_customize_set_option_callback(struct client
*c
, void *itemdata
,
957 const char *s
, __unused
int done
)
959 struct window_customize_itemdata
*item
= itemdata
;
960 struct window_customize_modedata
*data
= item
->data
;
961 struct options_entry
*o
;
962 const struct options_table_entry
*oe
;
963 struct options
*oo
= item
->oo
;
964 const char *name
= item
->name
;
968 if (s
== NULL
|| *s
== '\0' || data
->dead
)
970 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
972 o
= options_get(oo
, name
);
975 oe
= options_table_entry(o
);
977 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
979 for (idx
= 0; idx
< INT_MAX
; idx
++) {
980 if (options_array_get(o
, idx
) == NULL
)
984 if (options_array_set(o
, idx
, s
, 0, &cause
) != 0)
987 if (options_from_string(oo
, oe
, name
, s
, 0, &cause
) != 0)
991 options_push_changes(item
->name
);
992 mode_tree_build(data
->data
);
993 mode_tree_draw(data
->data
);
994 data
->wp
->flags
|= PANE_REDRAW
;
999 *cause
= toupper((u_char
)*cause
);
1000 status_message_set(c
, -1, 1, 0, "%s", cause
);
1006 window_customize_set_option(struct client
*c
,
1007 struct window_customize_modedata
*data
,
1008 struct window_customize_itemdata
*item
, int global
, int pane
)
1010 struct options_entry
*o
;
1011 const struct options_table_entry
*oe
;
1013 struct window_customize_itemdata
*new_item
;
1014 int flag
, idx
= item
->idx
;
1015 enum window_customize_scope scope
= WINDOW_CUSTOMIZE_NONE
;
1017 const char *name
= item
->name
, *space
= "";
1018 char *prompt
, *value
, *text
;
1019 struct cmd_find_state fs
;
1021 if (item
== NULL
|| !window_customize_check_item(data
, item
, &fs
))
1023 o
= options_get(item
->oo
, name
);
1027 oe
= options_table_entry(o
);
1028 if (oe
!= NULL
&& ~oe
->scope
& OPTIONS_TABLE_PANE
)
1030 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1031 scope
= item
->scope
;
1035 switch (item
->scope
) {
1036 case WINDOW_CUSTOMIZE_NONE
:
1037 case WINDOW_CUSTOMIZE_KEY
:
1038 case WINDOW_CUSTOMIZE_SERVER
:
1039 case WINDOW_CUSTOMIZE_GLOBAL_SESSION
:
1040 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW
:
1041 scope
= item
->scope
;
1043 case WINDOW_CUSTOMIZE_SESSION
:
1044 scope
= WINDOW_CUSTOMIZE_GLOBAL_SESSION
;
1046 case WINDOW_CUSTOMIZE_WINDOW
:
1047 case WINDOW_CUSTOMIZE_PANE
:
1048 scope
= WINDOW_CUSTOMIZE_GLOBAL_WINDOW
;
1052 switch (item
->scope
) {
1053 case WINDOW_CUSTOMIZE_NONE
:
1054 case WINDOW_CUSTOMIZE_KEY
:
1055 case WINDOW_CUSTOMIZE_SERVER
:
1056 case WINDOW_CUSTOMIZE_SESSION
:
1057 scope
= item
->scope
;
1059 case WINDOW_CUSTOMIZE_WINDOW
:
1060 case WINDOW_CUSTOMIZE_PANE
:
1062 scope
= WINDOW_CUSTOMIZE_PANE
;
1064 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1066 case WINDOW_CUSTOMIZE_GLOBAL_SESSION
:
1067 scope
= WINDOW_CUSTOMIZE_SESSION
;
1069 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW
:
1071 scope
= WINDOW_CUSTOMIZE_PANE
;
1073 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1077 if (scope
== item
->scope
)
1080 oo
= window_customize_get_tree(scope
, &fs
);
1083 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_FLAG
) {
1084 flag
= options_get_number(oo
, name
);
1085 options_set_number(oo
, name
, !flag
);
1086 } else if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_CHOICE
) {
1087 choice
= options_get_number(oo
, name
);
1088 if (oe
->choices
[choice
+ 1] == NULL
)
1092 options_set_number(oo
, name
, choice
);
1094 text
= window_customize_scope_text(scope
, &fs
);
1097 else if (scope
!= WINDOW_CUSTOMIZE_SERVER
)
1099 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1101 xasprintf(&prompt
, "(%s[+]%s%s) ", name
, space
,
1104 xasprintf(&prompt
, "(%s[%d]%s%s) ", name
, idx
,
1108 xasprintf(&prompt
, "(%s%s%s) ", name
, space
, text
);
1111 value
= options_to_string(o
, idx
, 0);
1113 new_item
= xcalloc(1, sizeof *new_item
);
1114 new_item
->data
= data
;
1115 new_item
->scope
= scope
;
1117 new_item
->name
= xstrdup(name
);
1118 new_item
->idx
= idx
;
1121 status_prompt_set(c
, NULL
, prompt
, value
,
1122 window_customize_set_option_callback
,
1123 window_customize_free_item_callback
, new_item
,
1124 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1132 window_customize_unset_option(struct window_customize_modedata
*data
,
1133 struct window_customize_itemdata
*item
)
1135 struct options_entry
*o
;
1137 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
1140 o
= options_get(item
->oo
, item
->name
);
1143 if (item
->idx
!= -1 && item
== mode_tree_get_current(data
->data
))
1144 mode_tree_up(data
->data
, 0);
1145 options_remove_or_default(o
, item
->idx
, NULL
);
1149 window_customize_reset_option(struct window_customize_modedata
*data
,
1150 struct window_customize_itemdata
*item
)
1153 struct options_entry
*o
;
1155 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
1157 if (item
->idx
!= -1)
1161 while (oo
!= NULL
) {
1162 o
= options_get_only(item
->oo
, item
->name
);
1164 options_remove_or_default(o
, -1, NULL
);
1165 oo
= options_get_parent(oo
);
1170 window_customize_set_command_callback(struct client
*c
, void *itemdata
,
1171 const char *s
, __unused
int done
)
1173 struct window_customize_itemdata
*item
= itemdata
;
1174 struct window_customize_modedata
*data
= item
->data
;
1175 struct key_binding
*bd
;
1176 struct cmd_parse_result
*pr
;
1179 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1181 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1184 pr
= cmd_parse_from_string(s
, NULL
);
1185 switch (pr
->status
) {
1186 case CMD_PARSE_ERROR
:
1189 case CMD_PARSE_SUCCESS
:
1192 cmd_list_free(bd
->cmdlist
);
1193 bd
->cmdlist
= pr
->cmdlist
;
1195 mode_tree_build(data
->data
);
1196 mode_tree_draw(data
->data
);
1197 data
->wp
->flags
|= PANE_REDRAW
;
1202 *error
= toupper((u_char
)*error
);
1203 status_message_set(c
, -1, 1, 0, "%s", error
);
1209 window_customize_set_note_callback(__unused
struct client
*c
, void *itemdata
,
1210 const char *s
, __unused
int done
)
1212 struct window_customize_itemdata
*item
= itemdata
;
1213 struct window_customize_modedata
*data
= item
->data
;
1214 struct key_binding
*bd
;
1216 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1218 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1221 free((void *)bd
->note
);
1222 bd
->note
= xstrdup(s
);
1224 mode_tree_build(data
->data
);
1225 mode_tree_draw(data
->data
);
1226 data
->wp
->flags
|= PANE_REDRAW
;
1232 window_customize_set_key(struct client
*c
,
1233 struct window_customize_modedata
*data
,
1234 struct window_customize_itemdata
*item
)
1236 key_code key
= item
->key
;
1237 struct key_binding
*bd
;
1239 char *prompt
, *value
;
1240 struct window_customize_itemdata
*new_item
;
1242 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1245 s
= mode_tree_get_current_name(data
->data
);
1246 if (strcmp(s
, "Repeat") == 0)
1247 bd
->flags
^= KEY_BINDING_REPEAT
;
1248 else if (strcmp(s
, "Command") == 0) {
1249 xasprintf(&prompt
, "(%s) ", key_string_lookup_key(key
, 0));
1250 value
= cmd_list_print(bd
->cmdlist
, 0);
1252 new_item
= xcalloc(1, sizeof *new_item
);
1253 new_item
->data
= data
;
1254 new_item
->scope
= item
->scope
;
1255 new_item
->table
= xstrdup(item
->table
);
1256 new_item
->key
= key
;
1259 status_prompt_set(c
, NULL
, prompt
, value
,
1260 window_customize_set_command_callback
,
1261 window_customize_free_item_callback
, new_item
,
1262 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1265 } else if (strcmp(s
, "Note") == 0) {
1266 xasprintf(&prompt
, "(%s) ", key_string_lookup_key(key
, 0));
1268 new_item
= xcalloc(1, sizeof *new_item
);
1269 new_item
->data
= data
;
1270 new_item
->scope
= item
->scope
;
1271 new_item
->table
= xstrdup(item
->table
);
1272 new_item
->key
= key
;
1275 status_prompt_set(c
, NULL
, prompt
,
1276 (bd
->note
== NULL
? "" : bd
->note
),
1277 window_customize_set_note_callback
,
1278 window_customize_free_item_callback
, new_item
,
1279 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1285 window_customize_unset_key(struct window_customize_modedata
*data
,
1286 struct window_customize_itemdata
*item
)
1288 struct key_table
*kt
;
1289 struct key_binding
*bd
;
1291 if (item
== NULL
|| !window_customize_get_key(item
, &kt
, &bd
))
1294 if (item
== mode_tree_get_current(data
->data
)) {
1295 mode_tree_collapse_current(data
->data
);
1296 mode_tree_up(data
->data
, 0);
1298 key_bindings_remove(kt
->name
, bd
->key
);
1302 window_customize_reset_key(struct window_customize_modedata
*data
,
1303 struct window_customize_itemdata
*item
)
1305 struct key_table
*kt
;
1306 struct key_binding
*dd
, *bd
;
1308 if (item
== NULL
|| !window_customize_get_key(item
, &kt
, &bd
))
1311 dd
= key_bindings_get_default(kt
, bd
->key
);
1312 if (dd
!= NULL
&& bd
->cmdlist
== dd
->cmdlist
)
1314 if (dd
== NULL
&& item
== mode_tree_get_current(data
->data
)) {
1315 mode_tree_collapse_current(data
->data
);
1316 mode_tree_up(data
->data
, 0);
1318 key_bindings_reset(kt
->name
, bd
->key
);
1322 window_customize_change_each(void *modedata
, void *itemdata
,
1323 __unused
struct client
*c
, __unused key_code key
)
1325 struct window_customize_modedata
*data
= modedata
;
1326 struct window_customize_itemdata
*item
= itemdata
;
1328 switch (data
->change
) {
1329 case WINDOW_CUSTOMIZE_UNSET
:
1330 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1331 window_customize_unset_key(data
, item
);
1333 window_customize_unset_option(data
, item
);
1335 case WINDOW_CUSTOMIZE_RESET
:
1336 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1337 window_customize_reset_key(data
, item
);
1339 window_customize_reset_option(data
, item
);
1342 if (item
->scope
!= WINDOW_CUSTOMIZE_KEY
)
1343 options_push_changes(item
->name
);
1347 window_customize_change_current_callback(__unused
struct client
*c
,
1348 void *modedata
, const char *s
, __unused
int done
)
1350 struct window_customize_modedata
*data
= modedata
;
1351 struct window_customize_itemdata
*item
;
1353 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1355 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\0')
1358 item
= mode_tree_get_current(data
->data
);
1359 switch (data
->change
) {
1360 case WINDOW_CUSTOMIZE_UNSET
:
1361 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1362 window_customize_unset_key(data
, item
);
1364 window_customize_unset_option(data
, item
);
1366 case WINDOW_CUSTOMIZE_RESET
:
1367 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1368 window_customize_reset_key(data
, item
);
1370 window_customize_reset_option(data
, item
);
1373 if (item
->scope
!= WINDOW_CUSTOMIZE_KEY
)
1374 options_push_changes(item
->name
);
1375 mode_tree_build(data
->data
);
1376 mode_tree_draw(data
->data
);
1377 data
->wp
->flags
|= PANE_REDRAW
;
1383 window_customize_change_tagged_callback(struct client
*c
, void *modedata
,
1384 const char *s
, __unused
int done
)
1386 struct window_customize_modedata
*data
= modedata
;
1388 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1390 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\0')
1393 mode_tree_each_tagged(data
->data
, window_customize_change_each
, c
,
1395 mode_tree_build(data
->data
);
1396 mode_tree_draw(data
->data
);
1397 data
->wp
->flags
|= PANE_REDRAW
;
1403 window_customize_key(struct window_mode_entry
*wme
, struct client
*c
,
1404 __unused
struct session
*s
, __unused
struct winlink
*wl
, key_code key
,
1405 struct mouse_event
*m
)
1407 struct window_pane
*wp
= wme
->wp
;
1408 struct window_customize_modedata
*data
= wme
->data
;
1409 struct window_customize_itemdata
*item
, *new_item
;
1414 item
= mode_tree_get_current(data
->data
);
1415 finished
= mode_tree_key(data
->data
, c
, &key
, m
, NULL
, NULL
);
1416 if (item
!= (new_item
= mode_tree_get_current(data
->data
)))
1424 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1425 window_customize_set_key(c
, data
, item
);
1427 window_customize_set_option(c
, data
, item
, 0, 1);
1428 options_push_changes(item
->name
);
1430 mode_tree_build(data
->data
);
1433 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1435 window_customize_set_option(c
, data
, item
, 0, 0);
1436 options_push_changes(item
->name
);
1437 mode_tree_build(data
->data
);
1441 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1443 window_customize_set_option(c
, data
, item
, 1, 0);
1444 options_push_changes(item
->name
);
1445 mode_tree_build(data
->data
);
1448 if (item
== NULL
|| item
->idx
!= -1)
1450 xasprintf(&prompt
, "Reset %s to default? ", item
->name
);
1452 data
->change
= WINDOW_CUSTOMIZE_RESET
;
1453 status_prompt_set(c
, NULL
, prompt
, "",
1454 window_customize_change_current_callback
,
1455 window_customize_free_callback
, data
,
1456 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1460 tagged
= mode_tree_count_tagged(data
->data
);
1463 xasprintf(&prompt
, "Reset %u tagged to default? ", tagged
);
1465 data
->change
= WINDOW_CUSTOMIZE_RESET
;
1466 status_prompt_set(c
, NULL
, prompt
, "",
1467 window_customize_change_tagged_callback
,
1468 window_customize_free_callback
, data
,
1469 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1477 xasprintf(&prompt
, "Unset %s[%d]? ", item
->name
, idx
);
1479 xasprintf(&prompt
, "Unset %s? ", item
->name
);
1481 data
->change
= WINDOW_CUSTOMIZE_UNSET
;
1482 status_prompt_set(c
, NULL
, prompt
, "",
1483 window_customize_change_current_callback
,
1484 window_customize_free_callback
, data
,
1485 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1489 tagged
= mode_tree_count_tagged(data
->data
);
1492 xasprintf(&prompt
, "Unset %u tagged? ", tagged
);
1494 data
->change
= WINDOW_CUSTOMIZE_UNSET
;
1495 status_prompt_set(c
, NULL
, prompt
, "",
1496 window_customize_change_tagged_callback
,
1497 window_customize_free_callback
, data
,
1498 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1502 data
->hide_global
= !data
->hide_global
;
1503 mode_tree_build(data
->data
);
1507 window_pane_reset_mode(wp
);
1509 mode_tree_draw(data
->data
);
1510 wp
->flags
|= PANE_REDRAW
;