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