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