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 <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 <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 <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 <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 <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 <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 tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users