1 /* $Id: cmd-split-window.c,v 1.1.1.1 2011/03/10 09:15:37 jmmv 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 <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