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