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
;
106 struct window_customize_itemdata
**item_list
;
109 struct cmd_find_state fs
;
110 enum window_customize_change change
;
114 window_customize_get_tag(struct options_entry
*o
, int idx
,
115 const struct options_table_entry
*oe
)
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
)
130 case WINDOW_CUSTOMIZE_NONE
:
131 case WINDOW_CUSTOMIZE_KEY
:
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
);
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
;
158 if (cmd_find_valid_state(&data
->fs
))
159 cmd_find_copy_state(fsp
, &data
->fs
);
161 cmd_find_from_pane(fsp
, data
->wp
, 0);
162 return (item
->oo
== window_customize_get_tree(item
->scope
, fsp
));
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);
175 bd
= key_bindings_get(kt
, item
->key
);
187 window_customize_scope_text(enum window_customize_scope scope
,
188 struct cmd_find_state
*fs
)
194 case WINDOW_CUSTOMIZE_PANE
:
195 window_pane_index(fs
->wp
, &idx
);
196 xasprintf(&s
, "pane %u", idx
);
198 case WINDOW_CUSTOMIZE_SESSION
:
199 xasprintf(&s
, "session %s", fs
->s
->name
);
201 case WINDOW_CUSTOMIZE_WINDOW
:
202 xasprintf(&s
, "window %u", fs
->wl
->idx
);
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
);
223 window_customize_free_item(struct window_customize_itemdata
*item
)
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
;
243 ai
= options_array_first(o
);
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
);
255 item
->name
= xstrdup(options_name(o
));
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);
266 ai
= options_array_next(ai
);
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;
284 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_HOOK
))
286 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
))
289 if (scope
== WINDOW_CUSTOMIZE_SERVER
||
290 scope
== WINDOW_CUSTOMIZE_GLOBAL_SESSION
||
291 scope
== WINDOW_CUSTOMIZE_GLOBAL_WINDOW
)
293 if (data
->hide_global
&& global
)
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
);
304 if (oe
!= NULL
&& oe
->unit
!= NULL
)
305 format_add(ft
, "option_unit", "%s", oe
->unit
);
307 format_add(ft
, "option_unit", "%s", "");
310 value
= options_to_string(o
, -1, 0);
311 format_add(ft
, "option_value", "%s", value
);
315 if (filter
!= NULL
) {
316 expanded
= format_expand(ft
, filter
);
317 if (!format_true(expanded
)) {
323 item
= window_customize_add_item(data
);
326 item
->name
= xstrdup(name
);
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);
338 window_customize_build_array(data
, top
, scope
, o
, ft
);
342 window_customize_find_user_options(struct options
*oo
, const char ***list
,
345 struct options_entry
*o
;
349 o
= options_first(oo
);
351 name
= options_name(o
);
356 for (i
= 0; i
< *size
; i
++) {
357 if (strcmp((*list
)[i
], name
) == 0)
364 *list
= xreallocarray(*list
, (*size
) + 1, sizeof **list
);
365 (*list
)[(*size
)++] = name
;
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
;
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
);
396 window_customize_find_user_options(oo1
, &list
, &size
);
398 window_customize_find_user_options(oo2
, &list
, &size
);
400 for (i
= 0; i
< size
; i
++) {
402 o
= options_get(oo2
, list
[i
]);
403 if (o
== NULL
&& oo1
!= NULL
)
404 o
= options_get(oo1
, list
[i
]);
406 o
= options_get(oo0
, list
[i
]);
407 if (options_owner(o
) == oo2
)
409 else if (options_owner(o
) == oo1
)
413 window_customize_build_option(data
, top
, scope
, o
, ft
, filter
,
418 loop
= options_first(oo0
);
419 while (loop
!= NULL
) {
420 name
= options_name(loop
);
422 loop
= options_next(loop
);
426 o
= options_get(oo2
, name
);
427 else if (oo1
!= NULL
)
428 o
= options_get(oo1
, name
);
431 if (options_owner(o
) == oo2
)
433 else if (options_owner(o
) == oo1
)
437 window_customize_build_option(data
, top
, scope
, o
, ft
, filter
,
439 loop
= options_next(loop
);
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
;
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
);
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
);
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
)) {
480 item
= window_customize_add_item(data
);
481 item
->scope
= WINDOW_CUSTOMIZE_KEY
;
482 item
->table
= xstrdup(kt
->name
);
484 item
->name
= xstrdup(key_string_lookup_key(item
->key
, 0));
487 expanded
= format_expand(ft
, data
->format
);
488 child
= mode_tree_add(data
->data
, top
, item
, (uint64_t)bd
,
492 tmp
= cmd_list_print(bd
->cmdlist
, 0);
493 xasprintf(&text
, "#[ignore]%s", 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
);
501 if (bd
->note
!= NULL
)
502 xasprintf(&text
, "#[ignore]%s", bd
->note
);
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
);
511 if (bd
->flags
& KEY_BINDING_REPEAT
)
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
);
527 window_customize_build(void *modedata
,
528 __unused
struct mode_tree_sort_criteria
*sort_crit
, __unused
uint64_t *tag
,
531 struct window_customize_modedata
*data
= modedata
;
532 struct cmd_find_state fs
;
533 struct format_tree
*ft
;
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
;
543 if (cmd_find_valid_state(&data
->fs
))
544 cmd_find_copy_state(&fs
, &data
->fs
);
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
,
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
,
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
,
572 ft
= format_create_from_state(NULL
, NULL
, &fs
);
575 kt
= key_bindings_first_table();
577 if (!RB_EMPTY(&kt
->key_bindings
)) {
578 window_customize_build_keys(data
, kt
, ft
, filter
, &fs
,
583 kt
= key_bindings_next_table(kt
);
590 window_customize_draw_key(__unused
struct window_customize_modedata
*data
,
591 struct window_customize_itemdata
*item
, struct screen_write_ctx
*ctx
,
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
))
606 note
= "There is no note for this key.";
607 if (*note
!= '\0' && note
[strlen (note
) - 1] != '.')
609 if (!screen_write_text(ctx
, cx
, sx
, sy
, 0, &grid_default_cell
, "%s%s",
612 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
613 if (s
->cy
>= cy
+ sy
- 1)
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
))
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"))
623 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
624 if (s
->cy
>= cy
+ sy
- 1)
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
)) {
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
)) {
649 window_customize_draw_option(struct window_customize_modedata
*data
,
650 struct window_customize_itemdata
*item
, struct screen_write_ctx
*ctx
,
653 struct screen
*s
= ctx
->s
;
654 u_int cx
= s
->cx
, cy
= s
->cy
;
656 struct options_entry
*o
, *parent
;
657 struct options
*go
, *wo
;
658 const struct options_table_entry
*oe
;
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
))
673 o
= options_get(item
->oo
, name
);
676 oe
= options_table_entry(o
);
678 if (oe
!= NULL
&& oe
->unit
!= NULL
) {
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.";
688 if (!screen_write_text(ctx
, cx
, sx
, sy
, 0, &grid_default_cell
, "%s",
691 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
692 if (s
->cy
>= cy
+ sy
- 1)
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
)
702 else if (oe
->scope
& OPTIONS_TABLE_SESSION
)
706 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0,
707 &grid_default_cell
, "This is a %s option.", text
))
709 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
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
))
716 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
),
717 0, &grid_default_cell
, "This is an array option."))
723 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
724 if (s
->cy
>= cy
+ sy
- 1)
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) {
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
))
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",
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",
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: "))
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
,
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: "))
773 style_apply(&gc
, item
->oo
, name
, ft
);
774 if (!screen_write_text(ctx
, cx
, sx
, sy
- (s
->cy
- cy
), 0, &gc
,
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
,
785 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0); /* skip line */
786 if (s
->cy
> cy
+ sy
- 1)
788 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
792 switch (item
->scope
) {
793 case WINDOW_CUSTOMIZE_PANE
:
794 wo
= options_get_parent(item
->oo
);
795 go
= options_get_parent(wo
);
797 case WINDOW_CUSTOMIZE_WINDOW
:
798 case WINDOW_CUSTOMIZE_SESSION
:
800 go
= options_get_parent(item
->oo
);
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
,
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
))
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
;
846 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
847 window_customize_draw_key(data
, item
, ctx
, sx
, sy
);
849 window_customize_draw_option(data
, item
, ctx
, sx
, sy
);
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
)
862 window_customize_key(wme
, c
, NULL
, NULL
, key
, NULL
);
866 window_customize_height(__unused
void *modedata
, __unused u_int height
)
871 static struct screen
*
872 window_customize_init(struct window_mode_entry
*wme
, struct cmd_find_state
*fs
,
875 struct window_pane
*wp
= wme
->wp
;
876 struct window_customize_modedata
*data
;
879 wme
->data
= data
= xcalloc(1, sizeof *data
);
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
);
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
,
896 mode_tree_zoom(data
->data
, args
);
898 mode_tree_build(data
->data
);
899 mode_tree_draw(data
->data
);
905 window_customize_destroy(struct window_customize_modedata
*data
)
909 if (--data
->references
!= 0)
912 for (i
= 0; i
< data
->item_size
; i
++)
913 window_customize_free_item(data
->item_list
[i
]);
914 free(data
->item_list
);
922 window_customize_free(struct window_mode_entry
*wme
)
924 struct window_customize_modedata
*data
= wme
->data
;
930 mode_tree_free(data
->data
);
931 window_customize_destroy(data
);
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
);
943 window_customize_free_callback(void *modedata
)
945 window_customize_destroy(modedata
);
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
);
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
;
971 if (s
== NULL
|| *s
== '\0' || data
->dead
)
973 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
975 o
= options_get(oo
, name
);
978 oe
= options_table_entry(o
);
980 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
982 for (idx
= 0; idx
< INT_MAX
; idx
++) {
983 if (options_array_get(o
, idx
) == NULL
)
987 if (options_array_set(o
, idx
, s
, 0, &cause
) != 0)
990 if (options_from_string(oo
, oe
, name
, s
, 0, &cause
) != 0)
994 options_push_changes(item
->name
);
995 mode_tree_build(data
->data
);
996 mode_tree_draw(data
->data
);
997 data
->wp
->flags
|= PANE_REDRAW
;
1002 *cause
= toupper((u_char
)*cause
);
1003 status_message_set(c
, -1, 1, 0, "%s", cause
);
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
;
1016 struct window_customize_itemdata
*new_item
;
1017 int flag
, idx
= item
->idx
;
1018 enum window_customize_scope scope
= WINDOW_CUSTOMIZE_NONE
;
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
))
1026 o
= options_get(item
->oo
, name
);
1030 oe
= options_table_entry(o
);
1031 if (oe
!= NULL
&& ~oe
->scope
& OPTIONS_TABLE_PANE
)
1033 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1034 scope
= item
->scope
;
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
;
1046 case WINDOW_CUSTOMIZE_SESSION
:
1047 scope
= WINDOW_CUSTOMIZE_GLOBAL_SESSION
;
1049 case WINDOW_CUSTOMIZE_WINDOW
:
1050 case WINDOW_CUSTOMIZE_PANE
:
1051 scope
= WINDOW_CUSTOMIZE_GLOBAL_WINDOW
;
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
;
1062 case WINDOW_CUSTOMIZE_WINDOW
:
1063 case WINDOW_CUSTOMIZE_PANE
:
1065 scope
= WINDOW_CUSTOMIZE_PANE
;
1067 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1069 case WINDOW_CUSTOMIZE_GLOBAL_SESSION
:
1070 scope
= WINDOW_CUSTOMIZE_SESSION
;
1072 case WINDOW_CUSTOMIZE_GLOBAL_WINDOW
:
1074 scope
= WINDOW_CUSTOMIZE_PANE
;
1076 scope
= WINDOW_CUSTOMIZE_WINDOW
;
1080 if (scope
== item
->scope
)
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
)
1095 options_set_number(oo
, name
, choice
);
1097 text
= window_customize_scope_text(scope
, &fs
);
1100 else if (scope
!= WINDOW_CUSTOMIZE_SERVER
)
1102 if (oe
!= NULL
&& (oe
->flags
& OPTIONS_TABLE_IS_ARRAY
)) {
1104 xasprintf(&prompt
, "(%s[+]%s%s) ", name
, space
,
1107 xasprintf(&prompt
, "(%s[%d]%s%s) ", name
, idx
,
1111 xasprintf(&prompt
, "(%s%s%s) ", name
, space
, 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
;
1120 new_item
->name
= xstrdup(name
);
1121 new_item
->idx
= idx
;
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
);
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
))
1143 o
= options_get(item
->oo
, item
->name
);
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
);
1152 window_customize_reset_option(struct window_customize_modedata
*data
,
1153 struct window_customize_itemdata
*item
)
1156 struct options_entry
*o
;
1158 if (item
== NULL
|| !window_customize_check_item(data
, item
, NULL
))
1160 if (item
->idx
!= -1)
1164 while (oo
!= NULL
) {
1165 o
= options_get_only(item
->oo
, item
->name
);
1167 options_remove_or_default(o
, -1, NULL
);
1168 oo
= options_get_parent(oo
);
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
;
1182 if (s
== NULL
|| *s
== '\0' || data
->dead
)
1184 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
1187 pr
= cmd_parse_from_string(s
, NULL
);
1188 switch (pr
->status
) {
1189 case CMD_PARSE_ERROR
:
1192 case CMD_PARSE_SUCCESS
:
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
;
1205 *error
= toupper((u_char
)*error
);
1206 status_message_set(c
, -1, 1, 0, "%s", error
);
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
)
1221 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
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
;
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
;
1242 char *prompt
, *value
;
1243 struct window_customize_itemdata
*new_item
;
1245 if (item
== NULL
|| !window_customize_get_key(item
, NULL
, &bd
))
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
;
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
);
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
;
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
);
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
))
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
);
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
))
1314 dd
= key_bindings_get_default(kt
, bd
->key
);
1315 if (dd
!= NULL
&& bd
->cmdlist
== dd
->cmdlist
)
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
);
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
);
1336 window_customize_unset_option(data
, item
);
1338 case WINDOW_CUSTOMIZE_RESET
:
1339 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1340 window_customize_reset_key(data
, item
);
1342 window_customize_reset_option(data
, item
);
1345 if (item
->scope
!= WINDOW_CUSTOMIZE_KEY
)
1346 options_push_changes(item
->name
);
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
)
1358 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\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
);
1367 window_customize_unset_option(data
, item
);
1369 case WINDOW_CUSTOMIZE_RESET
:
1370 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1371 window_customize_reset_key(data
, item
);
1373 window_customize_reset_option(data
, item
);
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
;
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
)
1393 if (tolower((u_char
) s
[0]) != 'y' || s
[1] != '\0')
1396 mode_tree_each_tagged(data
->data
, window_customize_change_each
, c
,
1398 mode_tree_build(data
->data
);
1399 mode_tree_draw(data
->data
);
1400 data
->wp
->flags
|= PANE_REDRAW
;
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
;
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
)))
1427 if (item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1428 window_customize_set_key(c
, data
, item
);
1430 window_customize_set_option(c
, data
, item
, 0, 1);
1431 options_push_changes(item
->name
);
1433 mode_tree_build(data
->data
);
1436 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1438 window_customize_set_option(c
, data
, item
, 0, 0);
1439 options_push_changes(item
->name
);
1440 mode_tree_build(data
->data
);
1444 if (item
== NULL
|| item
->scope
== WINDOW_CUSTOMIZE_KEY
)
1446 window_customize_set_option(c
, data
, item
, 1, 0);
1447 options_push_changes(item
->name
);
1448 mode_tree_build(data
->data
);
1451 if (item
== NULL
|| item
->idx
!= -1)
1453 xasprintf(&prompt
, "Reset %s to default? ", item
->name
);
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
);
1464 tagged
= mode_tree_count_tagged(data
->data
);
1467 xasprintf(&prompt
, "Reset %u tagged to default? ", tagged
);
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
);
1482 xasprintf(&prompt
, "Unset %s[%d]? ", item
->name
, idx
);
1484 xasprintf(&prompt
, "Unset %s? ", item
->name
);
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
);
1495 tagged
= mode_tree_count_tagged(data
->data
);
1498 xasprintf(&prompt
, "Unset %u tagged? ", tagged
);
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
);
1509 data
->hide_global
= !data
->hide_global
;
1510 mode_tree_build(data
->data
);
1514 window_pane_reset_mode(wp
);
1516 mode_tree_draw(data
->data
);
1517 wp
->flags
|= PANE_REDRAW
;