From b48e2ea8e900bb3961cb93b7f6588f4200d9adee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 30 Jun 2026 11:19:52 +0100 Subject: [PATCH] Handle key binding. --- arguments.c | 18 +++++++++++------- cmd-bind-key.c | 17 +++++++++-------- cmd-invoke.c | 18 ++++-------------- cmd-list-keys.c | 3 +-- cmd-parse.y | 38 ++++++++++++++++++++++++++++++++++++++ key-bindings.c | 45 +++++++++++++++++++++++++-------------------- tmux-parser.h | 1 + tmux.h | 14 +++++++------- window-customize.c | 10 +++++----- 9 files changed, 101 insertions(+), 63 deletions(-) diff --git a/arguments.c b/arguments.c index b61ddd9bf..52cdeea9c 100644 --- a/arguments.c +++ b/arguments.c @@ -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 { diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 8eba7005c..9c1c40db4 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -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); } diff --git a/cmd-invoke.c b/cmd-invoke.c index 146f3d4d2..3538d63ae 100644 --- a/cmd-invoke.c +++ b/cmd-invoke.c @@ -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); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index abb51b2c8..670e992a6 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -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); } diff --git a/cmd-parse.y b/cmd-parse.y index b42fd3cc6..6de541bff 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -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) { diff --git a/key-bindings.c b/key-bindings.c index fb2c5681f..4a0e90735 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -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) diff --git a/tmux-parser.h b/tmux-parser.h index 8ea783da6..361382b31 100644 --- a/tmux-parser.h +++ b/tmux-parser.h @@ -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 *); diff --git a/tmux.h b/tmux.h index 30d726a0a..1fbddd7c5 100644 --- a/tmux.h +++ b/tmux.h @@ -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 *); diff --git a/window-customize.c b/window-customize.c index 5d89de224..66f42bd88 100644 --- a/window-customize.c +++ b/window-customize.c @@ -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);