xref: /minix3/external/bsd/tmux/dist/cmd-split-window.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* Id */
2eda6f593SDavid van Moolenbroek 
3eda6f593SDavid van Moolenbroek /*
4eda6f593SDavid van Moolenbroek  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5eda6f593SDavid van Moolenbroek  *
6eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9eda6f593SDavid van Moolenbroek  *
10eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eda6f593SDavid van Moolenbroek  */
18eda6f593SDavid van Moolenbroek 
19eda6f593SDavid van Moolenbroek #include <sys/types.h>
20eda6f593SDavid van Moolenbroek 
21*0a6a1f1dSLionel Sambuc #include <errno.h>
22*0a6a1f1dSLionel Sambuc #include <fcntl.h>
23eda6f593SDavid van Moolenbroek #include <stdlib.h>
24*0a6a1f1dSLionel Sambuc #include <string.h>
25eda6f593SDavid van Moolenbroek #include <unistd.h>
26eda6f593SDavid van Moolenbroek 
27eda6f593SDavid van Moolenbroek #include "tmux.h"
28eda6f593SDavid van Moolenbroek 
29eda6f593SDavid van Moolenbroek /*
30eda6f593SDavid van Moolenbroek  * Split a window (add a new pane).
31eda6f593SDavid van Moolenbroek  */
32eda6f593SDavid van Moolenbroek 
33eda6f593SDavid van Moolenbroek void		 cmd_split_window_key_binding(struct cmd *, int);
34*0a6a1f1dSLionel Sambuc enum cmd_retval	 cmd_split_window_exec(struct cmd *, struct cmd_q *);
35eda6f593SDavid van Moolenbroek 
36eda6f593SDavid van Moolenbroek const struct cmd_entry cmd_split_window_entry = {
37eda6f593SDavid van Moolenbroek 	"split-window", "splitw",
38*0a6a1f1dSLionel Sambuc 	"c:dF:l:hp:Pt:v", 0, 1,
39*0a6a1f1dSLionel Sambuc 	"[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
40*0a6a1f1dSLionel Sambuc 	CMD_TARGET_PANE_USAGE " [command]",
41eda6f593SDavid van Moolenbroek 	0,
42eda6f593SDavid van Moolenbroek 	cmd_split_window_key_binding,
43eda6f593SDavid van Moolenbroek 	cmd_split_window_exec
44eda6f593SDavid van Moolenbroek };
45eda6f593SDavid van Moolenbroek 
46eda6f593SDavid van Moolenbroek void
cmd_split_window_key_binding(struct cmd * self,int key)47eda6f593SDavid van Moolenbroek cmd_split_window_key_binding(struct cmd *self, int key)
48eda6f593SDavid van Moolenbroek {
49eda6f593SDavid van Moolenbroek 	self->args = args_create(0);
50eda6f593SDavid van Moolenbroek 	if (key == '%')
51eda6f593SDavid van Moolenbroek 		args_set(self->args, 'h', NULL);
52eda6f593SDavid van Moolenbroek }
53eda6f593SDavid van Moolenbroek 
54*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_split_window_exec(struct cmd * self,struct cmd_q * cmdq)55*0a6a1f1dSLionel Sambuc cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
56eda6f593SDavid van Moolenbroek {
57eda6f593SDavid van Moolenbroek 	struct args		*args = self->args;
58eda6f593SDavid van Moolenbroek 	struct session		*s;
59eda6f593SDavid van Moolenbroek 	struct winlink		*wl;
60eda6f593SDavid van Moolenbroek 	struct window		*w;
61eda6f593SDavid van Moolenbroek 	struct window_pane	*wp, *new_wp = NULL;
62eda6f593SDavid van Moolenbroek 	struct environ		 env;
63*0a6a1f1dSLionel Sambuc 	const char		*cmd, *shell, *template;
64*0a6a1f1dSLionel Sambuc 	char			*cause, *new_cause, *cp;
65*0a6a1f1dSLionel Sambuc 	u_int			 hlimit;
66*0a6a1f1dSLionel Sambuc 	int			 size, percentage, cwd, fd = -1;
67eda6f593SDavid van Moolenbroek 	enum layout_type	 type;
68eda6f593SDavid van Moolenbroek 	struct layout_cell	*lc;
69*0a6a1f1dSLionel Sambuc 	struct client		*c;
70*0a6a1f1dSLionel Sambuc 	struct format_tree	*ft;
71eda6f593SDavid van Moolenbroek 
72*0a6a1f1dSLionel Sambuc 	if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
73*0a6a1f1dSLionel Sambuc 		return (CMD_RETURN_ERROR);
74eda6f593SDavid van Moolenbroek 	w = wl->window;
75*0a6a1f1dSLionel Sambuc 	server_unzoom_window(w);
76eda6f593SDavid van Moolenbroek 
77eda6f593SDavid van Moolenbroek 	environ_init(&env);
78eda6f593SDavid van Moolenbroek 	environ_copy(&global_environ, &env);
79eda6f593SDavid van Moolenbroek 	environ_copy(&s->environ, &env);
80eda6f593SDavid van Moolenbroek 	server_fill_environ(s, &env);
81eda6f593SDavid van Moolenbroek 
82eda6f593SDavid van Moolenbroek 	if (args->argc == 0)
83eda6f593SDavid van Moolenbroek 		cmd = options_get_string(&s->options, "default-command");
84eda6f593SDavid van Moolenbroek 	else
85eda6f593SDavid van Moolenbroek 		cmd = args->argv[0];
86*0a6a1f1dSLionel Sambuc 
87*0a6a1f1dSLionel Sambuc 	if (args_has(args, 'c')) {
88*0a6a1f1dSLionel Sambuc 		ft = format_create();
89*0a6a1f1dSLionel Sambuc 		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
90*0a6a1f1dSLionel Sambuc 			format_client(ft, c);
91*0a6a1f1dSLionel Sambuc 		format_session(ft, s);
92*0a6a1f1dSLionel Sambuc 		format_winlink(ft, s, s->curw);
93*0a6a1f1dSLionel Sambuc 		format_window_pane(ft, s->curw->window->active);
94*0a6a1f1dSLionel Sambuc 		cp = format_expand(ft, args_get(args, 'c'));
95*0a6a1f1dSLionel Sambuc 		format_free(ft);
96*0a6a1f1dSLionel Sambuc 
97*0a6a1f1dSLionel Sambuc 		if (cp != NULL && *cp != '\0') {
98*0a6a1f1dSLionel Sambuc 			fd = open(cp, O_RDONLY|O_DIRECTORY);
99*0a6a1f1dSLionel Sambuc 			free(cp);
100*0a6a1f1dSLionel Sambuc 			if (fd == -1) {
101*0a6a1f1dSLionel Sambuc 				cmdq_error(cmdq, "bad working directory: %s",
102*0a6a1f1dSLionel Sambuc 				    strerror(errno));
103*0a6a1f1dSLionel Sambuc 				return (CMD_RETURN_ERROR);
104*0a6a1f1dSLionel Sambuc 			}
105*0a6a1f1dSLionel Sambuc 		} else if (cp != NULL)
106*0a6a1f1dSLionel Sambuc 			free(cp);
107*0a6a1f1dSLionel Sambuc 		cwd = fd;
108*0a6a1f1dSLionel Sambuc 	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
109*0a6a1f1dSLionel Sambuc 		cwd = cmdq->client->cwd;
110eda6f593SDavid van Moolenbroek 	else
111eda6f593SDavid van Moolenbroek 		cwd = s->cwd;
112eda6f593SDavid van Moolenbroek 
113eda6f593SDavid van Moolenbroek 	type = LAYOUT_TOPBOTTOM;
114eda6f593SDavid van Moolenbroek 	if (args_has(args, 'h'))
115eda6f593SDavid van Moolenbroek 		type = LAYOUT_LEFTRIGHT;
116eda6f593SDavid van Moolenbroek 
117eda6f593SDavid van Moolenbroek 	size = -1;
118eda6f593SDavid van Moolenbroek 	if (args_has(args, 'l')) {
119eda6f593SDavid van Moolenbroek 		size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
120eda6f593SDavid van Moolenbroek 		if (cause != NULL) {
121*0a6a1f1dSLionel Sambuc 			xasprintf(&new_cause, "size %s", cause);
122*0a6a1f1dSLionel Sambuc 			free(cause);
123*0a6a1f1dSLionel Sambuc 			cause = new_cause;
124*0a6a1f1dSLionel Sambuc 			goto error;
125eda6f593SDavid van Moolenbroek 		}
126eda6f593SDavid van Moolenbroek 	} else if (args_has(args, 'p')) {
127eda6f593SDavid van Moolenbroek 		percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
128eda6f593SDavid van Moolenbroek 		if (cause != NULL) {
129*0a6a1f1dSLionel Sambuc 			xasprintf(&new_cause, "percentage %s", cause);
130*0a6a1f1dSLionel Sambuc 			free(cause);
131*0a6a1f1dSLionel Sambuc 			cause = new_cause;
132*0a6a1f1dSLionel Sambuc 			goto error;
133eda6f593SDavid van Moolenbroek 		}
134eda6f593SDavid van Moolenbroek 		if (type == LAYOUT_TOPBOTTOM)
135eda6f593SDavid van Moolenbroek 			size = (wp->sy * percentage) / 100;
136eda6f593SDavid van Moolenbroek 		else
137eda6f593SDavid van Moolenbroek 			size = (wp->sx * percentage) / 100;
138eda6f593SDavid van Moolenbroek 	}
139eda6f593SDavid van Moolenbroek 	hlimit = options_get_number(&s->options, "history-limit");
140eda6f593SDavid van Moolenbroek 
141eda6f593SDavid van Moolenbroek 	shell = options_get_string(&s->options, "default-shell");
142eda6f593SDavid van Moolenbroek 	if (*shell == '\0' || areshell(shell))
143eda6f593SDavid van Moolenbroek 		shell = _PATH_BSHELL;
144eda6f593SDavid van Moolenbroek 
145*0a6a1f1dSLionel Sambuc 	if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) {
146eda6f593SDavid van Moolenbroek 		cause = xstrdup("pane too small");
147eda6f593SDavid van Moolenbroek 		goto error;
148eda6f593SDavid van Moolenbroek 	}
149eda6f593SDavid van Moolenbroek 	new_wp = window_add_pane(w, hlimit);
150eda6f593SDavid van Moolenbroek 	if (window_pane_spawn(
151eda6f593SDavid van Moolenbroek 	    new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
152eda6f593SDavid van Moolenbroek 		goto error;
153eda6f593SDavid van Moolenbroek 	layout_assign_pane(lc, new_wp);
154eda6f593SDavid van Moolenbroek 
155eda6f593SDavid van Moolenbroek 	server_redraw_window(w);
156eda6f593SDavid van Moolenbroek 
157eda6f593SDavid van Moolenbroek 	if (!args_has(args, 'd')) {
158eda6f593SDavid van Moolenbroek 		window_set_active_pane(w, new_wp);
159eda6f593SDavid van Moolenbroek 		session_select(s, wl->idx);
160eda6f593SDavid van Moolenbroek 		server_redraw_session(s);
161eda6f593SDavid van Moolenbroek 	} else
162eda6f593SDavid van Moolenbroek 		server_status_session(s);
163eda6f593SDavid van Moolenbroek 
164eda6f593SDavid van Moolenbroek 	environ_free(&env);
165eda6f593SDavid van Moolenbroek 
166eda6f593SDavid van Moolenbroek 	if (args_has(args, 'P')) {
167*0a6a1f1dSLionel Sambuc 		if ((template = args_get(args, 'F')) == NULL)
168*0a6a1f1dSLionel Sambuc 			template = SPLIT_WINDOW_TEMPLATE;
169*0a6a1f1dSLionel Sambuc 
170*0a6a1f1dSLionel Sambuc 		ft = format_create();
171*0a6a1f1dSLionel Sambuc 		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
172*0a6a1f1dSLionel Sambuc 			format_client(ft, c);
173*0a6a1f1dSLionel Sambuc 		format_session(ft, s);
174*0a6a1f1dSLionel Sambuc 		format_winlink(ft, s, wl);
175*0a6a1f1dSLionel Sambuc 		format_window_pane(ft, new_wp);
176*0a6a1f1dSLionel Sambuc 
177*0a6a1f1dSLionel Sambuc 		cp = format_expand(ft, template);
178*0a6a1f1dSLionel Sambuc 		cmdq_print(cmdq, "%s", cp);
179*0a6a1f1dSLionel Sambuc 		free(cp);
180*0a6a1f1dSLionel Sambuc 
181*0a6a1f1dSLionel Sambuc 		format_free(ft);
182eda6f593SDavid van Moolenbroek 	}
183*0a6a1f1dSLionel Sambuc 	notify_window_layout_changed(w);
184*0a6a1f1dSLionel Sambuc 
185*0a6a1f1dSLionel Sambuc 	if (fd != -1)
186*0a6a1f1dSLionel Sambuc 		close(fd);
187*0a6a1f1dSLionel Sambuc 	return (CMD_RETURN_NORMAL);
188eda6f593SDavid van Moolenbroek 
189eda6f593SDavid van Moolenbroek error:
190eda6f593SDavid van Moolenbroek 	environ_free(&env);
191eda6f593SDavid van Moolenbroek 	if (new_wp != NULL)
192eda6f593SDavid van Moolenbroek 		window_remove_pane(w, new_wp);
193*0a6a1f1dSLionel Sambuc 	cmdq_error(cmdq, "create pane failed: %s", cause);
194*0a6a1f1dSLionel Sambuc 	free(cause);
195*0a6a1f1dSLionel Sambuc 	if (fd != -1)
196*0a6a1f1dSLionel Sambuc 		close(fd);
197*0a6a1f1dSLionel Sambuc 	return (CMD_RETURN_ERROR);
198eda6f593SDavid van Moolenbroek }
199