Home | History | Annotate | Line # | Download | only in dist
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