1*af11b61dSnicm /* $OpenBSD: window-customize.c,v 1.15 2024/10/04 19:16:13 nicm Exp $ */ 267c16a7cSnicm 367c16a7cSnicm /* 467c16a7cSnicm * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com> 567c16a7cSnicm * 667c16a7cSnicm * Permission to use, copy, modify, and distribute this software for any 767c16a7cSnicm * purpose with or without fee is hereby granted, provided that the above 867c16a7cSnicm * copyright notice and this permission notice appear in all copies. 967c16a7cSnicm * 1067c16a7cSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1167c16a7cSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1267c16a7cSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1367c16a7cSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1467c16a7cSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 1567c16a7cSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 1667c16a7cSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1767c16a7cSnicm */ 1867c16a7cSnicm 1967c16a7cSnicm #include <sys/types.h> 2067c16a7cSnicm 2167c16a7cSnicm #include <ctype.h> 2267c16a7cSnicm #include <stdlib.h> 2367c16a7cSnicm #include <string.h> 2467c16a7cSnicm 2567c16a7cSnicm #include "tmux.h" 2667c16a7cSnicm 2767c16a7cSnicm static struct screen *window_customize_init(struct window_mode_entry *, 2867c16a7cSnicm struct cmd_find_state *, struct args *); 2967c16a7cSnicm static void window_customize_free(struct window_mode_entry *); 3067c16a7cSnicm static void window_customize_resize(struct window_mode_entry *, 3167c16a7cSnicm u_int, u_int); 3267c16a7cSnicm static void window_customize_key(struct window_mode_entry *, 3367c16a7cSnicm struct client *, struct session *, 3467c16a7cSnicm struct winlink *, key_code, struct mouse_event *); 3567c16a7cSnicm 3667c16a7cSnicm #define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \ 3767c16a7cSnicm "#{?is_option," \ 3867c16a7cSnicm "#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \ 3967c16a7cSnicm "#[ignore]" \ 4067c16a7cSnicm "#{option_value}#{?option_unit, #{option_unit},}" \ 4167c16a7cSnicm "," \ 4267c16a7cSnicm "#{key}" \ 4367c16a7cSnicm "}" 4467c16a7cSnicm 4567c16a7cSnicm static const struct menu_item window_customize_menu_items[] = { 4667c16a7cSnicm { "Select", '\r', NULL }, 4767c16a7cSnicm { "Expand", KEYC_RIGHT, NULL }, 4867c16a7cSnicm { "", KEYC_NONE, NULL }, 4967c16a7cSnicm { "Tag", 't', NULL }, 5067c16a7cSnicm { "Tag All", '\024', NULL }, 5167c16a7cSnicm { "Tag None", 'T', NULL }, 5267c16a7cSnicm { "", KEYC_NONE, NULL }, 5367c16a7cSnicm { "Cancel", 'q', NULL }, 5467c16a7cSnicm 5567c16a7cSnicm { NULL, KEYC_NONE, NULL } 5667c16a7cSnicm }; 5767c16a7cSnicm 5867c16a7cSnicm const struct window_mode window_customize_mode = { 5967c16a7cSnicm .name = "options-mode", 6067c16a7cSnicm .default_format = WINDOW_CUSTOMIZE_DEFAULT_FORMAT, 6167c16a7cSnicm 6267c16a7cSnicm .init = window_customize_init, 6367c16a7cSnicm .free = window_customize_free, 6467c16a7cSnicm .resize = window_customize_resize, 6567c16a7cSnicm .key = window_customize_key, 6667c16a7cSnicm }; 6767c16a7cSnicm 6867c16a7cSnicm enum window_customize_scope { 6967c16a7cSnicm WINDOW_CUSTOMIZE_NONE, 7067c16a7cSnicm WINDOW_CUSTOMIZE_KEY, 7167c16a7cSnicm WINDOW_CUSTOMIZE_SERVER, 7267c16a7cSnicm WINDOW_CUSTOMIZE_GLOBAL_SESSION, 7367c16a7cSnicm WINDOW_CUSTOMIZE_SESSION, 7467c16a7cSnicm WINDOW_CUSTOMIZE_GLOBAL_WINDOW, 7567c16a7cSnicm WINDOW_CUSTOMIZE_WINDOW, 7667c16a7cSnicm WINDOW_CUSTOMIZE_PANE 7767c16a7cSnicm }; 7867c16a7cSnicm 7994c0d63cSnicm enum window_customize_change { 8094c0d63cSnicm WINDOW_CUSTOMIZE_UNSET, 8194c0d63cSnicm WINDOW_CUSTOMIZE_RESET, 8294c0d63cSnicm }; 8394c0d63cSnicm 8467c16a7cSnicm struct window_customize_itemdata { 8567c16a7cSnicm struct window_customize_modedata *data; 8667c16a7cSnicm enum window_customize_scope scope; 8767c16a7cSnicm 8867c16a7cSnicm char *table; 8967c16a7cSnicm key_code key; 9067c16a7cSnicm 9167c16a7cSnicm struct options *oo; 9267c16a7cSnicm char *name; 9367c16a7cSnicm int idx; 9467c16a7cSnicm }; 9567c16a7cSnicm 9667c16a7cSnicm struct window_customize_modedata { 9767c16a7cSnicm struct window_pane *wp; 9867c16a7cSnicm int dead; 9967c16a7cSnicm int references; 10067c16a7cSnicm 10167c16a7cSnicm struct mode_tree_data *data; 10267c16a7cSnicm char *format; 10367c16a7cSnicm int hide_global; 104*af11b61dSnicm int prompt_flags; 10567c16a7cSnicm 10667c16a7cSnicm struct window_customize_itemdata **item_list; 10767c16a7cSnicm u_int item_size; 10867c16a7cSnicm 10967c16a7cSnicm struct cmd_find_state fs; 11094c0d63cSnicm enum window_customize_change change; 11167c16a7cSnicm }; 11267c16a7cSnicm 11367c16a7cSnicm static uint64_t 11467c16a7cSnicm window_customize_get_tag(struct options_entry *o, int idx, 11567c16a7cSnicm const struct options_table_entry *oe) 11667c16a7cSnicm { 11767c16a7cSnicm uint64_t offset; 11867c16a7cSnicm 11967c16a7cSnicm if (oe == NULL) 12067c16a7cSnicm return ((uint64_t)o); 12167c16a7cSnicm offset = ((char *)oe - (char *)options_table) / sizeof *options_table; 12267c16a7cSnicm return ((2ULL << 62)|(offset << 32)|((idx + 1) << 1)|1); 12367c16a7cSnicm } 12467c16a7cSnicm 12567c16a7cSnicm static struct options * 12667c16a7cSnicm window_customize_get_tree(enum window_customize_scope scope, 12767c16a7cSnicm struct cmd_find_state *fs) 12867c16a7cSnicm { 12967c16a7cSnicm switch (scope) { 13067c16a7cSnicm case WINDOW_CUSTOMIZE_NONE: 13167c16a7cSnicm case WINDOW_CUSTOMIZE_KEY: 13267c16a7cSnicm return (NULL); 13367c16a7cSnicm case WINDOW_CUSTOMIZE_SERVER: 13467c16a7cSnicm return (global_options); 13567c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_SESSION: 13667c16a7cSnicm return (global_s_options); 13767c16a7cSnicm case WINDOW_CUSTOMIZE_SESSION: 13867c16a7cSnicm return (fs->s->options); 13967c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: 14067c16a7cSnicm return (global_w_options); 14167c16a7cSnicm case WINDOW_CUSTOMIZE_WINDOW: 14267c16a7cSnicm return (fs->w->options); 14367c16a7cSnicm case WINDOW_CUSTOMIZE_PANE: 14467c16a7cSnicm return (fs->wp->options); 14567c16a7cSnicm } 14667c16a7cSnicm return (NULL); 14767c16a7cSnicm } 14867c16a7cSnicm 14967c16a7cSnicm static int 15067c16a7cSnicm window_customize_check_item(struct window_customize_modedata *data, 15167c16a7cSnicm struct window_customize_itemdata *item, struct cmd_find_state *fsp) 15267c16a7cSnicm { 15367c16a7cSnicm struct cmd_find_state fs; 15467c16a7cSnicm 15567c16a7cSnicm if (fsp == NULL) 15667c16a7cSnicm fsp = &fs; 15767c16a7cSnicm 15867c16a7cSnicm if (cmd_find_valid_state(&data->fs)) 15967c16a7cSnicm cmd_find_copy_state(fsp, &data->fs); 16067c16a7cSnicm else 16167c16a7cSnicm cmd_find_from_pane(fsp, data->wp, 0); 16267c16a7cSnicm return (item->oo == window_customize_get_tree(item->scope, fsp)); 16367c16a7cSnicm } 16467c16a7cSnicm 16567c16a7cSnicm static int 16667c16a7cSnicm window_customize_get_key(struct window_customize_itemdata *item, 16767c16a7cSnicm struct key_table **ktp, struct key_binding **bdp) 16867c16a7cSnicm { 16967c16a7cSnicm struct key_table *kt; 17067c16a7cSnicm struct key_binding *bd; 17167c16a7cSnicm 17267c16a7cSnicm kt = key_bindings_get_table(item->table, 0); 17367c16a7cSnicm if (kt == NULL) 17467c16a7cSnicm return (0); 17567c16a7cSnicm bd = key_bindings_get(kt, item->key); 17667c16a7cSnicm if (bd == NULL) 17767c16a7cSnicm return (0); 17867c16a7cSnicm 17967c16a7cSnicm if (ktp != NULL) 18067c16a7cSnicm *ktp = kt; 18167c16a7cSnicm if (bdp != NULL) 18267c16a7cSnicm *bdp = bd; 18367c16a7cSnicm return (1); 18467c16a7cSnicm } 18567c16a7cSnicm 18667c16a7cSnicm static char * 18767c16a7cSnicm window_customize_scope_text(enum window_customize_scope scope, 18867c16a7cSnicm struct cmd_find_state *fs) 18967c16a7cSnicm { 19067c16a7cSnicm char *s; 19167c16a7cSnicm u_int idx; 19267c16a7cSnicm 19367c16a7cSnicm switch (scope) { 19467c16a7cSnicm case WINDOW_CUSTOMIZE_PANE: 19567c16a7cSnicm window_pane_index(fs->wp, &idx); 19667c16a7cSnicm xasprintf(&s, "pane %u", idx); 19767c16a7cSnicm break; 19867c16a7cSnicm case WINDOW_CUSTOMIZE_SESSION: 19967c16a7cSnicm xasprintf(&s, "session %s", fs->s->name); 20067c16a7cSnicm break; 20167c16a7cSnicm case WINDOW_CUSTOMIZE_WINDOW: 20267c16a7cSnicm xasprintf(&s, "window %u", fs->wl->idx); 20367c16a7cSnicm break; 2048f1cd816Snicm default: 2058f1cd816Snicm s = xstrdup(""); 2068f1cd816Snicm break; 20767c16a7cSnicm } 20867c16a7cSnicm return (s); 20967c16a7cSnicm } 21067c16a7cSnicm 21167c16a7cSnicm static struct window_customize_itemdata * 21267c16a7cSnicm window_customize_add_item(struct window_customize_modedata *data) 21367c16a7cSnicm { 21467c16a7cSnicm struct window_customize_itemdata *item; 21567c16a7cSnicm 21667c16a7cSnicm data->item_list = xreallocarray(data->item_list, data->item_size + 1, 21767c16a7cSnicm sizeof *data->item_list); 21867c16a7cSnicm item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item); 21967c16a7cSnicm return (item); 22067c16a7cSnicm } 22167c16a7cSnicm 22267c16a7cSnicm static void 22367c16a7cSnicm window_customize_free_item(struct window_customize_itemdata *item) 22467c16a7cSnicm { 22567c16a7cSnicm free(item->table); 22667c16a7cSnicm free(item->name); 22767c16a7cSnicm free(item); 22867c16a7cSnicm } 22967c16a7cSnicm 23067c16a7cSnicm static void 23167c16a7cSnicm window_customize_build_array(struct window_customize_modedata *data, 23267c16a7cSnicm struct mode_tree_item *top, enum window_customize_scope scope, 23367c16a7cSnicm struct options_entry *o, struct format_tree *ft) 23467c16a7cSnicm { 23567c16a7cSnicm const struct options_table_entry *oe = options_table_entry(o); 23667c16a7cSnicm struct options *oo = options_owner(o); 23767c16a7cSnicm struct window_customize_itemdata *item; 23867c16a7cSnicm struct options_array_item *ai; 23967c16a7cSnicm char *name, *value, *text; 24067c16a7cSnicm u_int idx; 24167c16a7cSnicm uint64_t tag; 24267c16a7cSnicm 24367c16a7cSnicm ai = options_array_first(o); 24467c16a7cSnicm while (ai != NULL) { 24567c16a7cSnicm idx = options_array_item_index(ai); 24667c16a7cSnicm 24767c16a7cSnicm xasprintf(&name, "%s[%u]", options_name(o), idx); 24867c16a7cSnicm format_add(ft, "option_name", "%s", name); 24967c16a7cSnicm value = options_to_string(o, idx, 0); 25067c16a7cSnicm format_add(ft, "option_value", "%s", value); 25167c16a7cSnicm 25267c16a7cSnicm item = window_customize_add_item(data); 25367c16a7cSnicm item->scope = scope; 25467c16a7cSnicm item->oo = oo; 25567c16a7cSnicm item->name = xstrdup(options_name(o)); 25667c16a7cSnicm item->idx = idx; 25767c16a7cSnicm 25867c16a7cSnicm text = format_expand(ft, data->format); 25967c16a7cSnicm tag = window_customize_get_tag(o, idx, oe); 26067c16a7cSnicm mode_tree_add(data->data, top, item, tag, name, text, -1); 26167c16a7cSnicm free(text); 26267c16a7cSnicm 26367c16a7cSnicm free(name); 26467c16a7cSnicm free(value); 26567c16a7cSnicm 26667c16a7cSnicm ai = options_array_next(ai); 26767c16a7cSnicm } 26867c16a7cSnicm } 26967c16a7cSnicm 27067c16a7cSnicm static void 27167c16a7cSnicm window_customize_build_option(struct window_customize_modedata *data, 27267c16a7cSnicm struct mode_tree_item *top, enum window_customize_scope scope, 27367c16a7cSnicm struct options_entry *o, struct format_tree *ft, 27467c16a7cSnicm const char *filter, struct cmd_find_state *fs) 27567c16a7cSnicm { 27667c16a7cSnicm const struct options_table_entry *oe = options_table_entry(o); 27767c16a7cSnicm struct options *oo = options_owner(o); 27867c16a7cSnicm const char *name = options_name(o); 27967c16a7cSnicm struct window_customize_itemdata *item; 28067c16a7cSnicm char *text, *expanded, *value; 28167c16a7cSnicm int global = 0, array = 0; 28267c16a7cSnicm uint64_t tag; 28367c16a7cSnicm 28467c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK)) 28567c16a7cSnicm return; 28667c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) 28767c16a7cSnicm array = 1; 28867c16a7cSnicm 28967c16a7cSnicm if (scope == WINDOW_CUSTOMIZE_SERVER || 29067c16a7cSnicm scope == WINDOW_CUSTOMIZE_GLOBAL_SESSION || 29167c16a7cSnicm scope == WINDOW_CUSTOMIZE_GLOBAL_WINDOW) 29267c16a7cSnicm global = 1; 29367c16a7cSnicm if (data->hide_global && global) 29467c16a7cSnicm return; 29567c16a7cSnicm 29667c16a7cSnicm format_add(ft, "option_name", "%s", name); 29767c16a7cSnicm format_add(ft, "option_is_global", "%d", global); 29867c16a7cSnicm format_add(ft, "option_is_array", "%d", array); 29967c16a7cSnicm 30067c16a7cSnicm text = window_customize_scope_text(scope, fs); 30167c16a7cSnicm format_add(ft, "option_scope", "%s", text); 30267c16a7cSnicm free(text); 30367c16a7cSnicm 30467c16a7cSnicm if (oe != NULL && oe->unit != NULL) 30567c16a7cSnicm format_add(ft, "option_unit", "%s", oe->unit); 30667c16a7cSnicm else 30767c16a7cSnicm format_add(ft, "option_unit", "%s", ""); 30867c16a7cSnicm 30967c16a7cSnicm if (!array) { 31067c16a7cSnicm value = options_to_string(o, -1, 0); 31167c16a7cSnicm format_add(ft, "option_value", "%s", value); 31267c16a7cSnicm free(value); 31367c16a7cSnicm } 31467c16a7cSnicm 31567c16a7cSnicm if (filter != NULL) { 31667c16a7cSnicm expanded = format_expand(ft, filter); 31767c16a7cSnicm if (!format_true(expanded)) { 31867c16a7cSnicm free(expanded); 31967c16a7cSnicm return; 32067c16a7cSnicm } 32167c16a7cSnicm free(expanded); 32267c16a7cSnicm } 32367c16a7cSnicm item = window_customize_add_item(data); 32467c16a7cSnicm item->oo = oo; 32567c16a7cSnicm item->scope = scope; 32667c16a7cSnicm item->name = xstrdup(name); 32767c16a7cSnicm item->idx = -1; 32867c16a7cSnicm 32967c16a7cSnicm if (array) 33067c16a7cSnicm text = NULL; 33167c16a7cSnicm else 33267c16a7cSnicm text = format_expand(ft, data->format); 33367c16a7cSnicm tag = window_customize_get_tag(o, -1, oe); 33467c16a7cSnicm top = mode_tree_add(data->data, top, item, tag, name, text, 0); 33567c16a7cSnicm free(text); 33667c16a7cSnicm 33767c16a7cSnicm if (array) 33867c16a7cSnicm window_customize_build_array(data, top, scope, o, ft); 33967c16a7cSnicm } 34067c16a7cSnicm 34167c16a7cSnicm static void 34267c16a7cSnicm window_customize_find_user_options(struct options *oo, const char ***list, 34367c16a7cSnicm u_int *size) 34467c16a7cSnicm { 34567c16a7cSnicm struct options_entry *o; 34667c16a7cSnicm const char *name; 34767c16a7cSnicm u_int i; 34867c16a7cSnicm 34967c16a7cSnicm o = options_first(oo); 35067c16a7cSnicm while (o != NULL) { 35167c16a7cSnicm name = options_name(o); 35267c16a7cSnicm if (*name != '@') { 35367c16a7cSnicm o = options_next(o); 35467c16a7cSnicm continue; 35567c16a7cSnicm } 35667c16a7cSnicm for (i = 0; i < *size; i++) { 35767c16a7cSnicm if (strcmp((*list)[i], name) == 0) 35867c16a7cSnicm break; 35967c16a7cSnicm } 36067c16a7cSnicm if (i != *size) { 36167c16a7cSnicm o = options_next(o); 36267c16a7cSnicm continue; 36367c16a7cSnicm } 36467c16a7cSnicm *list = xreallocarray(*list, (*size) + 1, sizeof **list); 36567c16a7cSnicm (*list)[(*size)++] = name; 36667c16a7cSnicm 36767c16a7cSnicm o = options_next(o); 36867c16a7cSnicm } 36967c16a7cSnicm } 37067c16a7cSnicm 37167c16a7cSnicm static void 37267c16a7cSnicm window_customize_build_options(struct window_customize_modedata *data, 37367c16a7cSnicm const char *title, uint64_t tag, 37467c16a7cSnicm enum window_customize_scope scope0, struct options *oo0, 37567c16a7cSnicm enum window_customize_scope scope1, struct options *oo1, 37667c16a7cSnicm enum window_customize_scope scope2, struct options *oo2, 37767c16a7cSnicm struct format_tree *ft, const char *filter, struct cmd_find_state *fs) 37867c16a7cSnicm { 37967c16a7cSnicm struct mode_tree_item *top; 380cf415eadSnicm struct options_entry *o = NULL, *loop; 38167c16a7cSnicm const char **list = NULL, *name; 38267c16a7cSnicm u_int size = 0, i; 38367c16a7cSnicm enum window_customize_scope scope; 38467c16a7cSnicm 38567c16a7cSnicm top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0); 38694c0d63cSnicm mode_tree_no_tag(top); 38767c16a7cSnicm 38867c16a7cSnicm /* 38967c16a7cSnicm * We get the options from the first tree, but build it using the 39067c16a7cSnicm * values from the other two. Any tree can have user options so we need 39167c16a7cSnicm * to build a separate list of them. 39267c16a7cSnicm */ 39367c16a7cSnicm 39467c16a7cSnicm window_customize_find_user_options(oo0, &list, &size); 39567c16a7cSnicm if (oo1 != NULL) 39667c16a7cSnicm window_customize_find_user_options(oo1, &list, &size); 39767c16a7cSnicm if (oo2 != NULL) 39867c16a7cSnicm window_customize_find_user_options(oo2, &list, &size); 39967c16a7cSnicm 40067c16a7cSnicm for (i = 0; i < size; i++) { 40167c16a7cSnicm if (oo2 != NULL) 40295143b6eSnicm o = options_get(oo2, list[i]); 4035784a26aSnicm if (o == NULL && oo1 != NULL) 40467c16a7cSnicm o = options_get(oo1, list[i]); 4055784a26aSnicm if (o == NULL) 40695143b6eSnicm o = options_get(oo0, list[i]); 40767c16a7cSnicm if (options_owner(o) == oo2) 40867c16a7cSnicm scope = scope2; 40967c16a7cSnicm else if (options_owner(o) == oo1) 41067c16a7cSnicm scope = scope1; 41167c16a7cSnicm else 41267c16a7cSnicm scope = scope0; 41367c16a7cSnicm window_customize_build_option(data, top, scope, o, ft, filter, 41467c16a7cSnicm fs); 41567c16a7cSnicm } 41667c16a7cSnicm free(list); 41767c16a7cSnicm 41867c16a7cSnicm loop = options_first(oo0); 41967c16a7cSnicm while (loop != NULL) { 42067c16a7cSnicm name = options_name(loop); 42167c16a7cSnicm if (*name == '@') { 42267c16a7cSnicm loop = options_next(loop); 42367c16a7cSnicm continue; 42467c16a7cSnicm } 42567c16a7cSnicm if (oo2 != NULL) 42667c16a7cSnicm o = options_get(oo2, name); 42767c16a7cSnicm else if (oo1 != NULL) 42867c16a7cSnicm o = options_get(oo1, name); 42967c16a7cSnicm else 43067c16a7cSnicm o = loop; 43167c16a7cSnicm if (options_owner(o) == oo2) 43267c16a7cSnicm scope = scope2; 43367c16a7cSnicm else if (options_owner(o) == oo1) 43467c16a7cSnicm scope = scope1; 43567c16a7cSnicm else 43667c16a7cSnicm scope = scope0; 43767c16a7cSnicm window_customize_build_option(data, top, scope, o, ft, filter, 43867c16a7cSnicm fs); 43967c16a7cSnicm loop = options_next(loop); 44067c16a7cSnicm } 44167c16a7cSnicm } 44267c16a7cSnicm 44367c16a7cSnicm static void 44467c16a7cSnicm window_customize_build_keys(struct window_customize_modedata *data, 44567c16a7cSnicm struct key_table *kt, struct format_tree *ft, const char *filter, 44667c16a7cSnicm struct cmd_find_state *fs, u_int number) 44767c16a7cSnicm { 44867c16a7cSnicm struct mode_tree_item *top, *child, *mti; 44967c16a7cSnicm struct window_customize_itemdata *item; 45067c16a7cSnicm struct key_binding *bd; 45167c16a7cSnicm char *title, *text, *tmp, *expanded; 45267c16a7cSnicm const char *flag; 45367c16a7cSnicm uint64_t tag; 45467c16a7cSnicm 45567c16a7cSnicm tag = (1ULL << 62)|((uint64_t)number << 54)|1; 45667c16a7cSnicm 45767c16a7cSnicm xasprintf(&title, "Key Table - %s", kt->name); 45867c16a7cSnicm top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0); 45994c0d63cSnicm mode_tree_no_tag(top); 46067c16a7cSnicm free(title); 46167c16a7cSnicm 46267c16a7cSnicm ft = format_create_from_state(NULL, NULL, fs); 46367c16a7cSnicm format_add(ft, "is_option", "0"); 46467c16a7cSnicm format_add(ft, "is_key", "1"); 46567c16a7cSnicm 46667c16a7cSnicm bd = key_bindings_first(kt); 46767c16a7cSnicm while (bd != NULL) { 4685416581eSnicm format_add(ft, "key", "%s", key_string_lookup_key(bd->key, 0)); 46967c16a7cSnicm if (bd->note != NULL) 47067c16a7cSnicm format_add(ft, "key_note", "%s", bd->note); 47167c16a7cSnicm if (filter != NULL) { 47267c16a7cSnicm expanded = format_expand(ft, filter); 47367c16a7cSnicm if (!format_true(expanded)) { 47467c16a7cSnicm free(expanded); 47567c16a7cSnicm continue; 47667c16a7cSnicm } 47767c16a7cSnicm free(expanded); 47867c16a7cSnicm } 47967c16a7cSnicm 48067c16a7cSnicm item = window_customize_add_item(data); 48167c16a7cSnicm item->scope = WINDOW_CUSTOMIZE_KEY; 48267c16a7cSnicm item->table = xstrdup(kt->name); 48367c16a7cSnicm item->key = bd->key; 48494c0d63cSnicm item->name = xstrdup(key_string_lookup_key(item->key, 0)); 48594c0d63cSnicm item->idx = -1; 48667c16a7cSnicm 48767c16a7cSnicm expanded = format_expand(ft, data->format); 48867c16a7cSnicm child = mode_tree_add(data->data, top, item, (uint64_t)bd, 48967c16a7cSnicm expanded, NULL, 0); 49067c16a7cSnicm free(expanded); 49167c16a7cSnicm 49267c16a7cSnicm tmp = cmd_list_print(bd->cmdlist, 0); 49367c16a7cSnicm xasprintf(&text, "#[ignore]%s", tmp); 49467c16a7cSnicm free(tmp); 49567c16a7cSnicm mti = mode_tree_add(data->data, child, item, 49667c16a7cSnicm tag|(bd->key << 3)|(0 << 1)|1, "Command", text, -1); 49767c16a7cSnicm mode_tree_draw_as_parent(mti); 49894c0d63cSnicm mode_tree_no_tag(mti); 49967c16a7cSnicm free(text); 50067c16a7cSnicm 50167c16a7cSnicm if (bd->note != NULL) 50267c16a7cSnicm xasprintf(&text, "#[ignore]%s", bd->note); 50367c16a7cSnicm else 50467c16a7cSnicm text = xstrdup(""); 50567c16a7cSnicm mti = mode_tree_add(data->data, child, item, 50667c16a7cSnicm tag|(bd->key << 3)|(1 << 1)|1, "Note", text, -1); 50767c16a7cSnicm mode_tree_draw_as_parent(mti); 50894c0d63cSnicm mode_tree_no_tag(mti); 50967c16a7cSnicm free(text); 51067c16a7cSnicm 51167c16a7cSnicm if (bd->flags & KEY_BINDING_REPEAT) 51267c16a7cSnicm flag = "on"; 51367c16a7cSnicm else 51467c16a7cSnicm flag = "off"; 51567c16a7cSnicm mti = mode_tree_add(data->data, child, item, 51667c16a7cSnicm tag|(bd->key << 3)|(2 << 1)|1, "Repeat", flag, -1); 51767c16a7cSnicm mode_tree_draw_as_parent(mti); 51894c0d63cSnicm mode_tree_no_tag(mti); 51967c16a7cSnicm 52067c16a7cSnicm bd = key_bindings_next(kt, bd); 52167c16a7cSnicm } 52267c16a7cSnicm 52367c16a7cSnicm format_free(ft); 52467c16a7cSnicm } 52567c16a7cSnicm 52667c16a7cSnicm static void 52767c16a7cSnicm window_customize_build(void *modedata, 52867c16a7cSnicm __unused struct mode_tree_sort_criteria *sort_crit, __unused uint64_t *tag, 52967c16a7cSnicm const char *filter) 53067c16a7cSnicm { 53167c16a7cSnicm struct window_customize_modedata *data = modedata; 53267c16a7cSnicm struct cmd_find_state fs; 53367c16a7cSnicm struct format_tree *ft; 53467c16a7cSnicm u_int i; 53567c16a7cSnicm struct key_table *kt; 53667c16a7cSnicm 53767c16a7cSnicm for (i = 0; i < data->item_size; i++) 53867c16a7cSnicm window_customize_free_item(data->item_list[i]); 53967c16a7cSnicm free(data->item_list); 54067c16a7cSnicm data->item_list = NULL; 54167c16a7cSnicm data->item_size = 0; 54267c16a7cSnicm 54367c16a7cSnicm if (cmd_find_valid_state(&data->fs)) 54467c16a7cSnicm cmd_find_copy_state(&fs, &data->fs); 54567c16a7cSnicm else 54667c16a7cSnicm cmd_find_from_pane(&fs, data->wp, 0); 54767c16a7cSnicm 54867c16a7cSnicm ft = format_create_from_state(NULL, NULL, &fs); 54967c16a7cSnicm format_add(ft, "is_option", "1"); 55067c16a7cSnicm format_add(ft, "is_key", "0"); 55167c16a7cSnicm 55267c16a7cSnicm window_customize_build_options(data, "Server Options", 55367c16a7cSnicm (3ULL << 62)|(OPTIONS_TABLE_SERVER << 1)|1, 55467c16a7cSnicm WINDOW_CUSTOMIZE_SERVER, global_options, 55567c16a7cSnicm WINDOW_CUSTOMIZE_NONE, NULL, 55667c16a7cSnicm WINDOW_CUSTOMIZE_NONE, NULL, 55767c16a7cSnicm ft, filter, &fs); 55867c16a7cSnicm window_customize_build_options(data, "Session Options", 55967c16a7cSnicm (3ULL << 62)|(OPTIONS_TABLE_SESSION << 1)|1, 56067c16a7cSnicm WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options, 56167c16a7cSnicm WINDOW_CUSTOMIZE_SESSION, fs.s->options, 56267c16a7cSnicm WINDOW_CUSTOMIZE_NONE, NULL, 56367c16a7cSnicm ft, filter, &fs); 56467c16a7cSnicm window_customize_build_options(data, "Window & Pane Options", 56567c16a7cSnicm (3ULL << 62)|(OPTIONS_TABLE_WINDOW << 1)|1, 56667c16a7cSnicm WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options, 56767c16a7cSnicm WINDOW_CUSTOMIZE_WINDOW, fs.w->options, 56867c16a7cSnicm WINDOW_CUSTOMIZE_PANE, fs.wp->options, 56967c16a7cSnicm ft, filter, &fs); 57067c16a7cSnicm 57167c16a7cSnicm format_free(ft); 57267c16a7cSnicm ft = format_create_from_state(NULL, NULL, &fs); 57367c16a7cSnicm 57467c16a7cSnicm i = 0; 57567c16a7cSnicm kt = key_bindings_first_table(); 57667c16a7cSnicm while (kt != NULL) { 57767c16a7cSnicm if (!RB_EMPTY(&kt->key_bindings)) { 57867c16a7cSnicm window_customize_build_keys(data, kt, ft, filter, &fs, 57967c16a7cSnicm i); 58067c16a7cSnicm if (++i == 256) 58167c16a7cSnicm break; 58267c16a7cSnicm } 58367c16a7cSnicm kt = key_bindings_next_table(kt); 58467c16a7cSnicm } 58567c16a7cSnicm 58667c16a7cSnicm format_free(ft); 58767c16a7cSnicm } 58867c16a7cSnicm 58967c16a7cSnicm static void 59067c16a7cSnicm window_customize_draw_key(__unused struct window_customize_modedata *data, 59167c16a7cSnicm struct window_customize_itemdata *item, struct screen_write_ctx *ctx, 59267c16a7cSnicm u_int sx, u_int sy) 59367c16a7cSnicm { 59467c16a7cSnicm struct screen *s = ctx->s; 59567c16a7cSnicm u_int cx = s->cx, cy = s->cy; 59667c16a7cSnicm struct key_table *kt; 59767c16a7cSnicm struct key_binding *bd, *default_bd; 59867c16a7cSnicm const char *note, *period = ""; 59967c16a7cSnicm char *cmd, *default_cmd; 60067c16a7cSnicm 60167c16a7cSnicm if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 60267c16a7cSnicm return; 60367c16a7cSnicm 60467c16a7cSnicm note = bd->note; 60567c16a7cSnicm if (note == NULL) 60667c16a7cSnicm note = "There is no note for this key."; 60767c16a7cSnicm if (*note != '\0' && note[strlen (note) - 1] != '.') 60867c16a7cSnicm period = "."; 60967c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s%s", 61067c16a7cSnicm note, period)) 61167c16a7cSnicm return; 61267c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 61367c16a7cSnicm if (s->cy >= cy + sy - 1) 61467c16a7cSnicm return; 61567c16a7cSnicm 61667c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 61767c16a7cSnicm &grid_default_cell, "This key is in the %s table.", kt->name)) 61867c16a7cSnicm return; 61967c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 62067c16a7cSnicm &grid_default_cell, "This key %s repeat.", 62167c16a7cSnicm (bd->flags & KEY_BINDING_REPEAT) ? "does" : "does not")) 62267c16a7cSnicm return; 62367c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 62467c16a7cSnicm if (s->cy >= cy + sy - 1) 62567c16a7cSnicm return; 62667c16a7cSnicm 62767c16a7cSnicm cmd = cmd_list_print(bd->cmdlist, 0); 62867c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 62967c16a7cSnicm &grid_default_cell, "Command: %s", cmd)) { 63067c16a7cSnicm free(cmd); 63167c16a7cSnicm return; 63267c16a7cSnicm } 63367c16a7cSnicm default_bd = key_bindings_get_default(kt, bd->key); 63467c16a7cSnicm if (default_bd != NULL) { 63567c16a7cSnicm default_cmd = cmd_list_print(default_bd->cmdlist, 0); 63667c16a7cSnicm if (strcmp(cmd, default_cmd) != 0 && 63767c16a7cSnicm !screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 63867c16a7cSnicm &grid_default_cell, "The default is: %s", default_cmd)) { 63967c16a7cSnicm free(default_cmd); 64067c16a7cSnicm free(cmd); 64167c16a7cSnicm return; 64267c16a7cSnicm } 64367c16a7cSnicm free(default_cmd); 64467c16a7cSnicm } 64567c16a7cSnicm free(cmd); 64667c16a7cSnicm } 64767c16a7cSnicm 64867c16a7cSnicm static void 64967c16a7cSnicm window_customize_draw_option(struct window_customize_modedata *data, 65067c16a7cSnicm struct window_customize_itemdata *item, struct screen_write_ctx *ctx, 65167c16a7cSnicm u_int sx, u_int sy) 65267c16a7cSnicm { 65367c16a7cSnicm struct screen *s = ctx->s; 65467c16a7cSnicm u_int cx = s->cx, cy = s->cy; 65567c16a7cSnicm int idx; 65667c16a7cSnicm struct options_entry *o, *parent; 65767c16a7cSnicm struct options *go, *wo; 65867c16a7cSnicm const struct options_table_entry *oe; 65967c16a7cSnicm struct grid_cell gc; 66067c16a7cSnicm const char **choice, *text, *name; 66167c16a7cSnicm const char *space = "", *unit = ""; 66267c16a7cSnicm char *value = NULL, *expanded; 66367c16a7cSnicm char *default_value = NULL; 66467c16a7cSnicm char choices[256] = ""; 66567c16a7cSnicm struct cmd_find_state fs; 66667c16a7cSnicm struct format_tree *ft; 66767c16a7cSnicm 66867c16a7cSnicm if (!window_customize_check_item(data, item, &fs)) 66967c16a7cSnicm return; 67067c16a7cSnicm name = item->name; 67167c16a7cSnicm idx = item->idx; 67267c16a7cSnicm 67367c16a7cSnicm o = options_get(item->oo, name); 67467c16a7cSnicm if (o == NULL) 67567c16a7cSnicm return; 67667c16a7cSnicm oe = options_table_entry(o); 67767c16a7cSnicm 67867c16a7cSnicm if (oe != NULL && oe->unit != NULL) { 67967c16a7cSnicm space = " "; 68067c16a7cSnicm unit = oe->unit; 68167c16a7cSnicm } 68267c16a7cSnicm ft = format_create_from_state(NULL, NULL, &fs); 68367c16a7cSnicm 6847320143cSnicm if (oe == NULL || oe->text == NULL) 68567c16a7cSnicm text = "This option doesn't have a description."; 68667c16a7cSnicm else 68767c16a7cSnicm text = oe->text; 68867c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s", 68967c16a7cSnicm text)) 69067c16a7cSnicm goto out; 69167c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 69267c16a7cSnicm if (s->cy >= cy + sy - 1) 69367c16a7cSnicm goto out; 69467c16a7cSnicm 69567c16a7cSnicm if (oe == NULL) 69667c16a7cSnicm text = "user"; 69767c16a7cSnicm else if ((oe->scope & (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) == 69867c16a7cSnicm (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) 69967c16a7cSnicm text = "window and pane"; 70067c16a7cSnicm else if (oe->scope & OPTIONS_TABLE_WINDOW) 70167c16a7cSnicm text = "window"; 70267c16a7cSnicm else if (oe->scope & OPTIONS_TABLE_SESSION) 70367c16a7cSnicm text = "session"; 70467c16a7cSnicm else 70567c16a7cSnicm text = "server"; 70667c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 70767c16a7cSnicm &grid_default_cell, "This is a %s option.", text)) 70867c16a7cSnicm goto out; 70967c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 71067c16a7cSnicm if (idx != -1) { 71167c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 71267c16a7cSnicm 0, &grid_default_cell, 71367c16a7cSnicm "This is an array option, index %u.", idx)) 71467c16a7cSnicm goto out; 71567c16a7cSnicm } else { 71667c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 71767c16a7cSnicm 0, &grid_default_cell, "This is an array option.")) 71867c16a7cSnicm goto out; 71967c16a7cSnicm } 72067c16a7cSnicm if (idx == -1) 72167c16a7cSnicm goto out; 72267c16a7cSnicm } 72367c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 72467c16a7cSnicm if (s->cy >= cy + sy - 1) 72567c16a7cSnicm goto out; 72667c16a7cSnicm 72767c16a7cSnicm value = options_to_string(o, idx, 0); 72867c16a7cSnicm if (oe != NULL && idx == -1) { 72967c16a7cSnicm default_value = options_default_to_string(oe); 73067c16a7cSnicm if (strcmp(default_value, value) == 0) { 73167c16a7cSnicm free(default_value); 73267c16a7cSnicm default_value = NULL; 73367c16a7cSnicm } 73467c16a7cSnicm } 73567c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 73667c16a7cSnicm &grid_default_cell, "Option value: %s%s%s", value, space, unit)) 73767c16a7cSnicm goto out; 73867c16a7cSnicm if (oe == NULL || oe->type == OPTIONS_TABLE_STRING) { 73967c16a7cSnicm expanded = format_expand(ft, value); 74067c16a7cSnicm if (strcmp(expanded, value) != 0) { 74167c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 74267c16a7cSnicm 0, &grid_default_cell, "This expands to: %s", 74367c16a7cSnicm expanded)) 74467c16a7cSnicm goto out; 74567c16a7cSnicm } 74667c16a7cSnicm free(expanded); 74767c16a7cSnicm } 74867c16a7cSnicm if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) { 74967c16a7cSnicm for (choice = oe->choices; *choice != NULL; choice++) { 75067c16a7cSnicm strlcat(choices, *choice, sizeof choices); 75167c16a7cSnicm strlcat(choices, ", ", sizeof choices); 75267c16a7cSnicm } 75367c16a7cSnicm choices[strlen(choices) - 2] = '\0'; 75467c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 75567c16a7cSnicm &grid_default_cell, "Available values are: %s", 75667c16a7cSnicm choices)) 75767c16a7cSnicm goto out; 75867c16a7cSnicm } 75967c16a7cSnicm if (oe != NULL && oe->type == OPTIONS_TABLE_COLOUR) { 76067c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1, 76167c16a7cSnicm &grid_default_cell, "This is a colour option: ")) 76267c16a7cSnicm goto out; 76367c16a7cSnicm memcpy(&gc, &grid_default_cell, sizeof gc); 76467c16a7cSnicm gc.fg = options_get_number(item->oo, name); 76567c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc, 76667c16a7cSnicm "EXAMPLE")) 76767c16a7cSnicm goto out; 76867c16a7cSnicm } 76967c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_STYLE)) { 77067c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1, 77167c16a7cSnicm &grid_default_cell, "This is a style option: ")) 77267c16a7cSnicm goto out; 77367c16a7cSnicm style_apply(&gc, item->oo, name, ft); 77467c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc, 77567c16a7cSnicm "EXAMPLE")) 77667c16a7cSnicm goto out; 77767c16a7cSnicm } 77867c16a7cSnicm if (default_value != NULL) { 77967c16a7cSnicm if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, 78067c16a7cSnicm &grid_default_cell, "The default is: %s%s%s", default_value, 78167c16a7cSnicm space, unit)) 78267c16a7cSnicm goto out; 78367c16a7cSnicm } 78467c16a7cSnicm 78567c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */ 78667c16a7cSnicm if (s->cy > cy + sy - 1) 78767c16a7cSnicm goto out; 78867c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 78967c16a7cSnicm wo = NULL; 79067c16a7cSnicm go = NULL; 79167c16a7cSnicm } else { 79267c16a7cSnicm switch (item->scope) { 79367c16a7cSnicm case WINDOW_CUSTOMIZE_PANE: 79467c16a7cSnicm wo = options_get_parent(item->oo); 79567c16a7cSnicm go = options_get_parent(wo); 79667c16a7cSnicm break; 79767c16a7cSnicm case WINDOW_CUSTOMIZE_WINDOW: 79867c16a7cSnicm case WINDOW_CUSTOMIZE_SESSION: 79967c16a7cSnicm wo = NULL; 80067c16a7cSnicm go = options_get_parent(item->oo); 80167c16a7cSnicm break; 80267c16a7cSnicm default: 80367c16a7cSnicm wo = NULL; 80467c16a7cSnicm go = NULL; 80567c16a7cSnicm break; 80667c16a7cSnicm } 80767c16a7cSnicm } 80867c16a7cSnicm if (wo != NULL && options_owner(o) != wo) { 80967c16a7cSnicm parent = options_get_only(wo, name); 81067c16a7cSnicm if (parent != NULL) { 81167c16a7cSnicm value = options_to_string(parent, -1 , 0); 81267c16a7cSnicm if (!screen_write_text(ctx, s->cx, sx, 81367c16a7cSnicm sy - (s->cy - cy), 0, &grid_default_cell, 81467c16a7cSnicm "Window value (from window %u): %s%s%s", fs.wl->idx, 81567c16a7cSnicm value, space, unit)) 81667c16a7cSnicm goto out; 81767c16a7cSnicm } 81867c16a7cSnicm } 81967c16a7cSnicm if (go != NULL && options_owner(o) != go) { 82067c16a7cSnicm parent = options_get_only(go, name); 82167c16a7cSnicm if (parent != NULL) { 82267c16a7cSnicm value = options_to_string(parent, -1 , 0); 82367c16a7cSnicm if (!screen_write_text(ctx, s->cx, sx, 82467c16a7cSnicm sy - (s->cy - cy), 0, &grid_default_cell, 82567c16a7cSnicm "Global value: %s%s%s", value, space, unit)) 82667c16a7cSnicm goto out; 82767c16a7cSnicm } 82867c16a7cSnicm } 82967c16a7cSnicm 83067c16a7cSnicm out: 83167c16a7cSnicm free(value); 83267c16a7cSnicm free(default_value); 83367c16a7cSnicm format_free(ft); 83467c16a7cSnicm } 83567c16a7cSnicm 83667c16a7cSnicm static void 83767c16a7cSnicm window_customize_draw(void *modedata, void *itemdata, 83867c16a7cSnicm struct screen_write_ctx *ctx, u_int sx, u_int sy) 83967c16a7cSnicm { 84067c16a7cSnicm struct window_customize_modedata *data = modedata; 84167c16a7cSnicm struct window_customize_itemdata *item = itemdata; 84267c16a7cSnicm 84367c16a7cSnicm if (item == NULL) 84467c16a7cSnicm return; 84567c16a7cSnicm 84667c16a7cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 84767c16a7cSnicm window_customize_draw_key(data, item, ctx, sx, sy); 84867c16a7cSnicm else 84967c16a7cSnicm window_customize_draw_option(data, item, ctx, sx, sy); 85067c16a7cSnicm } 85167c16a7cSnicm 85267c16a7cSnicm static void 85367c16a7cSnicm window_customize_menu(void *modedata, struct client *c, key_code key) 85467c16a7cSnicm { 85567c16a7cSnicm struct window_customize_modedata *data = modedata; 85667c16a7cSnicm struct window_pane *wp = data->wp; 85767c16a7cSnicm struct window_mode_entry *wme; 85867c16a7cSnicm 85967c16a7cSnicm wme = TAILQ_FIRST(&wp->modes); 86067c16a7cSnicm if (wme == NULL || wme->data != modedata) 86167c16a7cSnicm return; 86267c16a7cSnicm window_customize_key(wme, c, NULL, NULL, key, NULL); 86367c16a7cSnicm } 86467c16a7cSnicm 86567c16a7cSnicm static u_int 86667c16a7cSnicm window_customize_height(__unused void *modedata, __unused u_int height) 86767c16a7cSnicm { 86867c16a7cSnicm return (12); 86967c16a7cSnicm } 87067c16a7cSnicm 87167c16a7cSnicm static struct screen * 87267c16a7cSnicm window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs, 87367c16a7cSnicm struct args *args) 87467c16a7cSnicm { 87567c16a7cSnicm struct window_pane *wp = wme->wp; 87667c16a7cSnicm struct window_customize_modedata *data; 87767c16a7cSnicm struct screen *s; 87867c16a7cSnicm 87967c16a7cSnicm wme->data = data = xcalloc(1, sizeof *data); 88067c16a7cSnicm data->wp = wp; 88167c16a7cSnicm data->references = 1; 88267c16a7cSnicm 88367c16a7cSnicm memcpy(&data->fs, fs, sizeof data->fs); 88467c16a7cSnicm 88567c16a7cSnicm if (args == NULL || !args_has(args, 'F')) 88667c16a7cSnicm data->format = xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT); 88767c16a7cSnicm else 88867c16a7cSnicm data->format = xstrdup(args_get(args, 'F')); 889*af11b61dSnicm if (args_has(args, 'y')) 890*af11b61dSnicm data->prompt_flags = PROMPT_ACCEPT; 89167c16a7cSnicm 89267c16a7cSnicm data->data = mode_tree_start(wp, args, window_customize_build, 89367c16a7cSnicm window_customize_draw, NULL, window_customize_menu, 894438eed14Snicm window_customize_height, NULL, data, window_customize_menu_items, 895438eed14Snicm NULL, 0, &s); 89667c16a7cSnicm mode_tree_zoom(data->data, args); 89767c16a7cSnicm 89867c16a7cSnicm mode_tree_build(data->data); 89967c16a7cSnicm mode_tree_draw(data->data); 90067c16a7cSnicm 90167c16a7cSnicm return (s); 90267c16a7cSnicm } 90367c16a7cSnicm 90467c16a7cSnicm static void 90567c16a7cSnicm window_customize_destroy(struct window_customize_modedata *data) 90667c16a7cSnicm { 90767c16a7cSnicm u_int i; 90867c16a7cSnicm 90967c16a7cSnicm if (--data->references != 0) 91067c16a7cSnicm return; 91167c16a7cSnicm 91267c16a7cSnicm for (i = 0; i < data->item_size; i++) 91367c16a7cSnicm window_customize_free_item(data->item_list[i]); 91467c16a7cSnicm free(data->item_list); 91567c16a7cSnicm 91667c16a7cSnicm free(data->format); 91767c16a7cSnicm 91867c16a7cSnicm free(data); 91967c16a7cSnicm } 92067c16a7cSnicm 92167c16a7cSnicm static void 92267c16a7cSnicm window_customize_free(struct window_mode_entry *wme) 92367c16a7cSnicm { 92467c16a7cSnicm struct window_customize_modedata *data = wme->data; 92567c16a7cSnicm 92667c16a7cSnicm if (data == NULL) 92767c16a7cSnicm return; 92867c16a7cSnicm 92967c16a7cSnicm data->dead = 1; 93067c16a7cSnicm mode_tree_free(data->data); 93167c16a7cSnicm window_customize_destroy(data); 93267c16a7cSnicm } 93367c16a7cSnicm 93467c16a7cSnicm static void 93567c16a7cSnicm window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy) 93667c16a7cSnicm { 93767c16a7cSnicm struct window_customize_modedata *data = wme->data; 93867c16a7cSnicm 93967c16a7cSnicm mode_tree_resize(data->data, sx, sy); 94067c16a7cSnicm } 94167c16a7cSnicm 94267c16a7cSnicm static void 94367c16a7cSnicm window_customize_free_callback(void *modedata) 94467c16a7cSnicm { 94567c16a7cSnicm window_customize_destroy(modedata); 94667c16a7cSnicm } 94767c16a7cSnicm 94867c16a7cSnicm static void 94967c16a7cSnicm window_customize_free_item_callback(void *itemdata) 95067c16a7cSnicm { 95167c16a7cSnicm struct window_customize_itemdata *item = itemdata; 95267c16a7cSnicm struct window_customize_modedata *data = item->data; 95367c16a7cSnicm 95467c16a7cSnicm window_customize_free_item(item); 95567c16a7cSnicm window_customize_destroy(data); 95667c16a7cSnicm } 95767c16a7cSnicm 95867c16a7cSnicm static int 95967c16a7cSnicm window_customize_set_option_callback(struct client *c, void *itemdata, 96067c16a7cSnicm const char *s, __unused int done) 96167c16a7cSnicm { 96267c16a7cSnicm struct window_customize_itemdata *item = itemdata; 96367c16a7cSnicm struct window_customize_modedata *data = item->data; 96467c16a7cSnicm struct options_entry *o; 96567c16a7cSnicm const struct options_table_entry *oe; 96667c16a7cSnicm struct options *oo = item->oo; 96767c16a7cSnicm const char *name = item->name; 96867c16a7cSnicm char *cause; 96967c16a7cSnicm int idx = item->idx; 97067c16a7cSnicm 97167c16a7cSnicm if (s == NULL || *s == '\0' || data->dead) 97267c16a7cSnicm return (0); 97367c16a7cSnicm if (item == NULL || !window_customize_check_item(data, item, NULL)) 97467c16a7cSnicm return (0); 97567c16a7cSnicm o = options_get(oo, name); 97667c16a7cSnicm if (o == NULL) 97767c16a7cSnicm return (0); 97867c16a7cSnicm oe = options_table_entry(o); 97967c16a7cSnicm 98067c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 98167c16a7cSnicm if (idx == -1) { 98267c16a7cSnicm for (idx = 0; idx < INT_MAX; idx++) { 98367c16a7cSnicm if (options_array_get(o, idx) == NULL) 98467c16a7cSnicm break; 98567c16a7cSnicm } 98667c16a7cSnicm } 98767c16a7cSnicm if (options_array_set(o, idx, s, 0, &cause) != 0) 98867c16a7cSnicm goto fail; 98967c16a7cSnicm } else { 99067c16a7cSnicm if (options_from_string(oo, oe, name, s, 0, &cause) != 0) 99167c16a7cSnicm goto fail; 99267c16a7cSnicm } 99367c16a7cSnicm 99467c16a7cSnicm options_push_changes(item->name); 99567c16a7cSnicm mode_tree_build(data->data); 99667c16a7cSnicm mode_tree_draw(data->data); 99767c16a7cSnicm data->wp->flags |= PANE_REDRAW; 99867c16a7cSnicm 99967c16a7cSnicm return (0); 100067c16a7cSnicm 100167c16a7cSnicm fail: 100267c16a7cSnicm *cause = toupper((u_char)*cause); 1003e7e79d0aSnicm status_message_set(c, -1, 1, 0, "%s", cause); 100467c16a7cSnicm free(cause); 100567c16a7cSnicm return (0); 100667c16a7cSnicm } 100767c16a7cSnicm 100867c16a7cSnicm static void 100967c16a7cSnicm window_customize_set_option(struct client *c, 101067c16a7cSnicm struct window_customize_modedata *data, 101167c16a7cSnicm struct window_customize_itemdata *item, int global, int pane) 101267c16a7cSnicm { 101367c16a7cSnicm struct options_entry *o; 101467c16a7cSnicm const struct options_table_entry *oe; 101567c16a7cSnicm struct options *oo; 101667c16a7cSnicm struct window_customize_itemdata *new_item; 101767c16a7cSnicm int flag, idx = item->idx; 1018cf415eadSnicm enum window_customize_scope scope = WINDOW_CUSTOMIZE_NONE; 101967c16a7cSnicm u_int choice; 102067c16a7cSnicm const char *name = item->name, *space = ""; 102167c16a7cSnicm char *prompt, *value, *text; 102267c16a7cSnicm struct cmd_find_state fs; 102367c16a7cSnicm 102467c16a7cSnicm if (item == NULL || !window_customize_check_item(data, item, &fs)) 102567c16a7cSnicm return; 102667c16a7cSnicm o = options_get(item->oo, name); 102767c16a7cSnicm if (o == NULL) 102867c16a7cSnicm return; 102967c16a7cSnicm 103067c16a7cSnicm oe = options_table_entry(o); 1031cf415eadSnicm if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE) 103267c16a7cSnicm pane = 0; 103367c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 103467c16a7cSnicm scope = item->scope; 103567c16a7cSnicm oo = item->oo; 103667c16a7cSnicm } else { 103767c16a7cSnicm if (global) { 103867c16a7cSnicm switch (item->scope) { 103967c16a7cSnicm case WINDOW_CUSTOMIZE_NONE: 104067c16a7cSnicm case WINDOW_CUSTOMIZE_KEY: 104167c16a7cSnicm case WINDOW_CUSTOMIZE_SERVER: 104267c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_SESSION: 104367c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: 104467c16a7cSnicm scope = item->scope; 104567c16a7cSnicm break; 104667c16a7cSnicm case WINDOW_CUSTOMIZE_SESSION: 104767c16a7cSnicm scope = WINDOW_CUSTOMIZE_GLOBAL_SESSION; 104867c16a7cSnicm break; 104967c16a7cSnicm case WINDOW_CUSTOMIZE_WINDOW: 105067c16a7cSnicm case WINDOW_CUSTOMIZE_PANE: 105167c16a7cSnicm scope = WINDOW_CUSTOMIZE_GLOBAL_WINDOW; 105267c16a7cSnicm break; 105367c16a7cSnicm } 105467c16a7cSnicm } else { 105567c16a7cSnicm switch (item->scope) { 105667c16a7cSnicm case WINDOW_CUSTOMIZE_NONE: 105767c16a7cSnicm case WINDOW_CUSTOMIZE_KEY: 105867c16a7cSnicm case WINDOW_CUSTOMIZE_SERVER: 105967c16a7cSnicm case WINDOW_CUSTOMIZE_SESSION: 106067c16a7cSnicm scope = item->scope; 106167c16a7cSnicm break; 106267c16a7cSnicm case WINDOW_CUSTOMIZE_WINDOW: 106367c16a7cSnicm case WINDOW_CUSTOMIZE_PANE: 106467c16a7cSnicm if (pane) 106567c16a7cSnicm scope = WINDOW_CUSTOMIZE_PANE; 106667c16a7cSnicm else 106767c16a7cSnicm scope = WINDOW_CUSTOMIZE_WINDOW; 106867c16a7cSnicm break; 106967c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_SESSION: 107067c16a7cSnicm scope = WINDOW_CUSTOMIZE_SESSION; 107167c16a7cSnicm break; 107267c16a7cSnicm case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: 107367c16a7cSnicm if (pane) 107467c16a7cSnicm scope = WINDOW_CUSTOMIZE_PANE; 107567c16a7cSnicm else 107667c16a7cSnicm scope = WINDOW_CUSTOMIZE_WINDOW; 107767c16a7cSnicm break; 107867c16a7cSnicm } 107967c16a7cSnicm } 108067c16a7cSnicm if (scope == item->scope) 108167c16a7cSnicm oo = item->oo; 108267c16a7cSnicm else 108367c16a7cSnicm oo = window_customize_get_tree(scope, &fs); 108467c16a7cSnicm } 108567c16a7cSnicm 108667c16a7cSnicm if (oe != NULL && oe->type == OPTIONS_TABLE_FLAG) { 108767c16a7cSnicm flag = options_get_number(oo, name); 108867c16a7cSnicm options_set_number(oo, name, !flag); 108967c16a7cSnicm } else if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) { 109067c16a7cSnicm choice = options_get_number(oo, name); 109167c16a7cSnicm if (oe->choices[choice + 1] == NULL) 109267c16a7cSnicm choice = 0; 109367c16a7cSnicm else 109467c16a7cSnicm choice++; 109567c16a7cSnicm options_set_number(oo, name, choice); 109667c16a7cSnicm } else { 109767c16a7cSnicm text = window_customize_scope_text(scope, &fs); 109867c16a7cSnicm if (*text != '\0') 109967c16a7cSnicm space = ", for "; 110067c16a7cSnicm else if (scope != WINDOW_CUSTOMIZE_SERVER) 110167c16a7cSnicm space = ", global"; 110267c16a7cSnicm if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) { 110367c16a7cSnicm if (idx == -1) { 110467c16a7cSnicm xasprintf(&prompt, "(%s[+]%s%s) ", name, space, 110567c16a7cSnicm text); 110667c16a7cSnicm } else { 110767c16a7cSnicm xasprintf(&prompt, "(%s[%d]%s%s) ", name, idx, 110867c16a7cSnicm space, text); 110967c16a7cSnicm } 111067c16a7cSnicm } else 111167c16a7cSnicm xasprintf(&prompt, "(%s%s%s) ", name, space, text); 111267c16a7cSnicm free(text); 111367c16a7cSnicm 111467c16a7cSnicm value = options_to_string(o, idx, 0); 111567c16a7cSnicm 111667c16a7cSnicm new_item = xcalloc(1, sizeof *new_item); 111767c16a7cSnicm new_item->data = data; 111867c16a7cSnicm new_item->scope = scope; 111967c16a7cSnicm new_item->oo = oo; 112067c16a7cSnicm new_item->name = xstrdup(name); 112167c16a7cSnicm new_item->idx = idx; 112267c16a7cSnicm 112367c16a7cSnicm data->references++; 112494adf770Snicm status_prompt_set(c, NULL, prompt, value, 112567c16a7cSnicm window_customize_set_option_callback, 112667c16a7cSnicm window_customize_free_item_callback, new_item, 1127bc5a8fc2Snicm PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 112867c16a7cSnicm 112967c16a7cSnicm free(prompt); 113067c16a7cSnicm free(value); 113167c16a7cSnicm } 113267c16a7cSnicm } 113367c16a7cSnicm 113467c16a7cSnicm static void 113567c16a7cSnicm window_customize_unset_option(struct window_customize_modedata *data, 113667c16a7cSnicm struct window_customize_itemdata *item) 113767c16a7cSnicm { 113867c16a7cSnicm struct options_entry *o; 113967c16a7cSnicm 114067c16a7cSnicm if (item == NULL || !window_customize_check_item(data, item, NULL)) 114167c16a7cSnicm return; 114267c16a7cSnicm 114367c16a7cSnicm o = options_get(item->oo, item->name); 114467c16a7cSnicm if (o == NULL) 114567c16a7cSnicm return; 114694c0d63cSnicm if (item->idx != -1 && item == mode_tree_get_current(data->data)) 114767c16a7cSnicm mode_tree_up(data->data, 0); 114894c0d63cSnicm options_remove_or_default(o, item->idx, NULL); 114967c16a7cSnicm } 115094c0d63cSnicm 115194c0d63cSnicm static void 115294c0d63cSnicm window_customize_reset_option(struct window_customize_modedata *data, 115394c0d63cSnicm struct window_customize_itemdata *item) 115494c0d63cSnicm { 115594c0d63cSnicm struct options *oo; 115694c0d63cSnicm struct options_entry *o; 115794c0d63cSnicm 115894c0d63cSnicm if (item == NULL || !window_customize_check_item(data, item, NULL)) 115994c0d63cSnicm return; 116094c0d63cSnicm if (item->idx != -1) 116194c0d63cSnicm return; 116294c0d63cSnicm 116394c0d63cSnicm oo = item->oo; 116494c0d63cSnicm while (oo != NULL) { 116594c0d63cSnicm o = options_get_only(item->oo, item->name); 116694c0d63cSnicm if (o != NULL) 116794c0d63cSnicm options_remove_or_default(o, -1, NULL); 116894c0d63cSnicm oo = options_get_parent(oo); 116994c0d63cSnicm } 117067c16a7cSnicm } 117167c16a7cSnicm 117267c16a7cSnicm static int 117367c16a7cSnicm window_customize_set_command_callback(struct client *c, void *itemdata, 117467c16a7cSnicm const char *s, __unused int done) 117567c16a7cSnicm { 117667c16a7cSnicm struct window_customize_itemdata *item = itemdata; 117767c16a7cSnicm struct window_customize_modedata *data = item->data; 117867c16a7cSnicm struct key_binding *bd; 117967c16a7cSnicm struct cmd_parse_result *pr; 118067c16a7cSnicm char *error; 118167c16a7cSnicm 118267c16a7cSnicm if (s == NULL || *s == '\0' || data->dead) 118367c16a7cSnicm return (0); 118467c16a7cSnicm if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 118567c16a7cSnicm return (0); 118667c16a7cSnicm 118767c16a7cSnicm pr = cmd_parse_from_string(s, NULL); 118867c16a7cSnicm switch (pr->status) { 118967c16a7cSnicm case CMD_PARSE_ERROR: 119067c16a7cSnicm error = pr->error; 119167c16a7cSnicm goto fail; 119267c16a7cSnicm case CMD_PARSE_SUCCESS: 119367c16a7cSnicm break; 119467c16a7cSnicm } 119567c16a7cSnicm cmd_list_free(bd->cmdlist); 119667c16a7cSnicm bd->cmdlist = pr->cmdlist; 119767c16a7cSnicm 119867c16a7cSnicm mode_tree_build(data->data); 119967c16a7cSnicm mode_tree_draw(data->data); 120067c16a7cSnicm data->wp->flags |= PANE_REDRAW; 120167c16a7cSnicm 120267c16a7cSnicm return (0); 120367c16a7cSnicm 120467c16a7cSnicm fail: 120567c16a7cSnicm *error = toupper((u_char)*error); 1206e7e79d0aSnicm status_message_set(c, -1, 1, 0, "%s", error); 120767c16a7cSnicm free(error); 120867c16a7cSnicm return (0); 120967c16a7cSnicm } 121067c16a7cSnicm 121167c16a7cSnicm static int 121267c16a7cSnicm window_customize_set_note_callback(__unused struct client *c, void *itemdata, 121367c16a7cSnicm const char *s, __unused int done) 121467c16a7cSnicm { 121567c16a7cSnicm struct window_customize_itemdata *item = itemdata; 121667c16a7cSnicm struct window_customize_modedata *data = item->data; 121767c16a7cSnicm struct key_binding *bd; 121867c16a7cSnicm 121967c16a7cSnicm if (s == NULL || *s == '\0' || data->dead) 122067c16a7cSnicm return (0); 122167c16a7cSnicm if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 122267c16a7cSnicm return (0); 122367c16a7cSnicm 122467c16a7cSnicm free((void *)bd->note); 122567c16a7cSnicm bd->note = xstrdup(s); 122667c16a7cSnicm 122767c16a7cSnicm mode_tree_build(data->data); 122867c16a7cSnicm mode_tree_draw(data->data); 122967c16a7cSnicm data->wp->flags |= PANE_REDRAW; 123067c16a7cSnicm 123167c16a7cSnicm return (0); 123267c16a7cSnicm } 123367c16a7cSnicm 123467c16a7cSnicm static void 123567c16a7cSnicm window_customize_set_key(struct client *c, 123667c16a7cSnicm struct window_customize_modedata *data, 123767c16a7cSnicm struct window_customize_itemdata *item) 123867c16a7cSnicm { 123967c16a7cSnicm key_code key = item->key; 124067c16a7cSnicm struct key_binding *bd; 124167c16a7cSnicm const char *s; 124267c16a7cSnicm char *prompt, *value; 124367c16a7cSnicm struct window_customize_itemdata *new_item; 124467c16a7cSnicm 124567c16a7cSnicm if (item == NULL || !window_customize_get_key(item, NULL, &bd)) 124667c16a7cSnicm return; 124767c16a7cSnicm 124867c16a7cSnicm s = mode_tree_get_current_name(data->data); 124967c16a7cSnicm if (strcmp(s, "Repeat") == 0) 125067c16a7cSnicm bd->flags ^= KEY_BINDING_REPEAT; 125167c16a7cSnicm else if (strcmp(s, "Command") == 0) { 12525416581eSnicm xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 125367c16a7cSnicm value = cmd_list_print(bd->cmdlist, 0); 125467c16a7cSnicm 125567c16a7cSnicm new_item = xcalloc(1, sizeof *new_item); 125667c16a7cSnicm new_item->data = data; 125767c16a7cSnicm new_item->scope = item->scope; 125867c16a7cSnicm new_item->table = xstrdup(item->table); 125967c16a7cSnicm new_item->key = key; 126067c16a7cSnicm 126167c16a7cSnicm data->references++; 126294adf770Snicm status_prompt_set(c, NULL, prompt, value, 126367c16a7cSnicm window_customize_set_command_callback, 126467c16a7cSnicm window_customize_free_item_callback, new_item, 1265bc5a8fc2Snicm PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 126667c16a7cSnicm free(prompt); 126767c16a7cSnicm free(value); 126867c16a7cSnicm } else if (strcmp(s, "Note") == 0) { 12695416581eSnicm xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0)); 127067c16a7cSnicm 127167c16a7cSnicm new_item = xcalloc(1, sizeof *new_item); 127267c16a7cSnicm new_item->data = data; 127367c16a7cSnicm new_item->scope = item->scope; 127467c16a7cSnicm new_item->table = xstrdup(item->table); 127567c16a7cSnicm new_item->key = key; 127667c16a7cSnicm 127767c16a7cSnicm data->references++; 127894adf770Snicm status_prompt_set(c, NULL, prompt, 127994adf770Snicm (bd->note == NULL ? "" : bd->note), 128067c16a7cSnicm window_customize_set_note_callback, 128167c16a7cSnicm window_customize_free_item_callback, new_item, 1282bc5a8fc2Snicm PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND); 128367c16a7cSnicm free(prompt); 128467c16a7cSnicm } 128567c16a7cSnicm } 128667c16a7cSnicm 128767c16a7cSnicm static void 128867c16a7cSnicm window_customize_unset_key(struct window_customize_modedata *data, 128967c16a7cSnicm struct window_customize_itemdata *item) 129067c16a7cSnicm { 129167c16a7cSnicm struct key_table *kt; 129267c16a7cSnicm struct key_binding *bd; 129367c16a7cSnicm 129467c16a7cSnicm if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 129567c16a7cSnicm return; 129667c16a7cSnicm 129767c16a7cSnicm if (item == mode_tree_get_current(data->data)) { 129867c16a7cSnicm mode_tree_collapse_current(data->data); 129967c16a7cSnicm mode_tree_up(data->data, 0); 130067c16a7cSnicm } 130167c16a7cSnicm key_bindings_remove(kt->name, bd->key); 130267c16a7cSnicm } 130367c16a7cSnicm 130467c16a7cSnicm static void 130594c0d63cSnicm window_customize_reset_key(struct window_customize_modedata *data, 130694c0d63cSnicm struct window_customize_itemdata *item) 130794c0d63cSnicm { 130894c0d63cSnicm struct key_table *kt; 130994c0d63cSnicm struct key_binding *dd, *bd; 131094c0d63cSnicm 131194c0d63cSnicm if (item == NULL || !window_customize_get_key(item, &kt, &bd)) 131294c0d63cSnicm return; 131394c0d63cSnicm 131494c0d63cSnicm dd = key_bindings_get_default(kt, bd->key); 131594c0d63cSnicm if (dd != NULL && bd->cmdlist == dd->cmdlist) 131694c0d63cSnicm return; 131794c0d63cSnicm if (dd == NULL && item == mode_tree_get_current(data->data)) { 131894c0d63cSnicm mode_tree_collapse_current(data->data); 131994c0d63cSnicm mode_tree_up(data->data, 0); 132094c0d63cSnicm } 132194c0d63cSnicm key_bindings_reset(kt->name, bd->key); 132294c0d63cSnicm } 132394c0d63cSnicm 132494c0d63cSnicm static void 132594c0d63cSnicm window_customize_change_each(void *modedata, void *itemdata, 132667c16a7cSnicm __unused struct client *c, __unused key_code key) 132767c16a7cSnicm { 132894c0d63cSnicm struct window_customize_modedata *data = modedata; 132967c16a7cSnicm struct window_customize_itemdata *item = itemdata; 133067c16a7cSnicm 133194c0d63cSnicm switch (data->change) { 133294c0d63cSnicm case WINDOW_CUSTOMIZE_UNSET: 133367c16a7cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 133494c0d63cSnicm window_customize_unset_key(data, item); 133594c0d63cSnicm else 133694c0d63cSnicm window_customize_unset_option(data, item); 133794c0d63cSnicm break; 133894c0d63cSnicm case WINDOW_CUSTOMIZE_RESET: 133994c0d63cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 134094c0d63cSnicm window_customize_reset_key(data, item); 134194c0d63cSnicm else 134294c0d63cSnicm window_customize_reset_option(data, item); 134394c0d63cSnicm break; 134467c16a7cSnicm } 134594c0d63cSnicm if (item->scope != WINDOW_CUSTOMIZE_KEY) 134694c0d63cSnicm options_push_changes(item->name); 134767c16a7cSnicm } 134867c16a7cSnicm 134967c16a7cSnicm static int 135094c0d63cSnicm window_customize_change_current_callback(__unused struct client *c, 135167c16a7cSnicm void *modedata, const char *s, __unused int done) 135267c16a7cSnicm { 135367c16a7cSnicm struct window_customize_modedata *data = modedata; 135467c16a7cSnicm struct window_customize_itemdata *item; 135567c16a7cSnicm 135667c16a7cSnicm if (s == NULL || *s == '\0' || data->dead) 135767c16a7cSnicm return (0); 135867c16a7cSnicm if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 135967c16a7cSnicm return (0); 136067c16a7cSnicm 136167c16a7cSnicm item = mode_tree_get_current(data->data); 136294c0d63cSnicm switch (data->change) { 136394c0d63cSnicm case WINDOW_CUSTOMIZE_UNSET: 136467c16a7cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 136567c16a7cSnicm window_customize_unset_key(data, item); 136694c0d63cSnicm else 136767c16a7cSnicm window_customize_unset_option(data, item); 136894c0d63cSnicm break; 136994c0d63cSnicm case WINDOW_CUSTOMIZE_RESET: 137094c0d63cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 137194c0d63cSnicm window_customize_reset_key(data, item); 137294c0d63cSnicm else 137394c0d63cSnicm window_customize_reset_option(data, item); 137494c0d63cSnicm break; 137567c16a7cSnicm } 137694c0d63cSnicm if (item->scope != WINDOW_CUSTOMIZE_KEY) 137794c0d63cSnicm options_push_changes(item->name); 137867c16a7cSnicm mode_tree_build(data->data); 137967c16a7cSnicm mode_tree_draw(data->data); 138067c16a7cSnicm data->wp->flags |= PANE_REDRAW; 138167c16a7cSnicm 138267c16a7cSnicm return (0); 138367c16a7cSnicm } 138467c16a7cSnicm 138567c16a7cSnicm static int 138694c0d63cSnicm window_customize_change_tagged_callback(struct client *c, void *modedata, 138767c16a7cSnicm const char *s, __unused int done) 138867c16a7cSnicm { 138967c16a7cSnicm struct window_customize_modedata *data = modedata; 139067c16a7cSnicm 139167c16a7cSnicm if (s == NULL || *s == '\0' || data->dead) 139267c16a7cSnicm return (0); 139367c16a7cSnicm if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') 139467c16a7cSnicm return (0); 139567c16a7cSnicm 139694c0d63cSnicm mode_tree_each_tagged(data->data, window_customize_change_each, c, 139767c16a7cSnicm KEYC_NONE, 0); 139867c16a7cSnicm mode_tree_build(data->data); 139967c16a7cSnicm mode_tree_draw(data->data); 140067c16a7cSnicm data->wp->flags |= PANE_REDRAW; 140167c16a7cSnicm 140267c16a7cSnicm return (0); 140367c16a7cSnicm } 140467c16a7cSnicm 140567c16a7cSnicm static void 140667c16a7cSnicm window_customize_key(struct window_mode_entry *wme, struct client *c, 140767c16a7cSnicm __unused struct session *s, __unused struct winlink *wl, key_code key, 140867c16a7cSnicm struct mouse_event *m) 140967c16a7cSnicm { 141067c16a7cSnicm struct window_pane *wp = wme->wp; 141167c16a7cSnicm struct window_customize_modedata *data = wme->data; 141267c16a7cSnicm struct window_customize_itemdata *item, *new_item; 141394c0d63cSnicm int finished, idx; 141467c16a7cSnicm char *prompt; 141567c16a7cSnicm u_int tagged; 141667c16a7cSnicm 141767c16a7cSnicm item = mode_tree_get_current(data->data); 141867c16a7cSnicm finished = mode_tree_key(data->data, c, &key, m, NULL, NULL); 141967c16a7cSnicm if (item != (new_item = mode_tree_get_current(data->data))) 142067c16a7cSnicm item = new_item; 142167c16a7cSnicm 142267c16a7cSnicm switch (key) { 142367c16a7cSnicm case '\r': 142467c16a7cSnicm case 's': 142567c16a7cSnicm if (item == NULL) 142667c16a7cSnicm break; 142767c16a7cSnicm if (item->scope == WINDOW_CUSTOMIZE_KEY) 142867c16a7cSnicm window_customize_set_key(c, data, item); 142967c16a7cSnicm else { 143067c16a7cSnicm window_customize_set_option(c, data, item, 0, 1); 143167c16a7cSnicm options_push_changes(item->name); 143267c16a7cSnicm } 143367c16a7cSnicm mode_tree_build(data->data); 143467c16a7cSnicm break; 143567c16a7cSnicm case 'w': 143667c16a7cSnicm if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 143767c16a7cSnicm break; 143867c16a7cSnicm window_customize_set_option(c, data, item, 0, 0); 143967c16a7cSnicm options_push_changes(item->name); 144067c16a7cSnicm mode_tree_build(data->data); 144167c16a7cSnicm break; 144267c16a7cSnicm case 'S': 144367c16a7cSnicm case 'W': 144467c16a7cSnicm if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY) 144567c16a7cSnicm break; 144667c16a7cSnicm window_customize_set_option(c, data, item, 1, 0); 144767c16a7cSnicm options_push_changes(item->name); 144867c16a7cSnicm mode_tree_build(data->data); 144967c16a7cSnicm break; 145094c0d63cSnicm case 'd': 145194c0d63cSnicm if (item == NULL || item->idx != -1) 145294c0d63cSnicm break; 145394c0d63cSnicm xasprintf(&prompt, "Reset %s to default? ", item->name); 145494c0d63cSnicm data->references++; 145594c0d63cSnicm data->change = WINDOW_CUSTOMIZE_RESET; 145694c0d63cSnicm status_prompt_set(c, NULL, prompt, "", 145794c0d63cSnicm window_customize_change_current_callback, 145894c0d63cSnicm window_customize_free_callback, data, 1459*af11b61dSnicm PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags, 1460*af11b61dSnicm PROMPT_TYPE_COMMAND); 146194c0d63cSnicm free(prompt); 146294c0d63cSnicm break; 146394c0d63cSnicm case 'D': 146494c0d63cSnicm tagged = mode_tree_count_tagged(data->data); 146594c0d63cSnicm if (tagged == 0) 146694c0d63cSnicm break; 146794c0d63cSnicm xasprintf(&prompt, "Reset %u tagged to default? ", tagged); 146894c0d63cSnicm data->references++; 146994c0d63cSnicm data->change = WINDOW_CUSTOMIZE_RESET; 147094c0d63cSnicm status_prompt_set(c, NULL, prompt, "", 147194c0d63cSnicm window_customize_change_tagged_callback, 147294c0d63cSnicm window_customize_free_callback, data, 1473*af11b61dSnicm PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags, 1474*af11b61dSnicm PROMPT_TYPE_COMMAND); 147594c0d63cSnicm free(prompt); 147694c0d63cSnicm break; 147767c16a7cSnicm case 'u': 147867c16a7cSnicm if (item == NULL) 147967c16a7cSnicm break; 148094c0d63cSnicm idx = item->idx; 148194c0d63cSnicm if (idx != -1) 148294c0d63cSnicm xasprintf(&prompt, "Unset %s[%d]? ", item->name, idx); 148394c0d63cSnicm else 148494c0d63cSnicm xasprintf(&prompt, "Unset %s? ", item->name); 148567c16a7cSnicm data->references++; 148694c0d63cSnicm data->change = WINDOW_CUSTOMIZE_UNSET; 148794adf770Snicm status_prompt_set(c, NULL, prompt, "", 148894c0d63cSnicm window_customize_change_current_callback, 148967c16a7cSnicm window_customize_free_callback, data, 1490*af11b61dSnicm PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags, 1491*af11b61dSnicm PROMPT_TYPE_COMMAND); 149267c16a7cSnicm free(prompt); 149367c16a7cSnicm break; 149467c16a7cSnicm case 'U': 149567c16a7cSnicm tagged = mode_tree_count_tagged(data->data); 149667c16a7cSnicm if (tagged == 0) 149767c16a7cSnicm break; 149894c0d63cSnicm xasprintf(&prompt, "Unset %u tagged? ", tagged); 149967c16a7cSnicm data->references++; 150094c0d63cSnicm data->change = WINDOW_CUSTOMIZE_UNSET; 150194adf770Snicm status_prompt_set(c, NULL, prompt, "", 150294c0d63cSnicm window_customize_change_tagged_callback, 150367c16a7cSnicm window_customize_free_callback, data, 1504*af11b61dSnicm PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags, 1505*af11b61dSnicm PROMPT_TYPE_COMMAND); 150667c16a7cSnicm free(prompt); 150767c16a7cSnicm break; 150867c16a7cSnicm case 'H': 150967c16a7cSnicm data->hide_global = !data->hide_global; 151067c16a7cSnicm mode_tree_build(data->data); 151167c16a7cSnicm break; 151267c16a7cSnicm } 151367c16a7cSnicm if (finished) 151467c16a7cSnicm window_pane_reset_mode(wp); 151567c16a7cSnicm else { 151667c16a7cSnicm mode_tree_draw(data->data); 151767c16a7cSnicm wp->flags |= PANE_REDRAW; 151867c16a7cSnicm } 151967c16a7cSnicm } 1520