cmd-split-window.c revision 1.66
1/* $OpenBSD: cmd-split-window.c,v 1.66 2015/12/13 21:53:57 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 <errno.h> 22#include <fcntl.h> 23#include <paths.h> 24#include <stdlib.h> 25#include <string.h> 26#include <unistd.h> 27 28#include "tmux.h" 29 30/* 31 * Split a window (add a new pane). 32 */ 33 34#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" 35 36enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); 37 38const struct cmd_entry cmd_split_window_entry = { 39 .name = "split-window", 40 .alias = "splitw", 41 42 .args = { "bc:dF:l:hp:Pt:v", 0, -1 }, 43 .usage = "[-bdhvP] [-c start-directory] [-F format] " 44 "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", 45 46 .flags = CMD_PANE_T, 47 .exec = cmd_split_window_exec 48}; 49 50enum cmd_retval 51cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) 52{ 53 struct args *args = self->args; 54 struct session *s = cmdq->state.tflag.s; 55 struct winlink *wl = cmdq->state.tflag.wl; 56 struct window *w = wl->window; 57 struct window_pane *wp = cmdq->state.tflag.wp, *new_wp = NULL; 58 struct environ *env; 59 const char *cmd, *path, *shell, *template, *cwd, *to_free; 60 char **argv, *cause, *new_cause, *cp; 61 u_int hlimit; 62 int argc, size, percentage; 63 enum layout_type type; 64 struct layout_cell *lc; 65 struct format_tree *ft; 66 struct environ_entry *envent; 67 68 server_unzoom_window(w); 69 70 env = environ_create(); 71 environ_copy(global_environ, env); 72 environ_copy(s->environ, env); 73 server_fill_environ(s, env); 74 75 if (args->argc == 0) { 76 cmd = options_get_string(s->options, "default-command"); 77 if (cmd != NULL && *cmd != '\0') { 78 argc = 1; 79 argv = (char **)&cmd; 80 } else { 81 argc = 0; 82 argv = NULL; 83 } 84 } else { 85 argc = args->argc; 86 argv = args->argv; 87 } 88 89 to_free = NULL; 90 if (args_has(args, 'c')) { 91 ft = format_create(cmdq, 0); 92 format_defaults(ft, cmdq->state.c, s, NULL, NULL); 93 to_free = cwd = format_expand(ft, args_get(args, 'c')); 94 format_free(ft); 95 } else if (cmdq->client != NULL && cmdq->client->session == NULL) 96 cwd = cmdq->client->cwd; 97 else 98 cwd = s->cwd; 99 100 type = LAYOUT_TOPBOTTOM; 101 if (args_has(args, 'h')) 102 type = LAYOUT_LEFTRIGHT; 103 104 size = -1; 105 if (args_has(args, 'l')) { 106 size = args_strtonum(args, 'l', 0, INT_MAX, &cause); 107 if (cause != NULL) { 108 xasprintf(&new_cause, "size %s", cause); 109 free(cause); 110 cause = new_cause; 111 goto error; 112 } 113 } else if (args_has(args, 'p')) { 114 percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); 115 if (cause != NULL) { 116 xasprintf(&new_cause, "percentage %s", cause); 117 free(cause); 118 cause = new_cause; 119 goto error; 120 } 121 if (type == LAYOUT_TOPBOTTOM) 122 size = (wp->sy * percentage) / 100; 123 else 124 size = (wp->sx * percentage) / 100; 125 } 126 hlimit = options_get_number(s->options, "history-limit"); 127 128 shell = options_get_string(s->options, "default-shell"); 129 if (*shell == '\0' || areshell(shell)) 130 shell = _PATH_BSHELL; 131 132 lc = layout_split_pane(wp, type, size, args_has(args, 'b')); 133 if (lc == NULL) { 134 cause = xstrdup("pane too small"); 135 goto error; 136 } 137 new_wp = window_add_pane(w, hlimit); 138 layout_assign_pane(lc, new_wp); 139 140 path = NULL; 141 if (cmdq->client != NULL && cmdq->client->session == NULL) 142 envent = environ_find(cmdq->client->environ, "PATH"); 143 else 144 envent = environ_find(s->environ, "PATH"); 145 if (envent != NULL) 146 path = envent->value; 147 148 if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env, 149 s->tio, &cause) != 0) 150 goto error; 151 152 server_redraw_window(w); 153 154 if (!args_has(args, 'd')) { 155 window_set_active_pane(w, new_wp); 156 session_select(s, wl->idx); 157 server_redraw_session(s); 158 } else 159 server_status_session(s); 160 161 environ_free(env); 162 163 if (args_has(args, 'P')) { 164 if ((template = args_get(args, 'F')) == NULL) 165 template = SPLIT_WINDOW_TEMPLATE; 166 167 ft = format_create(cmdq, 0); 168 format_defaults(ft, cmdq->state.c, s, wl, new_wp); 169 170 cp = format_expand(ft, template); 171 cmdq_print(cmdq, "%s", cp); 172 free(cp); 173 174 format_free(ft); 175 } 176 notify_window_layout_changed(w); 177 178 if (to_free != NULL) 179 free((void *)to_free); 180 return (CMD_RETURN_NORMAL); 181 182error: 183 environ_free(env); 184 if (new_wp != NULL) { 185 layout_close_pane(new_wp); 186 window_remove_pane(w, new_wp); 187 } 188 cmdq_error(cmdq, "create pane failed: %s", cause); 189 free(cause); 190 191 if (to_free != NULL) 192 free((void *)to_free); 193 return (CMD_RETURN_ERROR); 194} 195