This adds an implementation hooks using a RB tree to store the name of the
hook and the command-list it uses. These will be accessed via commands to
add/remove hooks.
---
Makefile.am | 3 ++
cmd-set-hook.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
cmd-show-hooks.c | 69 +++++++++++++++++++++++++++++++++++
hooks.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
session.c | 2 +
tmux.c | 2 +
tmux.h | 27 ++++++++++++++
7 files changed, 310 insertions(+)
create mode 100644 cmd-set-hook.c
create mode 100644 cmd-show-hooks.c
create mode 100644 hooks.c
diff --git a/Makefile.am b/Makefile.am
index 2ce54b1..4a0bb2d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,8 +121,10 @@ dist_tmux_SOURCES = \
cmd-server-info.c \
cmd-set-buffer.c \
cmd-set-environment.c \
+ cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
+ cmd-show-hooks.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
@@ -145,6 +147,7 @@ dist_tmux_SOURCES = \
grid-cell.c \
grid-view.c \
grid.c \
+ hooks.c \
input-keys.c \
input.c \
job.c \
diff --git a/cmd-set-hook.c b/cmd-set-hook.c
new file mode 100644
index 0000000..ae29b99
--- /dev/null
+++ b/cmd-set-hook.c
@@ -0,0 +1,98 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <[email protected]>
+ *
+ * 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"
+
+enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *);
+void cmd_set_hook_prepare(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_set_hook_entry = {
+ "set-hook", NULL,
+ "gn:t:u", 0, 1,
+ "[-n hook-name] [-g]" CMD_TARGET_SESSION_USAGE " [-u hook-name]
[command]",
+ 0,
+ NULL,
+ NULL,
+ cmd_set_hook_exec,
+ cmd_set_hook_prepare
+};
+
+void
+cmd_set_hook_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ cmdq->cmd_ctx.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+}
+
+enum cmd_retval
+cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct session *s;
+ struct cmd_list *cmdlist;
+ struct hooks *hooks;
+ struct hook *hook;
+ char *cause;
+ const char *hook_name, *hook_cmd;
+
+ s = cmdq->cmd_ctx.s;
+
+ if (args_has(args, 't') && s == NULL)
+ return (CMD_RETURN_ERROR);
+
+ if (s == NULL && cmdq->client != NULL)
+ s = cmdq->client->session;
+
+ if ((hook_name = args_get(args, 'n')) == NULL) {
+ cmdq_error(cmdq, "no hook name given");
+ return (CMD_RETURN_ERROR);
+ }
+
+ hooks = args_has(args, 'g') ? &global_hooks : &s->hooks;
+
+ if (s != NULL && args_has(args, 'u')) {
+ if ((hook = hooks_find(hooks, (char *)hook_name)) != NULL)
+ hooks_remove(hooks, hook);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (args->argc == 0) {
+ cmdq_error(cmdq, "no command for hook '%s' given", hook_name);
+ return (CMD_RETURN_ERROR);
+ }
+ hook_cmd = args->argv[0];
+
+ if (cmd_string_parse(hook_cmd, &cmdlist, NULL, 0, &cause) != 0) {
+ if (cmdlist == NULL || cause != NULL) {
+ cmdq_error(cmdq, "hook error: (%s)", cause);
+ return (CMD_RETURN_ERROR);
+ }
+ }
+
+ if (cmdlist == NULL)
+ return (CMD_RETURN_ERROR);
+
+ hooks_add(hooks, hook_name, cmdlist);
+ return (CMD_RETURN_NORMAL);
+}
diff --git a/cmd-show-hooks.c b/cmd-show-hooks.c
new file mode 100644
index 0000000..8de7ab8
--- /dev/null
+++ b/cmd-show-hooks.c
@@ -0,0 +1,69 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <[email protected]>
+ *
+ * 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"
+
+enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_q *);
+void cmd_show_hooks_prepare(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_show_hooks_entry = {
+ "show-hooks", NULL,
+ "gt:", 0, 1,
+ "[-g] " CMD_TARGET_SESSION_USAGE,
+ 0,
+ NULL,
+ NULL,
+ cmd_show_hooks_exec,
+ cmd_show_hooks_prepare
+};
+
+void
+cmd_show_hooks_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ cmdq->cmd_ctx.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+}
+
+enum cmd_retval
+cmd_show_hooks_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct session *s;
+ struct hooks *hooks;
+ struct hook *hook;
+ char tmp[BUFSIZ];
+ size_t used;
+
+ if ((s = cmdq->cmd_ctx.s) == NULL)
+ return (CMD_RETURN_ERROR);
+
+ hooks = args_has(args, 'g') ? &global_hooks : &s->hooks;
+
+ RB_FOREACH(hook, hooks_tree, &hooks->tree) {
+ used = xsnprintf(tmp, sizeof tmp, "%s -> ", hook->name);
+ cmd_list_print(hook->cmdlist, tmp + used, (sizeof tmp) - used);
+ cmdq_print(cmdq, "%s", tmp);
+ }
+ return (CMD_RETURN_NORMAL);
+}
diff --git a/hooks.c b/hooks.c
new file mode 100644
index 0000000..e2aa8d7
--- /dev/null
+++ b/hooks.c
@@ -0,0 +1,109 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <[email protected]>
+ *
+ * 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"
+
+RB_GENERATE(hooks_tree, hook, entry, hooks_cmp);
+
+struct hook *hooks_find1(struct hooks *, const char *);
+
+int
+hooks_cmp(struct hook *hook1, struct hook *hook2)
+{
+ return (strcmp(hook1->name, hook2->name));
+}
+
+void
+hooks_init(struct hooks *hooks, struct hooks *copy)
+{
+ RB_INIT(&hooks->tree);
+ hooks->parent = copy;
+}
+
+void
+hooks_free(struct hooks *hooks)
+{
+ struct hook *h, *h2;
+
+ RB_FOREACH_SAFE(h, hooks_tree, &hooks->tree, h2)
+ hooks_remove(hooks, h);
+}
+
+void
+hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
+{
+ struct hook *h;
+
+ if ((h = hooks_find1(hooks, name)) != NULL)
+ hooks_remove(hooks, h);
+
+ h = xcalloc(1, sizeof *h);
+ h->name = xstrdup(name);
+ h->cmdlist = cmdlist;
+ h->cmdlist->references++;
+
+ RB_INSERT(hooks_tree, &hooks->tree, h);
+}
+
+void
+hooks_remove(struct hooks *hooks, struct hook *h)
+{
+ RB_REMOVE(hooks_tree, &hooks->tree, h);
+ cmd_list_free(h->cmdlist);
+ free(h->name);
+ free(h);
+}
+
+struct hook *
+hooks_find1(struct hooks *hooks, const char *name)
+{
+ struct hook h;
+
+ h.name = (char *) name;
+ return (RB_FIND(hooks_tree, &hooks->tree, &h));
+}
+
+struct hook *
+hooks_find(struct hooks *hooks, const char *name)
+{
+ struct hook h, *he;
+
+ h.name = (char *) name;
+ he = RB_FIND(hooks_tree, &hooks->tree, &h);
+ while (he == NULL) {
+ hooks = hooks->parent;
+ if (hooks == NULL)
+ break;
+ he = RB_FIND(hooks_tree, &hooks->tree, &h);
+ }
+ return (he);
+}
+
+void
+hooks_run(struct hook *hook, struct cmd_q *cmdq)
+{
+ struct cmd *cmd;
+
+ TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry)
+ cmd->entry->exec(cmd, cmdq);
+}
diff --git a/session.c b/session.c
index 74eb06a..b75d459 100644
--- a/session.c
+++ b/session.c
@@ -104,6 +104,7 @@ session_create(const char *name, const char *cmd, const
char *cwd,
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
+ hooks_init(&s->hooks, &global_hooks);
options_init(&s->options, &global_s_options);
environ_init(&s->environ);
if (env != NULL)
@@ -160,6 +161,7 @@ session_destroy(struct session *s)
session_group_remove(s);
environ_free(&s->environ);
options_free(&s->options);
+ hooks_free(&s->hooks);
while (!TAILQ_EMPTY(&s->lastw))
winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw));
diff --git a/tmux.c b/tmux.c
index e6de5cf..4aa996e 100644
--- a/tmux.c
+++ b/tmux.c
@@ -39,6 +39,7 @@ 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 event_base *ev_base;
@@ -322,6 +323,7 @@ main(int argc, char **argv)
flags |= IDENTIFY_UTF8;
}
+ hooks_init(&global_hooks, NULL);
environ_init(&global_environ);
for (var = environ; *var != NULL; var++)
environ_put(&global_environ, *var);
diff --git a/tmux.h b/tmux.h
index f0b9edf..22d0964 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1075,6 +1075,18 @@ struct environ_entry {
};
RB_HEAD(environ, environ_entry);
+/* Hooks. */
+struct hook {
+ char *name;
+ struct cmd_list *cmdlist;
+ RB_ENTRY(hook) entry;
+};
+
+struct hooks {
+ RB_HEAD(hooks_tree, hook) tree;
+ struct hooks *parent;
+};
+
/* Client session. */
struct session_group {
TAILQ_HEAD(, session) sessions;
@@ -1100,6 +1112,7 @@ struct session {
struct winlink_stack lastw;
struct winlinks windows;
+ struct hooks hooks;
struct options options;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
@@ -1500,6 +1513,7 @@ RB_HEAD(format_tree, format_entry);
#define CMD_BUFFER_USAGE "[-b buffer-index]"
/* tmux.c */
+extern struct hooks global_hooks;
extern struct options global_options;
extern struct options global_s_options;
extern struct options global_w_options;
@@ -1547,6 +1561,17 @@ void format_winlink(
void format_window_pane(struct format_tree *, struct window_pane *);
void format_paste_buffer(struct format_tree *, struct paste_buffer
*);
+/* hooks.c */
+int hooks_cmp(struct hook *, struct hook *);
+RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp);
+void hooks_init(struct hooks *, struct hooks *);
+void hooks_free(struct hooks *);
+void hooks_add(struct hooks *, const char *, struct cmd_list *);
+void hooks_copy(struct hooks *, struct hooks *);
+void hooks_remove(struct hooks *, struct hook *);
+void hooks_run(struct hook *, struct cmd_q *);
+struct hook *hooks_find(struct hooks *, const char *);
+
/* mode-key.c */
extern const struct mode_key_table mode_key_tables[];
extern struct mode_key_tree mode_key_tree_vi_edit;
@@ -1820,10 +1845,12 @@ extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry;
+extern const struct cmd_entry cmd_set_hook_entry;
extern const struct cmd_entry cmd_set_option_entry;
extern const struct cmd_entry cmd_set_window_option_entry;
extern const struct cmd_entry cmd_show_buffer_entry;
extern const struct cmd_entry cmd_show_environment_entry;
+extern const struct cmd_entry cmd_show_hooks_entry;
extern const struct cmd_entry cmd_show_messages_entry;
extern const struct cmd_entry cmd_show_options_entry;
extern const struct cmd_entry cmd_show_window_options_entry;
--
1.7.11.4
------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
tmux-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users