mirror of
https://github.com/tmux/tmux.git
synced 2025-01-07 16:28:48 +00:00
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.
This commit is contained in:
parent
7a1a01feef
commit
4289a1ebfa
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
90
cmd-queue.c
90
cmd-queue.c
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
3
hooks.c
3
hooks.c
@ -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
19
tmux.1
@ -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
4
tmux.h
@ -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 *);
|
||||||
|
Loading…
Reference in New Issue
Block a user