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