From fcfa0b6db481b48e707dd817f6fba9884e7c98ef Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 30 Jun 2026 10:03:49 +0100 Subject: [PATCH] Allow simple commands to be fired. --- cfg.c | 12 +++++-- cmd-invoke.c | 33 ++++++++++--------- .../command-body-unsupported.tmux | 3 ++ parser-test/test-configs/env-tilde.tmux | 2 ++ .../test-configs/failure-sequence.tmux | 5 +++ parser-test/test-configs/if-else-elif.tmux | 10 ++++++ parser-test/test-configs/if-true.tmux | 8 +++++ parser-test/test-configs/inline-if.tmux | 3 ++ parser-test/test-configs/semicolon.tmux | 3 ++ parser-test/test-configs/simple.tmux | 5 +++ tmux.h | 11 ++++++- 11 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 parser-test/test-configs/command-body-unsupported.tmux create mode 100644 parser-test/test-configs/env-tilde.tmux create mode 100644 parser-test/test-configs/failure-sequence.tmux create mode 100644 parser-test/test-configs/if-else-elif.tmux create mode 100644 parser-test/test-configs/if-true.tmux create mode 100644 parser-test/test-configs/inline-if.tmux create mode 100644 parser-test/test-configs/semicolon.tmux create mode 100644 parser-test/test-configs/simple.tmux diff --git a/cfg.c b/cfg.c index eb448f1b4..8e8b7d79d 100644 --- a/cfg.c +++ b/cfg.c @@ -98,6 +98,7 @@ load_cfg(const char *path, struct cmdq_item *item, { FILE *f; struct cmd_parse_input pi; + struct cmd_invoke_input ci; struct cmd_parse_tree *tree; struct cmdq_item *new_item0; struct cmdq_state *state; @@ -137,7 +138,10 @@ load_cfg(const char *path, struct cmdq_item *item, state = cmdq_new_state(NULL, NULL, 0); cmdq_add_format(state, "current_file", "%s", pi.file); - new_item0 = cmd_invoke_get(tree, state, 0, NULL); + memset(&ci, 0, sizeof ci); + ci.file = pi.file; + ci.flags = flags; + new_item0 = cmd_invoke_get(tree, state, &ci); if (item != NULL) new_item0 = cmdq_insert_after(item, new_item0); else @@ -156,6 +160,7 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path, struct cmdq_item **new_item) { struct cmd_parse_input pi; + struct cmd_invoke_input ci; struct cmd_parse_tree *tree; struct cmdq_item *new_item0; struct cmdq_state *state; @@ -188,7 +193,10 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path, state = cmdq_new_state(NULL, NULL, 0); cmdq_add_format(state, "current_file", "%s", pi.file); - new_item0 = cmd_invoke_get(tree, state, 0, NULL); + memset(&ci, 0, sizeof ci); + ci.file = pi.file; + ci.flags = flags; + new_item0 = cmd_invoke_get(tree, state, &ci); if (item != NULL) new_item0 = cmdq_insert_after(item, new_item0); else diff --git a/cmd-invoke.c b/cmd-invoke.c index dbc6873f2..a7f81f9ab 100644 --- a/cmd-invoke.c +++ b/cmd-invoke.c @@ -366,8 +366,8 @@ fail: /* Create the first invoke queue item for a parsed tree. */ struct cmdq_item * -cmd_invoke_get(struct cmd_parse_tree *tree, struct cmdq_state *state, int argc, - char **argv) +cmd_invoke_get(struct cmd_parse_tree *tree, struct cmdq_state *state, + const struct cmd_invoke_input *input) { struct cmd_invoke_state *is; struct cmd_parse_node *root = cmd_parse_root(tree), *first; @@ -377,14 +377,16 @@ cmd_invoke_get(struct cmd_parse_tree *tree, struct cmdq_state *state, int argc, is = xcalloc(1, sizeof *is); is->references = 1; is->tree = cmd_parse_add_ref(tree); - log_debug("%s: tree %p", __func__, tree); - cmd_parse_log(__func__, tree); - is->argc = argc; - if (argc != 0) { - is->argv = xreallocarray(NULL, argc, sizeof *is->argv); - for (i = 0; i < argc; i++) - is->argv[i] = xstrdup(argv[i]); + if (input->file != NULL) + is->file = xstrdup(input->file); + is->parse_flags = input->flags; + + is->argc = input->argc; + if (input->argc != 0) { + is->argv = xreallocarray(NULL, input->argc, sizeof *is->argv); + for (i = 0; i < input->argc; i++) + is->argv[i] = xstrdup(input->argv[i]); } first = cmd_parse_node_first_child(root); @@ -472,13 +474,12 @@ cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is) } break; case CMD_PARSE_ELIF: - case CMD_PARSE_ELSE: - break; - case CMD_PARSE_COMMAND: - fatalx("XXX: command execution not implemented yet"); - cmd = cmd_invoke_build_command(item, is, node); - if (cmd == NULL) { - cmd_invoke_skip_sequence(is); + case CMD_PARSE_ELSE: + break; + case CMD_PARSE_COMMAND: + cmd = cmd_invoke_build_command(item, is, node); + if (cmd == NULL) { + cmd_invoke_skip_sequence(is); break; } diff --git a/parser-test/test-configs/command-body-unsupported.tmux b/parser-test/test-configs/command-body-unsupported.tmux new file mode 100644 index 000000000..7a89a0200 --- /dev/null +++ b/parser-test/test-configs/command-body-unsupported.tmux @@ -0,0 +1,3 @@ +# Command body unsupported checkpoint. +# Expected at this stage: should parse, then fatal/XXX when invocation reaches ARGS_COMMANDS. +bind-key F1 { display-message "parser command body" } diff --git a/parser-test/test-configs/env-tilde.tmux b/parser-test/test-configs/env-tilde.tmux new file mode 100644 index 000000000..61e36148d --- /dev/null +++ b/parser-test/test-configs/env-tilde.tmux @@ -0,0 +1,2 @@ +display-message "HOME=$HOME" +display-message ~ diff --git a/parser-test/test-configs/failure-sequence.tmux b/parser-test/test-configs/failure-sequence.tmux new file mode 100644 index 000000000..60138e88d --- /dev/null +++ b/parser-test/test-configs/failure-sequence.tmux @@ -0,0 +1,5 @@ +# Failure scope test. +# Expected with sequence skipping: bad command fails, following command in same sequence is skipped, +# then next top-level sequence still runs. +display-message "parser failure: before bad command" ; no-such-tmux-command ; display-message "parser failure: should be skipped" +display-message "parser failure: next sequence should still run" diff --git a/parser-test/test-configs/if-else-elif.tmux b/parser-test/test-configs/if-else-elif.tmux new file mode 100644 index 000000000..4af18cbfd --- /dev/null +++ b/parser-test/test-configs/if-else-elif.tmux @@ -0,0 +1,10 @@ +# %if/%elif/%else. +# Expected: elif branch is selected. +%if 0 +display-message "parser elif: selected if branch - wrong" +%elif 1 +display-message "parser elif: selected elif branch" +%else +display-message "parser elif: selected else branch - wrong" +%endif +display-message "parser elif: after endif" diff --git a/parser-test/test-configs/if-true.tmux b/parser-test/test-configs/if-true.tmux new file mode 100644 index 000000000..a714cc45c --- /dev/null +++ b/parser-test/test-configs/if-true.tmux @@ -0,0 +1,8 @@ +# %if true branch. +# Expected: first branch is selected. +%if 1 +display-message "parser if true: selected if branch" +%else +display-message "parser if true: selected else branch - wrong" +%endif +display-message "parser if true: after endif" diff --git a/parser-test/test-configs/inline-if.tmux b/parser-test/test-configs/inline-if.tmux new file mode 100644 index 000000000..61d3aecae --- /dev/null +++ b/parser-test/test-configs/inline-if.tmux @@ -0,0 +1,3 @@ +# Inline %if form. +# Expected: inline true branch selected, then following command in same sequence is processed. +display-message "parser inline if: before" ; %if 1 display-message "parser inline if: branch" %endif ; display-message "parser inline if: after" diff --git a/parser-test/test-configs/semicolon.tmux b/parser-test/test-configs/semicolon.tmux new file mode 100644 index 000000000..faf198996 --- /dev/null +++ b/parser-test/test-configs/semicolon.tmux @@ -0,0 +1,3 @@ +# Semicolon sequence. +# Expected: one top-level sequence containing three commands. +set -g status on ; set -g message-style fg=yellow ; display-message "parser semicolon sequence" diff --git a/parser-test/test-configs/simple.tmux b/parser-test/test-configs/simple.tmux new file mode 100644 index 000000000..fce14a2ca --- /dev/null +++ b/parser-test/test-configs/simple.tmux @@ -0,0 +1,5 @@ +# Simple straight-line commands. +# Expected: all commands parse and run in order. +set -g status off +set -g message-style fg=green +display-message "parser simple: status=#{status}" diff --git a/tmux.h b/tmux.h index 98d08eac1..30d726a0a 100644 --- a/tmux.h +++ b/tmux.h @@ -1977,6 +1977,15 @@ struct cmd_entry { enum cmd_retval (*exec)(struct cmd *, struct cmdq_item *); }; +/* Command invocation input. */ +struct cmd_invoke_input { + const char *file; + int flags; + + int argc; + char **argv; +}; + /* Status line. */ #define STATUS_LINES_LIMIT 5 struct status_line { @@ -2988,7 +2997,7 @@ enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int, /* cmd-invoke.c */ struct cmdq_item *cmd_invoke_get(struct cmd_parse_tree *, struct cmdq_state *, - int, char **); + const struct cmd_invoke_input *); struct cmd_invoke_state *cmd_invoke_state_add_ref(struct cmd_invoke_state *); void cmd_invoke_state_free(struct cmd_invoke_state *); void cmd_invoke_result(struct cmd_invoke_state *, enum cmd_retval);