When removing a pane, don't change the active pane unless the active
[tmux-openbsd.git] / cmd-split-window.c
blobe4f46c34e8ce4969819eb5aee845ab3ad993c107
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <paths.h>
22 #include <stdlib.h>
23 #include <unistd.h>
25 #include "tmux.h"
28 * Split a window (add a new pane).
31 int cmd_split_window_parse(struct cmd *, int, char **, char **);
32 int cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
33 void cmd_split_window_free(struct cmd *);
34 void cmd_split_window_init(struct cmd *, int);
35 size_t cmd_split_window_print(struct cmd *, char *, size_t);
37 struct cmd_split_window_data {
38 char *target;
39 char *cmd;
40 int flag_detached;
41 int flag_horizontal;
42 int percentage;
43 int size;
46 const 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
57 void
58 cmd_split_window_init(struct cmd *self, int key)
60 struct cmd_split_window_data *data;
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;
70 switch (key) {
71 case '%':
72 data->flag_horizontal = 1;
73 break;
74 case '"':
75 data->flag_horizontal = 0;
76 break;
80 int
81 cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause)
83 struct cmd_split_window_data *data;
84 int opt;
85 const char *errstr;
87 self->entry->init(self, KEYC_NONE);
88 data = self->data;
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;
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;
119 break;
120 case 'v':
121 data->flag_horizontal = 0;
122 break;
123 default:
124 goto usage;
127 argc -= optind;
128 argv += optind;
129 if (argc != 0 && argc != 1)
130 goto usage;
132 if (argc == 1)
133 data->cmd = xstrdup(argv[0]);
135 return (0);
137 usage:
138 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
140 error:
141 self->entry->free(self);
142 return (-1);
146 cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
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 = NULL;
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 struct layout_cell *lc;
161 if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL)
162 return (-1);
163 w = wl->window;
165 environ_init(&env);
166 environ_copy(&global_environ, &env);
167 environ_copy(&s->environ, &env);
168 server_fill_environ(s, &env);
170 cmd = data->cmd;
171 if (cmd == NULL)
172 cmd = options_get_string(&s->options, "default-command");
173 cwd = options_get_string(&s->options, "default-path");
174 if (*cwd == '\0') {
175 if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
176 cwd = ctx->cmdclient->cwd;
177 else
178 cwd = s->cwd;
181 type = LAYOUT_TOPBOTTOM;
182 if (data->flag_horizontal)
183 type = LAYOUT_LEFTRIGHT;
185 size = -1;
186 if (data->size != -1)
187 size = data->size;
188 else if (data->percentage != -1) {
189 if (type == LAYOUT_TOPBOTTOM)
190 size = (wp->sy * data->percentage) / 100;
191 else
192 size = (wp->sx * data->percentage) / 100;
194 hlimit = options_get_number(&s->options, "history-limit");
196 shell = options_get_string(&s->options, "default-shell");
197 if (*shell == '\0' || areshell(shell))
198 shell = _PATH_BSHELL;
200 if ((lc = layout_split_pane(wp, type, size)) == NULL) {
201 cause = xstrdup("pane too small");
202 goto error;
204 new_wp = window_add_pane(w, hlimit);
205 if (window_pane_spawn(
206 new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
207 goto error;
208 layout_assign_pane(lc, new_wp);
210 server_redraw_window(w);
212 if (!data->flag_detached) {
213 window_set_active_pane(w, new_wp);
214 session_select(s, wl->idx);
215 server_redraw_session(s);
216 } else
217 server_status_session(s);
219 environ_free(&env);
220 return (0);
222 error:
223 environ_free(&env);
224 if (new_wp != NULL)
225 window_remove_pane(w, new_wp);
226 ctx->error(ctx, "create pane failed: %s", cause);
227 xfree(cause);
228 return (-1);
231 void
232 cmd_split_window_free(struct cmd *self)
234 struct cmd_split_window_data *data = self->data;
236 if (data->target != NULL)
237 xfree(data->target);
238 if (data->cmd != NULL)
239 xfree(data->cmd);
240 xfree(data);
243 size_t
244 cmd_split_window_print(struct cmd *self, char *buf, size_t len)
246 struct cmd_split_window_data *data = self->data;
247 size_t off = 0;
249 off += xsnprintf(buf, len, "%s", self->entry->name);
250 if (data == NULL)
251 return (off);
252 if (off < len && data->flag_detached)
253 off += xsnprintf(buf + off, len - off, " -d");
254 if (off < len && data->flag_horizontal)
255 off += xsnprintf(buf + off, len - off, " -h");
256 if (off < len && data->size > 0)
257 off += xsnprintf(buf + off, len - off, " -l %d", data->size);
258 if (off < len && data->percentage > 0) {
259 off += xsnprintf(
260 buf + off, len - off, " -p %d", data->percentage);
262 if (off < len && data->target != NULL)
263 off += cmd_prarg(buf + off, len - off, " -t ", data->target);
264 if (off < len && data->cmd != NULL)
265 off += cmd_prarg(buf + off, len - off, " ", data->cmd);
266 return (off);