cmd-split-window.c revision 1.17
1/* $OpenBSD: cmd-split-window.c,v 1.17 2010/01/07 19:47:10 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
31int	cmd_split_window_parse(struct cmd *, int, char **, char **);
32int	cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
33void	cmd_split_window_free(struct cmd *);
34void	cmd_split_window_init(struct cmd *, int);
35size_t	cmd_split_window_print(struct cmd *, char *, size_t);
36
37struct cmd_split_window_data {
38	char	*target;
39	char	*cmd;
40	int	 flag_detached;
41	int	 flag_horizontal;
42	int	 percentage;
43	int	 size;
44};
45
46const struct cmd_entry cmd_split_window_entry = {
47	"split-window", "splitw",
48	"[-dhv] [-p percentage|-l size] [-t target-pane] [command]",
49	0, "",
50	cmd_split_window_init,
51	cmd_split_window_parse,
52	cmd_split_window_exec,
53	cmd_split_window_free,
54	cmd_split_window_print
55};
56
57void
58cmd_split_window_init(struct cmd *self, int key)
59{
60	struct cmd_split_window_data	 *data;
61
62	self->data = data = xmalloc(sizeof *data);
63	data->target = NULL;
64	data->cmd = NULL;
65	data->flag_detached = 0;
66	data->flag_horizontal = 0;
67	data->percentage = -1;
68	data->size = -1;
69
70	switch (key) {
71	case '%':
72		data->flag_horizontal = 1;
73		break;
74	case '"':
75		data->flag_horizontal = 0;
76		break;
77	}
78}
79
80int
81cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause)
82{
83	struct cmd_split_window_data	*data;
84	int				 opt;
85	const char			*errstr;
86
87	self->entry->init(self, KEYC_NONE);
88	data = self->data;
89
90	while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) {
91		switch (opt) {
92		case 'd':
93			data->flag_detached = 1;
94			break;
95		case 'h':
96			data->flag_horizontal = 1;
97			break;
98		case 't':
99			if (data->target == NULL)
100				data->target = xstrdup(optarg);
101			break;
102		case 'l':
103			if (data->percentage != -1 || data->size != -1)
104				break;
105			data->size = strtonum(optarg, 1, INT_MAX, &errstr);
106			if (errstr != NULL) {
107				xasprintf(cause, "size %s", errstr);
108				goto error;
109			}
110			break;
111		case 'p':
112			if (data->size != -1 || data->percentage != -1)
113				break;
114			data->percentage = strtonum(optarg, 1, 100, &errstr);
115			if (errstr != NULL) {
116				xasprintf(cause, "percentage %s", errstr);
117				goto error;
118			}
119			break;
120		case 'v':
121			data->flag_horizontal = 0;
122			break;
123		default:
124			goto usage;
125		}
126	}
127	argc -= optind;
128	argv += optind;
129	if (argc != 0 && argc != 1)
130		goto usage;
131
132	if (argc == 1)
133		data->cmd = xstrdup(argv[0]);
134
135	return (0);
136
137usage:
138	xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
139
140error:
141	self->entry->free(self);
142	return (-1);
143}
144
145int
146cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
147{
148	struct cmd_split_window_data	*data = self->data;
149	struct session			*s;
150	struct winlink			*wl;
151	struct window			*w;
152	struct window_pane		*wp, *new_wp;
153	struct environ			 env;
154	char		 		*cmd, *cwd, *cause;
155	const char			*shell;
156	u_int				 hlimit;
157	int				 size;
158	enum layout_type		 type;
159
160	if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL)
161		return (-1);
162	w = wl->window;
163
164	environ_init(&env);
165	environ_copy(&global_environ, &env);
166	environ_copy(&s->environ, &env);
167	server_fill_environ(s, &env);
168
169	cmd = data->cmd;
170	if (cmd == NULL)
171		cmd = options_get_string(&s->options, "default-command");
172	if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
173		cwd = options_get_string(&s->options, "default-path");
174	else
175		cwd = ctx->cmdclient->cwd;
176
177	type = LAYOUT_TOPBOTTOM;
178	if (data->flag_horizontal)
179		type = LAYOUT_LEFTRIGHT;
180
181	size = -1;
182	if (data->size != -1)
183		size = data->size;
184	else if (data->percentage != -1) {
185		if (type == LAYOUT_TOPBOTTOM)
186			size = (w->active->sy * data->percentage) / 100;
187		else
188			size = (w->active->sx * data->percentage) / 100;
189	}
190	hlimit = options_get_number(&s->options, "history-limit");
191
192	shell = options_get_string(&s->options, "default-shell");
193	if (*shell == '\0' || areshell(shell))
194		shell = _PATH_BSHELL;
195
196	new_wp = window_add_pane(w, hlimit);
197	if (window_pane_spawn(new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
198		goto error;
199	if (layout_split_pane(wp, type, size, new_wp) != 0) {
200		cause = xstrdup("pane too small");
201		goto error;
202	}
203
204	server_redraw_window(w);
205
206	if (!data->flag_detached) {
207		window_set_active_pane(w, new_wp);
208		session_select(s, wl->idx);
209		server_redraw_session(s);
210	} else
211		server_status_session(s);
212
213	environ_free(&env);
214	return (0);
215
216error:
217	environ_free(&env);
218	if (new_wp != NULL)
219		window_remove_pane(w, new_wp);
220	ctx->error(ctx, "create pane failed: %s", cause);
221	xfree(cause);
222	return (-1);
223}
224
225void
226cmd_split_window_free(struct cmd *self)
227{
228	struct cmd_split_window_data	*data = self->data;
229
230	if (data->target != NULL)
231		xfree(data->target);
232	if (data->cmd != NULL)
233		xfree(data->cmd);
234	xfree(data);
235}
236
237size_t
238cmd_split_window_print(struct cmd *self, char *buf, size_t len)
239{
240	struct cmd_split_window_data	*data = self->data;
241	size_t				 off = 0;
242
243	off += xsnprintf(buf, len, "%s", self->entry->name);
244	if (data == NULL)
245		return (off);
246	if (off < len && data->flag_detached)
247		off += xsnprintf(buf + off, len - off, " -d");
248	if (off < len && data->flag_horizontal)
249		off += xsnprintf(buf + off, len - off, " -h");
250	if (off < len && data->size > 0)
251		off += xsnprintf(buf + off, len - off, " -l %d", data->size);
252	if (off < len && data->percentage > 0) {
253		off += xsnprintf(
254		    buf + off, len - off, " -p %d", data->percentage);
255	}
256	if (off < len && data->target != NULL)
257		off += cmd_prarg(buf + off, len - off, " -t ", data->target);
258	if (off < len && data->cmd != NULL)
259		off += cmd_prarg(buf + off, len - off, " ", data->cmd);
260	return (off);
261}
262