cmd-split-window.c revision 1.37
1/* $OpenBSD: cmd-split-window.c,v 1.37 2012/12/09 23:17:35 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_ctx *);
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	NULL,
42	cmd_split_window_exec
43};
44
45void
46cmd_split_window_key_binding(struct cmd *self, int key)
47{
48	self->args = args_create(0);
49	if (key == '%')
50		args_set(self->args, 'h', NULL);
51}
52
53enum cmd_retval
54cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
55{
56	struct args		*args = self->args;
57	struct session		*s;
58	struct winlink		*wl;
59	struct window		*w;
60	struct window_pane	*wp, *new_wp = NULL;
61	struct environ		 env;
62	const char		*cmd, *cwd, *shell;
63	char			*cause, *new_cause;
64	u_int			 hlimit;
65	int			 size, percentage;
66	enum layout_type	 type;
67	struct layout_cell	*lc;
68	const char		*template;
69	struct client		*c;
70	struct format_tree	*ft;
71	char			*cp;
72
73	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
74		return (CMD_RETURN_ERROR);
75	w = wl->window;
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 = cmd_get_default_path(ctx, 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(ctx, NULL)) != 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		ctx->print(ctx, "%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	ctx->error(ctx, "create pane failed: %s", cause);
166	free(cause);
167	return (CMD_RETURN_ERROR);
168}
169