Replace the notification system with events. Events can carry a payload of

additional payload (to reduce problems with lifetime of objects) and are
delivered to one or more event sinks. This is more powerful and reduces the
complex dependencies between control mode and hooks. Events are now used for
hooks, control mode notifications and for monitors (set-hook -B).

wait-for can now wait for an event to fire (-E flag, with -F to for filter),
with -v to print the payload, as well as listing (-l) waiting clients on an
event and forcing one to wake (-w).

A few additional hooks are also now available (pane-created, pane-resized, etc)
and some of the existing ones have additional format variables available.
This commit is contained in:
nicm
2026-07-10 13:38:45 +00:00
parent 1508bec957
commit d29aa12117
153 changed files with 2543 additions and 1787 deletions

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $OpenBSD: cmd-queue.c,v 1.120 2026/07/10 13:38:45 nicm Exp $ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -351,74 +351,53 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
/* Insert a hook. */
void
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
cmdq_insert_hook(__unused struct session *s, struct cmdq_item *item,
struct cmd_find_state *current, const char *fmt, ...)
{
struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd);
struct args_entry *ae;
struct args_value *av;
struct options *oo;
struct event_payload *ep;
va_list ap;
char *name, tmp[32], flag, *arguments;
u_int i;
const char *value;
struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
if (item->state->flags & CMDQ_STATE_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
else
oo = s->options;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
va_end(ap);
o = options_get(oo, name);
if (o == NULL) {
free(name);
return;
}
log_debug("running hook %s (parent %p)", name, item);
/*
* The hooks get a new state because they should not update the current
* target or formats for any subsequent commands.
*/
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
cmdq_add_format(new_state, "hook", "%s", name);
ep = event_payload_create();
if (current != NULL)
event_payload_set_target(ep, current);
event_payload_set_pointer(ep, "_cmdq_item", item, NULL, NULL);
arguments = args_print(args);
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
event_payload_set_string(ep, "arguments", "%s", arguments);
free(arguments);
for (i = 0; i < args_count(args); i++) {
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
cmdq_add_format(new_state, tmp, "%s", args_string(args, i));
xsnprintf(tmp, sizeof tmp, "argument_%u", i);
event_payload_set_string(ep, tmp, "%s", args_string(args, i));
}
flag = args_first(args, &ae);
while (flag != 0) {
value = args_get(args, flag);
if (value == NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "1");
} else {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "%s", value);
}
xsnprintf(tmp, sizeof tmp, "flag_%c", flag);
if (value == NULL)
event_payload_set_string(ep, tmp, "1");
else
event_payload_set_string(ep, tmp, "%s", value);
i = 0;
av = args_first_value(args, flag);
while (av != NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
cmdq_add_format(new_state, tmp, "%s", av->string);
xsnprintf(tmp, sizeof tmp, "flag_%c_%u", flag, i);
event_payload_set_string(ep, tmp, "%s", av->string);
i++;
av = args_next_value(av);
}
@@ -426,20 +405,7 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
flag = args_next(&ae);
}
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) {
new_item = cmdq_get_command(cmdlist, new_state);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
}
a = options_array_next(a);
}
cmdq_free_state(new_state);
events_fire(name, ep);
free(name);
}