Trying to do hooks generically is way too complicated and unreliable and

confusing, particularly trying to automatically figure out what target
hooks should be using. So simplify it:

- drop before hooks entirely, they don't seem to be very useful;

- commands with special requirements now fire their own after hook (for
  example, if they change session or window, or if they have -t and -s
  and need to choose which one the hook uses as current target);

- commands with no special requirements can have the CMD_AFTERHOOK flag
  added and they will use the -t state.

At the moment new-session, new-window, split-window fire their own hook,
and display-message uses the flag. The remaining commands still need to
be looked at.
pull/587/head
nicm 2016-10-13 22:48:51 +00:00
parent 7a1a01feef
commit 4289a1ebfa
13 changed files with 58 additions and 114 deletions

View File

@ -45,7 +45,7 @@ const struct cmd_entry cmd_display_message_entry = {
.cflag = CMD_CLIENT_CANFAIL, .cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE, .tflag = CMD_PANE,
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
}; };

View File

@ -165,7 +165,6 @@ cmd_if_shell_callback(struct job *job)
} }
cmdq1 = cmdq_new(cmdq->client); cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_if_shell_done; cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata; cmdq1->data = cdata;

View File

@ -156,12 +156,5 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
notify_window_layout_changed(src_w); notify_window_layout_changed(src_w);
notify_window_layout_changed(dst_w); notify_window_layout_changed(dst_w);
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->current.s = dst_s;
cmdq->current.wl = dst_wl;
cmdq->current.w = dst_w;
cmdq->current.wp = dst_wp;
cmd_find_log_state(__func__, &cmdq->current);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -80,6 +80,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
u_int sx, sy; u_int sx, sy;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent; struct environ_entry *envent;
struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) { if (self->entry == &cmd_has_session_entry) {
/* /*
@ -310,13 +311,15 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
format_free(ft); format_free(ft);
} }
cmd_find_from_session(&cmdq->current, s);
if (!detached) if (!detached)
cmdq->client_exit = 0; cmdq->client_exit = 0;
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_from_session(&fs, s);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-session") == 0)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -61,6 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
int argc, detached; int argc, detached;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent; struct environ_entry *envent;
struct cmd_find_state fs;
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) { if ((idx = winlink_shuffle_up(s, wl)) == -1) {
@ -152,10 +153,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
format_free(ft); format_free(ft);
} }
cmd_find_from_winlink(&cmdq->current, s, wl);
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-window") == 0)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -182,34 +182,16 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
item->mouse.valid = 0; item->mouse.valid = 0;
} }
/* Find hooks list. */
static struct hooks *
cmdq_get_hooks(struct cmd_q *cmdq)
{
struct session *s;
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)
return (s->hooks);
return (global_hooks);
}
/* Process one command. */ /* Process one command. */
static enum cmd_retval static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq) cmdq_continue_one(struct cmd_q *cmdq)
{ {
struct cmd *cmd = cmdq->cmd; struct cmd *cmd = cmdq->cmd;
const char *name = cmd->entry->name; enum cmd_retval retval;
struct hooks *hooks; char *tmp;
enum cmd_retval retval; int flags = !!(cmd->flags & CMD_CONTROL);
char *tmp; const char *name;
int flags = !!(cmd->flags & CMD_CONTROL); struct cmd_find_state *fsp, fs;
tmp = cmd_print(cmd); tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp); log_debug("cmdq %p: %s", cmdq, tmp);
@ -218,44 +200,35 @@ cmdq_continue_one(struct cmd_q *cmdq)
cmdq->time = time(NULL); cmdq->time = time(NULL);
cmdq->number++; cmdq->number++;
if (~cmdq->flags & CMD_Q_REENTRY) cmdq_guard(cmdq, "begin", flags);
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0) if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error; goto error;
if (~cmdq->flags & CMD_Q_NOHOOKS) {
hooks = cmdq_get_hooks(cmdq);
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); retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
goto error; goto error;
if (hooks != NULL) { if (~cmd->entry->flags & CMD_AFTERHOOK)
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0) goto end;
goto error;
hooks = cmdq_get_hooks(cmdq);
if (hooks_wait(hooks, cmdq, NULL, "after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
}
cmdq_guard(cmdq, "end", flags);
if (cmd_find_valid_state(&cmdq->state.tflag))
fsp = &cmdq->state.tflag;
else {
if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
goto end;
fsp = &fs;
}
name = cmd->entry->name;
if (hooks_wait(fsp->s->hooks, cmdq, fsp, "after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
end:
cmdq_guard(cmdq, "end", flags);
return (retval); return (retval);
error: error:
cmdq_guard(cmdq, "error", flags); cmdq_guard(cmdq, "error", flags);
cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -271,8 +244,6 @@ cmdq_continue(struct cmd_q *cmdq)
cmdq->references++; cmdq->references++;
notify_disable(); notify_disable();
cmd_find_clear_state(&cmdq->current, NULL, 0);
log_debug("continuing cmdq %p: flags %#x, client %p", cmdq, cmdq->flags, log_debug("continuing cmdq %p: flags %#x, client %p", cmdq, cmdq->flags,
c); c);
@ -280,18 +251,11 @@ cmdq_continue(struct cmd_q *cmdq)
if (empty) if (empty)
goto empty; goto empty;
/* if (cmdq->item == NULL) {
* If the command isn't in the middle of running hooks (due to cmdq->item = TAILQ_FIRST(&cmdq->queue);
* CMD_RETURN_WAIT), move onto the next command; otherwise, leave the cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
* state of the queue as it is. } else
*/ cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
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 { do {
while (cmdq->cmd != NULL) { while (cmdq->cmd != NULL) {

View File

@ -49,7 +49,6 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
int quiet; int quiet;
cmdq1 = cmdq_new(cmdq->client); cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_source_file_done; cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq; cmdq1->data = cmdq;

View File

@ -66,6 +66,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct layout_cell *lc; struct layout_cell *lc;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent; struct environ_entry *envent;
struct cmd_find_state fs;
server_unzoom_window(w); server_unzoom_window(w);
@ -178,15 +179,17 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
notify_window_layout_changed(w); notify_window_layout_changed(w);
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->current.s = s;
cmdq->current.wl = wl;
cmdq->current.w = wl->window;
cmdq->current.wp = new_wp;
cmd_find_log_state(__func__, &cmdq->current);
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_clear_state(&fs, NULL, 0);
fs.s = s;
fs.wl = wl;
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
if (hooks_wait(s->hooks, cmdq, &fs, "after-split-window") == 0)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -124,12 +124,5 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_window(src_w); server_redraw_window(src_w);
server_redraw_window(dst_w); server_redraw_window(dst_w);
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->current.s = cmdq->state.tflag.s;
cmdq->current.wl = cmdq->state.tflag.wl;
cmdq->current.w = dst_w;
cmdq->current.wp = src_wp;
cmd_find_log_state(__func__, &cmdq->current);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -84,12 +84,5 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
recalculate_sizes(); recalculate_sizes();
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->current.s = dst;
cmdq->current.wl = wl_dst;
cmdq->current.w = wl_dst->window;
cmdq->current.wp = cmdq->state.sflag.wp;
cmd_find_log_state(__func__, &cmdq->current);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -196,6 +196,9 @@ hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
va_list ap; va_list ap;
char *name; char *name;
if (cmdq->flags & CMD_Q_NOHOOKS)
return (-1);
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&name, fmt, ap); xvasprintf(&name, fmt, ap);
va_end(ap); va_end(ap);

19
tmux.1
View File

@ -3204,20 +3204,16 @@ shows only the option value, not the name.
.Nm .Nm
allows commands to run on various triggers, called allows commands to run on various triggers, called
.Em hooks . .Em hooks .
Each Most
.Nm .Nm
command has a commands have an
.Em before
hook and an
.Em after .Em after
hook and there are a number of hooks not associated with commands. hook and there are a number of hooks not associated with commands.
.Pp .Pp
A command's before hook is run before the command is executed and its after A command's after
hook is run afterwards, except when the command is run as part of a hook hook is run after it completes, except when the command is run as part of a hook
itself. itself.
Before hooks are named using the They are named with an
.Ql before-
prefix and after hooks the
.Ql after- .Ql after-
prefix. prefix.
For example, the following command adds a hook to select the even-vertical For example, the following command adds a hook to select the even-vertical
@ -3227,11 +3223,6 @@ layout after every
set-hook after-split-window "selectl even-vertical" set-hook after-split-window "selectl even-vertical"
.Ed .Ed
.Pp .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: In addition, the following hooks are available:
.Bl -tag -width "XXXXXXXXXXXXXXXX" .Bl -tag -width "XXXXXXXXXXXXXXXX"
.It alert-activity .It alert-activity

4
tmux.h
View File

@ -1339,8 +1339,7 @@ struct cmd_q {
int references; int references;
int flags; int flags;
#define CMD_Q_DEAD 0x1 #define CMD_Q_DEAD 0x1
#define CMD_Q_REENTRY 0x2 #define CMD_Q_NOHOOKS 0x2
#define CMD_Q_NOHOOKS 0x4
struct client *client; struct client *client;
int client_exit; int client_exit;
@ -1404,6 +1403,7 @@ struct cmd_entry {
#define CMD_STARTSERVER 0x1 #define CMD_STARTSERVER 0x1
#define CMD_READONLY 0x2 #define CMD_READONLY 0x2
#define CMD_AFTERHOOK 0x4
int flags; int flags;
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);