diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 9c1c40db4..426c20672 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -88,26 +88,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } -#if 0 /* XXX: command parser conversion */ - struct cmd_parse_result *pr; - - if (count == 2) - pr = cmd_parse_from_string(args_string(args, 1), NULL); - else { - pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1, - NULL); - } - switch (pr->status) { - case CMD_PARSE_ERROR: - cmdq_error(item, "%s", pr->error); - free(pr->error); - return (CMD_RETURN_ERROR); - case CMD_PARSE_SUCCESS: - break; - } - key_bindings_add(tablename, key, note, repeat, pr->cmdlist); + cmd = cmd_parse_from_arguments(args_values(args) + 1, count - 1); + key_bindings_add(tablename, key, note, repeat, cmd); return (CMD_RETURN_NORMAL); -#else - fatalx("XXX: command parser conversion not done for bind-key"); -#endif } diff --git a/cmd-invoke.c b/cmd-invoke.c index 3538d63ae..5a6131d6c 100644 --- a/cmd-invoke.c +++ b/cmd-invoke.c @@ -252,12 +252,22 @@ cmd_invoke_is_true(struct cmdq_item *item, return (0); } -/* Push the selected conditional branch onto the traversal stack. */ -static void -cmd_invoke_push_branch(struct cmd_invoke_state *is, - struct cmd_parse_node *node, struct cmd_parse_node *first) +/* Skip else branches. */ +static struct cmd_parse_node * +cmd_invoke_if_branch_end(struct cmd_parse_node *first) { - cmd_invoke_push(is, node, first, NULL); + struct cmd_parse_node *node; + + for (node = first; node != NULL; node = cmd_parse_node_next(node)) { + switch (cmd_parse_node_type(node)) { + case CMD_PARSE_ELIF: + case CMD_PARSE_ELSE: + return (node); + default: + break; + } + } + return (NULL); } /* Select and queue the branch for a conditional node. */ @@ -275,7 +285,8 @@ cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is, if (cmd_invoke_is_true(item, is, next, &r) != 0) return (-1); if (r) { - cmd_invoke_push_branch(is, node, first); + next = cmd_invoke_if_branch_end(first); + cmd_invoke_push(is, node, first, next); return (0); } @@ -289,13 +300,13 @@ cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is, return (-1); if (r) { next = cmd_parse_node_next(next); - cmd_invoke_push_branch(is, child, next); + cmd_invoke_push(is, child, next, NULL); return (0); } break; case CMD_PARSE_ELSE: next = cmd_parse_node_first_child(child); - cmd_invoke_push_branch(is, child, next); + cmd_invoke_push(is, child, next, NULL); return (0); default: break; diff --git a/cmd-parse.y b/cmd-parse.y index 6de541bff..7f64ff70a 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -697,13 +697,13 @@ struct cmd_parse_tree * cmd_parse_from_node(struct cmd_parse_node *node) { struct cmd_parse_tree *new; - struct cmd_parse_node *root, *child; + struct cmd_parse_node *root, *child, *copy; 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); + copy = cmd_parse_copy_node(child); + TAILQ_INSERT_TAIL(&root->children, copy, entry); } new = xcalloc(1, sizeof *new); @@ -712,6 +712,73 @@ cmd_parse_from_node(struct cmd_parse_node *node) return (new); } +/* Build a string node with a single literal text child. */ +static struct cmd_parse_node * +cmd_parse_new_string_node(const char *s, u_int line) +{ + struct cmd_parse_node *string, *text; + + string = cmd_parse_new_node(CMD_PARSE_STRING, line); + if (*s != '\0') { + text = cmd_parse_new_node(CMD_PARSE_TEXT, line); + text->value = xstrdup(s); + TAILQ_INSERT_TAIL(&string->children, text, entry); + } + return (string); +} + +/* Build a commands node from a copy of the children of a tree's root. */ +static struct cmd_parse_node * +cmd_parse_new_commands_node(struct cmd_parse_tree *tree, u_int line) +{ + struct cmd_parse_node *commands, *root, *child, *copy; + + commands = cmd_parse_new_node(CMD_PARSE_COMMANDS, line); + + root = cmd_parse_root(tree); + TAILQ_FOREACH(child, &root->children, entry) { + copy = cmd_parse_copy_node(child); + TAILQ_INSERT_TAIL(&commands->children, copy, entry); + } + + return (commands); +} + +/* Build a parse tree directly from existing argument values. */ +struct cmd_parse_tree * +cmd_parse_from_arguments(struct args_value *values, u_int count) +{ + struct cmd_parse_tree *new; + struct cmd_parse_node *root, *seq, *cmd, *child; + u_int i; + + cmd = cmd_parse_new_node(CMD_PARSE_COMMAND, 0); + for (i = 0; i < count; i++) { + switch (values[i].type) { + case ARGS_NONE: + continue; + case ARGS_STRING: + child = cmd_parse_new_string_node(values[i].string, 0); + break; + case ARGS_COMMANDS: + child = cmd_parse_new_commands_node(values[i].cmd, 0); + break; + } + TAILQ_INSERT_TAIL(&cmd->children, child, entry); + } + + seq = cmd_parse_new_node(CMD_PARSE_SEQUENCE, 0); + TAILQ_INSERT_TAIL(&seq->children, cmd, entry); + + root = cmd_parse_new_node(CMD_PARSE_ROOT, 0); + TAILQ_INSERT_TAIL(&root->children, seq, 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 4a0e90735..5ccc8e20c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -192,7 +192,8 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat, { struct key_table *table = key_bindings_get_table(name, 1); struct key_binding *bd; - char *k, *s; + const char *k; + char *s; bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS); if (cmd == NULL) { @@ -670,23 +671,21 @@ key_bindings_init(void) "bind -Tcopy-mode-vi C-Down { send -X scroll-down }", }; -#if 0 /* XXX: command parser conversion */ u_int i; - struct cmd_parse_result *pr; + struct cmd_parse_tree *tree; + struct cmdq_item *new_item; + struct cmd_invoke_input ci = { 0 }; + char *cause = NULL; for (i = 0; i < nitems(defaults); i++) { - pr = cmd_parse_from_string(defaults[i], NULL); - if (pr->status != CMD_PARSE_SUCCESS) { - log_debug("%s", pr->error); + tree = cmd_parse_from_string(defaults[i], NULL, &cause); + if (tree == NULL) fatalx("bad default key: %s", defaults[i]); - } - cmdq_append(NULL, cmdq_get_command(pr->cmdlist, NULL)); - cmd_list_free(pr->cmdlist); + + new_item = cmd_invoke_get(tree, NULL, &ci); + cmdq_append(NULL, new_item); + cmd_parse_free(tree); } -#else - log_debug("XXX: command parser conversion not done for %u default keys", - (u_int)nitems(defaults)); -#endif cmdq_append(NULL, cmdq_get_callback(key_bindings_init_done, NULL)); } diff --git a/parser-test/test-configs/bind-key-body-verify.tmux b/parser-test/test-configs/bind-key-body-verify.tmux new file mode 100644 index 000000000..da2b458ce --- /dev/null +++ b/parser-test/test-configs/bind-key-body-verify.tmux @@ -0,0 +1,9 @@ +set -g status off +bind-key F1 { + display-message "parser bind body: F1" + run-shell "echo F1-FIRED >> /tmp/claude-1000/-home-nicholas-tmux-claude/9fb594c3-5fb9-41b2-8a5a-8d3d0b39b009/scratchpad/bindresult.txt" +} +bind-key F2 { + run-shell "echo F2-FIRST >> /tmp/claude-1000/-home-nicholas-tmux-claude/9fb594c3-5fb9-41b2-8a5a-8d3d0b39b009/scratchpad/bindresult.txt" + run-shell "echo F2-SECOND >> /tmp/claude-1000/-home-nicholas-tmux-claude/9fb594c3-5fb9-41b2-8a5a-8d3d0b39b009/scratchpad/bindresult.txt" +} diff --git a/parser-test/test-configs/bind-key-body.tmux b/parser-test/test-configs/bind-key-body.tmux new file mode 100644 index 000000000..038f4b640 --- /dev/null +++ b/parser-test/test-configs/bind-key-body.tmux @@ -0,0 +1,5 @@ +bind-key F1 { display-message "parser bind body: F1" } +bind-key F2 { + display-message "parser bind body: first" + display-message "parser bind body: second" +} diff --git a/tmux-parser.h b/tmux-parser.h index 361382b31..df363f553 100644 --- a/tmux-parser.h +++ b/tmux-parser.h @@ -38,6 +38,7 @@ struct cmd_parse_tree; struct cmd_parse_node; +struct args_value; struct cmd_parse_input { int flags; @@ -78,6 +79,7 @@ struct cmd_parse_tree *cmd_parse_from_buffer(const void *, size_t, 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_from_arguments(struct args_value *, u_int); 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 *);