diff --git a/config.c b/config.c index d77b50b8..2c18c27e 100644 --- a/config.c +++ b/config.c @@ -108,6 +108,7 @@ static const char *const binding_action_map[] = { [BIND_ACTION_MINIMIZE] = "minimize", [BIND_ACTION_MAXIMIZE] = "maximize", [BIND_ACTION_FULLSCREEN] = "fullscreen", + [BIND_ACTION_EXEC] = "exec", [BIND_ACTION_PIPE_SCROLLBACK] = "pipe-scrollback", [BIND_ACTION_PIPE_VIEW] = "pipe-visible", [BIND_ACTION_PIPE_SELECTED] = "pipe-selected", diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 07a3cb94..d41657fa 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -812,6 +812,20 @@ e.g. *search-start=none*. Default: _not bound_ +*exec* + Executes a slave process bound to the same tty as the main + session process. The syntax is similar to *pipe-visible* and + similar bindings. + + Note that the process is controlling the tty at the same time + as the currently running process and it can mess up completely + the terminal state. Be careful of what you configure. + + Example: + *exec=[clear] Control+Shift+l* + + Default: _not bound_ + *show-urls-launch* Enter URL mode, where all currently visible URLs are tagged with a jump label with a key sequence that will open the URL (and exit diff --git a/input.c b/input.c index 0a3773bc..79f9f927 100644 --- a/input.c +++ b/input.c @@ -42,6 +42,7 @@ #include "vt.h" #include "xmalloc.h" #include "xsnprintf.h" +#include "slave.h" struct pipe_context { char *text; @@ -204,6 +205,22 @@ execute_binding(struct seat *seat, struct terminal *term, xdg_toplevel_set_fullscreen(term->window->xdg_toplevel, NULL); return true; + case BIND_ACTION_EXEC: + if (binding->aux->type != BINDING_AUX_PIPE) + return true; + + int argc = 0; + while(binding->aux->pipe.args[argc]) argc++; + + if (slave_spawn( + term->ptmx, argc, term->cwd, binding->aux->pipe.args, NULL, + &term->conf->env_vars, term->conf->term, NULL, false, false, NULL) == -1) { + LOG_ERRNO("failed to spawn slave for exec action"); + return true; + } + + return true; + case BIND_ACTION_PIPE_SCROLLBACK: if (term->grid == &term->alt) break; diff --git a/key-binding.h b/key-binding.h index f607644f..6e0a4883 100644 --- a/key-binding.h +++ b/key-binding.h @@ -29,6 +29,7 @@ enum bind_action_normal { BIND_ACTION_MINIMIZE, BIND_ACTION_MAXIMIZE, BIND_ACTION_FULLSCREEN, + BIND_ACTION_EXEC, BIND_ACTION_PIPE_SCROLLBACK, BIND_ACTION_PIPE_VIEW, BIND_ACTION_PIPE_SELECTED, diff --git a/slave.c b/slave.c index d4861ad0..784e169a 100644 --- a/slave.c +++ b/slave.c @@ -205,16 +205,16 @@ emit_notifications(int fd, const user_notifications_t *notifications) static noreturn void slave_exec(int ptmx, char *argv[], char *const envp[], int err_fd, - bool login_shell, const user_notifications_t *notifications) + bool login_shell, bool init, const user_notifications_t *notifications) { int pts = -1; const char *pts_name = ptsname(ptmx); - if (grantpt(ptmx) == -1) { + if (init && grantpt(ptmx) == -1) { LOG_ERRNO("failed to grantpt()"); goto err; } - if (unlockpt(ptmx) == -1) { + if (init && unlockpt(ptmx) == -1) { LOG_ERRNO("failed to unlockpt()"); goto err; } @@ -222,7 +222,7 @@ slave_exec(int ptmx, char *argv[], char *const envp[], int err_fd, close(ptmx); ptmx = -1; - if (setsid() == -1) { + if (init && setsid() == -1) { LOG_ERRNO("failed to setsid()"); goto err; } @@ -233,7 +233,7 @@ slave_exec(int ptmx, char *argv[], char *const envp[], int err_fd, goto err; } - if (ioctl(pts, TIOCSCTTY, 0) < 0) { + if (init && ioctl(pts, TIOCSCTTY, 0) < 0) { LOG_ERRNO("failed to configure controlling terminal"); goto err; } @@ -254,7 +254,7 @@ slave_exec(int ptmx, char *argv[], char *const envp[], int err_fd, } #endif - if (tll_length(*notifications) > 0) { + if (notifications && tll_length(*notifications) > 0) { int flags = fcntl(pts, F_GETFL); if (flags < 0) goto err; @@ -307,7 +307,7 @@ pid_t slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv, char *const *envp, const env_var_list_t *extra_env_vars, const char *term_env, const char *conf_shell, bool login_shell, - const user_notifications_t *notifications) + bool init, const user_notifications_t *notifications) { int fork_pipe[2]; if (pipe2(fork_pipe, O_CLOEXEC) < 0) { @@ -393,7 +393,7 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv, setenv("SHELL", shell_argv[0], 1); slave_exec(ptmx, shell_argv, envp != NULL ? envp : environ, - fork_pipe[1], login_shell, notifications); + fork_pipe[1], login_shell, init, notifications); BUG("Unexpected return from slave_exec()"); break; diff --git a/slave.h b/slave.h index b1c08f14..2d67a622 100644 --- a/slave.h +++ b/slave.h @@ -9,5 +9,5 @@ pid_t slave_spawn( int ptmx, int argc, const char *cwd, char *const *argv, char *const *envp, const env_var_list_t *extra_env_vars, const char *term_env, - const char *conf_shell, bool login_shell, + const char *conf_shell, bool login_shell, bool init, const user_notifications_t *notifications); diff --git a/terminal.c b/terminal.c index 78ce4bc3..edb9e9f8 100644 --- a/terminal.c +++ b/terminal.c @@ -1336,7 +1336,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, /* Start the slave/client */ if ((term->slave = slave_spawn( term->ptmx, argc, term->cwd, argv, envp, &conf->env_vars, - conf->term, conf->shell, conf->login_shell, + conf->term, conf->shell, conf->login_shell, true, &conf->notifications)) == -1) { goto err;