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