aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Adam <thomas@xteddy.org>2019-04-27 20:09:07 +0100
committerThomas Adam <thomas@xteddy.org>2019-04-27 20:09:07 +0100
commit5489796737108cb9bba01f831421e531a50b946b (patch)
tree4f3c2727315adabaf5d932a1d81d4fad3e491752
parent85f09f9a4cf52b5af6b84464ea643c7c3686b0ad (diff)
parentdfb7bb683057d08303955c49073f4b475bd0e2d6 (diff)
downloadrtmux-5489796737108cb9bba01f831421e531a50b946b.tar.gz
rtmux-5489796737108cb9bba01f831421e531a50b946b.tar.bz2
rtmux-5489796737108cb9bba01f831421e531a50b946b.zip
Merge branch 'obsd-master'
-rw-r--r--Makefile.am2
-rw-r--r--cmd-new-session.c2
-rw-r--r--cmd-new-window.c2
-rw-r--r--cmd-queue.c56
-rw-r--r--cmd-select-pane.c2
-rw-r--r--cmd-select-window.c4
-rw-r--r--cmd-set-hook.c133
-rw-r--r--cmd-set-option.c39
-rw-r--r--cmd-show-options.c52
-rw-r--r--cmd-split-window.c2
-rw-r--r--cmd-string.c5
-rw-r--r--hooks.c173
-rw-r--r--notify.c74
-rw-r--r--options-table.c74
-rw-r--r--options.c73
-rw-r--r--session.c3
-rw-r--r--status.c2
-rw-r--r--tmux.130
-rw-r--r--tmux.c3
-rw-r--r--tmux.h39
20 files changed, 356 insertions, 414 deletions
diff --git a/Makefile.am b/Makefile.am
index 942a9e28..4f267a23 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -112,7 +112,6 @@ dist_tmux_SOURCES = \
cmd-send-keys.c \
cmd-set-buffer.c \
cmd-set-environment.c \
- cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
cmd-show-messages.c \
@@ -135,7 +134,6 @@ dist_tmux_SOURCES = \
format-draw.c \
grid-view.c \
grid.c \
- hooks.c \
input-keys.c \
input.c \
job.c \
diff --git a/cmd-new-session.c b/cmd-new-session.c
index f0a353d8..6818ce9c 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -329,7 +329,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
cmd_find_from_session(&fs, s, 0);
- hooks_insert(s->hooks, item, &fs, "after-new-session");
+ cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd);
free(newname);
diff --git a/cmd-new-window.c b/cmd-new-window.c
index e3bacff8..1007c597 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -105,7 +105,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
}
cmd_find_from_winlink(&fs, new_wl, 0);
- hooks_insert(s->hooks, item, &fs, "after-new-window");
+ cmdq_insert_hook(s, item, &fs, "after-new-window");
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-queue.c b/cmd-queue.c
index 03fd5f10..9ce25f5f 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -98,6 +98,60 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
} while (item != NULL);
}
+
+/* Insert a hook. */
+void
+cmdq_insert_hook(struct session *s, struct cmdq_item *item,
+ struct cmd_find_state *fs, const char *fmt, ...)
+{
+ struct options *oo;
+ va_list ap;
+ char *name;
+ struct cmdq_item *new_item;
+ struct options_entry *o;
+ struct options_array_item *a;
+ struct cmd_list *cmdlist;
+
+ if (item->flags & CMDQ_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);
+
+ a = options_array_first(o);
+ while (a != NULL) {
+ cmdlist = options_array_item_value(a)->cmdlist;
+ if (cmdlist == NULL) {
+ a = options_array_next(a);
+ continue;
+ }
+
+ new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
+ cmdq_format(new_item, "hook", "%s", name);
+ if (item != NULL) {
+ cmdq_insert_after(item, new_item);
+ item = new_item;
+ } else
+ cmdq_append(NULL, new_item);
+
+ a = options_array_next(a);
+ }
+
+ free(name);
+}
+
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
@@ -245,7 +299,7 @@ cmdq_fire_command(struct cmdq_item *item)
fsp = &fs;
else
goto out;
- hooks_insert(fsp->s->hooks, item, fsp, "after-%s", entry->name);
+ cmdq_insert_hook(fsp->s, item, fsp, "after-%s", entry->name);
}
out:
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index af0f033b..89c6fb20 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -196,7 +196,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
- hooks_insert(s->hooks, item, current, "after-select-pane");
+ cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
}
diff --git a/cmd-select-window.c b/cmd-select-window.c
index f35b8202..54965e89 100644
--- a/cmd-select-window.c
+++ b/cmd-select-window.c
@@ -119,7 +119,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
}
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
- hooks_insert(s->hooks, item, current, "after-select-window");
+ cmdq_insert_hook(s, item, current, "after-select-window");
} else {
/*
* If -T and select-window is invoked on same window as
@@ -137,7 +137,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
}
- hooks_insert(s->hooks, item, current, "after-select-window");
+ cmdq_insert_hook(s, item, current, "after-select-window");
}
recalculate_sizes();
diff --git a/cmd-set-hook.c b/cmd-set-hook.c
deleted file mode 100644
index b04e6335..00000000
--- a/cmd-set-hook.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "tmux.h"
-
-/*
- * Set or show global or session hooks.
- */
-
-static enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmdq_item *);
-
-const struct cmd_entry cmd_set_hook_entry = {
- .name = "set-hook",
- .alias = NULL,
-
- .args = { "gRt:u", 1, 2 },
- .usage = "[-gRu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
-
- .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
-
- .flags = CMD_AFTERHOOK,
- .exec = cmd_set_hook_exec
-};
-
-const struct cmd_entry cmd_show_hooks_entry = {
- .name = "show-hooks",
- .alias = NULL,
-
- .args = { "gt:", 0, 1 },
- .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
-
- .target = { 't', CMD_FIND_SESSION, 0 },
-
- .flags = CMD_AFTERHOOK,
- .exec = cmd_set_hook_exec
-};
-
-static enum cmd_retval
-cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
-{
- struct args *args = self->args;
- struct cmd_list *cmdlist;
- struct hooks *hooks;
- struct hook *hook;
- char *cause, *tmp;
- const char *name, *cmd, *target;
-
- if (args_has(args, 'g'))
- hooks = global_hooks;
- else {
- if (item->target.s == NULL) {
- target = args_get(args, 't');
- if (target != NULL)
- cmdq_error(item, "no such session: %s", target);
- else
- cmdq_error(item, "no current session");
- return (CMD_RETURN_ERROR);
- }
- hooks = item->target.s->hooks;
- }
-
- if (self->entry == &cmd_show_hooks_entry) {
- hook = hooks_first(hooks);
- while (hook != NULL) {
- tmp = cmd_list_print(hook->cmdlist);
- cmdq_print(item, "%s -> %s", hook->name, tmp);
- free(tmp);
-
- hook = hooks_next(hook);
- }
- return (CMD_RETURN_NORMAL);
- }
-
- name = args->argv[0];
- if (*name == '\0') {
- cmdq_error(item, "invalid hook name");
- return (CMD_RETURN_ERROR);
- }
- if (args->argc < 2)
- cmd = NULL;
- else
- cmd = args->argv[1];
-
- if (cmd != NULL && (args_has(args, 'R') || args_has(args, 'u'))) {
- cmdq_error(item, "no command allowed");
- return (CMD_RETURN_ERROR);
- }
- if (args_has(args, 'R')) {
- notify_hook(item, name);
- return (CMD_RETURN_NORMAL);
- }
- if (args_has(args, 'u')) {
- hooks_remove(hooks, name);
- return (CMD_RETURN_NORMAL);
- }
-
- if (cmd == NULL) {
- cmdq_error(item, "no command given");
- return (CMD_RETURN_ERROR);
- }
- cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
- if (cmdlist == NULL) {
- if (cause != NULL) {
- cmdq_error(item, "%s", cause);
- free(cause);
- }
- return (CMD_RETURN_ERROR);
- }
- hooks_add(hooks, name, cmdlist);
- cmd_list_free(cmdlist);
-
- return (CMD_RETURN_NORMAL);
-}
diff --git a/cmd-set-option.c b/cmd-set-option.c
index edeb8385..7be561f2 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -65,6 +65,19 @@ const struct cmd_entry cmd_set_window_option_entry = {
.exec = cmd_set_option_exec
};
+const struct cmd_entry cmd_set_hook_entry = {
+ .name = "set-hook",
+ .alias = NULL,
+
+ .args = { "agRt:u", 1, 2 },
+ .usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
+
+ .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
+
+ .flags = CMD_AFTERHOOK,
+ .exec = cmd_set_option_exec
+};
+
static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{
@@ -87,6 +100,11 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
+ if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
+ notify_hook(item, argument);
+ return (CMD_RETURN_NORMAL);
+ }
+
/* Parse option name and index. */
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
@@ -200,8 +218,11 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
options_default(oo, options_table_entry(o));
else
options_remove(o);
- } else
- options_array_set(o, idx, NULL, 0);
+ } else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
+ cmdq_error(item, "%s", cause);
+ free(cause);
+ goto fail;
+ }
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
@@ -222,9 +243,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1) {
if (!append)
options_array_clear(o);
- options_array_assign(o, value);
- } else if (options_array_set(o, idx, value, append) != 0) {
- cmdq_error(item, "invalid index: %s", argument);
+ if (options_array_assign(o, value, &cause) != 0) {
+ cmdq_error(item, "%s", cause);
+ free(cause);
+ goto fail;
+ }
+ } else if (options_array_set(o, idx, value, append,
+ &cause) != 0) {
+ cmdq_error(item, "%s", cause);
+ free(cause);
goto fail;
}
}
@@ -366,6 +393,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
return (-1);
}
return (0);
+ case OPTIONS_TABLE_COMMAND:
+ break;
}
return (-1);
}
diff --git a/cmd-show-options.c b/cmd-show-options.c
index 642b3f89..4948ff79 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_options_entry = {
.name = "show-options",
.alias = "show",
- .args = { "gqst:vw", 0, 1 },
- .usage = "[-gqsvw] [-t target-session|target-window] [option]",
+ .args = { "gHqst:vw", 0, 1 },
+ .usage = "[-gHqsvw] [-t target-session|target-window] [option]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
@@ -60,6 +60,19 @@ const struct cmd_entry cmd_show_window_options_entry = {
.exec = cmd_show_options_exec
};
+const struct cmd_entry cmd_show_hooks_entry = {
+ .name = "show-hooks",
+ .alias = NULL,
+
+ .args = { "gt:", 0, 1 },
+ .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
+
+ .target = { 't', CMD_FIND_SESSION, 0 },
+
+ .flags = CMD_AFTERHOOK,
+ .exec = cmd_show_options_exec
+};
+
static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
@@ -161,15 +174,20 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx)
{
struct options_array_item *a;
- const char *name;
- char *value, *tmp, *escaped;
+ const char *name = options_name(o);
+ char *value, *tmp = NULL, *escaped;
if (idx != -1) {
- xasprintf(&tmp, "%s[%d]", options_name(o), idx);
+ xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_isarray(o)) {
a = options_array_first(o);
+ if (a == NULL) {
+ if (!args_has(self->args, 'v'))
+ cmdq_print(item, "%s", name);
+ return;
+ }
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
@@ -177,8 +195,6 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
return;
}
- tmp = NULL;
- name = options_name(o);
}
value = options_tostring(o, idx, 0);
@@ -199,16 +215,28 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
- struct options_entry *o;
- struct options_array_item *a;
- u_int idx;
+ struct options_entry *o;
+ struct options_array_item *a;
+ u_int idx;
+ int flags;
o = options_first(oo);
while (o != NULL) {
+ flags = options_table_entry(o)->flags;
+ if ((self->entry != &cmd_show_hooks_entry &&
+ !args_has(self->args, 'H') &&
+ (flags & OPTIONS_TABLE_IS_HOOK)) ||
+ (self->entry == &cmd_show_hooks_entry &&
+ (~flags & OPTIONS_TABLE_IS_HOOK))) {
+ o = options_next(o);
+ continue;
+ }
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1);
- else {
- a = options_array_first(o);
+ else if ((a = options_array_first(o)) == NULL) {
+ if (!args_has(self->args, 'v'))
+ cmdq_print(item, "%s", options_name(o));
+ } else {
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
diff --git a/cmd-split-window.c b/cmd-split-window.c
index e64e9247..e9da1f3e 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -143,7 +143,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
}
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
- hooks_insert(s->hooks, item, &fs, "after-split-window");
+ cmdq_insert_hook(s, item, &fs, "after-split-window");
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-string.c b/cmd-string.c
index 440a0231..058f997c 100644
--- a/cmd-string.c
+++ b/cmd-string.c
@@ -174,7 +174,10 @@ cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
int argc;
char **argv;
- *cause = NULL;
+ if (cause != NULL)
+ *cause = NULL;
+ log_debug ("%s: %s", __func__, s);
+
if (cmd_string_split(s, &argc, &argv) != 0) {
xasprintf(cause, "invalid or unknown command: %s", s);
return (NULL);
diff --git a/hooks.c b/hooks.c
deleted file mode 100644
index 361f3522..00000000
--- a/hooks.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "tmux.h"
-
-struct hooks {
- RB_HEAD(hooks_tree, hook) tree;
- struct hooks *parent;
-};
-
-static int hooks_cmp(struct hook *, struct hook *);
-RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp);
-
-static struct hook *hooks_find1(struct hooks *, const char *);
-static void hooks_free1(struct hooks *, struct hook *);
-
-static int
-hooks_cmp(struct hook *hook1, struct hook *hook2)
-{
- return (strcmp(hook1->name, hook2->name));
-}
-
-struct hooks *
-hooks_get(struct session *s)
-{
- if (s != NULL)
- return (s->hooks);
- return (global_hooks);
-}
-
-struct hooks *
-hooks_create(struct hooks *parent)
-{
- struct hooks *hooks;
-
- hooks = xcalloc(1, sizeof *hooks);
- RB_INIT(&hooks->tree);
- hooks->parent = parent;
- return (hooks);
-}
-
-static void
-hooks_free1(struct hooks *hooks, struct hook *hook)
-{
- RB_REMOVE(hooks_tree, &hooks->tree, hook);
- cmd_list_free(hook->cmdlist);
- free((char *)hook->name);
- free(hook);
-}
-
-void
-hooks_free(struct hooks *hooks)
-{
- struct hook *hook, *hook1;
-
- RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
- hooks_free1(hooks, hook);
- free(hooks);
-}
-
-struct hook *
-hooks_first(struct hooks *hooks)
-{
- return (RB_MIN(hooks_tree, &hooks->tree));
-}
-
-struct hook *
-hooks_next(struct hook *hook)
-{
- return (RB_NEXT(hooks_tree, &hooks->tree, hook));
-}
-
-void
-hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
-{
- struct hook *hook;
-
- if ((hook = hooks_find1(hooks, name)) != NULL)
- hooks_free1(hooks, hook);
-
- hook = xcalloc(1, sizeof *hook);
- hook->name = xstrdup(name);
- hook->cmdlist = cmdlist;
- hook->cmdlist->references++;
- RB_INSERT(hooks_tree, &hooks->tree, hook);
-}
-
-void
-hooks_remove(struct hooks *hooks, const char *name)
-{
- struct hook *hook;
-
- if ((hook = hooks_find1(hooks, name)) != NULL)
- hooks_free1(hooks, hook);
-}
-
-static struct hook *
-hooks_find1(struct hooks *hooks, const char *name)
-{
- struct hook hook;
-
- hook.name = name;
- return (RB_FIND(hooks_tree, &hooks->tree, &hook));
-}
-
-struct hook *
-hooks_find(struct hooks *hooks, const char *name)
-{
- struct hook hook0, *hook;
-
- hook0.name = name;
- hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
- while (hook == NULL) {
- hooks = hooks->parent;
- if (hooks == NULL)
- break;
- hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
- }
- return (hook);
-}
-
-void
-hooks_insert(struct hooks *hooks, struct cmdq_item *item,
- struct cmd_find_state *fs, const char *fmt, ...)
-{
- struct hook *hook;
- va_list ap;
- char *name;
- struct cmdq_item *new_item;
-
- if (item->flags & CMDQ_NOHOOKS)
- return;
-
- va_start(ap, fmt);
- xvasprintf(&name, fmt, ap);
- va_end(ap);
-
- hook = hooks_find(hooks, name);
- if (hook == NULL) {
- free(name);
- return;
- }
- log_debug("running hook %s (parent %p)", name, item);
-
- new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS);
- cmdq_format(new_item, "hook", "%s", name);
- if (item != NULL)
- cmdq_insert_after(item, new_item);
- else
- cmdq_append(NULL, new_item);
-
- free(name);
-}
diff --git a/notify.c b/notify.c
index adef3d4e..163aa1a9 100644
--- a/notify.c
+++ b/notify.c
@@ -35,13 +35,34 @@ struct notify_entry {
};
static void
-notify_hook1(struct cmdq_item *item, struct notify_entry *ne)
+notify_hook_formats(struct cmdq_item *item, struct session *s, struct window *w,
+ int pane)
{
- struct cmd_find_state fs;
- struct hook *hook;
- struct cmdq_item *new_item;
- struct session *s = ne->session;
- struct window *w = ne->window;
+ if (s != NULL) {
+ cmdq_format(item, "hook_session", "$%u", s->id);
+ cmdq_format(item, "hook_session_name", "%s", s->name);
+ }
+ if (w != NULL) {
+ cmdq_format(item, "hook_window", "@%u", w->id);
+ cmdq_format(item, "hook_window_name", "%s", w->name);
+ }
+ if (pane != -1)
+ cmdq_format(item, "hook_pane", "%%%d", pane);
+}
+
+static void
+notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
+{
+ struct cmd_find_state fs;
+ struct options *oo;
+ struct cmdq_item *new_item;
+ struct session *s = ne->session;
+ struct window *w = ne->window;
+ struct options_entry *o;
+ struct options_array_item *a;
+ struct cmd_list *cmdlist;
+
+ log_debug("%s: %s", __func__, ne->name);
cmd_find_clear_state(&fs, 0);
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
@@ -49,26 +70,31 @@ notify_hook1(struct cmdq_item *item, struct notify_entry *ne)
else
cmd_find_copy_state(&fs, &ne->fs);
- hook = hooks_find(hooks_get(fs.s), ne->name);
- if (hook == NULL)
+ if (fs.s == NULL)
+ oo = global_s_options;
+ else
+ oo = fs.s->options;
+ o = options_get(oo, ne->name);
+ if (o == NULL)
return;
- log_debug("notify hook %s", ne->name);
- new_item = cmdq_get_command(hook->cmdlist, &fs, NULL, CMDQ_NOHOOKS);
- cmdq_format(new_item, "hook", "%s", ne->name);
+ a = options_array_first(o);
+ while (a != NULL) {
+ cmdlist = options_array_item_value(a)->cmdlist;
+ if (cmdlist == NULL) {
+ a = options_array_next(a);
+ continue;
+ }
- if (s != NULL) {
- cmdq_format(new_item, "hook_session", "$%u", s->id);
- cmdq_format(new_item, "hook_session_name", "%s", s->name);
- }
- if (w != NULL) {
- cmdq_format(new_item, "hook_window", "@%u", w->id);
- cmdq_format(new_item, "hook_window_name", "%s", w->name);
- }
- if (ne->pane != -1)
- cmdq_format(new_item, "hook_pane", "%%%d", ne->pane);
+ new_item = cmdq_get_command(cmdlist, &fs, NULL, CMDQ_NOHOOKS);
+ cmdq_format(new_item, "hook", "%s", ne->name);
+ notify_hook_formats(new_item, s, w, ne->pane);
- cmdq_insert_after(item, new_item);
+ cmdq_insert_after(item, new_item);
+ item = new_item;
+
+ a = options_array_next(a);
+ }
}
static enum cmd_retval
@@ -101,7 +127,7 @@ notify_callback(struct cmdq_item *item, void *data)
if (strcmp(ne->name, "session-window-changed") == 0)
control_notify_session_window_changed(ne->session);
- notify_hook1(item, ne);
+ notify_insert_hook(item, ne);
if (ne->client != NULL)
server_client_unref(ne->client);
@@ -168,7 +194,7 @@ notify_hook(struct cmdq_item *item, const char *name)
ne.window = item->target.w;
ne.pane = item->target.wp->id;
- notify_hook1(item, &ne);
+ notify_insert_hook(item, &ne);
}
void
diff --git a/options-table.c b/options-table.c
index a8beea06..19cf39f4 100644
--- a/options-table.c
+++ b/options-table.c
@@ -129,8 +129,19 @@ static const char *options_table_status_format_default[] = {
OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
};
+/* Helper for hook options. */
+#define OPTIONS_TABLE_HOOK(hook_name, default_value) \
+ { .name = hook_name, \
+ .type = OPTIONS_TABLE_COMMAND, \
+ .scope = OPTIONS_TABLE_SESSION, \
+ .flags = OPTIONS_TABLE_IS_ARRAY|OPTIONS_TABLE_IS_HOOK, \
+ .default_str = default_value, \
+ .separator = "" \
+ }
+
/* Top-level options. */
const struct options_table_entry options_table[] = {
+ /* Server options. */
{ .name = "buffer-limit",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
@@ -223,6 +234,7 @@ const struct options_table_entry options_table[] = {
.separator = ","
},
+ /* Session options. */
{ .name = "activity-action",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
@@ -541,6 +553,7 @@ const struct options_table_entry options_table[] = {
.default_str = " -_@"
},
+ /* Window options. */
{ .name = "aggressive-resize",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
@@ -775,5 +788,66 @@ const struct options_table_entry options_table[] = {
.default_num = 1
},
+ /* Hook options. */
+ OPTIONS_TABLE_HOOK("after-bind-key", ""),
+ OPTIONS_TABLE_HOOK("after-capture-pane", ""),
+ OPTIONS_TABLE_HOOK("after-copy-mode", ""),
+ OPTIONS_TABLE_HOOK("after-display-message", ""),
+ OPTIONS_TABLE_HOOK("after-display-panes", ""),
+ OPTIONS_TABLE_HOOK("after-list-buffers", ""),
+ OPTIONS_TABLE_HOOK("after-list-clients", ""),
+ OPTIONS_TABLE_HOOK("after-list-keys", ""),
+ OPTIONS_TABLE_HOOK("after-list-panes", ""),
+ OPTIONS_TABLE_HOOK("after-list-sessions", ""),
+ OPTIONS_TABLE_HOOK("after-list-windows", ""),
+ OPTIONS_TABLE_HOOK("after-load-buffer", ""),
+ OPTIONS_TABLE_HOOK("after-lock-server", ""),
+ OPTIONS_TABLE_HOOK("after-new-session", ""),
+ OPTIONS_TABLE_HOOK("after-new-window", ""),
+ OPTIONS_TABLE_HOOK("after-paste-buffer", ""),
+ OPTIONS_TABLE_HOOK("after-pipe-pane", ""),
+ OPTIONS_TABLE_HOOK("after-queue", ""),
+ OPTIONS_TABLE_HOOK("after-refresh-client", ""),
+ OPTIONS_TABLE_HOOK("after-rename-session", ""),
+ OPTIONS_TABLE_HOOK("after-rename-window", ""),
+ OPTIONS_TABLE_HOOK("after-resize-pane", ""),
+ OPTIONS_TABLE_HOOK("after-resize-window", ""),
+ OPTIONS_TABLE_HOOK("after-save-buffer", ""),
+ OPTIONS_TABLE_HOOK("after-select-layout", ""),
+ OPTIONS_TABLE_HOOK("after-select-pane", ""),
+ OPTIONS_TABLE_HOOK("after-select-window", ""),
+ OPTIONS_TABLE_HOOK("after-send-keys", ""),
+ OPTIONS_TABLE_HOOK("after-set-buffer", ""),
+ OPTIONS_TABLE_HOOK("after-set-environment", ""),
+ OPTIONS_TABLE_HOOK("after-set-hook", ""),
+ OPTIONS_TABLE_HOOK("after-set-option", ""),
+ OPTIONS_TABLE_HOOK("after-show-environment", ""),
+ OPTIONS_TABLE_HOOK("after-show-messages", ""),
+ OPTIONS_TABLE_HOOK("after-show-options", ""),
+ OPTIONS_TABLE_HOOK("after-split-window", ""),
+ OPTIONS_TABLE_HOOK("after-unbind-key", ""),
+ OPTIONS_TABLE_HOOK("alert-activity", ""),
+ OPTIONS_TABLE_HOOK("alert-bell", ""),
+ OPTIONS_TABLE_HOOK("alert-silence", ""),
+ OPTIONS_TABLE_HOOK("client-attached", ""),
+ OPTIONS_TABLE_HOOK("client-detached", ""),
+ OPTIONS_TABLE_HOOK("client-resized", ""),
+ OPTIONS_TABLE_HOOK("client-session-changed", ""),
+ OPTIONS_TABLE_HOOK("pane-died", ""),
+ OPTIONS_TABLE_HOOK("pane-exited", ""),
+ OPTIONS_TABLE_HOOK("pane-focus-in", ""),
+ OPTIONS_TABLE_HOOK("pane-focus-out", ""),
+ OPTIONS_TABLE_HOOK("pane-mode-changed", ""),
+ OPTIONS_TABLE_HOOK("pane-set-clipboard", ""),
+ OPTIONS_TABLE_HOOK("session-closed", ""),
+ OPTIONS_TABLE_HOOK("session-created", ""),
+ OPTIONS_TABLE_HOOK("session-renamed", ""),
+ OPTIONS_TABLE_HOOK("session-window-changed", ""),
+ OPTIONS_TABLE_HOOK("window-layout-changed", ""),
+ OPTIONS_TABLE_HOOK("window-linked", ""),
+ OPTIONS_TABLE_HOOK("window-pane-changed", ""),
+ OPTIONS_TABLE_HOOK("window-renamed", ""),
+ OPTIONS_TABLE_HOOK("window-unlinked", ""),
+
{ .name = NULL }
};
diff --git a/options.c b/options.c
index fb271d5e..c5a776e5 100644
--- a/options.c
+++ b/options.c
@@ -76,6 +76,9 @@ static struct options_entry *options_add(struct options *, const char *);
#define OPTIONS_IS_STYLE(o) \
((o)->tableentry != NULL && \
(o)->tableentry->type == OPTIONS_TABLE_STYLE)
+#define OPTIONS_IS_COMMAND(o) \
+ ((o)->tableentry != NULL && \
+ (o)->tableentry->type == OPTIONS_TABLE_COMMAND)
#define OPTIONS_IS_ARRAY(o) \
((o)->tableentry != NULL && \
@@ -108,6 +111,8 @@ options_value_free(struct options_entry *o, union options_value *ov)
{
if (OPTIONS_IS_STRING(o))
free(ov->string);
+ if (OPTIONS_IS_COMMAND(o) && ov->cmdlist != NULL)
+ cmd_list_free(ov->cmdlist);
}
static char *
@@ -116,6 +121,8 @@ options_value_tostring(struct options_entry *o, union options_value *ov,
{
char *s;
+ if (OPTIONS_IS_COMMAND(o))
+ return (cmd_list_print(ov->cmdlist));
if (OPTIONS_IS_STYLE(o))
return (xstrdup(style_tostring(&ov->style)));
if (OPTIONS_IS_NUMBER(o)) {
@@ -140,6 +147,7 @@ options_value_tostring(struct options_entry *o, union options_value *ov,
break;
case OPTIONS_TABLE_STRING:
case OPTIONS_TABLE_STYLE:
+ case OPTIONS_TABLE_COMMAND:
fatalx("not a number option type");
}
return (s);
@@ -231,11 +239,12 @@ options_default(struct options *oo, const struct options_table_entry *oe)
ov = &o->value;
if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
- if (oe->default_arr != NULL) {
- for (i = 0; oe->default_arr[i] != NULL; i++)
- options_array_set(o, i, oe->default_arr[i], 0);
- } else
- options_array_assign(o, oe->default_str);
+ if (oe->default_arr == NULL) {
+ options_array_assign(o, oe->default_str, NULL);
+ return (o);
+ }
+ for (i = 0; oe->default_arr[i] != NULL; i++)
+ options_array_set(o, i, oe->default_arr[i], 0, NULL);
return (o);
}
@@ -340,13 +349,22 @@ options_array_get(struct options_entry *o, u_int idx)
int
options_array_set(struct options_entry *o, u_int idx, const char *value,
- int append)
+ int append, char **cause)
{
struct options_array_item *a;
char *new;
+ struct cmd_list *cmdlist;
- if (!OPTIONS_IS_ARRAY(o))
+ if (!OPTIONS_IS_ARRAY(o)) {
+ *cause = xstrdup("not an array");
return (-1);
+ }
+
+ if (OPTIONS_IS_COMMAND(o)) {
+ cmdlist = cmd_string_parse(value, NULL, 0, cause);
+ if (cmdlist == NULL && *cause != NULL)
+ return (-1);
+ }
a = options_array_item(o, idx);
if (value == NULL) {
@@ -355,25 +373,29 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
return (0);
}
- if (a == NULL) {
- a = xcalloc(1, sizeof *a);
- a->index = idx;
- a->value.string = xstrdup(value);
- RB_INSERT(options_array, &o->value.array, a);
- } else {
- options_value_free(o, &a->value);
+ if (OPTIONS_IS_STRING(o)) {
if (a != NULL && append)
xasprintf(&new, "%s%s", a->value.string, value);
else
new = xstrdup(value);
- a->value.string = new;
}
+ if (a == NULL) {
+ a = xcalloc(1, sizeof *a);
+ a->index = idx;
+ RB_INSERT(options_array, &o->value.array, a);
+ } else
+ options_value_free(o, &a->value);
+
+ if (OPTIONS_IS_STRING(o))
+ a->value.string = new;
+ else if (OPTIONS_IS_COMMAND(o))
+ a->value.cmdlist = cmdlist;
return (0);
}
-void
-options_array_assign(struct options_entry *o, const char *s)
+int
+options_array_assign(struct options_entry *o, const char *s, char **cause)
{
const char *separator;
char *copy, *next, *string;
@@ -382,7 +404,18 @@ options_array_assign(struct options_entry *o, const char *s)
separator = o->tableentry->separator;
if (separator == NULL)
separator = " ,";
+ if (*separator == '\0') {
+ if (*s == '\0')
+ return (0);
+ for (i = 0; i < UINT_MAX; i++) {
+ if (options_array_item(o, i) == NULL)
+ break;
+ }
+ return (options_array_set(o, i, s, 0, cause));
+ }
+ if (*s == '\0')
+ return (0);
copy = string = xstrdup(s);
while ((next = strsep(&string, separator)) != NULL) {
if (*next == '\0')
@@ -393,9 +426,13 @@ options_array_assign(struct options_entry *o, const char *s)
}
if (i == UINT_MAX)
break;
- options_array_set(o, i, next, 0);
+ if (options_array_set(o, i, next, 0, cause) != 0) {
+ free(copy);
+ return (-1);
+ }
}
free(copy);
+ return (0);
}
struct options_array_item *
diff --git a/session.c b/session.c
index 9a32990e..b361bde3 100644
--- a/session.c
+++ b/session.c
@@ -128,7 +128,6 @@ session_create(const char *prefix, const char *name, const char *cwd,
s->environ = env;
s->options = oo;
- s->hooks = hooks_create(global_hooks);
status_update_cache(s);
@@ -192,9 +191,7 @@ session_free(__unused int fd, __unused short events, void *arg)
if (s->references == 0) {
environ_free(s->environ);
-
options_free(s->options);
- hooks_free(s->hooks);
free(s->name);
free(s);
diff --git a/status.c b/status.c
index 34ed3778..89912114 100644
--- a/status.c
+++ b/status.c
@@ -1323,7 +1323,7 @@ status_prompt_complete_list(u_int *size, const char *s)
while (a != NULL) {
value = options_array_item_value(a)->string;
if ((cp = strchr(value, '=')) == NULL)
- goto next;
+ goto next;
valuelen = cp - value;
if (slen > valuelen || strncmp(value, s, slen) != 0)
goto next;
diff --git a/tmux.1 b/tmux.1
index 8a5caf09..fa810f7b 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3461,7 +3461,7 @@ function key sequences; these have a number included to indicate modifiers such
as Shift, Alt or Ctrl.
.El
.It Xo Ic show-options
-.Op Fl gqsvw
+.Op Fl gHqsvw
.Op Fl t Ar target-session | Ar target-window
.Op Ar option
.Xc
@@ -3493,6 +3493,8 @@ If
is set, no error will be returned if
.Ar option
is unset.
+.Fl H
+includes hooks (omitted by default).
.It Xo Ic show-window-options
.Op Fl gv
.Op Fl t Ar target-window
@@ -3517,6 +3519,26 @@ commands have an
.Em after
hook and there are a number of hooks not associated with commands.
.Pp
+Hooks are stored as array options, members of the array are executed in
+order when the hook is triggered.
+Hooks may be configured with the
+.Ic set-hook
+or
+.Ic set-option
+commands and displayed with
+.Ic show-hooks
+or
+.Ic show-options
+.Fl H .
+The following two commands are equivalent:
+.Bd -literal -offset indent.
+set-hook -g pane-mode-changed[42] 'set -g status-left-style bg=red'
+set-option -g pane-mode-changed[42] 'set -g status-left-style bg=red'
+.Ed
+.Pp
+Setting a hook without specifying an array index clears the hook and sets the
+first member of the array.
+.Pp
A command's after
hook is run after it completes, except when the command is run as part of a hook
itself.
@@ -3527,7 +3549,7 @@ 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"
+set-hook -g after-split-window "selectl even-vertical"
.Ed
.Pp
All the notifications listed in the
@@ -3591,7 +3613,7 @@ Run when a window is unlinked from a session.
Hooks are managed with these commands:
.Bl -tag -width Ds
.It Xo Ic set-hook
-.Op Fl gRu
+.Op Fl agRu
.Op Fl t Ar target-session
.Ar hook-name
.Ar command
@@ -3613,6 +3635,8 @@ hooks (for
.Ar target-session
with
.Fl t ) .
+.Fl a
+appends to a hook.
Like options, session hooks inherit from the global ones.
.Pp
With
diff --git a/tmux.c b/tmux.c
index f4265e0a..685827d4 100644
--- a/tmux.c
+++ b/tmux.c
@@ -36,7 +36,6 @@ struct options *global_options; /* server options */
struct options *global_s_options; /* session options */
struct options *global_w_options; /* window options */
struct environ *global_environ;
-struct hooks *global_hooks;
struct timeval start_time;
const char *socket_path;
@@ -312,8 +311,6 @@ main(int argc, char **argv)
flags |= CLIENT_UTF8;
}
- global_hooks = hooks_create(NULL);
-
global_environ = environ_create();
for (var = environ; *var != NULL; var++)
environ_put(global_environ, *var);
diff --git a/tmux.h b/tmux.h
index 03ed41af..d6f8a376 100644
--- a/tmux.h
+++ b/tmux.h
@@ -685,15 +685,6 @@ struct style {
u_int range_argument;
};
-/* Hook data structures. */
-struct hook {
- const char *name;
-
- struct cmd_list *cmdlist;
-
- RB_ENTRY(hook) entry;
-};
-
/* Virtual screen. */
struct screen_sel;
struct screen_titles;
@@ -997,7 +988,6 @@ struct session {
int statusat;
u_int statuslines;
- struct hooks *hooks;
struct options *options;
#define SESSION_PASTING 0x1
@@ -1523,6 +1513,7 @@ union options_value {
long long number;
struct style style;
struct options_array array;
+ struct cmd_list *cmdlist;
};
/* Option table entries. */
@@ -1533,17 +1524,19 @@ enum options_table_type {
OPTIONS_TABLE_COLOUR,
OPTIONS_TABLE_FLAG,
OPTIONS_TABLE_CHOICE,
- OPTIONS_TABLE_STYLE
+ OPTIONS_TABLE_STYLE,
+ OPTIONS_TABLE_COMMAND
};
enum options_table_scope {
OPTIONS_TABLE_NONE,
OPTIONS_TABLE_SERVER,
OPTIONS_TABLE_SESSION,
- OPTIONS_TABLE_WINDOW,
+ OPTIONS_TABLE_WINDOW
};
#define OPTIONS_TABLE_IS_ARRAY 0x1
+#define OPTIONS_TABLE_IS_HOOK 0x2
struct options_table_entry {
const char *name;
@@ -1601,7 +1594,6 @@ struct spawn_context {
};
/* tmux.c */
-extern struct hooks *global_hooks;
extern struct options *global_options;
extern struct options *global_s_options;
extern struct options *global_w_options;
@@ -1695,20 +1687,6 @@ u_int format_width(const char *);
char *format_trim_left(const char *, u_int);
char *format_trim_right(const char *, u_int);
-/* hooks.c */
-struct hook;
-struct hooks *hooks_get(struct session *);
-struct hooks *hooks_create(struct hooks *);
-void hooks_free(struct hooks *);
-struct hook *hooks_first(struct hooks *);
-struct hook *hooks_next(struct hook *);
-void hooks_add(struct hooks *, const char *, struct cmd_list *);
-void hooks_copy(struct hooks *, struct hooks *);
-void hooks_remove(struct hooks *, const char *);
-struct hook *hooks_find(struct hooks *, const char *);
-void printflike(4, 5) hooks_insert(struct hooks *, struct cmdq_item *,
- struct cmd_find_state *, const char *, ...);
-
/* notify.c */
void notify_hook(struct cmdq_item *, const char *);
void notify_input(struct window_pane *, struct evbuffer *);
@@ -1736,8 +1714,9 @@ void options_remove(struct options_entry *);
void options_array_clear(struct options_entry *);
union options_value *options_array_get(struct options_entry *, u_int);
int options_array_set(struct options_entry *, u_int, const char *,
- int);
-void options_array_assign(struct options_entry *, const char *);
+ int, char **);
+int options_array_assign(struct options_entry *, const char *,
+ char **);
struct options_array_item *options_array_first(struct options_entry *);
struct options_array_item *options_array_next(struct options_array_item *);
u_int options_array_item_index(struct options_array_item *);
@@ -1958,6 +1937,8 @@ struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmd_find_state *,
struct cmdq_item *cmdq_get_callback1(const char *, cmdq_cb, void *);
void cmdq_insert_after(struct cmdq_item *, struct cmdq_item *);
void cmdq_append(struct client *, struct cmdq_item *);
+void cmdq_insert_hook(struct session *, struct cmdq_item *,
+ struct cmd_find_state *, const char *, ...);
void printflike(3, 4) cmdq_format(struct cmdq_item *, const char *,
const char *, ...);
u_int cmdq_next(struct client *);