15494e770Schristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4f26e8bc9Schristos * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 21928fc495Schristos #include <errno.h> 22928fc495Schristos #include <fcntl.h> 23698d5317Sjmmv #include <stdlib.h> 24928fc495Schristos #include <string.h> 25698d5317Sjmmv #include <unistd.h> 26698d5317Sjmmv 27698d5317Sjmmv #include "tmux.h" 28698d5317Sjmmv 29698d5317Sjmmv /* 30698d5317Sjmmv * Split a window (add a new pane). 31698d5317Sjmmv */ 32698d5317Sjmmv 335494e770Schristos #define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" 345494e770Schristos 35e9a2d6faSchristos static enum cmd_retval cmd_split_window_exec(struct cmd *, 36e9a2d6faSchristos struct cmdq_item *); 37698d5317Sjmmv 38698d5317Sjmmv const struct cmd_entry cmd_split_window_entry = { 39f26e8bc9Schristos .name = "split-window", 40f26e8bc9Schristos .alias = "splitw", 41f26e8bc9Schristos 4246548964Swiz .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, 43e271dbb8Schristos .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " 4446548964Swiz "[-F format] [-l size] " CMD_TARGET_PANE_USAGE 4546548964Swiz "[shell-command]", 46f26e8bc9Schristos 47fe99a117Schristos .target = { 't', CMD_FIND_PANE, 0 }, 48f26e8bc9Schristos 49f26e8bc9Schristos .flags = 0, 50f26e8bc9Schristos .exec = cmd_split_window_exec 51698d5317Sjmmv }; 52698d5317Sjmmv 53e9a2d6faSchristos static enum cmd_retval 54e9a2d6faSchristos cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) 55698d5317Sjmmv { 56e271dbb8Schristos struct args *args = cmd_get_args(self); 57e271dbb8Schristos struct cmd_find_state *current = cmdq_get_current(item); 58e271dbb8Schristos struct cmd_find_state *target = cmdq_get_target(item); 5946548964Swiz struct spawn_context sc = { 0 }; 60e271dbb8Schristos struct client *tc = cmdq_get_target_client(item); 61e271dbb8Schristos struct session *s = target->s; 62e271dbb8Schristos struct winlink *wl = target->wl; 6346548964Swiz struct window *w = wl->window; 64e271dbb8Schristos struct window_pane *wp = target->wp, *new_wp; 65698d5317Sjmmv enum layout_type type; 66698d5317Sjmmv struct layout_cell *lc; 67e9a2d6faSchristos struct cmd_find_state fs; 68f844e94eSwiz int size, flags, input; 69f844e94eSwiz const char *template; 70f844e94eSwiz char *cause = NULL, *cp; 7146548964Swiz struct args_value *av; 72f844e94eSwiz u_int count = args_count(args), curval = 0; 73698d5317Sjmmv 74f844e94eSwiz type = LAYOUT_TOPBOTTOM; 75d530c4d0Sjmmv if (args_has(args, 'h')) 76698d5317Sjmmv type = LAYOUT_LEFTRIGHT; 77f844e94eSwiz 78f844e94eSwiz /* If the 'p' flag is dropped then this bit can be moved into 'l'. */ 79f844e94eSwiz if (args_has(args, 'l') || args_has(args, 'p')) { 8046548964Swiz if (args_has(args, 'f')) { 8146548964Swiz if (type == LAYOUT_TOPBOTTOM) 82f844e94eSwiz curval = w->sy; 8346548964Swiz else 84f844e94eSwiz curval = w->sx; 8546548964Swiz } else { 8668e6ba84Schristos if (type == LAYOUT_TOPBOTTOM) 87f844e94eSwiz curval = wp->sy; 8868e6ba84Schristos else 89f844e94eSwiz curval = wp->sx; 90d530c4d0Sjmmv } 9168e6ba84Schristos } 92f844e94eSwiz 9330744affSchristos size = -1; 94f844e94eSwiz if (args_has(args, 'l')) { 95f844e94eSwiz size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, 96f844e94eSwiz item, &cause); 97f844e94eSwiz } else if (args_has(args, 'p')) { 98*890b6d91Swiz size = args_strtonum_and_expand(args, 'p', 0, 100, item, 99f844e94eSwiz &cause); 100f844e94eSwiz if (cause == NULL) 101f844e94eSwiz size = curval * size / 100; 102f844e94eSwiz } 103f844e94eSwiz if (cause != NULL) { 104f844e94eSwiz cmdq_error(item, "size %s", cause); 105f844e94eSwiz free(cause); 106f844e94eSwiz return (CMD_RETURN_ERROR); 107f844e94eSwiz } 10830744affSchristos 109e271dbb8Schristos window_push_zoom(wp->window, 1, args_has(args, 'Z')); 11046548964Swiz input = (args_has(args, 'I') && count == 0); 11130744affSchristos 11230744affSchristos flags = 0; 11330744affSchristos if (args_has(args, 'b')) 11430744affSchristos flags |= SPAWN_BEFORE; 11530744affSchristos if (args_has(args, 'f')) 11630744affSchristos flags |= SPAWN_FULLSIZE; 11746548964Swiz if (input || (count == 1 && *args_string(args, 0) == '\0')) 11830744affSchristos flags |= SPAWN_EMPTY; 11930744affSchristos 12030744affSchristos lc = layout_split_pane(wp, type, size, flags); 12130744affSchristos if (lc == NULL) { 12230744affSchristos cmdq_error(item, "no space for new pane"); 12330744affSchristos return (CMD_RETURN_ERROR); 12430744affSchristos } 12530744affSchristos 12630744affSchristos sc.item = item; 12730744affSchristos sc.s = s; 12830744affSchristos sc.wl = wl; 12930744affSchristos 13030744affSchristos sc.wp0 = wp; 13130744affSchristos sc.lc = lc; 13230744affSchristos 13346548964Swiz args_to_vector(args, &sc.argc, &sc.argv); 13430744affSchristos sc.environ = environ_create(); 13530744affSchristos 13646548964Swiz av = args_first_value(args, 'e'); 13746548964Swiz while (av != NULL) { 13846548964Swiz environ_put(sc.environ, av->string, 0); 13946548964Swiz av = args_next_value(av); 14030744affSchristos } 14130744affSchristos 14230744affSchristos sc.idx = -1; 14330744affSchristos sc.cwd = args_get(args, 'c'); 14430744affSchristos 14530744affSchristos sc.flags = flags; 14630744affSchristos if (args_has(args, 'd')) 14730744affSchristos sc.flags |= SPAWN_DETACHED; 148e271dbb8Schristos if (args_has(args, 'Z')) 149e271dbb8Schristos sc.flags |= SPAWN_ZOOM; 15030744affSchristos 15130744affSchristos if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { 15230744affSchristos cmdq_error(item, "create pane failed: %s", cause); 15330744affSchristos free(cause); 15446548964Swiz if (sc.argv != NULL) 15546548964Swiz cmd_free_argv(sc.argc, sc.argv); 15646548964Swiz environ_free(sc.environ); 15730744affSchristos return (CMD_RETURN_ERROR); 15830744affSchristos } 15946548964Swiz if (input) { 16046548964Swiz switch (window_pane_start_input(new_wp, item, &cause)) { 16146548964Swiz case -1: 162e271dbb8Schristos server_client_remove_pane(new_wp); 16330744affSchristos layout_close_pane(new_wp); 16430744affSchristos window_remove_pane(wp->window, new_wp); 16530744affSchristos cmdq_error(item, "%s", cause); 16630744affSchristos free(cause); 16746548964Swiz if (sc.argv != NULL) 16846548964Swiz cmd_free_argv(sc.argc, sc.argv); 16946548964Swiz environ_free(sc.environ); 17030744affSchristos return (CMD_RETURN_ERROR); 17146548964Swiz case 1: 17246548964Swiz input = 0; 17346548964Swiz break; 17446548964Swiz } 17530744affSchristos } 17630744affSchristos if (!args_has(args, 'd')) 17730744affSchristos cmd_find_from_winlink_pane(current, wl, new_wp, 0); 178e271dbb8Schristos window_pop_zoom(wp->window); 17930744affSchristos server_redraw_window(wp->window); 180698d5317Sjmmv server_status_session(s); 181698d5317Sjmmv 182d530c4d0Sjmmv if (args_has(args, 'P')) { 183928fc495Schristos if ((template = args_get(args, 'F')) == NULL) 184928fc495Schristos template = SPLIT_WINDOW_TEMPLATE; 185e271dbb8Schristos cp = format_single(item, template, tc, s, wl, new_wp); 186e9a2d6faSchristos cmdq_print(item, "%s", cp); 187928fc495Schristos free(cp); 188d530c4d0Sjmmv } 189928fc495Schristos 190fe99a117Schristos cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); 19130744affSchristos cmdq_insert_hook(s, item, &fs, "after-split-window"); 192e9a2d6faSchristos 19346548964Swiz if (sc.argv != NULL) 19446548964Swiz cmd_free_argv(sc.argc, sc.argv); 19530744affSchristos environ_free(sc.environ); 19630744affSchristos if (input) 19730744affSchristos return (CMD_RETURN_WAIT); 198928fc495Schristos return (CMD_RETURN_NORMAL); 199698d5317Sjmmv } 200