From 606bd5f8c6be326ea2e4746de5d5e007fd04eef8 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 1 Jan 2021 08:36:51 +0000 Subject: [PATCH] Add a -C flag to run-shell to use a tmux command rather than a shell command. --- cmd-run-shell.c | 85 +++++++++++++++++++++++++++++++++++++------------ tmux.1 | 23 ++++++++----- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 647f533f..b259276d 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -40,8 +40,8 @@ const struct cmd_entry cmd_run_shell_entry = { .name = "run-shell", .alias = "run", - .args = { "bd:t:", 0, 1 }, - .usage = "[-b] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]", + .args = { "bd:Ct:", 0, 1 }, + .usage = "[-bC] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]", .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, @@ -50,13 +50,16 @@ const struct cmd_entry cmd_run_shell_entry = { }; struct cmd_run_shell_data { + struct client *client; char *cmd; + int shell; char *cwd; struct cmdq_item *item; struct session *s; int wp_id; struct event timer; int flags; + struct cmd_parse_input pi; }; static void @@ -93,49 +96,69 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); struct cmd_run_shell_data *cdata; + struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; struct window_pane *wp = target->wp; const char *delay; double d; struct timeval tv; char *end; + int wait = !args_has(args, 'b'); + + if ((delay = args_get(args, 'd')) != NULL) { + d = strtod(delay, &end); + if (*end != '\0') { + cmdq_error(item, "invalid delay time: %s", delay); + return (CMD_RETURN_ERROR); + } + } else if (args->argc == 0) + return (CMD_RETURN_NORMAL); cdata = xcalloc(1, sizeof *cdata); if (args->argc != 0) cdata->cmd = format_single_from_target(item, args->argv[0]); + cdata->shell = !args_has(args, 'C'); + if (!cdata->shell) { + memset(&cdata->pi, 0, sizeof cdata->pi); + cmd_get_source(self, &cdata->pi.file, &cdata->pi.line); + if (wait) + cdata->pi.item = item; + cdata->pi.c = tc; + cmd_find_copy_state(&cdata->pi.fs, target); + } + if (args_has(args, 't') && wp != NULL) cdata->wp_id = wp->id; else cdata->wp_id = -1; - if (!args_has(args, 'b')) + if (wait) { + cdata->client = cmdq_get_client(item); cdata->item = item; - else + } else { + cdata->client = tc; cdata->flags |= JOB_NOWAIT; + } + if (cdata->client != NULL) + cdata->client->references++; cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s)); + cdata->s = s; if (s != NULL) session_add_ref(s, __func__); evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata); - - if ((delay = args_get(args, 'd')) != NULL) { - d = strtod(delay, &end); - if (*end != '\0') { - cmdq_error(item, "invalid delay time: %s", delay); - cmd_run_shell_free(cdata); - return (CMD_RETURN_ERROR); - } + if (delay != NULL) { timerclear(&tv); tv.tv_sec = (time_t)d; tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U; evtimer_add(&cdata->timer, &tv); } else - cmd_run_shell_timer(-1, 0, cdata); + event_active(&cdata->timer, EV_TIMEOUT, 1); - if (args_has(args, 'b')) + if (!wait) return (CMD_RETURN_NORMAL); return (CMD_RETURN_WAIT); } @@ -144,17 +167,37 @@ static void cmd_run_shell_timer(__unused int fd, __unused short events, void* arg) { struct cmd_run_shell_data *cdata = arg; + struct client *c = cdata->client; + const char *cmd = cdata->cmd; + char *error; + struct cmdq_item *item = cdata->item; + enum cmd_parse_status status; - if (cdata->cmd != NULL) { - if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL, + if (cmd != NULL && cdata->shell) { + if (job_run(cmd, cdata->s, cdata->cwd, NULL, cmd_run_shell_callback, cmd_run_shell_free, cdata, cdata->flags, -1, -1) == NULL) cmd_run_shell_free(cdata); - } else { - if (cdata->item != NULL) - cmdq_continue(cdata->item); - cmd_run_shell_free(cdata); + return; } + + if (cmd != NULL) { + if (item != NULL) { + status = cmd_parse_and_insert(cmd, &cdata->pi, item, + cmdq_get_state(item), &error); + } else { + status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL, + &error); + } + if (status == CMD_PARSE_ERROR) { + cmdq_error(cdata->item, "%s", error); + free(error); + } + } + + if (cdata->item != NULL) + cmdq_continue(cdata->item); + cmd_run_shell_free(cdata); } static void @@ -215,6 +258,8 @@ cmd_run_shell_free(void *data) evtimer_del(&cdata->timer); if (cdata->s != NULL) session_remove_ref(cdata->s, __func__); + if (cdata->client != NULL) + server_client_unref(cdata->client); free(cdata->cwd); free(cdata->cmd); free(cdata); diff --git a/tmux.1 b/tmux.1 index 344f3b72..1376df95 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5827,7 +5827,7 @@ Lock each client individually by running the command specified by the .Ic lock-command option. .It Xo Ic run-shell -.Op Fl b +.Op Fl bC .Op Fl d Ar delay .Op Fl t Ar target-pane .Op Ar shell-command @@ -5835,9 +5835,14 @@ option. .D1 (alias: Ic run ) Execute .Ar shell-command -in the background without creating a window. -Before being executed, shell-command is expanded using the rules specified in -the +or (with +.Fl C ) +a +.Nm +command in the background without creating a window. +Before being executed, +.Ar shell-command +is expanded using the rules specified in the .Sx FORMATS section. With @@ -5847,11 +5852,13 @@ the command is run in the background. waits for .Ar delay seconds before starting the command. -After the command finishes, any output to stdout is displayed in view mode (in -the pane specified by +If +.Fl C +is not given, any output to stdout is displayed in view mode (in the pane +specified by .Fl t -or the current pane if omitted). -If the command doesn't return success, the exit status is also displayed. +or the current pane if omitted) after the command finishes. +If the command fails, the exit status is also displayed. .It Xo Ic wait-for .Op Fl L | S | U .Ar channel