mirror of
https://github.com/tmux/tmux.git
synced 2026-08-03 14:08:59 +00:00
Add wait-for -F and -v for events.
This commit is contained in:
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_wait_for_entry = {
|
||||
.name = "wait-for",
|
||||
.alias = "wait",
|
||||
|
||||
.args = { "ELSU", 1, 1, NULL },
|
||||
.usage = "[-E|-L|-S|-U] channel",
|
||||
.args = { "EF:LSUv", 1, 1, NULL },
|
||||
.usage = "[-ELSUv] [-F format] channel",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_wait_for_exec
|
||||
@@ -49,6 +49,8 @@ struct wait_item {
|
||||
struct wait_event_item {
|
||||
struct cmdq_item *item;
|
||||
struct events_sink *sink;
|
||||
char *filter;
|
||||
int verbose;
|
||||
TAILQ_ENTRY(wait_event_item) entry;
|
||||
};
|
||||
static TAILQ_HEAD(, wait_event_item) wait_event_items =
|
||||
@@ -84,7 +86,8 @@ static enum cmd_retval cmd_wait_for_lock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *,
|
||||
struct args *);
|
||||
static void cmd_wait_for_event_cb(const char *,
|
||||
struct event_payload *, void *);
|
||||
|
||||
@@ -131,23 +134,14 @@ cmd_wait_for_remove(struct wait_channel *wc)
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *name = args_string(args, 0);
|
||||
struct wait_channel *wc, find;
|
||||
|
||||
if (args_has(args, 'E') &&
|
||||
(args_has(args, 'L') || args_has(args, 'S') ||
|
||||
args_has(args, 'U'))) {
|
||||
cmdq_error(item, "-E cannot be used with -L, -S or -U");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
struct wait_channel *wc, find = { .name = name };
|
||||
|
||||
if (args_has(args, 'E'))
|
||||
return (cmd_wait_for_event(item, name));
|
||||
return (cmd_wait_for_event(item, name, args));
|
||||
|
||||
find.name = name;
|
||||
wc = RB_FIND(wait_channels, &wait_channels, &find);
|
||||
|
||||
if (args_has(args, 'S'))
|
||||
return (cmd_wait_for_signal(item, name, wc));
|
||||
if (args_has(args, 'L'))
|
||||
@@ -158,21 +152,61 @@ cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, void *item_data)
|
||||
cmd_wait_for_event_print(struct wait_event_item *wei, struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
const char *key;
|
||||
char *value;
|
||||
|
||||
epi = event_payload_first(ep);
|
||||
while (epi != NULL) {
|
||||
key = event_payload_item_name(epi);
|
||||
if (*key != '_') {
|
||||
value = event_payload_item_print(epi);
|
||||
cmdq_print(wei->item, "%s=%s", key, value);
|
||||
free(value);
|
||||
}
|
||||
epi = event_payload_next(epi);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(const char *name, struct event_payload *ep,
|
||||
void *item_data)
|
||||
{
|
||||
struct wait_event_item *wei = item_data;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (wei->verbose)
|
||||
cmd_wait_for_event_print(wei, ep);
|
||||
|
||||
if (wei->filter != NULL) {
|
||||
ft = format_create(cmdq_get_client(wei->item), wei->item,
|
||||
FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, NULL);
|
||||
expanded = format_expand(ft, wei->filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
events_remove_sink(wei->sink);
|
||||
cmdq_continue(wei->item);
|
||||
free(wei->filter);
|
||||
free(wei);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event(struct cmdq_item *item, const char *name)
|
||||
cmd_wait_for_event(struct cmdq_item *item, const char *name, struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
const char *filter = args_get(args, 'F');
|
||||
|
||||
if (cmdq_get_client(item) == NULL) {
|
||||
cmdq_error(item, "not able to wait");
|
||||
@@ -181,6 +215,8 @@ cmd_wait_for_event(struct cmdq_item *item, const char *name)
|
||||
|
||||
wei = xcalloc(1, sizeof *wei);
|
||||
wei->item = item;
|
||||
wei->filter = (filter != NULL ? xstrdup(filter) : NULL);
|
||||
wei->verbose = args_has(args, 'v');
|
||||
wei->sink = events_add_sink(name, cmd_wait_for_event_cb, wei);
|
||||
TAILQ_INSERT_TAIL(&wait_event_items, wei, entry);
|
||||
|
||||
@@ -302,6 +338,7 @@ cmd_wait_for_flush(void)
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
events_remove_sink(wei->sink);
|
||||
cmdq_continue(wei->item);
|
||||
free(wei->filter);
|
||||
free(wei);
|
||||
}
|
||||
|
||||
|
||||
@@ -480,6 +480,41 @@ event_payload_print(struct event_payload *ep, const char *name)
|
||||
return (event_payload_item_print(epi));
|
||||
}
|
||||
|
||||
/* Add payload items as formats. */
|
||||
void
|
||||
event_payload_add_formats(struct event_payload *ep, struct format_tree *ft,
|
||||
const char *prefix)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
char *name, *value;
|
||||
const char *key;
|
||||
|
||||
if (prefix == NULL)
|
||||
prefix = "";
|
||||
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
key = epi->name;
|
||||
if (*key == '_')
|
||||
continue;
|
||||
|
||||
value = event_payload_item_print(epi);
|
||||
xasprintf(&name, "%s%s", prefix, key);
|
||||
format_add(ft, name, "%s", value);
|
||||
free(name);
|
||||
free(value);
|
||||
|
||||
if (epi->type == EVENT_PAYLOAD_SESSION) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->session->name);
|
||||
free(name);
|
||||
} else if (epi->type == EVENT_PAYLOAD_WINDOW) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->window->name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_first(struct event_payload *ep)
|
||||
|
||||
2
events.c
2
events.c
@@ -96,6 +96,8 @@ events_fire(const char *name, struct event_payload *ep)
|
||||
struct events_sink *es;
|
||||
u_int generation = events_generation;
|
||||
|
||||
event_payload_set_string(ep, "event", "%s", name);
|
||||
|
||||
if (log_get_level() != 0)
|
||||
event_payload_log(ep, "%s: %s: ", __func__, name);
|
||||
|
||||
|
||||
63
hooks.c
63
hooks.c
@@ -195,66 +195,6 @@ hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
|
||||
cmdq_free_state(state);
|
||||
}
|
||||
|
||||
/* Add payload formats for a hook. */
|
||||
static void
|
||||
hooks_add_formats(struct format_tree *ft, const char *name,
|
||||
struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
char *fname, *value;
|
||||
const char *key;
|
||||
const char *svalue;
|
||||
|
||||
epi = event_payload_first(ep);
|
||||
while (epi != NULL) {
|
||||
key = event_payload_item_name(epi);
|
||||
if (*key != '_') {
|
||||
value = event_payload_item_print(epi);
|
||||
xasprintf(&fname, "hook_%s", key);
|
||||
format_add(ft, fname, "%s", value);
|
||||
free(fname);
|
||||
free(value);
|
||||
}
|
||||
epi = event_payload_next(epi);
|
||||
}
|
||||
|
||||
format_add(ft, "hook", "%s", name);
|
||||
|
||||
c = event_payload_get_client(ep, "client");
|
||||
if (c != NULL)
|
||||
format_add(ft, "hook_client", "%s", c->name);
|
||||
s = event_payload_get_session(ep, "session");
|
||||
if (s != NULL) {
|
||||
format_add(ft, "hook_session", "$%u", s->id);
|
||||
format_add(ft, "hook_session_name", "%s", s->name);
|
||||
}
|
||||
w = event_payload_get_window(ep, "window");
|
||||
if (w != NULL) {
|
||||
format_add(ft, "hook_window", "@%u", w->id);
|
||||
format_add(ft, "hook_window_name", "%s", w->name);
|
||||
}
|
||||
wp = event_payload_get_pane(ep, "pane");
|
||||
if (wp != NULL)
|
||||
format_add(ft, "hook_pane", "%%%u", wp->id);
|
||||
else {
|
||||
value = event_payload_print(ep, "pane");
|
||||
if (value != NULL) {
|
||||
format_add(ft, "hook_pane", "%s", value);
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
svalue = event_payload_get_string(ep, "value");
|
||||
if (svalue != NULL)
|
||||
format_add(ft, "hook_value", "%s", svalue);
|
||||
svalue = event_payload_get_string(ep, "last");
|
||||
if (svalue != NULL)
|
||||
format_add(ft, "hook_last", "%s", svalue);
|
||||
}
|
||||
|
||||
/* Insert commands for a hook event. */
|
||||
static void
|
||||
hooks_insert_event(struct cmdq_item *item, const char *name,
|
||||
@@ -269,7 +209,8 @@ hooks_insert_event(struct cmdq_item *item, const char *name,
|
||||
|
||||
c = event_payload_get_client(ep, "client");
|
||||
ft = format_create(c, item, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
hooks_add_formats(ft, name, ep);
|
||||
event_payload_add_formats(ep, ft, "hook_");
|
||||
format_add(ft, "hook", "%s", name);
|
||||
format_log_debug(ft, __func__);
|
||||
|
||||
memset(&hd, 0, sizeof hd);
|
||||
|
||||
@@ -94,6 +94,34 @@ $TMUX set -g @wf_value 2 || fail "set @wf_value 2 failed"
|
||||
wait_channel wf-late
|
||||
wait "$late_pid" || fail "late wait-for -E command failed"
|
||||
|
||||
$TMUX set -g @filtered 0 || fail "set @filtered failed"
|
||||
$TMUX wait-for -E -F '#{==:#{value},3}' @wf \; set -g @filtered 1 \; \
|
||||
wait-for -S wf-filtered &
|
||||
filtered_pid=$!
|
||||
assert_unchanged @filtered 0 5
|
||||
|
||||
$TMUX set -g @wf_value unmatched || fail "set @wf_value unmatched failed"
|
||||
assert_unchanged @filtered 0 5
|
||||
|
||||
$TMUX set -g @wf_value 3 || fail "set @wf_value 3 failed"
|
||||
wait_channel wf-filtered
|
||||
wait "$filtered_pid" || fail "filtered wait-for -E command failed"
|
||||
|
||||
verbose_file="$OUT/verbose"
|
||||
$TMUX wait-for -E -v @wf \; wait-for -S wf-verbose >"$verbose_file" &
|
||||
verbose_pid=$!
|
||||
|
||||
sleep 0.5
|
||||
$TMUX set -g @wf_value 4 || fail "set @wf_value 4 failed"
|
||||
wait_channel wf-verbose
|
||||
wait "$verbose_pid" || fail "verbose wait-for -E command failed"
|
||||
grep '^event=@wf$' "$verbose_file" >/dev/null ||
|
||||
fail "verbose wait-for -E did not print event payload"
|
||||
grep '^value=4$' "$verbose_file" >/dev/null ||
|
||||
fail "verbose wait-for -E did not print value payload"
|
||||
grep '^_hook_monitor=' "$verbose_file" >/dev/null &&
|
||||
fail "verbose wait-for -E printed private payload"
|
||||
|
||||
$TMUX new -d -s wf2 || fail "new-session wf2 failed"
|
||||
|
||||
$TMUX wait-for -E window-renamed \; wait-for -S wf-renamed &
|
||||
|
||||
29
tmux.1
29
tmux.1
@@ -8553,7 +8553,8 @@ or the current pane if omitted) after the command finishes.
|
||||
If the command fails, the exit status is also displayed.
|
||||
.Tg wait
|
||||
.It Xo Ic wait\-for
|
||||
.Op Fl E | L | S | U
|
||||
.Op Fl ELSUv
|
||||
.Op Fl F Ar format
|
||||
.Ar channel | event\-name
|
||||
.Xc
|
||||
.D1 Pq alias: Ic wait
|
||||
@@ -8562,8 +8563,14 @@ When used without options, prevents the client from exiting until woken using
|
||||
.Fl S
|
||||
with the same channel.
|
||||
When
|
||||
.Fl E
|
||||
is used,
|
||||
.Fl L
|
||||
is used, the channel is locked and any clients that try to lock the same
|
||||
channel are made to wait until the channel is unlocked with
|
||||
.Ic wait\-for
|
||||
.Fl U .
|
||||
.Pp
|
||||
With
|
||||
.Fl E ,
|
||||
.Nm
|
||||
waits for the next event with the given name.
|
||||
Events include hook and notification names, and user
|
||||
@@ -8571,12 +8578,16 @@ Events include hook and notification names, and user
|
||||
events generated by
|
||||
.Ic set-hook
|
||||
.Fl B .
|
||||
When
|
||||
.Fl L
|
||||
is used, the channel is locked and any clients that try to lock the same
|
||||
channel are made to wait until the channel is unlocked with
|
||||
.Ic wait\-for
|
||||
.Fl U .
|
||||
If
|
||||
.Fl F
|
||||
is given,
|
||||
.Ar format
|
||||
must also be true.
|
||||
If
|
||||
.Fl v
|
||||
is given, event payload keys are printed (whether or not
|
||||
.Ar format
|
||||
is true).
|
||||
.El
|
||||
.Sh EXIT MESSAGES
|
||||
When a
|
||||
|
||||
2
tmux.h
2
tmux.h
@@ -2697,6 +2697,8 @@ void event_payload_set_pointer(struct event_payload *, const char *, void *,
|
||||
event_payload_free_cb, event_payload_print_cb);
|
||||
const char *event_payload_get_string(struct event_payload *, const char *);
|
||||
char *event_payload_print(struct event_payload *, const char *);
|
||||
void event_payload_add_formats(struct event_payload *,
|
||||
struct format_tree *, const char *);
|
||||
struct event_payload_item *event_payload_first(struct event_payload *);
|
||||
struct event_payload_item *event_payload_next(struct event_payload_item *);
|
||||
const char *event_payload_item_name(struct event_payload_item *);
|
||||
|
||||
Reference in New Issue
Block a user