mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Add a choose-client command and extend choose-{session,window} to accept a
template. After a choice is made, %% (or %1) in the template is replaced by the name of the session, window or client suitable for -t and the result executed as a command. So, for example, "choose-window "killw -t '%%'"" will kill the selected window. The defaults if no template is given are (as now) select-window for choose-window, switch-client for choose-session, and detach-client for choose-client (now bound to D).
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -25,7 +25,7 @@ SRCS=	attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ | |||||||
| 	cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ | 	cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ | ||||||
| 	cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ | 	cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ | ||||||
| 	cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ | 	cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ | ||||||
| 	cmd-set-environment.c cmd-show-environment.c \ | 	cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \ | ||||||
| 	cmd-up-pane.c cmd-display-message.c cmd.c \ | 	cmd-up-pane.c cmd-display-message.c cmd.c \ | ||||||
| 	colour.c environ.c grid-view.c grid.c input-keys.c \ | 	colour.c environ.c grid-view.c grid.c input-keys.c \ | ||||||
| 	imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ | 	imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \ | ||||||
|   | |||||||
							
								
								
									
										149
									
								
								cmd-choose-client.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								cmd-choose-client.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | |||||||
|  | /* $OpenBSD$ */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> | ||||||
|  |  * | ||||||
|  |  * 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 "tmux.h" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Enter choice mode to choose a client. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | int	cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); | ||||||
|  |  | ||||||
|  | void	cmd_choose_client_callback(void *, int); | ||||||
|  | void	cmd_choose_client_free(void *); | ||||||
|  |  | ||||||
|  | const struct cmd_entry cmd_choose_client_entry = { | ||||||
|  | 	"choose-client", NULL, | ||||||
|  | 	CMD_TARGET_WINDOW_USAGE " [template]", | ||||||
|  | 	CMD_ARG01, 0, | ||||||
|  | 	cmd_target_init, | ||||||
|  | 	cmd_target_parse, | ||||||
|  | 	cmd_choose_client_exec, | ||||||
|  | 	cmd_target_free, | ||||||
|  | 	cmd_target_print | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct cmd_choose_client_data { | ||||||
|  | 	u_int		 client; | ||||||
|  | 	char   		*template; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int | ||||||
|  | cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) | ||||||
|  | { | ||||||
|  | 	struct cmd_target_data		*data = self->data; | ||||||
|  | 	struct cmd_choose_client_data	*cdata; | ||||||
|  | 	struct winlink			*wl; | ||||||
|  | 	struct client			*c; | ||||||
|  | 	u_int			 	 i, idx, cur; | ||||||
|  |  | ||||||
|  | 	if (ctx->curclient == NULL) { | ||||||
|  | 		ctx->error(ctx, "must be run interactively"); | ||||||
|  | 		return (-1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | ||||||
|  | 		return (-1); | ||||||
|  |  | ||||||
|  | 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) | ||||||
|  | 		return (0); | ||||||
|  |  | ||||||
|  | 	cur = idx = 0; | ||||||
|  | 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) { | ||||||
|  | 		c = ARRAY_ITEM(&clients, i); | ||||||
|  | 		if (c == NULL || c->session == NULL) | ||||||
|  | 			continue; | ||||||
|  | 		if (c == ctx->curclient) | ||||||
|  | 			cur = idx; | ||||||
|  | 		idx++; | ||||||
|  |  | ||||||
|  | 		window_choose_add(wl->window->active, i, | ||||||
|  | 		    "%s: %s [%ux%u %s]%s", c->tty.path, | ||||||
|  | 		    c->session->name, c->tty.sx, c->tty.sy, | ||||||
|  | 		    c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : ""); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cdata = xmalloc(sizeof *cdata); | ||||||
|  | 	if (data->arg != NULL) | ||||||
|  | 		cdata->template = xstrdup(data->arg); | ||||||
|  | 	else | ||||||
|  | 		cdata->template = xstrdup("detach-client -t '%%'"); | ||||||
|  | 	cdata->client = server_client_index(ctx->curclient); | ||||||
|  |  | ||||||
|  | 	window_choose_ready(wl->window->active, | ||||||
|  | 	    cur, cmd_choose_client_callback, cmd_choose_client_free, cdata); | ||||||
|  |  | ||||||
|  | 	return (0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | cmd_choose_client_callback(void *data, int idx) | ||||||
|  | { | ||||||
|  | 	struct cmd_choose_client_data	*cdata = data; | ||||||
|  | 	struct client  			*c, *c2; | ||||||
|  | 	struct cmd_list			*cmdlist; | ||||||
|  | 	struct cmd_ctx			 ctx; | ||||||
|  | 	char				*template, *cause; | ||||||
|  |  | ||||||
|  | 	if (idx == -1) | ||||||
|  | 		return; | ||||||
|  | 	if (cdata->client > ARRAY_LENGTH(&clients) - 1) | ||||||
|  | 		return; | ||||||
|  | 	c = ARRAY_ITEM(&clients, cdata->client); | ||||||
|  |  | ||||||
|  | 	if ((u_int) idx > ARRAY_LENGTH(&clients) - 1) | ||||||
|  | 		return; | ||||||
|  | 	c2 = ARRAY_ITEM(&clients, idx); | ||||||
|  | 	if (c2 == NULL || c2->session == NULL) | ||||||
|  | 		return; | ||||||
|  | 	template = cmd_template_replace(cdata->template, c2->tty.path, 1); | ||||||
|  |  | ||||||
|  | 	if (cmd_string_parse(template, &cmdlist, &cause) != 0) { | ||||||
|  | 		if (cause != NULL) { | ||||||
|  | 			*cause = toupper((u_char) *cause); | ||||||
|  | 			status_message_set(c, "%s", cause); | ||||||
|  | 			xfree(cause); | ||||||
|  | 		} | ||||||
|  | 		xfree(template); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	xfree(template); | ||||||
|  |  | ||||||
|  | 	ctx.msgdata = NULL; | ||||||
|  | 	ctx.curclient = c; | ||||||
|  |  | ||||||
|  | 	ctx.error = key_bindings_error; | ||||||
|  | 	ctx.print = key_bindings_print; | ||||||
|  | 	ctx.info = key_bindings_info; | ||||||
|  |  | ||||||
|  | 	ctx.cmdclient = NULL; | ||||||
|  |  | ||||||
|  | 	cmd_list_exec(cmdlist, &ctx); | ||||||
|  | 	cmd_list_free(cmdlist); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | cmd_choose_client_free(void *data) | ||||||
|  | { | ||||||
|  | 	struct cmd_choose_client_data	*cdata = data; | ||||||
|  |  | ||||||
|  | 	xfree(cdata->template); | ||||||
|  | 	xfree(cdata); | ||||||
|  | } | ||||||
| @@ -27,11 +27,12 @@ | |||||||
| int	cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); | int	cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); | ||||||
|  |  | ||||||
| void	cmd_choose_session_callback(void *, int); | void	cmd_choose_session_callback(void *, int); | ||||||
|  | void	cmd_choose_session_free(void *); | ||||||
|  |  | ||||||
| const struct cmd_entry cmd_choose_session_entry = { | const struct cmd_entry cmd_choose_session_entry = { | ||||||
| 	"choose-session", NULL, | 	"choose-session", NULL, | ||||||
| 	CMD_TARGET_WINDOW_USAGE, | 	CMD_TARGET_WINDOW_USAGE " [template]", | ||||||
| 	0, 0, | 	CMD_ARG01, 0, | ||||||
| 	cmd_target_init, | 	cmd_target_init, | ||||||
| 	cmd_target_parse, | 	cmd_target_parse, | ||||||
| 	cmd_choose_session_exec, | 	cmd_choose_session_exec, | ||||||
| @@ -41,6 +42,7 @@ const struct cmd_entry cmd_choose_session_entry = { | |||||||
|  |  | ||||||
| struct cmd_choose_session_data { | struct cmd_choose_session_data { | ||||||
| 	u_int		 client; | 	u_int		 client; | ||||||
|  | 	char   		*template; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| int | int | ||||||
| @@ -79,10 +81,14 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cdata = xmalloc(sizeof *cdata); | 	cdata = xmalloc(sizeof *cdata); | ||||||
|  | 	if (data->arg != NULL) | ||||||
|  | 		cdata->template = xstrdup(data->arg); | ||||||
|  | 	else | ||||||
|  | 		cdata->template = xstrdup("switch-client -t '%%'"); | ||||||
| 	cdata->client = server_client_index(ctx->curclient); | 	cdata->client = server_client_index(ctx->curclient); | ||||||
|  |  | ||||||
| 	window_choose_ready( | 	window_choose_ready(wl->window->active, | ||||||
| 	    wl->window->active, cur, cmd_choose_session_callback, xfree, cdata); | 	    cur, cmd_choose_session_callback, cmd_choose_session_free, cdata); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
| @@ -92,13 +98,53 @@ cmd_choose_session_callback(void *data, int idx) | |||||||
| { | { | ||||||
| 	struct cmd_choose_session_data	*cdata = data; | 	struct cmd_choose_session_data	*cdata = data; | ||||||
| 	struct client  			*c; | 	struct client  			*c; | ||||||
|  | 	struct session			*s; | ||||||
|  | 	struct cmd_list			*cmdlist; | ||||||
|  | 	struct cmd_ctx			 ctx; | ||||||
|  | 	char				*template, *cause; | ||||||
|  |  | ||||||
| 	if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) { | 	if (idx == -1) | ||||||
|  | 		return; | ||||||
|  | 	if (cdata->client > ARRAY_LENGTH(&clients) - 1) | ||||||
|  | 		return; | ||||||
| 	c = ARRAY_ITEM(&clients, cdata->client); | 	c = ARRAY_ITEM(&clients, cdata->client); | ||||||
| 		if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) { |  | ||||||
| 			c->session = ARRAY_ITEM(&sessions, idx); | 	if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1) | ||||||
| 			recalculate_sizes(); | 		return; | ||||||
| 			server_redraw_client(c); | 	s = ARRAY_ITEM(&sessions, idx); | ||||||
|  | 	if (s == NULL) | ||||||
|  | 		return; | ||||||
|  | 	template = cmd_template_replace(cdata->template, s->name, 1); | ||||||
|  |  | ||||||
|  | 	if (cmd_string_parse(template, &cmdlist, &cause) != 0) { | ||||||
|  | 		if (cause != NULL) { | ||||||
|  | 			*cause = toupper((u_char) *cause); | ||||||
|  | 			status_message_set(c, "%s", cause); | ||||||
|  | 			xfree(cause); | ||||||
| 		} | 		} | ||||||
|  | 		xfree(template); | ||||||
|  | 		return; | ||||||
| 	} | 	} | ||||||
|  | 	xfree(template); | ||||||
|  |  | ||||||
|  | 	ctx.msgdata = NULL; | ||||||
|  | 	ctx.curclient = c; | ||||||
|  |  | ||||||
|  | 	ctx.error = key_bindings_error; | ||||||
|  | 	ctx.print = key_bindings_print; | ||||||
|  | 	ctx.info = key_bindings_info; | ||||||
|  |  | ||||||
|  | 	ctx.cmdclient = NULL; | ||||||
|  |  | ||||||
|  | 	cmd_list_exec(cmdlist, &ctx); | ||||||
|  | 	cmd_list_free(cmdlist); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | cmd_choose_session_free(void *data) | ||||||
|  | { | ||||||
|  | 	struct cmd_choose_session_data	*cdata = data; | ||||||
|  |  | ||||||
|  | 	xfree(cdata->template); | ||||||
|  | 	xfree(cdata); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,11 +27,12 @@ | |||||||
| int	cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); | int	cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); | ||||||
|  |  | ||||||
| void	cmd_choose_window_callback(void *, int); | void	cmd_choose_window_callback(void *, int); | ||||||
|  | void	cmd_choose_window_free(void *); | ||||||
|  |  | ||||||
| const struct cmd_entry cmd_choose_window_entry = { | const struct cmd_entry cmd_choose_window_entry = { | ||||||
| 	"choose-window", NULL, | 	"choose-window", NULL, | ||||||
| 	CMD_TARGET_WINDOW_USAGE, | 	CMD_TARGET_WINDOW_USAGE " [template]", | ||||||
| 	0, 0, | 	CMD_ARG01, 0, | ||||||
| 	cmd_target_init, | 	cmd_target_init, | ||||||
| 	cmd_target_parse, | 	cmd_target_parse, | ||||||
| 	cmd_choose_window_exec, | 	cmd_choose_window_exec, | ||||||
| @@ -40,7 +41,9 @@ const struct cmd_entry cmd_choose_window_entry = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| struct cmd_choose_window_data { | struct cmd_choose_window_data { | ||||||
|  | 	u_int		 client; | ||||||
| 	u_int		 session; | 	u_int		 session; | ||||||
|  | 	char   		*template; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| int | int | ||||||
| @@ -104,9 +107,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	cdata = xmalloc(sizeof *cdata); | 	cdata = xmalloc(sizeof *cdata); | ||||||
| 	if (session_index(s, &cdata->session) != 0) | 	if (session_index(s, &cdata->session) != 0) | ||||||
| 		fatalx("session not found"); | 		fatalx("session not found"); | ||||||
|  | 	if (data->arg != NULL) | ||||||
|  | 		cdata->template = xstrdup(data->arg); | ||||||
|  | 	else | ||||||
|  | 		cdata->template = xstrdup("select-window -t '%%'"); | ||||||
|  | 	cdata->client = server_client_index(ctx->curclient); | ||||||
|  |  | ||||||
| 	window_choose_ready( | 	window_choose_ready(wl->window->active,  | ||||||
| 	    wl->window->active, cur, cmd_choose_window_callback, xfree, cdata); | 	    cur, cmd_choose_window_callback, cmd_choose_window_free, cdata); | ||||||
|  |  | ||||||
|  	return (0); |  	return (0); | ||||||
| } | } | ||||||
| @@ -115,12 +123,56 @@ void | |||||||
| cmd_choose_window_callback(void *data, int idx) | cmd_choose_window_callback(void *data, int idx) | ||||||
| { | { | ||||||
| 	struct cmd_choose_window_data	*cdata = data; | 	struct cmd_choose_window_data	*cdata = data; | ||||||
|  | 	struct client			*c; | ||||||
| 	struct session			*s; | 	struct session			*s; | ||||||
|  | 	struct cmd_list			*cmdlist; | ||||||
|  | 	struct cmd_ctx			 ctx; | ||||||
|  | 	char				*target, *template, *cause; | ||||||
|  |  | ||||||
| 	if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { | 	if (idx == -1) | ||||||
|  | 		return; | ||||||
|  | 	if (cdata->client > ARRAY_LENGTH(&clients) - 1) | ||||||
|  | 		return; | ||||||
|  | 	c = ARRAY_ITEM(&clients, cdata->client); | ||||||
|  | 	if (cdata->session > ARRAY_LENGTH(&sessions) - 1) | ||||||
|  | 		return; | ||||||
| 	s = ARRAY_ITEM(&sessions, cdata->session); | 	s = ARRAY_ITEM(&sessions, cdata->session); | ||||||
| 		if (s != NULL && session_select(s, idx) == 0) | 	if (c->session != s) | ||||||
| 			server_redraw_session(s); | 		return; | ||||||
| 		recalculate_sizes(); |  | ||||||
|  | 	xasprintf(&target, "%s:%d", s->name, idx); | ||||||
|  | 	template = cmd_template_replace(cdata->template, target, 1); | ||||||
|  | 	xfree(target); | ||||||
|  |  | ||||||
|  | 	if (cmd_string_parse(template, &cmdlist, &cause) != 0) { | ||||||
|  | 		if (cause != NULL) { | ||||||
|  | 			*cause = toupper((u_char) *cause); | ||||||
|  | 			status_message_set(c, "%s", cause); | ||||||
|  | 			xfree(cause); | ||||||
| 		} | 		} | ||||||
|  | 		xfree(template); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	xfree(template); | ||||||
|  |  | ||||||
|  | 	ctx.msgdata = NULL; | ||||||
|  | 	ctx.curclient = c; | ||||||
|  |  | ||||||
|  | 	ctx.error = key_bindings_error; | ||||||
|  | 	ctx.print = key_bindings_print; | ||||||
|  | 	ctx.info = key_bindings_info; | ||||||
|  |  | ||||||
|  | 	ctx.cmdclient = NULL; | ||||||
|  |  | ||||||
|  | 	cmd_list_exec(cmdlist, &ctx); | ||||||
|  | 	cmd_list_free(cmdlist); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | cmd_choose_window_free(void *data) | ||||||
|  | { | ||||||
|  | 	struct cmd_choose_window_data	*cdata = data; | ||||||
|  |  | ||||||
|  | 	xfree(cdata->template); | ||||||
|  | 	xfree(cdata); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -35,7 +35,6 @@ size_t	 cmd_command_prompt_print(struct cmd *, char *, size_t); | |||||||
|  |  | ||||||
| int	 cmd_command_prompt_callback(void *, const char *); | int	 cmd_command_prompt_callback(void *, const char *); | ||||||
| void	 cmd_command_prompt_cfree(void *); | void	 cmd_command_prompt_cfree(void *); | ||||||
| char	*cmd_command_prompt_replace(char *, const char *, int); |  | ||||||
|  |  | ||||||
| const struct cmd_entry cmd_command_prompt_entry = { | const struct cmd_entry cmd_command_prompt_entry = { | ||||||
| 	"command-prompt", NULL, | 	"command-prompt", NULL, | ||||||
| @@ -216,7 +215,7 @@ cmd_command_prompt_callback(void *data, const char *s) | |||||||
| 	if (s == NULL) | 	if (s == NULL) | ||||||
| 		return (0); | 		return (0); | ||||||
|  |  | ||||||
| 	newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx); | 	newtempl = cmd_template_replace(cdata->template, s, cdata->idx); | ||||||
| 	xfree(cdata->template); | 	xfree(cdata->template); | ||||||
| 	cdata->template = newtempl; | 	cdata->template = newtempl; | ||||||
|  |  | ||||||
| @@ -265,43 +264,3 @@ cmd_command_prompt_cfree(void *data) | |||||||
| 		xfree(cdata->template); | 		xfree(cdata->template); | ||||||
| 	xfree(cdata); | 	xfree(cdata); | ||||||
| } | } | ||||||
|  |  | ||||||
| char * |  | ||||||
| cmd_command_prompt_replace(char *template, const char *s, int idx) |  | ||||||
| { |  | ||||||
| 	char	 ch; |  | ||||||
| 	char	*buf, *ptr; |  | ||||||
| 	int	 replaced; |  | ||||||
| 	size_t	 len; |  | ||||||
|  |  | ||||||
| 	if (strstr(template, "%") == NULL) |  | ||||||
| 		return (xstrdup(template)); |  | ||||||
|  |  | ||||||
| 	buf = xmalloc(1); |  | ||||||
| 	*buf = '\0'; |  | ||||||
| 	len = 0; |  | ||||||
| 	replaced = 0; |  | ||||||
|  |  | ||||||
| 	ptr = template; |  | ||||||
| 	while (*ptr != '\0') { |  | ||||||
| 		switch (ch = *ptr++) { |  | ||||||
| 		case '%': |  | ||||||
| 			if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) { |  | ||||||
| 				if (*ptr != '%' || replaced) |  | ||||||
| 					break; |  | ||||||
| 				replaced = 1; |  | ||||||
| 			} |  | ||||||
| 			ptr++; |  | ||||||
|  |  | ||||||
| 			len += strlen(s); |  | ||||||
| 			buf = xrealloc(buf, 1, len + 1); |  | ||||||
| 			strlcat(buf, s, len + 1); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 		buf = xrealloc(buf, 1, len + 2); |  | ||||||
| 		buf[len++] = ch; |  | ||||||
| 		buf[len] = '\0'; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return (buf); |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = { | |||||||
| 	&cmd_attach_session_entry, | 	&cmd_attach_session_entry, | ||||||
| 	&cmd_bind_key_entry, | 	&cmd_bind_key_entry, | ||||||
| 	&cmd_break_pane_entry, | 	&cmd_break_pane_entry, | ||||||
|  | 	&cmd_choose_client_entry, | ||||||
| 	&cmd_choose_session_entry, | 	&cmd_choose_session_entry, | ||||||
| 	&cmd_choose_window_entry, | 	&cmd_choose_window_entry, | ||||||
| 	&cmd_clear_history_entry, | 	&cmd_clear_history_entry, | ||||||
| @@ -858,3 +859,44 @@ error: | |||||||
| 	xfree(winptr); | 	xfree(winptr); | ||||||
| 	return (NULL); | 	return (NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Replace the first %% or %idx in template by s. */ | ||||||
|  | char * | ||||||
|  | cmd_template_replace(char *template, const char *s, int idx) | ||||||
|  | { | ||||||
|  | 	char	 ch; | ||||||
|  | 	char	*buf, *ptr; | ||||||
|  | 	int	 replaced; | ||||||
|  | 	size_t	 len; | ||||||
|  |  | ||||||
|  | 	if (strstr(template, "%") == NULL) | ||||||
|  | 		return (xstrdup(template)); | ||||||
|  |  | ||||||
|  | 	buf = xmalloc(1); | ||||||
|  | 	*buf = '\0'; | ||||||
|  | 	len = 0; | ||||||
|  | 	replaced = 0; | ||||||
|  |  | ||||||
|  | 	ptr = template; | ||||||
|  | 	while (*ptr != '\0') { | ||||||
|  | 		switch (ch = *ptr++) { | ||||||
|  | 		case '%': | ||||||
|  | 			if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) { | ||||||
|  | 				if (*ptr != '%' || replaced) | ||||||
|  | 					break; | ||||||
|  | 				replaced = 1; | ||||||
|  | 			} | ||||||
|  | 			ptr++; | ||||||
|  |  | ||||||
|  | 			len += strlen(s); | ||||||
|  | 			buf = xrealloc(buf, 1, len + 1); | ||||||
|  | 			strlcat(buf, s, len + 1); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		buf = xrealloc(buf, 1, len + 2); | ||||||
|  | 		buf[len++] = ch; | ||||||
|  | 		buf[len] = '\0'; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return (buf); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -130,6 +130,7 @@ key_bindings_init(void) | |||||||
| 		{ ']', 			  0, &cmd_paste_buffer_entry }, | 		{ ']', 			  0, &cmd_paste_buffer_entry }, | ||||||
| 		{ 'c', 			  0, &cmd_new_window_entry }, | 		{ 'c', 			  0, &cmd_new_window_entry }, | ||||||
| 		{ 'd', 			  0, &cmd_detach_client_entry }, | 		{ 'd', 			  0, &cmd_detach_client_entry }, | ||||||
|  | 		{ 'D',			  0, &cmd_choose_client_entry }, | ||||||
| 		{ 'f', 			  0, &cmd_command_prompt_entry }, | 		{ 'f', 			  0, &cmd_command_prompt_entry }, | ||||||
| 		{ 'i',			  0, &cmd_display_message_entry }, | 		{ 'i',			  0, &cmd_display_message_entry }, | ||||||
| 		{ 'l', 			  0, &cmd_last_window_entry }, | 		{ 'l', 			  0, &cmd_last_window_entry }, | ||||||
| @@ -143,7 +144,7 @@ key_bindings_init(void) | |||||||
| 		{ 'x', 			  0, &cmd_confirm_before_entry }, | 		{ 'x', 			  0, &cmd_confirm_before_entry }, | ||||||
| 		{ '{',			  0, &cmd_swap_pane_entry }, | 		{ '{',			  0, &cmd_swap_pane_entry }, | ||||||
| 		{ '}',			  0, &cmd_swap_pane_entry }, | 		{ '}',			  0, &cmd_swap_pane_entry }, | ||||||
| 		{ '\002', 		  0, &cmd_send_prefix_entry }, | 		{ '\002', /* C-b */	  0, &cmd_send_prefix_entry }, | ||||||
| 		{ '1' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | 		{ '1' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||||
| 		{ '2' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | 		{ '2' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||||
| 		{ '3' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | 		{ '3' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||||
| @@ -162,7 +163,7 @@ key_bindings_init(void) | |||||||
| 		{ KEYC_LEFT | KEYC_CTRL,  1, &cmd_resize_pane_entry }, | 		{ KEYC_LEFT | KEYC_CTRL,  1, &cmd_resize_pane_entry }, | ||||||
| 		{ KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, | 		{ KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, | ||||||
| 		{ 'o' | KEYC_ESCAPE,	  0, &cmd_rotate_window_entry }, | 		{ 'o' | KEYC_ESCAPE,	  0, &cmd_rotate_window_entry }, | ||||||
| 		{ '\017',	          0, &cmd_rotate_window_entry }, | 		{ '\017', /* C-o */	  0, &cmd_rotate_window_entry }, | ||||||
| 	}; | 	}; | ||||||
| 	u_int		 i; | 	u_int		 i; | ||||||
| 	struct cmd	*cmd; | 	struct cmd	*cmd; | ||||||
|   | |||||||
							
								
								
									
										55
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -622,14 +622,57 @@ off from its containing window to make it the only pane in a new window. | |||||||
| If | If | ||||||
| .Fl d | .Fl d | ||||||
| is given, the new window does not become the current window. | is given, the new window does not become the current window. | ||||||
| .It Ic choose-session Op Fl t Ar target-window | .It Xo | ||||||
| Put a window into session choice mode, where the session for the current | .Ic choose-client | ||||||
| client may be selected interactively from a list. | .Op Fl t Ar target-window | ||||||
|  | .Op Ar template | ||||||
|  | .Xc | ||||||
|  | Put a window into client choice mode, allowing a client to be selected | ||||||
|  | interactively from a list. | ||||||
|  | After a client is chosen, | ||||||
|  | .Ql %% | ||||||
|  | is replaced by the client | ||||||
|  | .Xr pty 4 | ||||||
|  | path in | ||||||
|  | .Ar template | ||||||
|  | and the result executed as a command. | ||||||
|  | If | ||||||
|  | .Ar template | ||||||
|  | is not given, "detach-client -t '%%'" is used. | ||||||
| This command works only from inside | This command works only from inside | ||||||
| .Nm . | .Nm . | ||||||
| .It Ic choose-window Op Fl t Ar target-window | .It Xo | ||||||
| Put a window into window choice mode, where the window for the session | .Ic choose-session | ||||||
| attached to the current client may be selected interactively from a list. | .Op Fl t Ar target-window | ||||||
|  | .Op Ar template | ||||||
|  | .Xc | ||||||
|  | Put a window into session choice mode, where a session may be selected | ||||||
|  | interactively from a list. | ||||||
|  | When one is chosen, | ||||||
|  | .Ql %% | ||||||
|  | is replaced by the session name in | ||||||
|  | .Ar template | ||||||
|  | and the result executed as a command. | ||||||
|  | If | ||||||
|  | .Ar template | ||||||
|  | is not given, "switch-client -t '%%'" is used. | ||||||
|  | This command works only from inside | ||||||
|  | .Nm . | ||||||
|  | .It Xo | ||||||
|  | .Ic choose-window | ||||||
|  | .Op Fl t Ar target-window | ||||||
|  | .Op Ar template | ||||||
|  | .Xc | ||||||
|  | Put a window into window choice mode, where a window may be chosen | ||||||
|  | interactively from a list. | ||||||
|  | After a window is selected, | ||||||
|  | .Ql %% | ||||||
|  | is replaced by the session name and window index in | ||||||
|  | .Ar template | ||||||
|  | and the result executed as a command. | ||||||
|  | If | ||||||
|  | .Ar template | ||||||
|  | is not given, "select-window -t '%%'" is used. | ||||||
| This command works only from inside | This command works only from inside | ||||||
| .Nm . | .Nm . | ||||||
| .It Ic down-pane Op Fl t Ar target-pane | .It Ic down-pane Op Fl t Ar target-pane | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1268,10 +1268,12 @@ int		 cmd_find_index( | |||||||
| 		     struct cmd_ctx *, const char *, struct session **); | 		     struct cmd_ctx *, const char *, struct session **); | ||||||
| struct winlink	*cmd_find_pane(struct cmd_ctx *, | struct winlink	*cmd_find_pane(struct cmd_ctx *, | ||||||
| 		     const char *, struct session **, struct window_pane **); | 		     const char *, struct session **, struct window_pane **); | ||||||
|  | char		*cmd_template_replace(char *, const char *, int); | ||||||
| extern const struct cmd_entry *cmd_table[]; | extern const struct cmd_entry *cmd_table[]; | ||||||
| extern const struct cmd_entry cmd_attach_session_entry; | extern const struct cmd_entry cmd_attach_session_entry; | ||||||
| extern const struct cmd_entry cmd_bind_key_entry; | extern const struct cmd_entry cmd_bind_key_entry; | ||||||
| extern const struct cmd_entry cmd_break_pane_entry; | extern const struct cmd_entry cmd_break_pane_entry; | ||||||
|  | extern const struct cmd_entry cmd_choose_client_entry; | ||||||
| extern const struct cmd_entry cmd_choose_session_entry; | extern const struct cmd_entry cmd_choose_session_entry; | ||||||
| extern const struct cmd_entry cmd_choose_window_entry; | extern const struct cmd_entry cmd_choose_window_entry; | ||||||
| extern const struct cmd_entry cmd_clear_history_entry; | extern const struct cmd_entry cmd_clear_history_entry; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott