Define a structure for holding hook information, as well as set/show hook commands. --- Makefile.am | 3 ++ cmd-set-hook.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ cmd-show-hooks.c | 62 ++++++++++++++++++++++++++++++ cmd.c | 2 + hooks.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ session.c | 2 + tmux.c | 2 + tmux.h | 27 ++++++++++++++ 8 files changed, 305 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 071c3a1..7739f24 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,8 +118,10 @@ 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-hooks.c \ cmd-show-messages.c \ cmd-show-options.c \ cmd-source-file.c \ @@ -139,6 +141,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..75aebb9 --- /dev/null +++ b/cmd-set-hook.c @@ -0,0 +1,95 @@ +/* $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" + +/* + * Set a global or session hook. + */ + +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, + "gt:u", 1, 2, + "[-gu]" CMD_TARGET_SESSION_USAGE " hook-name [command]", + CMD_PREPARESESSION, + cmd_set_hook_exec, + NULL +}; + +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 *name, *cmd; + + s = cmdq->state.s; + if (s == NULL || args_has(args, 'g')) + hooks = &global_hooks; + else + hooks = &s->hooks; + + name = args->argv[0]; + if (*name == '\0') { + cmdq_error(cmdq, "invalid hook name"); + return (CMD_RETURN_ERROR); + } + if (args->argc < 2) + cmd = NULL; + else + cmd = args->argv[1]; + + if (args_has(args, 'u')) { + if (cmd != NULL) { + cmdq_error(cmdq, "command passed to unset hook: %s", + name); + return (CMD_RETURN_ERROR); + } + if ((hook = hooks_find(hooks, name)) != NULL) + hooks_remove(hooks, hook); + return (CMD_RETURN_NORMAL); + } + + if (cmd == NULL) { + cmdq_error(cmdq, "no command to set hook: %s", name); + return (CMD_RETURN_ERROR); + } + if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { + if (cause != NULL) { + cmdq_error(cmdq, "%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-show-hooks.c b/cmd-show-hooks.c new file mode 100644 index 0000000..4babd76 --- /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 <stdlib.h> +#include <string.h> + +#include "tmux.h" + +/* + * Show global or session hooks. + */ + +enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_q *); + +const struct cmd_entry cmd_show_hooks_entry = { + "show-hooks", NULL, + "gt:", 0, 1, + "[-g] " CMD_TARGET_SESSION_USAGE, + CMD_PREPARESESSION, + cmd_show_hooks_exec, + NULL +}; + +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->state.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/cmd.c b/cmd.c index 66716bd..205b241 100644 --- a/cmd.c +++ b/cmd.c @@ -95,10 +95,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, diff --git a/hooks.c b/hooks.c new file mode 100644 index 0000000..c41a5e3 --- /dev/null +++ b/hooks.c @@ -0,0 +1,112 @@ +/* $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 *parent) +{ + RB_INIT(&hooks->tree); + hooks->parent = parent; +} + +void +hooks_free(struct hooks *hooks) +{ + struct hook *hook, *hook1; + + RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1) + hooks_remove(hooks, 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_remove(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, struct hook *hook) +{ + RB_REMOVE(hooks_tree, &hooks->tree, hook); + cmd_list_free(hook->cmdlist); + free((char *) hook->name); + free(hook); +} + +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_run(struct hook *hook, struct cmd_q *cmdq) +{ + struct cmd *cmd; + + TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry) { + cmd_prepare(cmd, cmdq); + /* TA: FIXME: How do we handle errors here, if at all??? */ + cmd->entry->exec(cmd, cmdq); + } +} diff --git a/session.c b/session.c index 3ac9fb2..4453164 100644 --- a/session.c +++ b/session.c @@ -105,6 +105,7 @@ session_create(const char *name, int argc, char **argv, const char *path, 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) @@ -163,6 +164,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 5a1988e..36ca7a8 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; @@ -289,6 +290,7 @@ main(int argc, char **argv) flags |= CLIENT_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 ab191c6..ba79969 100644 --- a/tmux.h +++ b/tmux.h @@ -1027,6 +1027,18 @@ struct environ_entry { }; RB_HEAD(environ, environ_entry); +/* Hooks. */ +struct hook { + const 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; @@ -1052,6 +1064,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 */ @@ -1503,6 +1516,7 @@ struct options_table_entry { #define CMD_BUFFER_USAGE "[-b buffer-name]" /* tmux.c */ +extern struct hooks global_hooks; extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; @@ -1551,6 +1565,17 @@ void format_window_pane(struct format_tree *, void format_paste_buffer(struct format_tree *, struct paste_buffer *, int); +/* 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; @@ -1828,10 +1853,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; -- 2.1.4 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users