Suggested patch on how to implement before/after hook support.
---
 Makefile.am      |   3 ++
 cmd-set-hook.c   |  90 +++++++++++++++++++++++++++++++++++++++++++
 cmd-show-hooks.c |  62 ++++++++++++++++++++++++++++++
 cmd.c            |  70 +++++++++++++++++++++++++++++++++-
 hooks.c          | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 session.c        |   2 +
 tmux.c           |   2 +
 tmux.h           |  23 +++++++++++
 8 files changed, 365 insertions(+), 1 deletion(-)
 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 672208b..8341d9b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -118,9 +118,11 @@ 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-buffer.c \
        cmd-show-environment.c \
+       cmd-show-hooks.c \
        cmd-show-messages.c \
        cmd-show-options.c \
        cmd-source-file.c \
@@ -142,6 +144,7 @@ dist_tmux_SOURCES = \
        grid-utf8.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..d42ead7
--- /dev/null
+++ b/cmd-set-hook.c
@@ -0,0 +1,90 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <tho...@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 <ctype.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_ctx *);
+
+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
+};
+
+enum cmd_retval
+cmd_set_hook_exec(struct cmd *self, struct cmd_ctx *ctx)
+{
+       struct args     *args = self->args;
+       struct session  *s;
+       struct cmd_list *cmdlist;
+       struct hooks    *hooks_ent;
+       struct hook     *hook;
+       char            *cause;
+       const char      *hook_name, *hook_cmd;
+
+       if (args_has(args, 't'))
+               if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+                       return (CMD_RETURN_ERROR);
+
+       if (s == NULL && ctx->curclient != NULL)
+               s = ctx->curclient->session;
+
+       if ((hook_name = args_get(args, 'n')) == NULL) {
+               ctx->error(ctx, "No hook name given.");
+               return (CMD_RETURN_ERROR);
+       }
+
+       hooks_ent = args_has(args, 'g') ? &global_hooks : &s->hooks;
+
+       if (s != NULL && args_has(args, 'u')) {
+               hook = hooks_find(hooks_ent, (char *)hook_name);
+               hook_remove(hooks_ent, hook);
+               return (CMD_RETURN_NORMAL);
+       }
+
+       if (args->argc == 0) {
+               ctx->error(ctx, "No command for hook '%s' given.", hook_name);
+               return (CMD_RETURN_ERROR);
+       }
+       hook_cmd = args->argv[0];
+
+       if (cmd_string_parse(hook_cmd, &cmdlist, &cause) != 0) {
+               if (cmdlist == NULL || cause != NULL) {
+                       log_debug("Hook error: (%s)", cause);
+                       ctx->error(ctx, "Hook error: (%s)", cause);
+                       return (CMD_RETURN_ERROR);
+               }
+       }
+
+       if (cmdlist == NULL)
+               return (CMD_RETURN_ERROR);
+
+       hooks_add(hooks_ent, 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..08e646e
--- /dev/null
+++ b/cmd-show-hooks.c
@@ -0,0 +1,62 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <tho...@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 <ctype.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_ctx *);
+
+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
+};
+
+enum cmd_retval
+cmd_show_hooks_exec(struct cmd *self, struct cmd_ctx *ctx)
+{
+       struct args     *args = self->args;
+       struct session  *s;
+       struct hook     *hook;
+       struct hooks    *hooks_ent;
+       struct cmd      *cmd;
+       char             tmp[BUFSIZ];
+       size_t           used;
+
+       if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+               return (CMD_RETURN_ERROR);
+
+       hooks_ent = args_has(args, 'g') ? &global_hooks : &s->hooks;
+
+       RB_FOREACH(hook, hooks, hooks_ent) {
+               used = xsnprintf(tmp, sizeof tmp, "%s -> ", hook->name);
+               cmd_list_print(hook->cmdlist, tmp + used, (sizeof tmp) - used);
+               ctx->print(ctx, "%s", tmp);
+       }
+       return (CMD_RETURN_NORMAL);
+}
diff --git a/cmd.c b/cmd.c
index 4a17ddc..f88c071 100644
--- a/cmd.c
+++ b/cmd.c
@@ -96,10 +96,12 @@ const struct cmd_entry *cmd_table[] = {
        &cmd_server_info_entry,
        &cmd_set_buffer_entry,
        &cmd_set_environment_entry,
+       &cmd_set_hook_entry,
        &cmd_set_option_entry,
        &cmd_set_window_option_entry,
        &cmd_show_buffer_entry,
        &cmd_show_environment_entry,
+       &cmd_show_hooks_entry,
        &cmd_show_messages_entry,
        &cmd_show_options_entry,
        &cmd_show_window_options_entry,
@@ -130,6 +132,10 @@ struct session     *cmd_window_session(struct cmd_ctx *,
 struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
 int             cmd_find_index_offset(const char *, struct session *, int *);
 struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
+enum cmd_retval         run_hook_before(struct hooks *, struct cmd *,
+                   struct cmd_ctx *);
+enum cmd_retval         run_hook_after(struct hooks *, struct cmd *,
+                   struct cmd_ctx *);
 
 int
 cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
@@ -281,9 +287,71 @@ usage:
 }
 
 enum cmd_retval
+run_hook_before(struct hooks *hooks, struct cmd *cmd, struct cmd_ctx *ctx)
+{
+       struct cmd_ctx   hook_ctx;
+       char            *hook_name;
+       enum cmd_retval  retval;
+
+       memcpy(&hook_ctx, ctx, sizeof hook_ctx);
+       hook_ctx.cmdclient = NULL;
+       xasprintf(&hook_name, "before-%s", cmd->entry->name);
+
+       retval = hooks_call(hooks, hook_name, &hook_ctx);
+       if (retval == CMD_RETURN_ERROR)
+               log_debug("Failed to run cmd hook (before) <<%s>>", hook_name);
+
+       free (hook_name);
+       return (retval);
+}
+
+enum cmd_retval
+run_hook_after(struct hooks *hooks, struct cmd *cmd, struct cmd_ctx *ctx)
+{
+       struct cmd_ctx   hook_ctx;
+       char            *hook_name;
+       enum cmd_retval  retval;
+
+       memcpy(&hook_ctx, ctx, sizeof hook_ctx);
+       hook_ctx.cmdclient = NULL;
+       xasprintf(&hook_name, "after-%s", cmd->entry->name);
+
+       retval = hooks_call(hooks, hook_name, &hook_ctx);
+       if (retval == CMD_RETURN_ERROR)
+               log_debug("Failed to run cmd hook (after) <<%s>>", hook_name);
+
+       free (hook_name);
+       return (retval);
+}
+
+enum cmd_retval
 cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
 {
-       return (cmd->entry->exec(cmd, ctx));
+       struct session  *s = NULL;
+       struct hooks    *hooks;
+       enum cmd_retval  retval, hooks_retval;
+
+       if (ctx->curclient != NULL)
+               s = ctx->curclient->session;
+
+       hooks = (s == NULL) ? &global_hooks : &s->hooks;
+
+       /* Call any hooks set to run before the intended command. */
+       hooks_retval = run_hook_before(hooks, cmd, ctx);
+       if (hooks_retval == CMD_RETURN_ERROR)
+               return (hooks_retval);
+
+       /* Call the intended command. */
+       if ((retval = cmd->entry->exec(cmd, ctx)) == CMD_RETURN_ERROR)
+               return (retval);
+
+       /* Call any hooks set to run after the intended command. */
+       hooks_retval = run_hook_after(hooks, cmd, ctx);
+       if (hooks_retval == CMD_RETURN_ERROR)
+               return (hooks_retval);
+
+       /* Return the result of the intended command. */
+       return (retval);
 }
 
 void
diff --git a/hooks.c b/hooks.c
new file mode 100644
index 0000000..e4f791c
--- /dev/null
+++ b/hooks.c
@@ -0,0 +1,114 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <tho...@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 <ctype.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+RB_GENERATE(hooks, hook, entry, hooks_cmp);
+
+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);
+
+       if (copy != NULL)
+               hooks_copy(copy, hooks);
+}
+
+void
+hooks_copy(struct hooks *src, struct hooks *dst)
+{
+       struct hook     *h;
+
+       RB_FOREACH(h, hooks, src)
+               hooks_add(dst, h->name, h->cmdlist);
+}
+
+void
+hooks_free(struct hooks *hooks)
+{
+       struct hook     *h, *h2;
+
+       RB_FOREACH_SAFE(h, hooks, hooks, h2)
+               hook_remove(hooks, h);
+}
+
+void
+hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
+{
+       struct hook     *h;
+
+       if ((h = hooks_find(hooks, (char *)name)) != NULL)
+               hook_remove(hooks, h);
+
+       h = xmalloc(sizeof *h);
+       h->name = xstrdup(name);
+       h->cmdlist = cmdlist;
+
+       RB_INSERT(hooks, hooks, h);
+}
+
+void
+hook_remove(struct hooks *hooks, struct hook *h)
+{
+       if (h == NULL)
+               return;
+
+       RB_REMOVE(hooks, hooks, h);
+       cmd_list_free(h->cmdlist);
+       free(h->name);
+       free(h);
+}
+
+struct hook *
+hooks_find(struct hooks *hooks, const char *name)
+{
+       struct hook      h;
+
+       if (name == NULL)
+               return (NULL);
+
+       h.name = (char *)name;
+
+       return (RB_FIND(hooks, hooks, &h));
+}
+
+enum cmd_retval
+hooks_call(struct hooks *hooks, const char *name, struct cmd_ctx *ctx)
+{
+       struct hook     *hook;
+
+       if ((hook = hooks_find(hooks, name)) != NULL) {
+               log_debug("Running hook '%s'", hook->name);
+
+               return (cmd_list_exec(hook->cmdlist, ctx));
+       }
+       return (CMD_RETURN_NORMAL);
+}
diff --git a/session.c b/session.c
index 1f4fb30..09b44c9 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 5a773f6..23ab8f7 100644
--- a/tmux.c
+++ b/tmux.c
@@ -37,6 +37,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;
 
@@ -318,6 +319,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 c37a024..34f9616 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1074,6 +1074,14 @@ struct environ_entry {
 };
 RB_HEAD(environ, environ_entry);
 
+/* Hooks. */
+struct hook {
+       char            *name;
+       struct cmd_list *cmdlist;
+       RB_ENTRY(hook)   entry;
+};
+RB_HEAD(hooks, hook);
+
 /* Client session. */
 struct session_group {
        TAILQ_HEAD(, session) sessions;
@@ -1098,6 +1106,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 */
@@ -1488,6 +1497,7 @@ ARRAY_DECL(causelist, char *);
 #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;
@@ -1532,6 +1542,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, 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            hook_remove(struct hooks *, struct hook *);
+struct hook    *hooks_find(struct hooks *, const char *);
+enum cmd_retval         hooks_call(struct hooks *, const char *, struct 
cmd_ctx *);
+
 /* mode-key.c */
 extern const struct mode_key_table mode_key_tables[];
 extern struct mode_key_tree mode_key_tree_vi_edit;
@@ -1804,10 +1825,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


------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to