Include key bindings in customize mode.

This commit is contained in:
Nicholas Marriott 2020-05-12 08:57:55 +01:00
parent c489bf0a1e
commit 5a34f51d33
5 changed files with 496 additions and 59 deletions

View File

@ -68,7 +68,8 @@ cmd_list_keys_get_width(const char *tablename, key_code only)
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL) { bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
@ -99,14 +100,15 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
(bd->note == NULL && !args_has(args, 'a'))) { ((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
found = 1; found = 1;
key = key_string_lookup_key(bd->key); key = key_string_lookup_key(bd->key);
if (bd->note == NULL) if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist, 1); note = cmd_list_print(bd->cmdlist, 1);
else else
note = xstrdup(bd->note); note = xstrdup(bd->note);

View File

@ -80,6 +80,7 @@ struct mode_tree_item {
int expanded; int expanded;
int tagged; int tagged;
int draw_as_parent;
struct mode_tree_list children; struct mode_tree_list children;
TAILQ_ENTRY(mode_tree_item) entry; TAILQ_ENTRY(mode_tree_item) entry;
@ -248,6 +249,12 @@ mode_tree_get_current(struct mode_tree_data *mtd)
return (mtd->line_list[mtd->current].item->itemdata); return (mtd->line_list[mtd->current].item->itemdata);
} }
const char *
mode_tree_get_current_name(struct mode_tree_data *mtd)
{
return (mtd->line_list[mtd->current].item->name);
}
void void
mode_tree_expand_current(struct mode_tree_data *mtd) mode_tree_expand_current(struct mode_tree_data *mtd)
{ {
@ -257,6 +264,15 @@ mode_tree_expand_current(struct mode_tree_data *mtd)
} }
} }
void
mode_tree_collapse_current(struct mode_tree_data *mtd)
{
if (mtd->line_list[mtd->current].item->expanded) {
mtd->line_list[mtd->current].item->expanded = 0;
mode_tree_build(mtd);
}
}
static int static int
mode_tree_get_tag(struct mode_tree_data *mtd, uint64_t tag, u_int *found) mode_tree_get_tag(struct mode_tree_data *mtd, uint64_t tag, u_int *found)
{ {
@ -543,6 +559,12 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
return (mti); return (mti);
} }
void
mode_tree_draw_as_parent(struct mode_tree_item *mti)
{
mti->draw_as_parent = 1;
}
void void
mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti) mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
{ {
@ -683,6 +705,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
line = &mtd->line_list[mtd->current]; line = &mtd->line_list[mtd->current];
mti = line->item; mti = line->item;
if (mti->draw_as_parent)
mti = mti->parent;
screen_write_cursormove(&ctx, 0, h, 0); screen_write_cursormove(&ctx, 0, h, 0);
screen_write_box(&ctx, w, sy - h); screen_write_box(&ctx, w, sy - h);

10
tmux.1
View File

@ -1970,8 +1970,8 @@ This command works only if at least one client is attached.
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Op Ar template .Op Ar template
.Xc .Xc
Put a pane into customize mode, where options may be browsed and modified from a Put a pane into customize mode, where options and key bindings may be browsed
list. and modified from a list.
Option values in the list are shown for the active pane in the current window. Option values in the list are shown for the active pane in the current window.
.Fl Z .Fl Z
zooms the pane. zooms the pane.
@ -1985,11 +1985,11 @@ The following keys may be used in customize mode:
.It Li "-" Ta "Collapse selected item" .It Li "-" Ta "Collapse selected item"
.It Li "M-+" Ta "Expand all items" .It Li "M-+" Ta "Expand all items"
.It Li "M--" Ta "Collapse all items" .It Li "M--" Ta "Collapse all items"
.It Li "s" Ta "Set pane, window, session or global option value" .It Li "s" Ta "Set option value or key attribute"
.It Li "S" Ta "Set global option value" .It Li "S" Ta "Set global option value"
.It Li "w" Ta "Set window option value, if option is for pane and window" .It Li "w" Ta "Set window option value, if option is for pane and window"
.It Li "u" Ta "Unset an option (set to default value if global)" .It Li "u" Ta "Unset an option (set to default value if global) or unbind a key"
.It Li "U" Ta "Unset tagged options" .It Li "U" Ta "Unset tagged options and unbind tagged keys"
.It Li "C-s" Ta "Search by name" .It Li "C-s" Ta "Search by name"
.It Li "n" Ta "Repeat last search" .It Li "n" Ta "Repeat last search"
.It Li "t" Ta "Toggle if item is tagged" .It Li "t" Ta "Toggle if item is tagged"

3
tmux.h
View File

@ -2698,7 +2698,9 @@ typedef u_int (*mode_tree_height_cb)(void *, u_int);
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code); typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
u_int mode_tree_count_tagged(struct mode_tree_data *); u_int mode_tree_count_tagged(struct mode_tree_data *);
void *mode_tree_get_current(struct mode_tree_data *); void *mode_tree_get_current(struct mode_tree_data *);
const char *mode_tree_get_current_name(struct mode_tree_data *);
void mode_tree_expand_current(struct mode_tree_data *); void mode_tree_expand_current(struct mode_tree_data *);
void mode_tree_collapse_current(struct mode_tree_data *);
void mode_tree_expand(struct mode_tree_data *, uint64_t); void mode_tree_expand(struct mode_tree_data *, uint64_t);
int mode_tree_set_current(struct mode_tree_data *, uint64_t); int mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb, void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
@ -2716,6 +2718,7 @@ void mode_tree_resize(struct mode_tree_data *, u_int, u_int);
struct mode_tree_item *mode_tree_add(struct mode_tree_data *, struct mode_tree_item *mode_tree_add(struct mode_tree_data *,
struct mode_tree_item *, void *, uint64_t, const char *, struct mode_tree_item *, void *, uint64_t, const char *,
const char *, int); const char *, int);
void mode_tree_draw_as_parent(struct mode_tree_item *);
void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *); void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
void mode_tree_draw(struct mode_tree_data *); void mode_tree_draw(struct mode_tree_data *);
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *, int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,

View File

@ -34,9 +34,13 @@ static void window_customize_key(struct window_mode_entry *,
struct winlink *, key_code, struct mouse_event *); struct winlink *, key_code, struct mouse_event *);
#define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \ #define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \
"#{?is_option," \
"#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \ "#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \
"#[ignore]" \ "#[ignore]" \
"#{option_value}#{?option_unit, #{option_unit},}" "#{option_value}#{?option_unit, #{option_unit},}" \
"," \
"#{key}" \
"}"
static const struct menu_item window_customize_menu_items[] = { static const struct menu_item window_customize_menu_items[] = {
{ "Select", '\r', NULL }, { "Select", '\r', NULL },
@ -63,6 +67,7 @@ const struct window_mode window_customize_mode = {
enum window_customize_scope { enum window_customize_scope {
WINDOW_CUSTOMIZE_NONE, WINDOW_CUSTOMIZE_NONE,
WINDOW_CUSTOMIZE_KEY,
WINDOW_CUSTOMIZE_SERVER, WINDOW_CUSTOMIZE_SERVER,
WINDOW_CUSTOMIZE_GLOBAL_SESSION, WINDOW_CUSTOMIZE_GLOBAL_SESSION,
WINDOW_CUSTOMIZE_SESSION, WINDOW_CUSTOMIZE_SESSION,
@ -74,6 +79,10 @@ enum window_customize_scope {
struct window_customize_itemdata { struct window_customize_itemdata {
struct window_customize_modedata *data; struct window_customize_modedata *data;
enum window_customize_scope scope; enum window_customize_scope scope;
char *table;
key_code key;
struct options *oo; struct options *oo;
char *name; char *name;
int idx; int idx;
@ -103,7 +112,7 @@ window_customize_get_tag(struct options_entry *o, int idx,
if (oe == NULL) if (oe == NULL)
return ((uint64_t)o); return ((uint64_t)o);
offset = ((char *)oe - (char *)options_table) / sizeof *options_table; offset = ((char *)oe - (char *)options_table) / sizeof *options_table;
return ((offset << 32) | ((idx + 1) << 1) | 1); return ((2ULL << 62)|(offset << 32)|((idx + 1) << 1)|1);
} }
static struct options * static struct options *
@ -112,6 +121,7 @@ window_customize_get_tree(enum window_customize_scope scope,
{ {
switch (scope) { switch (scope) {
case WINDOW_CUSTOMIZE_NONE: case WINDOW_CUSTOMIZE_NONE:
case WINDOW_CUSTOMIZE_KEY:
return (NULL); return (NULL);
case WINDOW_CUSTOMIZE_SERVER: case WINDOW_CUSTOMIZE_SERVER:
return (global_options); return (global_options);
@ -145,6 +155,27 @@ window_customize_check_item(struct window_customize_modedata *data,
return (item->oo == window_customize_get_tree(item->scope, fsp)); return (item->oo == window_customize_get_tree(item->scope, fsp));
} }
static int
window_customize_get_key(struct window_customize_itemdata *item,
struct key_table **ktp, struct key_binding **bdp)
{
struct key_table *kt;
struct key_binding *bd;
kt = key_bindings_get_table(item->table, 0);
if (kt == NULL)
return (0);
bd = key_bindings_get(kt, item->key);
if (bd == NULL)
return (0);
if (ktp != NULL)
*ktp = kt;
if (bdp != NULL)
*bdp = bd;
return (1);
}
static char * static char *
window_customize_scope_text(enum window_customize_scope scope, window_customize_scope_text(enum window_customize_scope scope,
struct cmd_find_state *fs) struct cmd_find_state *fs)
@ -154,6 +185,7 @@ window_customize_scope_text(enum window_customize_scope scope,
switch (scope) { switch (scope) {
case WINDOW_CUSTOMIZE_NONE: case WINDOW_CUSTOMIZE_NONE:
case WINDOW_CUSTOMIZE_KEY:
case WINDOW_CUSTOMIZE_SERVER: case WINDOW_CUSTOMIZE_SERVER:
case WINDOW_CUSTOMIZE_GLOBAL_SESSION: case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
@ -187,6 +219,7 @@ window_customize_add_item(struct window_customize_modedata *data)
static void static void
window_customize_free_item(struct window_customize_itemdata *item) window_customize_free_item(struct window_customize_itemdata *item)
{ {
free(item->table);
free(item->name); free(item->name);
free(item); free(item);
} }
@ -403,6 +436,83 @@ window_customize_build_options(struct window_customize_modedata *data,
} }
} }
static void
window_customize_build_keys(struct window_customize_modedata *data,
struct key_table *kt, struct format_tree *ft, const char *filter,
struct cmd_find_state *fs, u_int number)
{
struct mode_tree_item *top, *child, *mti;
struct window_customize_itemdata *item;
struct key_binding *bd;
char *title, *text, *tmp, *expanded;
const char *flag;
uint64_t tag;
tag = (1ULL << 62)|((uint64_t)number << 54)|1;
xasprintf(&title, "Key Table - %s", kt->name);
top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
free(title);
ft = format_create_from_state(NULL, NULL, fs);
format_add(ft, "is_option", "0");
format_add(ft, "is_key", "1");
bd = key_bindings_first(kt);
while (bd != NULL) {
format_add(ft, "key", "%s", key_string_lookup_key(bd->key));
if (bd->note != NULL)
format_add(ft, "key_note", "%s", bd->note);
if (filter != NULL) {
expanded = format_expand(ft, filter);
if (!format_true(expanded)) {
free(expanded);
continue;
}
free(expanded);
}
item = window_customize_add_item(data);
item->scope = WINDOW_CUSTOMIZE_KEY;
item->table = xstrdup(kt->name);
item->key = bd->key;
expanded = format_expand(ft, data->format);
child = mode_tree_add(data->data, top, item, (uint64_t)bd,
expanded, NULL, 0);
free(expanded);
tmp = cmd_list_print(bd->cmdlist, 0);
xasprintf(&text, "#[ignore]%s", tmp);
free(tmp);
mti = mode_tree_add(data->data, child, item,
tag|(bd->key << 3)|(0 << 1)|1, "Command", text, -1);
mode_tree_draw_as_parent(mti);
free(text);
if (bd->note != NULL)
xasprintf(&text, "#[ignore]%s", bd->note);
else
text = xstrdup("");
mti = mode_tree_add(data->data, child, item,
tag|(bd->key << 3)|(1 << 1)|1, "Note", text, -1);
mode_tree_draw_as_parent(mti);
free(text);
if (bd->flags & KEY_BINDING_REPEAT)
flag = "on";
else
flag = "off";
mti = mode_tree_add(data->data, child, item,
tag|(bd->key << 3)|(2 << 1)|1, "Repeat", flag, -1);
mode_tree_draw_as_parent(mti);
bd = key_bindings_next(kt, bd);
}
format_free(ft);
}
static void static void
window_customize_build(void *modedata, window_customize_build(void *modedata,
__unused struct mode_tree_sort_criteria *sort_crit, __unused uint64_t *tag, __unused struct mode_tree_sort_criteria *sort_crit, __unused uint64_t *tag,
@ -412,6 +522,7 @@ window_customize_build(void *modedata,
struct cmd_find_state fs; struct cmd_find_state fs;
struct format_tree *ft; struct format_tree *ft;
u_int i; u_int i;
struct key_table *kt;
for (i = 0; i < data->item_size; i++) for (i = 0; i < data->item_size; i++)
window_customize_free_item(data->item_list[i]); window_customize_free_item(data->item_list[i]);
@ -425,35 +536,94 @@ window_customize_build(void *modedata,
cmd_find_from_pane(&fs, data->wp, 0); cmd_find_from_pane(&fs, data->wp, 0);
ft = format_create_from_state(NULL, NULL, &fs); ft = format_create_from_state(NULL, NULL, &fs);
format_add(ft, "is_option", "1");
format_add(ft, "is_key", "0");
window_customize_build_options(data, "Server Options", window_customize_build_options(data, "Server Options",
(1ULL << 63)|OPTIONS_TABLE_SERVER, (3ULL << 62)|(OPTIONS_TABLE_SERVER << 1)|1,
WINDOW_CUSTOMIZE_SERVER, global_options, WINDOW_CUSTOMIZE_SERVER, global_options,
WINDOW_CUSTOMIZE_NONE, NULL, WINDOW_CUSTOMIZE_NONE, NULL,
WINDOW_CUSTOMIZE_NONE, NULL, WINDOW_CUSTOMIZE_NONE, NULL,
ft, filter, &fs); ft, filter, &fs);
window_customize_build_options(data, "Session Options", window_customize_build_options(data, "Session Options",
(1ULL << 63)|OPTIONS_TABLE_SESSION, (3ULL << 62)|(OPTIONS_TABLE_SESSION << 1)|1,
WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options, WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options,
WINDOW_CUSTOMIZE_SESSION, fs.s->options, WINDOW_CUSTOMIZE_SESSION, fs.s->options,
WINDOW_CUSTOMIZE_NONE, NULL, WINDOW_CUSTOMIZE_NONE, NULL,
ft, filter, &fs); ft, filter, &fs);
window_customize_build_options(data, "Window & Pane Options", window_customize_build_options(data, "Window & Pane Options",
(1ULL << 63)|OPTIONS_TABLE_WINDOW, (3ULL << 62)|(OPTIONS_TABLE_WINDOW << 1)|1,
WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options, WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options,
WINDOW_CUSTOMIZE_WINDOW, fs.w->options, WINDOW_CUSTOMIZE_WINDOW, fs.w->options,
WINDOW_CUSTOMIZE_PANE, fs.wp->options, WINDOW_CUSTOMIZE_PANE, fs.wp->options,
ft, filter, &fs); ft, filter, &fs);
format_free(ft);
ft = format_create_from_state(NULL, NULL, &fs);
i = 0;
kt = key_bindings_first_table();
while (kt != NULL) {
window_customize_build_keys(data, kt, ft, filter, &fs, i);
if (++i == 256)
break;
kt = key_bindings_next_table(kt);
}
format_free(ft); format_free(ft);
} }
static void static void
window_customize_draw(void *modedata, void *itemdata, window_customize_draw_key(__unused struct window_customize_modedata *data,
struct screen_write_ctx *ctx, u_int sx, u_int sy) struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
u_int sx, u_int sy)
{
struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy;
struct key_table *kt;
struct key_binding *bd;
const char *note, *period = "";
char *tmp;
if (item == NULL || !window_customize_get_key(item, &kt, &bd))
return;
note = bd->note;
if (note == NULL)
note = "There is no note for this key.";
if (*note != '\0' && note[strlen (note) - 1] != '.')
period = ".";
if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s%s",
note, period))
return;
screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
if (s->cy >= cy + sy - 1)
return;
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
&grid_default_cell, "This key is in the %s table.", kt->name))
return;
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
&grid_default_cell, "This key %s repeat.",
(bd->flags & KEY_BINDING_REPEAT) ? "does" : "does not"))
return;
screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
if (s->cy >= cy + sy - 1)
return;
tmp = cmd_list_print(bd->cmdlist, 0);
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
&grid_default_cell, "Command: %s", tmp)) {
free(tmp);
return;
}
}
static void
window_customize_draw_option(struct window_customize_modedata *data,
struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
u_int sx, u_int sy)
{ {
struct window_customize_modedata *data = modedata;
struct window_customize_itemdata *item = itemdata;
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy; u_int cx = s->cx, cy = s->cy;
int idx; int idx;
@ -469,7 +639,7 @@ window_customize_draw(void *modedata, void *itemdata,
struct cmd_find_state fs; struct cmd_find_state fs;
struct format_tree *ft; struct format_tree *ft;
if (item == NULL || !window_customize_check_item(data, item, &fs)) if (!window_customize_check_item(data, item, &fs))
return; return;
name = item->name; name = item->name;
idx = item->idx; idx = item->idx;
@ -639,6 +809,22 @@ out:
format_free(ft); format_free(ft);
} }
static void
window_customize_draw(void *modedata, void *itemdata,
struct screen_write_ctx *ctx, u_int sx, u_int sy)
{
struct window_customize_modedata *data = modedata;
struct window_customize_itemdata *item = itemdata;
if (item == NULL)
return;
if (item->scope == WINDOW_CUSTOMIZE_KEY)
window_customize_draw_key(data, item, ctx, sx, sy);
else
window_customize_draw_option(data, item, ctx, sx, sy);
}
static void static void
window_customize_menu(void *modedata, struct client *c, key_code key) window_customize_menu(void *modedata, struct client *c, key_code key)
{ {
@ -727,9 +913,25 @@ window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
mode_tree_resize(data->data, sx, sy); mode_tree_resize(data->data, sx, sy);
} }
static void
window_customize_free_callback(void *modedata)
{
window_customize_destroy(modedata);
}
static void
window_customize_free_item_callback(void *itemdata)
{
struct window_customize_itemdata *item = itemdata;
struct window_customize_modedata *data = item->data;
window_customize_free_item(item);
window_customize_destroy(data);
}
static int static int
window_customize_set_callback(struct client *c, void *itemdata, const char *s, window_customize_set_option_callback(struct client *c, void *itemdata,
__unused int done) const char *s, __unused int done)
{ {
struct window_customize_itemdata *item = itemdata; struct window_customize_itemdata *item = itemdata;
struct window_customize_modedata *data = item->data; struct window_customize_modedata *data = item->data;
@ -778,17 +980,8 @@ fail:
} }
static void static void
window_customize_set_free(void *itemdata) window_customize_set_option(struct client *c,
{ struct window_customize_modedata *data,
struct window_customize_itemdata *item = itemdata;
struct window_customize_modedata *data = item->data;
window_customize_free_item(item);
window_customize_destroy(data);
}
static void
window_customize_set_option(struct client *c, struct window_customize_modedata *data,
struct window_customize_itemdata *item, int global, int pane) struct window_customize_itemdata *item, int global, int pane)
{ {
struct options_entry *o; struct options_entry *o;
@ -807,7 +1000,6 @@ window_customize_set_option(struct client *c, struct window_customize_modedata *
o = options_get(item->oo, name); o = options_get(item->oo, name);
if (o == NULL) if (o == NULL)
return; return;
value = options_to_string(o, idx, 0);
oe = options_table_entry(o); oe = options_table_entry(o);
if (~oe->scope & OPTIONS_TABLE_PANE) if (~oe->scope & OPTIONS_TABLE_PANE)
@ -819,6 +1011,7 @@ window_customize_set_option(struct client *c, struct window_customize_modedata *
if (global) { if (global) {
switch (item->scope) { switch (item->scope) {
case WINDOW_CUSTOMIZE_NONE: case WINDOW_CUSTOMIZE_NONE:
case WINDOW_CUSTOMIZE_KEY:
case WINDOW_CUSTOMIZE_SERVER: case WINDOW_CUSTOMIZE_SERVER:
case WINDOW_CUSTOMIZE_GLOBAL_SESSION: case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
case WINDOW_CUSTOMIZE_GLOBAL_WINDOW: case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
@ -835,6 +1028,7 @@ window_customize_set_option(struct client *c, struct window_customize_modedata *
} else { } else {
switch (item->scope) { switch (item->scope) {
case WINDOW_CUSTOMIZE_NONE: case WINDOW_CUSTOMIZE_NONE:
case WINDOW_CUSTOMIZE_KEY:
case WINDOW_CUSTOMIZE_SERVER: case WINDOW_CUSTOMIZE_SERVER:
case WINDOW_CUSTOMIZE_SESSION: case WINDOW_CUSTOMIZE_SESSION:
scope = item->scope; scope = item->scope;
@ -891,7 +1085,9 @@ window_customize_set_option(struct client *c, struct window_customize_modedata *
xasprintf(&prompt, "(%s%s%s) ", name, space, text); xasprintf(&prompt, "(%s%s%s) ", name, space, text);
free(text); free(text);
new_item = xmalloc(sizeof *new_item); value = options_to_string(o, idx, 0);
new_item = xcalloc(1, sizeof *new_item);
new_item->data = data; new_item->data = data;
new_item->scope = scope; new_item->scope = scope;
new_item->oo = oo; new_item->oo = oo;
@ -899,10 +1095,14 @@ window_customize_set_option(struct client *c, struct window_customize_modedata *
new_item->idx = idx; new_item->idx = idx;
data->references++; data->references++;
status_prompt_set(c, prompt, value, window_customize_set_callback, status_prompt_set(c, prompt, value,
window_customize_set_free, new_item, PROMPT_NOFORMAT); window_customize_set_option_callback,
} window_customize_free_item_callback, new_item,
PROMPT_NOFORMAT);
free(prompt);
free(value); free(value);
}
} }
static void static void
@ -919,6 +1119,7 @@ window_customize_unset_option(struct window_customize_modedata *data,
if (o == NULL) if (o == NULL)
return; return;
if (item->idx != -1) { if (item->idx != -1) {
if (item == mode_tree_get_current(data->data))
mode_tree_up(data->data, 0); mode_tree_up(data->data, 0);
options_array_set(o, item->idx, NULL, 0, NULL); options_array_set(o, item->idx, NULL, 0, NULL);
return; return;
@ -933,11 +1134,198 @@ window_customize_unset_option(struct window_customize_modedata *data,
options_default(options_owner(o), oe); options_default(options_owner(o), oe);
} }
static int
window_customize_set_command_callback(struct client *c, void *itemdata,
const char *s, __unused int done)
{
struct window_customize_itemdata *item = itemdata;
struct window_customize_modedata *data = item->data;
struct key_binding *bd;
struct cmd_parse_result *pr;
char *error;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (item == NULL || !window_customize_get_key(item, NULL, &bd))
return (0);
pr = cmd_parse_from_string(s, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
error = xstrdup("empty command");
goto fail;
case CMD_PARSE_ERROR:
error = pr->error;
goto fail;
case CMD_PARSE_SUCCESS:
break;
}
cmd_list_free(bd->cmdlist);
bd->cmdlist = pr->cmdlist;
mode_tree_build(data->data);
mode_tree_draw(data->data);
data->wp->flags |= PANE_REDRAW;
return (0);
fail:
*error = toupper((u_char)*error);
status_message_set(c, 1, "%s", error);
free(error);
return (0);
}
static int
window_customize_set_note_callback(__unused struct client *c, void *itemdata,
const char *s, __unused int done)
{
struct window_customize_itemdata *item = itemdata;
struct window_customize_modedata *data = item->data;
struct key_binding *bd;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (item == NULL || !window_customize_get_key(item, NULL, &bd))
return (0);
free((void *)bd->note);
bd->note = xstrdup(s);
mode_tree_build(data->data);
mode_tree_draw(data->data);
data->wp->flags |= PANE_REDRAW;
return (0);
}
static void
window_customize_set_key(struct client *c,
struct window_customize_modedata *data,
struct window_customize_itemdata *item)
{
key_code key = item->key;
struct key_binding *bd;
const char *s;
char *prompt, *value;
struct window_customize_itemdata *new_item;
if (item == NULL || !window_customize_get_key(item, NULL, &bd))
return;
s = mode_tree_get_current_name(data->data);
if (strcmp(s, "Repeat") == 0)
bd->flags ^= KEY_BINDING_REPEAT;
else if (strcmp(s, "Command") == 0) {
xasprintf(&prompt, "(%s) ", key_string_lookup_key(key));
value = cmd_list_print(bd->cmdlist, 0);
new_item = xcalloc(1, sizeof *new_item);
new_item->data = data;
new_item->scope = item->scope;
new_item->table = xstrdup(item->table);
new_item->key = key;
data->references++;
status_prompt_set(c, prompt, value,
window_customize_set_command_callback,
window_customize_free_item_callback, new_item,
PROMPT_NOFORMAT);
free(prompt);
free(value);
} else if (strcmp(s, "Note") == 0) {
xasprintf(&prompt, "(%s) ", key_string_lookup_key(key));
new_item = xcalloc(1, sizeof *new_item);
new_item->data = data;
new_item->scope = item->scope;
new_item->table = xstrdup(item->table);
new_item->key = key;
data->references++;
status_prompt_set(c, prompt, (bd->note == NULL ? "" : bd->note),
window_customize_set_note_callback,
window_customize_free_item_callback, new_item,
PROMPT_NOFORMAT);
free(prompt);
}
}
static void
window_customize_unset_key(struct window_customize_modedata *data,
struct window_customize_itemdata *item)
{
struct key_table *kt;
struct key_binding *bd;
if (item == NULL || !window_customize_get_key(item, &kt, &bd))
return;
if (item == mode_tree_get_current(data->data)) {
mode_tree_collapse_current(data->data);
mode_tree_up(data->data, 0);
}
key_bindings_remove(kt->name, bd->key);
}
static void static void
window_customize_unset_each(void *modedata, void *itemdata, window_customize_unset_each(void *modedata, void *itemdata,
__unused struct client *c, __unused key_code key) __unused struct client *c, __unused key_code key)
{ {
window_customize_unset_option(modedata, itemdata); struct window_customize_itemdata *item = itemdata;
if (item->scope == WINDOW_CUSTOMIZE_KEY)
window_customize_unset_key(modedata, item);
else {
window_customize_unset_option(modedata, item);
options_push_changes(item->name);
}
}
static int
window_customize_unset_current_callback(__unused struct client *c,
void *modedata, const char *s, __unused int done)
{
struct window_customize_modedata *data = modedata;
struct window_customize_itemdata *item;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
item = mode_tree_get_current(data->data);
if (item->scope == WINDOW_CUSTOMIZE_KEY)
window_customize_unset_key(data, item);
else {
window_customize_unset_option(data, item);
options_push_changes(item->name);
}
mode_tree_build(data->data);
mode_tree_draw(data->data);
data->wp->flags |= PANE_REDRAW;
return (0);
}
static int
window_customize_unset_tagged_callback(struct client *c, void *modedata,
const char *s, __unused int done)
{
struct window_customize_modedata *data = modedata;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
mode_tree_each_tagged(data->data, window_customize_unset_each, c,
KEYC_NONE, 0);
mode_tree_build(data->data);
mode_tree_draw(data->data);
data->wp->flags |= PANE_REDRAW;
return (0);
} }
static void static void
@ -949,6 +1337,8 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
struct window_customize_modedata *data = wme->data; struct window_customize_modedata *data = wme->data;
struct window_customize_itemdata *item, *new_item; struct window_customize_itemdata *item, *new_item;
int finished; int finished;
char *prompt;
u_int tagged;
item = mode_tree_get_current(data->data); item = mode_tree_get_current(data->data);
finished = mode_tree_key(data->data, c, &key, m, NULL, NULL); finished = mode_tree_key(data->data, c, &key, m, NULL, NULL);
@ -960,12 +1350,16 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
case 's': case 's':
if (item == NULL) if (item == NULL)
break; break;
if (item->scope == WINDOW_CUSTOMIZE_KEY)
window_customize_set_key(c, data, item);
else {
window_customize_set_option(c, data, item, 0, 1); window_customize_set_option(c, data, item, 0, 1);
options_push_changes(item->name); options_push_changes(item->name);
}
mode_tree_build(data->data); mode_tree_build(data->data);
break; break;
case 'w': case 'w':
if (item == NULL) if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY)
break; break;
window_customize_set_option(c, data, item, 0, 0); window_customize_set_option(c, data, item, 0, 0);
options_push_changes(item->name); options_push_changes(item->name);
@ -973,7 +1367,7 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
break; break;
case 'S': case 'S':
case 'W': case 'W':
if (item == NULL) if (item == NULL || item->scope == WINDOW_CUSTOMIZE_KEY)
break; break;
window_customize_set_option(c, data, item, 1, 0); window_customize_set_option(c, data, item, 1, 0);
options_push_changes(item->name); options_push_changes(item->name);
@ -982,15 +1376,29 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
case 'u': case 'u':
if (item == NULL) if (item == NULL)
break; break;
window_customize_unset_option(data, item); if (item->scope == WINDOW_CUSTOMIZE_KEY) {
options_push_changes(item->name); xasprintf(&prompt, "Unbind key %s? ",
mode_tree_build(data->data); key_string_lookup_key(item->key));
} else
xasprintf(&prompt, "Unset option %s? ", item->name);
data->references++;
status_prompt_set(c, prompt, "",
window_customize_unset_current_callback,
window_customize_free_callback, data,
PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break; break;
case 'U': case 'U':
mode_tree_each_tagged(data->data, window_customize_unset_each, tagged = mode_tree_count_tagged(data->data);
c, KEYC_NONE, 1); if (tagged == 0)
options_push_changes(item->name); break;
mode_tree_build(data->data); xasprintf(&prompt, "Unset or unbind %u tagged? ", tagged);
data->references++;
status_prompt_set(c, prompt, "",
window_customize_unset_tagged_callback,
window_customize_free_callback, data,
PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break; break;
case 'H': case 'H':
data->hide_global = !data->hide_global; data->hide_global = !data->hide_global;