mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Merge branch 'obsd-master'
This commit is contained in:
		@@ -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 \
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								cmd-queue.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										133
									
								
								cmd-set-hook.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								cmd-set-hook.c
									
									
									
									
									
								
							@@ -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);
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -202,13 +218,25 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
 | 
			
		||||
	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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -174,7 +174,10 @@ cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
 | 
			
		||||
	int		  argc;
 | 
			
		||||
	char		**argv;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										173
									
								
								hooks.c
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								hooks.c
									
									
									
									
									
								
							@@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								notify.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								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)
 | 
			
		||||
{
 | 
			
		||||
	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 hook		*hook;
 | 
			
		||||
	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);
 | 
			
		||||
	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", ne->name);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
		notify_hook_formats(new_item, s, w, ne->pane);
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								options.c
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								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) {
 | 
			
		||||
		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);
 | 
			
		||||
		} else
 | 
			
		||||
			options_array_assign(o, oe->default_str);
 | 
			
		||||
			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 *
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								tmux.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								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 *);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user