summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd-if-shell.c1
-rw-r--r--cmd-queue.c56
-rw-r--r--cmd-source-file.c1
-rw-r--r--format.c5
-rw-r--r--tmux.133
5 files changed, 86 insertions, 10 deletions
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 3e2a5251..2f47a0d7 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -157,6 +157,7 @@ cmd_if_shell_callback(struct job *job)
}
cmdq1 = cmdq_new(cmdq->client);
+ cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;
diff --git a/cmd-queue.c b/cmd-queue.c
index 1c80c59d..c35d0c62 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -186,6 +186,9 @@ static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd *cmd = cmdq->cmd;
+ const char *name = cmd->entry->name;
+ struct session *s;
+ struct hooks *hooks;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
@@ -197,19 +200,51 @@ cmdq_continue_one(struct cmd_q *cmdq)
cmdq->time = time(NULL);
cmdq->number++;
- cmdq_guard(cmdq, "begin", flags);
+ if (~cmdq->flags & CMD_Q_REENTRY)
+ cmdq_guard(cmdq, "begin", flags);
- if (cmd_prepare_state(cmd, cmdq, NULL) != 0)
+ if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
+
+ if (~cmdq->flags & CMD_Q_NOHOOKS) {
+ s = NULL;
+ if (cmdq->state.tflag.s != NULL)
+ s = cmdq->state.tflag.s;
+ else if (cmdq->state.sflag.s != NULL)
+ s = cmdq->state.sflag.s;
+ else if (cmdq->state.c != NULL)
+ s = cmdq->state.c->session;
+ if (s != NULL)
+ hooks = s->hooks;
+ else
+ hooks = global_hooks;
+
+ if (~cmdq->flags & CMD_Q_REENTRY) {
+ cmdq->flags |= CMD_Q_REENTRY;
+ if (hooks_wait(hooks, cmdq, NULL,
+ "before-%s", name) == 0)
+ return (CMD_RETURN_WAIT);
+ if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
+ goto error;
+ }
+ } else
+ hooks = NULL;
+ cmdq->flags &= ~CMD_Q_REENTRY;
+
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
+ if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
+ "after-%s", name) == 0)
+ retval = CMD_RETURN_WAIT;
cmdq_guard(cmdq, "end", flags);
+
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
+ cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR);
}
@@ -232,11 +267,18 @@ cmdq_continue(struct cmd_q *cmdq)
if (empty)
goto empty;
- if (cmdq->item == NULL) {
- cmdq->item = TAILQ_FIRST(&cmdq->queue);
- cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
- } else
- cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
+ /*
+ * If the command isn't in the middle of running hooks (due to
+ * CMD_RETURN_WAIT), move onto the next command; otherwise, leave the
+ * state of the queue as it is.
+ */
+ if (~cmdq->flags & CMD_Q_REENTRY) {
+ if (cmdq->item == NULL) {
+ cmdq->item = TAILQ_FIRST(&cmdq->queue);
+ cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
+ } else
+ cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
+ }
do {
while (cmdq->cmd != NULL) {
diff --git a/cmd-source-file.c b/cmd-source-file.c
index 9d2d6d68..d5f5209a 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -49,6 +49,7 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
char *cause;
cmdq1 = cmdq_new(cmdq->client);
+ cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq;
diff --git a/format.c b/format.c
index 78c177cd..d2b75b9b 100644
--- a/format.c
+++ b/format.c
@@ -468,6 +468,7 @@ struct format_tree *
format_create(struct cmd_q *cmdq, int flags)
{
struct format_tree *ft;
+ struct cmd *cmd;
if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL);
@@ -486,6 +487,10 @@ format_create(struct cmd_q *cmdq, int flags)
if (cmdq != NULL && cmdq->cmd != NULL)
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name);
+ if (cmdq != NULL && cmdq->parent != NULL) {
+ cmd = cmdq->parent->cmd;
+ format_add(ft, "command_hooked", "%s", cmd->entry->name);
+ }
return (ft);
}
diff --git a/tmux.1 b/tmux.1
index d2bfe32b..0aeefc32 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3221,9 +3221,35 @@ shows only the option value, not the name.
.Nm
allows commands to run on various triggers, called
.Em hooks .
-Each hook has a
-.Em name .
-The following hooks are available:
+Each
+.Nm
+command has a
+.Em before
+hook and an
+.Em after
+hook and there are a number of hooks not associated with commands.
+.Pp
+A command's before hook is run before the command is executed and its after
+hook is run afterwards, except when the command is run as part of a hook
+itself.
+Before hooks are named using the
+.Ql before-
+prefix and after hooks the
+.Ql after-
+prefix.
+For example, the following command adds a hook to select the even-vertical
+layout after every
+.Ic split-window :
+.Bd -literal -offset indent
+set-hook after-split-window "selectl even-vertical"
+.Ed
+.Pp
+Or to write when each new window is created to a file:
+.Bd -literal -offset indent
+set-hook before-new-window 'run "date >>/tmp/log"'
+.Ed
+.Pp
+In addition, the following hooks are available:
.Bl -tag -width "XXXXXXXXXXXXXXXX"
.It alert-activity
Run when a window has activity.
@@ -3450,6 +3476,7 @@ The following variables are available, where appropriate:
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
.It Li "client_width" Ta "" Ta "Width of client"
+.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any"
.It Li "command_name" Ta "" Ta "Name of command in use, if any"
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"