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
);
684 text
= "This is a user option.";
685 else if (oe
->text
== NULL
)
686 text
= "This option doesn't have a description.";
689 if (!screen_write_text(ctx
, cx
, sx
, sy
, 0, &grid_default_cell
, "%s",
692 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
693 if (s
->cy
>= cy
+ sy
- 1)
698 else if ((oe
->scope
& (OPTIONS_TABLE_WINDOW
|OPTIONS_TABLE_PANE
)) ==
699 (OPTIONS_TABLE_WINDOW
|OPTIONS_TABLE_PANE
))
700 text
= "window and pane";
701 else if (oe
->scope
& OPTIONS_TABLE_WINDOW
)
703 else if (oe
->scope
& OPTIONS_TABLE_SESSION
)
707 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
708 &grid_default_cell
, "This is a %s option.", text
))
710 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
712 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
713 0, &grid_default_cell
,
714 "This is an array option, index %u.", idx
))
717 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
718 0, &grid_default_cell
, "This is an array option."))
724 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
725 if (s
->cy
>= cy
+ sy
- 1)
728 value
= options_to_string(o
, idx
, 0);
729 if (oe
!= NULL
&& idx
== -1) {
730 default_value
= options_default_to_string(oe
);
731 if (strcmp(default_value
, value
) == 0) {
733 default_value
= NULL
;
736 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
737 &grid_default_cell
, "Option value: %s%s%s", value
, space
, unit
))
739 if (oe
== NULL
|| oe
->type
== OPTIONS_TABLE_STRING
) {
740 expanded
= format_expand(ft
, value
);
741 if (strcmp(expanded
, value
) != 0) {
742 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
743 0, &grid_default_cell
, "This expands to: %s",
749 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_CHOICE
) {
750 for (choice
= oe
->choices
; *choice
!= NULL
; choice
++) {
751 strlcat(choices
, *choice
, sizeof choices
);
752 strlcat(choices
, ", ", sizeof choices
);
754 choices
[strlen(choices
) - 2] = '\0';
755 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
756 &grid_default_cell
, "Available values are: %s",
760 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_COLOUR
) {
761 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 1,
762 &grid_default_cell
, "This is a colour option: "))
764 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
765 gc
.fg
= options_get_number(item
->oo
, name
);
766 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0, &gc
,
770 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_STYLE
)) {
771 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 1,
772 &grid_default_cell
, "This is a style option: "))
774 style_apply(&gc
, item
->oo
, name
, ft
);
775 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0, &gc
,
779 if (default_value
!= NULL
) {
780 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
781 &grid_default_cell
, "The default is: %s%s%s", default_value
,
786 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
787 if (s
->cy
> cy
+ sy
- 1)
789 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
793 switch (item
->scope
) {
794 case WINDOW_CUSTOMIZE_PANE
:
795 wo
= options_get_parent(item
->oo
);
796 go
= options_get_parent(wo
);
798 case WINDOW_CUSTOMIZE_WINDOW
:
799 case WINDOW_CUSTOMIZE_SESSION
:
801 go
= options_get_parent(item
->oo
);
809 if (wo
!= NULL
&& options_owner(o
) != wo
) {
810 parent
= options_get_only(wo
, name
);
811 if (parent
!= NULL
) {
812 value
= options_to_string(parent
, -1 , 0);
813 if (!screen_write_text(ctx
, s
->cx
, sx
,
814 sy
- (s
->cy
- cy
), 0, &grid_default_cell
,
815 "Window value (from window %u): %s%s%s", fs
.wl
->idx
,
820 if (go
!= NULL
&& options_owner(o
) != go
) {
821 parent
= options_get_only(go
, name
);
822 if (parent
!= NULL
) {
823 value
= options_to_string(parent
, -1 , 0);
824 if (!screen_write_text(ctx
, s
->cx
, sx
,
825 sy
- (s
->cy
- cy
), 0, &grid_default_cell
,
826 "Global value: %s%s%s", value
, space
, unit
))
838 window_customize_draw(void *modedata
, void *itemdata
,
839 struct screen_write_ctx
*ctx
, u_int sx
, u_int sy
)
841 struct window_customize_modedata
*data
= modedata
;
842 struct window_customize_itemdata
*item
= itemdata
;
847 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
848 window_customize_draw_key(data
, item
, ctx
, sx
, sy
);
850 window_customize_draw_option(data
, item
, ctx
, sx
, sy
);
854 window_customize_menu(void *modedata
, struct client
*c
, key_code key
)
856 struct window_customize_modedata
*data
= modedata
;
857 struct window_pane
*wp
= data
->wp
;
858 struct window_mode_entry
*wme
;
860 wme
= TAILQ_FIRST(&wp
->modes
);
861 if (wme
== NULL
|| wme
->data
!= modedata
)
863 window_customize_key(wme
, c
, NULL
, NULL
, key
, NULL
);
867 window_customize_height(__unused
void *modedata
, __unused u_int height
)
872 static struct screen
*
873 window_customize_init(struct window_mode_entry
*wme
, struct cmd_find_state
*fs
,
876 struct window_pane
*wp
= wme
->wp
;
877 struct window_customize_modedata
*data
;
880 wme
->data
= data
= xcalloc(1, sizeof *data
);
882 data
->references
= 1;
884 memcpy(&data
->fs
, fs
, sizeof data
->fs
);
886 if (args
== NULL
|| !args_has(args
, 'F'))
887 data
->format
= xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT
);
889 data
->format
= xstrdup(args_get(args
, 'F'));
891 data
->data
= mode_tree_start(wp
, args
, window_customize_build
,
892 window_customize_draw
, NULL
, window_customize_menu
,
893 window_customize_height
, NULL
, data
, window_customize_menu_items
,
895 mode_tree_zoom(data
->data
, args
);
897 mode_tree_build(data
->data
);
898 mode_tree_draw(data
->data
);
904 window_customize_destroy(struct window_customize_modedata
*data
)
908 if (--data
->references
!= 0)
911 for (i
= 0; i
< data
->item_size
; i
++)
912 window_customize_free_item(data
->item_list
[i
]);
913 free(data
->item_list
);
921 window_customize_free(struct window_mode_entry
*wme
)
923 struct window_customize_modedata
*data
= wme
->data
;
929 mode_tree_free(data
->data
);
930 window_customize_destroy(data
);
934 window_customize_resize(struct window_mode_entry
*wme
, u_int sx
, u_int sy
)
936 struct window_customize_modedata
*data
= wme
->data
;
938 mode_tree_resize(data
->data
, sx
, sy
);
942 window_customize_free_callback(void *modedata
)
944 window_customize_destroy(modedata
);
948 window_customize_free_item_callback(void *itemdata
)
950 struct window_customize_itemdata
*item
= itemdata
;
951 struct window_customize_modedata
*data
= item
->data
;
953 window_customize_free_item(item
);
954 window_customize_destroy(data
);
958 window_customize_set_option_callback(struct client
*c
, void *itemdata
,
959 const char *s
, __unused
int done
)
961 struct window_customize_itemdata
*item
= itemdata
;
962 struct window_customize_modedata
*data
= item
->data
;
963 struct options_entry
*o
;
964 const struct options_table_entry
*oe
;
965 struct options
*oo
= item
->oo
;
966 const char *name
= item
->name
;
970 if (s
== NULL
|| *s
== '\0' || data
->dead
)
972 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
974 o
= options_get(oo
, name
);
977 oe
= options_table_entry(o
);
979 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
981 for (idx
= 0; idx
< INT_MAX
; idx
++) {
982 if (options_array_get(o
, idx
) == NULL
)
986 if (options_array_set(o
, idx
, s
, 0, &cause
) != 0)
989 if (options_from_string(oo
, oe
, name
, s
, 0, &cause
) != 0)
993 options_push_changes(item
->name
);
994 mode_tree_build(data
->data
);
995 mode_tree_draw(data
->data
);
996 data
->wp
->flags
|= PANE_REDRAW
;
1001 *cause
= toupper((u_char
)*cause
);
1002 status_message_set(c
, -1, 1, 0, "%s", cause
);
1008 window_customize_set_option(struct client
*c
,
1009 struct window_customize_modedata
*data
,
1010 struct window_customize_itemdata
*item
, int global
, int pane
)
1012 struct options_entry
*o
;
1013 const struct options_table_entry
*oe
;
1015 struct window_customize_itemdata
*new_item
;
1016 int flag
, idx
= item
->idx
;
1017 enum window_customize_scope scope
= WINDOW_CUSTOMIZE_NONE
;
1019 const char *name
= item
->name
, *space
= "";
1020 char *prompt
, *value
, *text
;
1021 struct cmd_find_state fs
;
1023 if (item
== NULL
|| !window_customize_check_item(data
, item
, &fs
))
1025 o
= options_get(item
->oo
, name
);
1029 oe
= options_table_entry(o
);
1030 if (oe
!= NULL
&& ~oe
->scope
& OPTIONS_TABLE_PANE
)
1032 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1033 scope
= item
->scope
;
1037 switch (item
->scope
) {
1038 case WINDOW_CUSTOMIZE_NONE
:
1039 case WINDOW_CUSTOMIZE_KEY
:
1040 case WINDOW_CUSTOMIZE_SERVER
:
1041 case WINDOW_CUSTOMIZE_GLOBAL_SESSION
:
1042 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW
:
1043 scope
= item
->scope
;
1045 case WINDOW_CUSTOMIZE_SESSION
:
1046 scope
= WINDOW_CUSTOMIZE_GLOBAL_SESSION
;
1048 case WINDOW_CUSTOMIZE_WINDOW
:
1049 case WINDOW_CUSTOMIZE_PANE
:
1050 scope
= WINDOW_CUSTOMIZE_GLOBAL_WINDOW
;
1054 switch (item
->scope
) {
1055 case WINDOW_CUSTOMIZE_NONE
:
1056 case WINDOW_CUSTOMIZE_KEY
:
1057 case WINDOW_CUSTOMIZE_SERVER
:
1058 case WINDOW_CUSTOMIZE_SESSION
:
1059 scope
= item
->scope
;
1061 case WINDOW_CUSTOMIZE_WINDOW
:
1062 case WINDOW_CUSTOMIZE_PANE
:
1064 scope
= WINDOW_CUSTOMIZE_PANE
;
1066 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1068 case WINDOW_CUSTOMIZE_GLOBAL_SESSION
:
1069 scope
= WINDOW_CUSTOMIZE_SESSION
;
1071 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW
:
1073 scope
= WINDOW_CUSTOMIZE_PANE
;
1075 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1079 if (scope
== item
->scope
)
1082 oo
= window_customize_get_tree(scope
, &fs
);
1085 if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_FLAG
) {
1086 flag
= options_get_number(oo
, name
);
1087 options_set_number(oo
, name
, !flag
);
1088 } else if (oe
!= NULL
&& oe
->type
== OPTIONS_TABLE_CHOICE
) {
1089 choice
= options_get_number(oo
, name
);
1090 if (oe
->choices
[choice
+ 1] == NULL
)
1094 options_set_number(oo
, name
, choice
);
1096 text
= window_customize_scope_text(scope
, &fs
);
1099 else if (scope
!= WINDOW_CUSTOMIZE_SERVER
)
1101 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1103 xasprintf(&prompt
, "(%s[+]%s%s) ", name
, space
,
1106 xasprintf(&prompt
, "(%s[%d]%s%s) ", name
, idx
,
1110 xasprintf(&prompt
, "(%s%s%s) ", name
, space
, text
);
1113 value
= options_to_string(o
, idx
, 0);
1115 new_item
= xcalloc(1, sizeof *new_item
);
1116 new_item
->data
= data
;
1117 new_item
->scope
= scope
;
1119 new_item
->name
= xstrdup(name
);
1120 new_item
->idx
= idx
;
1123 status_prompt_set(c
, NULL
, prompt
, value
,
1124 window_customize_set_option_callback
,
1125 window_customize_free_item_callback
, new_item
,
1126 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1134 window_customize_unset_option(struct window_customize_modedata
*data
,
1135 struct window_customize_itemdata
*item
)
1137 struct options_entry
*o
;
1139 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
1142 o
= options_get(item
->oo
, item
->name
);
1145 if (item
->idx
!= -1 && item
== mode_tree_get_current(data
->data
))
1146 mode_tree_up(data
->data
, 0);
1147 options_remove_or_default(o
, item
->idx
, NULL
);
1151 window_customize_reset_option(struct window_customize_modedata
*data
,
1152 struct window_customize_itemdata
*item
)
1155 struct options_entry
*o
;
1157 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
1159 if (item
->idx
!= -1)
1163 while (oo
!= NULL
) {
1164 o
= options_get_only(item
->oo
, item
->name
);
1166 options_remove_or_default(o
, -1, NULL
);
1167 oo
= options_get_parent(oo
);
1172 window_customize_set_command_callback(struct client
*c
, void *itemdata
,
1173 const char *s
, __unused
int done
)
1175 struct window_customize_itemdata
*item
= itemdata
;
1176 struct window_customize_modedata
*data
= item
->data
;
1177 struct key_binding
*bd
;
1178 struct cmd_parse_result
*pr
;
1181 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1183 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1186 pr
= cmd_parse_from_string(s
, NULL
);
1187 switch (pr
->status
) {
1188 case CMD_PARSE_ERROR
:
1191 case CMD_PARSE_SUCCESS
:
1194 cmd_list_free(bd
->cmdlist
);
1195 bd
->cmdlist
= pr
->cmdlist
;
1197 mode_tree_build(data
->data
);
1198 mode_tree_draw(data
->data
);
1199 data
->wp
->flags
|= PANE_REDRAW
;
1204 *error
= toupper((u_char
)*error
);
1205 status_message_set(c
, -1, 1, 0, "%s", error
);
1211 window_customize_set_note_callback(__unused
struct client
*c
, void *itemdata
,
1212 const char *s
, __unused
int done
)
1214 struct window_customize_itemdata
*item
= itemdata
;
1215 struct window_customize_modedata
*data
= item
->data
;
1216 struct key_binding
*bd
;
1218 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1220 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1223 free((void *)bd
->note
);
1224 bd
->note
= xstrdup(s
);
1226 mode_tree_build(data
->data
);
1227 mode_tree_draw(data
->data
);
1228 data
->wp
->flags
|= PANE_REDRAW
;
1234 window_customize_set_key(struct client
*c
,
1235 struct window_customize_modedata
*data
,
1236 struct window_customize_itemdata
*item
)
1238 key_code key
= item
->key
;
1239 struct key_binding
*bd
;
1241 char *prompt
, *value
;
1242 struct window_customize_itemdata
*new_item
;
1244 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1247 s
= mode_tree_get_current_name(data
->data
);
1248 if (strcmp(s
, "Repeat") == 0)
1249 bd
->flags
^= KEY_BINDING_REPEAT
;
1250 else if (strcmp(s
, "Command") == 0) {
1251 xasprintf(&prompt
, "(%s) ", key_string_lookup_key(key
, 0));
1252 value
= cmd_list_print(bd
->cmdlist
, 0);
1254 new_item
= xcalloc(1, sizeof *new_item
);
1255 new_item
->data
= data
;
1256 new_item
->scope
= item
->scope
;
1257 new_item
->table
= xstrdup(item
->table
);
1258 new_item
->key
= key
;
1261 status_prompt_set(c
, NULL
, prompt
, value
,
1262 window_customize_set_command_callback
,
1263 window_customize_free_item_callback
, new_item
,
1264 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1267 } else if (strcmp(s
, "Note") == 0) {
1268 xasprintf(&prompt
, "(%s) ", key_string_lookup_key(key
, 0));
1270 new_item
= xcalloc(1, sizeof *new_item
);
1271 new_item
->data
= data
;
1272 new_item
->scope
= item
->scope
;
1273 new_item
->table
= xstrdup(item
->table
);
1274 new_item
->key
= key
;
1277 status_prompt_set(c
, NULL
, prompt
,
1278 (bd
->note
== NULL
? "" : bd
->note
),
1279 window_customize_set_note_callback
,
1280 window_customize_free_item_callback
, new_item
,
1281 PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1287 window_customize_unset_key(struct window_customize_modedata
*data
,
1288 struct window_customize_itemdata
*item
)
1290 struct key_table
*kt
;
1291 struct key_binding
*bd
;
1293 if (item
== NULL
|| !window_customize_get_key(item
, &kt
, &bd
))
1296 if (item
== mode_tree_get_current(data
->data
)) {
1297 mode_tree_collapse_current(data
->data
);
1298 mode_tree_up(data
->data
, 0);
1300 key_bindings_remove(kt
->name
, bd
->key
);
1304 window_customize_reset_key(struct window_customize_modedata
*data
,
1305 struct window_customize_itemdata
*item
)
1307 struct key_table
*kt
;
1308 struct key_binding
*dd
, *bd
;
1310 if (item
== NULL
|| !window_customize_get_key(item
, &kt
, &bd
))
1313 dd
= key_bindings_get_default(kt
, bd
->key
);
1314 if (dd
!= NULL
&& bd
->cmdlist
== dd
->cmdlist
)
1316 if (dd
== NULL
&& item
== mode_tree_get_current(data
->data
)) {
1317 mode_tree_collapse_current(data
->data
);
1318 mode_tree_up(data
->data
, 0);
1320 key_bindings_reset(kt
->name
, bd
->key
);
1324 window_customize_change_each(void *modedata
, void *itemdata
,
1325 __unused
struct client
*c
, __unused key_code key
)
1327 struct window_customize_modedata
*data
= modedata
;
1328 struct window_customize_itemdata
*item
= itemdata
;
1330 switch (data
->change
) {
1331 case WINDOW_CUSTOMIZE_UNSET
:
1332 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1333 window_customize_unset_key(data
, item
);
1335 window_customize_unset_option(data
, item
);
1337 case WINDOW_CUSTOMIZE_RESET
:
1338 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1339 window_customize_reset_key(data
, item
);
1341 window_customize_reset_option(data
, item
);
1344 if (item
->scope
!= WINDOW_CUSTOMIZE_KEY
)
1345 options_push_changes(item
->name
);
1349 window_customize_change_current_callback(__unused
struct client
*c
,
1350 void *modedata
, const char *s
, __unused
int done
)
1352 struct window_customize_modedata
*data
= modedata
;
1353 struct window_customize_itemdata
*item
;
1355 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1357 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\0')
1360 item
= mode_tree_get_current(data
->data
);
1361 switch (data
->change
) {
1362 case WINDOW_CUSTOMIZE_UNSET
:
1363 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1364 window_customize_unset_key(data
, item
);
1366 window_customize_unset_option(data
, item
);
1368 case WINDOW_CUSTOMIZE_RESET
:
1369 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1370 window_customize_reset_key(data
, item
);
1372 window_customize_reset_option(data
, item
);
1375 if (item
->scope
!= WINDOW_CUSTOMIZE_KEY
)
1376 options_push_changes(item
->name
);
1377 mode_tree_build(data
->data
);
1378 mode_tree_draw(data
->data
);
1379 data
->wp
->flags
|= PANE_REDRAW
;
1385 window_customize_change_tagged_callback(struct client
*c
, void *modedata
,
1386 const char *s
, __unused
int done
)
1388 struct window_customize_modedata
*data
= modedata
;
1390 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1392 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\0')
1395 mode_tree_each_tagged(data
->data
, window_customize_change_each
, c
,
1397 mode_tree_build(data
->data
);
1398 mode_tree_draw(data
->data
);
1399 data
->wp
->flags
|= PANE_REDRAW
;
1405 window_customize_key(struct window_mode_entry
*wme
, struct client
*c
,
1406 __unused
struct session
*s
, __unused
struct winlink
*wl
, key_code key
,
1407 struct mouse_event
*m
)
1409 struct window_pane
*wp
= wme
->wp
;
1410 struct window_customize_modedata
*data
= wme
->data
;
1411 struct window_customize_itemdata
*item
, *new_item
;
1416 item
= mode_tree_get_current(data
->data
);
1417 finished
= mode_tree_key(data
->data
, c
, &key
, m
, NULL
, NULL
);
1418 if (item
!= (new_item
= mode_tree_get_current(data
->data
)))
1426 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1427 window_customize_set_key(c
, data
, item
);
1429 window_customize_set_option(c
, data
, item
, 0, 1);
1430 options_push_changes(item
->name
);
1432 mode_tree_build(data
->data
);
1435 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1437 window_customize_set_option(c
, data
, item
, 0, 0);
1438 options_push_changes(item
->name
);
1439 mode_tree_build(data
->data
);
1443 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1445 window_customize_set_option(c
, data
, item
, 1, 0);
1446 options_push_changes(item
->name
);
1447 mode_tree_build(data
->data
);
1450 if (item
== NULL
|| item
->idx
!= -1)
1452 xasprintf(&prompt
, "Reset %s to default? ", item
->name
);
1454 data
->change
= WINDOW_CUSTOMIZE_RESET
;
1455 status_prompt_set(c
, NULL
, prompt
, "",
1456 window_customize_change_current_callback
,
1457 window_customize_free_callback
, data
,
1458 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1462 tagged
= mode_tree_count_tagged(data
->data
);
1465 xasprintf(&prompt
, "Reset %u tagged to default? ", tagged
);
1467 data
->change
= WINDOW_CUSTOMIZE_RESET
;
1468 status_prompt_set(c
, NULL
, prompt
, "",
1469 window_customize_change_tagged_callback
,
1470 window_customize_free_callback
, data
,
1471 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1479 xasprintf(&prompt
, "Unset %s[%d]? ", item
->name
, idx
);
1481 xasprintf(&prompt
, "Unset %s? ", item
->name
);
1483 data
->change
= WINDOW_CUSTOMIZE_UNSET
;
1484 status_prompt_set(c
, NULL
, prompt
, "",
1485 window_customize_change_current_callback
,
1486 window_customize_free_callback
, data
,
1487 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1491 tagged
= mode_tree_count_tagged(data
->data
);
1494 xasprintf(&prompt
, "Unset %u tagged? ", tagged
);
1496 data
->change
= WINDOW_CUSTOMIZE_UNSET
;
1497 status_prompt_set(c
, NULL
, prompt
, "",
1498 window_customize_change_tagged_callback
,
1499 window_customize_free_callback
, data
,
1500 PROMPT_SINGLE
|PROMPT_NOFORMAT
, PROMPT_TYPE_COMMAND
);
1504 data
->hide_global
= !data
->hide_global
;
1505 mode_tree_build(data
->data
);
1509 window_pane_reset_mode(wp
);
1511 mode_tree_draw(data
->data
);
1512 wp
->flags
|= PANE_REDRAW
;