Handle key binding.

This commit is contained in:
Nicholas Marriott
2026-06-30 11:19:52 +01:00
parent f7cd6ab547
commit b48e2ea8e9
9 changed files with 101 additions and 63 deletions

View File

@@ -89,8 +89,7 @@ args_copy_value(struct args_value *to, struct args_value *from)
case ARGS_NONE:
break;
case ARGS_COMMANDS:
to->cmdlist = from->cmdlist;
to->cmdlist->references++;
to->cmd = cmd_parse_add_ref(from->cmd);
break;
case ARGS_STRING:
to->string = xstrdup(from->string);
@@ -123,7 +122,7 @@ args_value_as_string(struct args_value *value)
return ("");
case ARGS_COMMANDS:
if (value->cached == NULL)
value->cached = cmd_list_print(value->cmdlist, 0);
value->cached = cmd_parse_print(value->cmd);
return (value->cached);
case ARGS_STRING:
return (value->string);
@@ -367,7 +366,7 @@ args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
to->string = expanded;
break;
case ARGS_COMMANDS:
to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
to->cmd = cmd_parse_add_ref(from->cmd);
break;
}
}
@@ -418,7 +417,7 @@ args_free_value(struct args_value *value)
free(value->string);
break;
case ARGS_COMMANDS:
cmd_list_free(value->cmdlist);
cmd_parse_free(value->cmd);
break;
}
free(value->cached);
@@ -477,7 +476,7 @@ args_to_vector(struct args *args, int *argc, char ***argv)
cmd_append_argv(argc, argv, args->values[i].string);
break;
case ARGS_COMMANDS:
s = cmd_list_print(args->values[i].cmdlist, 0);
s = cmd_parse_print(args->values[i].cmd);
cmd_append_argv(argc, argv, s);
free(s);
break;
@@ -532,7 +531,7 @@ args_print_add_value(char **buf, size_t *len, struct args_value *value)
case ARGS_NONE:
break;
case ARGS_COMMANDS:
expanded = cmd_list_print(value->cmdlist, 0);
expanded = cmd_parse_print(value->cmd);
args_print_add(buf, len, "{ %s }", expanded);
break;
case ARGS_STRING:
@@ -784,9 +783,14 @@ args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
if (idx < args->count) {
value = &args->values[idx];
if (value->type == ARGS_COMMANDS) {
#if 0 /* XXX: command parser conversion */
state->cmdlist = value->cmdlist;
state->cmdlist->references++;
return (state);
#else
fatalx("XXX: command parser conversion not done for "
"ARGS_COMMANDS");
#endif
}
cmd = value->string;
} else {

View File

@@ -54,12 +54,13 @@ cmd_bind_key_args_parse(__unused struct args *args, __unused u_int idx,
static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
key_code key;
const char *tablename, *note = args_get(args, 'N');
int repeat;
struct args_value *value;
u_int count = args_count(args);
struct args *args = cmd_get_args(self);
key_code key;
const char *tablename, *note = args_get(args, 'N');
int repeat;
struct args_value *value;
u_int count = args_count(args);
struct cmd_parse_tree *cmd;
key = key_string_lookup_string(args_string(args, 0));
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
@@ -82,8 +83,8 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
value = args_value(args, 1);
if (count == 2 && value->type == ARGS_COMMANDS) {
key_bindings_add(tablename, key, note, repeat, value->cmdlist);
value->cmdlist->references++;
cmd = cmd_parse_add_ref(value->cmd);
key_bindings_add(tablename, key, note, repeat, cmd);
return (CMD_RETURN_NORMAL);
}

View File

@@ -313,7 +313,7 @@ cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is,
struct args_value *values = NULL;
struct cmd *cmd;
char *cause = NULL;
u_int count = 0, i;
u_int count = 0;
child = cmd_parse_node_first_child(node);
while (child != NULL) {
@@ -328,11 +328,7 @@ cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is,
break;
case CMD_PARSE_COMMANDS:
values[count].type = ARGS_COMMANDS;
#if 0 /* XXX: command parser conversion */
values[count].cmdparse = child;
#else
fatalx("XXX: command parser conversion not done for ARGS_COMMANDS");
#endif
values[count].cmd = cmd_parse_from_node(child);
break;
default:
fatalx("unexpected node type in command");
@@ -348,18 +344,12 @@ cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is,
free(cause);
goto fail;
}
for (i = 0; i < count; i++) {
if (values[i].type == ARGS_STRING)
free(values[i].string);
}
args_free_values(values, count);
free(values);
return (cmd);
fail:
for (i = 0; i < count; i++) {
if (values[i].type == ARGS_STRING)
free(values[i].string);
}
args_free_values(values, count);
free(values);
return (NULL);
}

View File

@@ -157,8 +157,7 @@ cmd_list_keys_format_add_key_binding(struct format_tree *ft,
format_add(ft, "key_string", "%s", key_string_lookup_key(bd->key, 0));
s = cmd_list_print(bd->cmdlist, CMD_LIST_PRINT_ESCAPED|
CMD_LIST_PRINT_NO_GROUPS);
s = cmd_parse_print(bd->cmd); /* XXX: command parser conversion */
format_add(ft, "key_command", "%s", s);
free(s);
}

View File

@@ -88,6 +88,7 @@ struct cmd_parse_scan {
static char *cmd_parse_get_error(const char *, u_int, const char *);
static struct cmd_parse_node *cmd_parse_new_node(enum cmd_parse_node_type,
u_int);
static struct cmd_parse_node *cmd_parse_copy_node(struct cmd_parse_node *);
static struct cmd_parse_nodes *cmd_parse_new_nodes(void);
static void cmd_parse_free_node(struct cmd_parse_node *);
static void cmd_parse_append(struct cmd_parse_nodes *,
@@ -466,6 +467,24 @@ cmd_parse_free_node(struct cmd_parse_node *node)
free(node);
}
/* Recursively copy a node and all of its descendants. */
static struct cmd_parse_node *
cmd_parse_copy_node(struct cmd_parse_node *node)
{
struct cmd_parse_node *new, *child, *copy;
new = cmd_parse_new_node(node->type, node->line);
new->end_line = node->end_line;
if (node->value != NULL)
new->value = xstrdup(node->value);
TAILQ_FOREACH(child, &node->children, entry) {
copy = cmd_parse_copy_node(child);
TAILQ_INSERT_TAIL(&new->children, copy, entry);
}
return (new);
}
/* Move all nodes from src to the tail of dst, then free the src list head. */
static void
cmd_parse_append(struct cmd_parse_nodes *dst, struct cmd_parse_nodes *src)
@@ -674,6 +693,25 @@ cmd_parse_from_string(const char *s, struct cmd_parse_input *pi, char **cause)
return (cmd_parse_from_buffer(s, strlen(s), &input, cause));
}
struct cmd_parse_tree *
cmd_parse_from_node(struct cmd_parse_node *node)
{
struct cmd_parse_tree *new;
struct cmd_parse_node *root, *child;
root = cmd_parse_new_node(CMD_PARSE_ROOT, node->line);
root->end_line = node->end_line;
TAILQ_FOREACH(child, &node->children, entry) {
TAILQ_INSERT_TAIL(&root->children, cmd_parse_copy_node(child),
entry);
}
new = xcalloc(1, sizeof *new);
new->references = 1;
new->root = root;
return (new);
}
struct cmd_parse_tree *
cmd_parse_add_ref(struct cmd_parse_tree *tree)
{

View File

@@ -96,7 +96,7 @@ key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
static void
key_bindings_free(struct key_binding *bd)
{
cmd_list_free(bd->cmdlist);
cmd_parse_free(bd->cmd);
free((void *)bd->note);
free(bd);
}
@@ -188,16 +188,14 @@ key_bindings_next(__unused struct key_table *table, struct key_binding *bd)
void
key_bindings_add(const char *name, key_code key, const char *note, int repeat,
struct cmd_list *cmdlist)
struct cmd_parse_tree *cmd)
{
struct key_table *table;
struct key_table *table = key_bindings_get_table(name, 1);
struct key_binding *bd;
char *s;
table = key_bindings_get_table(name, 1);
char *k, *s;
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
if (cmdlist == NULL) {
if (cmd == NULL) {
if (bd != NULL) {
if (note != NULL) {
free((void *)bd->note);
@@ -222,11 +220,11 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
if (repeat)
bd->flags |= KEY_BINDING_REPEAT;
bd->cmdlist = cmdlist;
bd->cmd = cmd;
s = cmd_list_print(bd->cmdlist, 0);
log_debug("%s: %#llx %s = %s", __func__, bd->key,
key_string_lookup_key(bd->key, 1), s);
k = key_string_lookup_key(bd->key, 1);
s = cmd_parse_print(bd->cmd);
log_debug("%s: %#llx %s = %s", __func__, bd->key, k, s);
free(s);
}
@@ -235,6 +233,7 @@ key_bindings_remove(const char *name, key_code key)
{
struct key_table *table;
struct key_binding *bd;
const char *k;
table = key_bindings_get_table(name, 0);
if (table == NULL)
@@ -244,8 +243,8 @@ key_bindings_remove(const char *name, key_code key)
if (bd == NULL)
return;
log_debug("%s: %#llx %s", __func__, bd->key,
key_string_lookup_key(bd->key, 1));
k = key_string_lookup_key(bd->key, 1);
log_debug("%s: %#llx %s", __func__, bd->key, k);
RB_REMOVE(key_bindings, &table->key_bindings, bd);
key_bindings_free(bd);
@@ -277,9 +276,8 @@ key_bindings_reset(const char *name, key_code key)
return;
}
cmd_list_free(bd->cmdlist);
bd->cmdlist = dd->cmdlist;
bd->cmdlist->references++;
cmd_parse_free(bd->cmd);
bd->cmd = cmd_parse_add_ref(dd->cmd);
free((void *)bd->note);
if (dd->note != NULL)
@@ -336,8 +334,7 @@ key_bindings_init_done(__unused struct cmdq_item *item, __unused void *data)
if (bd->note != NULL)
new_bd->note = xstrdup(bd->note);
new_bd->flags = bd->flags;
new_bd->cmdlist = bd->cmdlist;
new_bd->cmdlist->references++;
new_bd->cmd = cmd_parse_add_ref(bd->cmd);
RB_INSERT(key_bindings, &table->default_key_bindings,
new_bd);
}
@@ -706,12 +703,18 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
{
struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct cmd_invoke_input ci;
int readonly, flags = 0;
if (c == NULL || (~c->flags & CLIENT_READONLY))
readonly = 1;
else
else {
#if 0 /* XXX: command parser conversion */
readonly = cmd_list_all_have(bd->cmdlist, CMD_READONLY);
#else
readonly = 0;
#endif
}
if (!readonly)
new_item = cmdq_get_callback(key_bindings_read_only, NULL);
@@ -719,7 +722,9 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
if (bd->flags & KEY_BINDING_REPEAT)
flags |= CMDQ_STATE_REPEAT;
new_state = cmdq_new_state(fs, event, flags);
new_item = cmdq_get_command(bd->cmdlist, new_state);
memset(&ci, 0, sizeof ci);
new_item = cmd_invoke_get(bd->cmd, new_state, &ci);
cmdq_free_state(new_state);
}
if (item != NULL)

View File

@@ -77,6 +77,7 @@ struct cmd_parse_tree *cmd_parse_from_buffer(const void *, size_t,
struct cmd_parse_input *, char **);
struct cmd_parse_tree *cmd_parse_from_string(const char *,
struct cmd_parse_input *, char **);
struct cmd_parse_tree *cmd_parse_from_node(struct cmd_parse_node *);
struct cmd_parse_tree *cmd_parse_add_ref(struct cmd_parse_tree *);
void cmd_parse_free(struct cmd_parse_tree *);
struct cmd_parse_node *cmd_parse_root(struct cmd_parse_tree *);

14
tmux.h
View File

@@ -1869,13 +1869,13 @@ enum args_type {
/* Argument value. */
struct args_value {
enum args_type type;
enum args_type type;
union {
char *string;
struct cmd_list *cmdlist;
char *string;
struct cmd_parse_tree *cmd;
};
char *cached;
TAILQ_ENTRY(args_value) entry;
char *cached;
TAILQ_ENTRY(args_value) entry;
};
/* Arguments set. */
@@ -2311,7 +2311,7 @@ enum control_sub_type {
/* Key binding and key table. */
struct key_binding {
key_code key;
struct cmd_list *cmdlist;
struct cmd_parse_tree *cmd;
const char *note;
const char *tablename;
@@ -3061,7 +3061,7 @@ struct key_binding *key_bindings_get_default(struct key_table *, key_code);
struct key_binding *key_bindings_first(struct key_table *);
struct key_binding *key_bindings_next(struct key_table *, struct key_binding *);
void key_bindings_add(const char *, key_code, const char *, int,
struct cmd_list *);
struct cmd_parse_tree *);
void key_bindings_remove(const char *, key_code);
void key_bindings_reset(const char *, key_code);
void key_bindings_remove_table(const char *);

View File

@@ -490,7 +490,7 @@ window_customize_build_keys(struct window_customize_modedata *data,
expanded, NULL, 0);
free(expanded);
tmp = cmd_list_print(bd->cmdlist, 0);
tmp = cmd_parse_print(bd->cmd); /* XXX: command parser conversion */
xasprintf(&text, "#[ignore]%s", tmp);
free(tmp);
mti = mode_tree_add(data->data, child, item,
@@ -625,7 +625,7 @@ window_customize_draw_key(__unused struct window_customize_modedata *data,
if (s->cy >= cy + sy - 1)
return;
cmd = cmd_list_print(bd->cmdlist, 0);
cmd = cmd_parse_print(bd->cmd); /* XXX: command parser conversion */
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
&grid_default_cell, "Command: %s", cmd)) {
free(cmd);
@@ -633,7 +633,7 @@ window_customize_draw_key(__unused struct window_customize_modedata *data,
}
default_bd = key_bindings_get_default(kt, bd->key);
if (default_bd != NULL) {
default_cmd = cmd_list_print(default_bd->cmdlist, 0);
default_cmd = cmd_parse_print(default_bd->cmd); /* XXX */
if (strcmp(cmd, default_cmd) != 0 &&
!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
&grid_default_cell, "The default is: %s", default_cmd)) {
@@ -1298,7 +1298,7 @@ window_customize_set_key(struct client *c,
bd->flags ^= KEY_BINDING_REPEAT;
else if (strcmp(s, "Command") == 0) {
xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0));
value = cmd_list_print(bd->cmdlist, 0);
value = cmd_parse_print(bd->cmd); /* XXX: command parser conversion */
new_item = xcalloc(1, sizeof *new_item);
new_item->data = data;
@@ -1360,7 +1360,7 @@ window_customize_reset_key(struct window_customize_modedata *data,
return;
dd = key_bindings_get_default(kt, bd->key);
if (dd != NULL && bd->cmdlist == dd->cmdlist)
if (dd != NULL && bd->cmd == dd->cmd) /* XXX: command parser conversion */
return;
if (dd == NULL && item == mode_tree_get_current(data->data)) {
mode_tree_collapse_current(data->data);