Home | History | Annotate | Line # | Download | only in dist
cmd-split-window.c revision 1.12.2.1
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      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 static enum cmd_retval	cmd_split_window_exec(struct cmd *,
     36 			    struct cmdq_item *);
     37 
     38 const struct cmd_entry cmd_split_window_entry = {
     39 	.name = "split-window",
     40 	.alias = "splitw",
     41 
     42 	.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
     43 	.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
     44 		 "[-F format] [-l size] " CMD_TARGET_PANE_USAGE
     45 		 "[shell-command]",
     46 
     47 	.target = { 't', CMD_FIND_PANE, 0 },
     48 
     49 	.flags = 0,
     50 	.exec = cmd_split_window_exec
     51 };
     52 
     53 static enum cmd_retval
     54 cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
     55 {
     56 	struct args		*args = cmd_get_args(self);
     57 	struct cmd_find_state	*current = cmdq_get_current(item);
     58 	struct cmd_find_state	*target = cmdq_get_target(item);
     59 	struct spawn_context	 sc = { 0 };
     60 	struct client		*tc = cmdq_get_target_client(item);
     61 	struct session		*s = target->s;
     62 	struct winlink		*wl = target->wl;
     63 	struct window		*w = wl->window;
     64 	struct window_pane	*wp = target->wp, *new_wp;
     65 	enum layout_type	 type;
     66 	struct layout_cell	*lc;
     67 	struct cmd_find_state	 fs;
     68 	int			 size, flags, input;
     69 	const char		*template;
     70 	char			*cause = NULL, *cp;
     71 	struct args_value	*av;
     72 	u_int			 count = args_count(args), curval = 0;
     73 
     74 	type = LAYOUT_TOPBOTTOM;
     75 	if (args_has(args, 'h'))
     76 		type = LAYOUT_LEFTRIGHT;
     77 
     78 	/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
     79 	if (args_has(args, 'l') || args_has(args, 'p')) {
     80 		if (args_has(args, 'f')) {
     81 			if (type == LAYOUT_TOPBOTTOM)
     82 				curval = w->sy;
     83 			else
     84 				curval = w->sx;
     85 		} else {
     86 			if (type == LAYOUT_TOPBOTTOM)
     87 				curval = wp->sy;
     88 			else
     89 				curval = wp->sx;
     90 		}
     91 	}
     92 
     93 	size = -1;
     94 	if (args_has(args, 'l')) {
     95 		size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
     96 		    item, &cause);
     97 	} else if (args_has(args, 'p')) {
     98 		size = args_strtonum_and_expand(args, 'p', 0, 100, item,
     99 		    &cause);
    100 		if (cause == NULL)
    101 			size = curval * size / 100;
    102 	}
    103 	if (cause != NULL) {
    104 		cmdq_error(item, "size %s", cause);
    105 		free(cause);
    106 		return (CMD_RETURN_ERROR);
    107 	}
    108 
    109 	window_push_zoom(wp->window, 1, args_has(args, 'Z'));
    110 	input = (args_has(args, 'I') && count == 0);
    111 
    112 	flags = 0;
    113 	if (args_has(args, 'b'))
    114 		flags |= SPAWN_BEFORE;
    115 	if (args_has(args, 'f'))
    116 		flags |= SPAWN_FULLSIZE;
    117 	if (input || (count == 1 && *args_string(args, 0) == '\0'))
    118 		flags |= SPAWN_EMPTY;
    119 
    120 	lc = layout_split_pane(wp, type, size, flags);
    121 	if (lc == NULL) {
    122 		cmdq_error(item, "no space for new pane");
    123 		return (CMD_RETURN_ERROR);
    124 	}
    125 
    126 	sc.item = item;
    127 	sc.s = s;
    128 	sc.wl = wl;
    129 
    130 	sc.wp0 = wp;
    131 	sc.lc = lc;
    132 
    133 	args_to_vector(args, &sc.argc, &sc.argv);
    134 	sc.environ = environ_create();
    135 
    136 	av = args_first_value(args, 'e');
    137 	while (av != NULL) {
    138 		environ_put(sc.environ, av->string, 0);
    139 		av = args_next_value(av);
    140 	}
    141 
    142 	sc.idx = -1;
    143 	sc.cwd = args_get(args, 'c');
    144 
    145 	sc.flags = flags;
    146 	if (args_has(args, 'd'))
    147 		sc.flags |= SPAWN_DETACHED;
    148 	if (args_has(args, 'Z'))
    149 		sc.flags |= SPAWN_ZOOM;
    150 
    151 	if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
    152 		cmdq_error(item, "create pane failed: %s", cause);
    153 		free(cause);
    154 		if (sc.argv != NULL)
    155 			cmd_free_argv(sc.argc, sc.argv);
    156 		environ_free(sc.environ);
    157 		return (CMD_RETURN_ERROR);
    158 	}
    159 	if (input) {
    160 		switch (window_pane_start_input(new_wp, item, &cause)) {
    161 		case -1:
    162 			server_client_remove_pane(new_wp);
    163 			layout_close_pane(new_wp);
    164 			window_remove_pane(wp->window, new_wp);
    165 			cmdq_error(item, "%s", cause);
    166 			free(cause);
    167 			if (sc.argv != NULL)
    168 				cmd_free_argv(sc.argc, sc.argv);
    169 			environ_free(sc.environ);
    170 			return (CMD_RETURN_ERROR);
    171 		case 1:
    172 			input = 0;
    173 			break;
    174 		}
    175 	}
    176 	if (!args_has(args, 'd'))
    177 		cmd_find_from_winlink_pane(current, wl, new_wp, 0);
    178 	window_pop_zoom(wp->window);
    179 	server_redraw_window(wp->window);
    180 	server_status_session(s);
    181 
    182 	if (args_has(args, 'P')) {
    183 		if ((template = args_get(args, 'F')) == NULL)
    184 			template = SPLIT_WINDOW_TEMPLATE;
    185 		cp = format_single(item, template, tc, s, wl, new_wp);
    186 		cmdq_print(item, "%s", cp);
    187 		free(cp);
    188 	}
    189 
    190 	cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
    191 	cmdq_insert_hook(s, item, &fs, "after-split-window");
    192 
    193 	if (sc.argv != NULL)
    194 		cmd_free_argv(sc.argc, sc.argv);
    195 	environ_free(sc.environ);
    196 	if (input)
    197 		return (CMD_RETURN_WAIT);
    198 	return (CMD_RETURN_NORMAL);
    199 }
    200