1*b0ba1202Snicm /* $OpenBSD: cmd-split-window.c,v 1.115 2025/01/27 09:05:22 nicm Exp $ */ 2311827fbSnicm 3311827fbSnicm /* 498ca8272Snicm * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5311827fbSnicm * 6311827fbSnicm * Permission to use, copy, modify, and distribute this software for any 7311827fbSnicm * purpose with or without fee is hereby granted, provided that the above 8311827fbSnicm * copyright notice and this permission notice appear in all copies. 9311827fbSnicm * 10311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17311827fbSnicm */ 18311827fbSnicm 19311827fbSnicm #include <sys/types.h> 20311827fbSnicm 21e1803d63Snicm #include <errno.h> 22e1803d63Snicm #include <fcntl.h> 233a5ec08bSnicm #include <paths.h> 24311827fbSnicm #include <stdlib.h> 25e1803d63Snicm #include <string.h> 26311827fbSnicm #include <unistd.h> 27311827fbSnicm 28311827fbSnicm #include "tmux.h" 29311827fbSnicm 30311827fbSnicm /* 31311827fbSnicm * Split a window (add a new pane). 32311827fbSnicm */ 33311827fbSnicm 341905ff33Snicm #define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" 351905ff33Snicm 3668e0a7f2Snicm static enum cmd_retval cmd_split_window_exec(struct cmd *, 3768e0a7f2Snicm struct cmdq_item *); 38311827fbSnicm 39311827fbSnicm const struct cmd_entry cmd_split_window_entry = { 40c057646bSnicm .name = "split-window", 41c057646bSnicm .alias = "splitw", 42c057646bSnicm 43a51dead1Snicm .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, 44baddd6b2Snicm .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " 45d8b32369Snicm "[-F format] [-l size] " CMD_TARGET_PANE_USAGE 46d8b32369Snicm " [shell-command]", 47c057646bSnicm 48bf0d297eSnicm .target = { 't', CMD_FIND_PANE, 0 }, 498d471e80Snicm 508d471e80Snicm .flags = 0, 51c057646bSnicm .exec = cmd_split_window_exec 52311827fbSnicm }; 53311827fbSnicm 54dc1f0f5fSnicm static enum cmd_retval 5568e0a7f2Snicm cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) 56311827fbSnicm { 5790d7ba38Snicm struct args *args = cmd_get_args(self); 58823b6d6dSnicm struct cmd_find_state *current = cmdq_get_current(item); 59040343aeSnicm struct cmd_find_state *target = cmdq_get_target(item); 601693b10bSnicm struct spawn_context sc = { 0 }; 61035dc73dSnicm struct client *tc = cmdq_get_target_client(item); 62040343aeSnicm struct session *s = target->s; 63040343aeSnicm struct winlink *wl = target->wl; 6479fb7095Snicm struct window *w = wl->window; 65040343aeSnicm struct window_pane *wp = target->wp, *new_wp; 66af9e4c5dSnicm enum layout_type type; 67572cd943Snicm struct layout_cell *lc; 6845436ca5Snicm struct cmd_find_state fs; 69113211eaSnicm int size, flags, input; 70113211eaSnicm const char *template; 71113211eaSnicm char *cause = NULL, *cp; 7205b80794Snicm struct args_value *av; 73113211eaSnicm u_int count = args_count(args), curval = 0; 74311827fbSnicm 75113211eaSnicm type = LAYOUT_TOPBOTTOM; 76ca7befccSnicm if (args_has(args, 'h')) 77af9e4c5dSnicm type = LAYOUT_LEFTRIGHT; 78113211eaSnicm 79113211eaSnicm /* If the 'p' flag is dropped then this bit can be moved into 'l'. */ 80113211eaSnicm if (args_has(args, 'l') || args_has(args, 'p')) { 8179fb7095Snicm if (args_has(args, 'f')) { 8279fb7095Snicm if (type == LAYOUT_TOPBOTTOM) 83113211eaSnicm curval = w->sy; 8479fb7095Snicm else 85113211eaSnicm curval = w->sx; 8679fb7095Snicm } else { 8728988ef6Snicm if (type == LAYOUT_TOPBOTTOM) 88113211eaSnicm curval = wp->sy; 8928988ef6Snicm else 90113211eaSnicm curval = wp->sx; 91ca7befccSnicm } 9228988ef6Snicm } 93113211eaSnicm 94c26c4f79Snicm size = -1; 95113211eaSnicm if (args_has(args, 'l')) { 96113211eaSnicm size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, 97113211eaSnicm item, &cause); 98113211eaSnicm } else if (args_has(args, 'p')) { 99e9310faaSnicm size = args_strtonum_and_expand(args, 'p', 0, 100, item, 100113211eaSnicm &cause); 101113211eaSnicm if (cause == NULL) 102113211eaSnicm size = curval * size / 100; 103113211eaSnicm } 104113211eaSnicm if (cause != NULL) { 105113211eaSnicm cmdq_error(item, "size %s", cause); 106113211eaSnicm free(cause); 107113211eaSnicm return (CMD_RETURN_ERROR); 108113211eaSnicm } 109c26c4f79Snicm 110baddd6b2Snicm window_push_zoom(wp->window, 1, args_has(args, 'Z')); 1111693b10bSnicm input = (args_has(args, 'I') && count == 0); 112c26c4f79Snicm 113c26c4f79Snicm flags = 0; 114c26c4f79Snicm if (args_has(args, 'b')) 115c26c4f79Snicm flags |= SPAWN_BEFORE; 116c26c4f79Snicm if (args_has(args, 'f')) 117c26c4f79Snicm flags |= SPAWN_FULLSIZE; 1181693b10bSnicm if (input || (count == 1 && *args_string(args, 0) == '\0')) 119aab3c1a6Snicm flags |= SPAWN_EMPTY; 120c26c4f79Snicm 121c26c4f79Snicm lc = layout_split_pane(wp, type, size, flags); 122c26c4f79Snicm if (lc == NULL) { 123c26c4f79Snicm cmdq_error(item, "no space for new pane"); 124c26c4f79Snicm return (CMD_RETURN_ERROR); 125c26c4f79Snicm } 126c26c4f79Snicm 127c26c4f79Snicm sc.item = item; 128c26c4f79Snicm sc.s = s; 129c26c4f79Snicm sc.wl = wl; 130c26c4f79Snicm 131c26c4f79Snicm sc.wp0 = wp; 132c26c4f79Snicm sc.lc = lc; 133c26c4f79Snicm 134d8b32369Snicm args_to_vector(args, &sc.argc, &sc.argv); 135d0772b58Snicm sc.environ = environ_create(); 136d0772b58Snicm 13705b80794Snicm av = args_first_value(args, 'e'); 13805b80794Snicm while (av != NULL) { 139825f884aSnicm environ_put(sc.environ, av->string, 0); 14005b80794Snicm av = args_next_value(av); 141d0772b58Snicm } 142c26c4f79Snicm 143c26c4f79Snicm sc.idx = -1; 144c26c4f79Snicm sc.cwd = args_get(args, 'c'); 145c26c4f79Snicm 146c26c4f79Snicm sc.flags = flags; 147c26c4f79Snicm if (args_has(args, 'd')) 148c26c4f79Snicm sc.flags |= SPAWN_DETACHED; 149baddd6b2Snicm if (args_has(args, 'Z')) 150baddd6b2Snicm sc.flags |= SPAWN_ZOOM; 151c26c4f79Snicm 152c26c4f79Snicm if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { 153c26c4f79Snicm cmdq_error(item, "create pane failed: %s", cause); 154c26c4f79Snicm free(cause); 1551693b10bSnicm if (sc.argv != NULL) 1561693b10bSnicm cmd_free_argv(sc.argc, sc.argv); 15705b80794Snicm environ_free(sc.environ); 158c26c4f79Snicm return (CMD_RETURN_ERROR); 159c26c4f79Snicm } 160d110efb0Snicm if (input) { 161d110efb0Snicm switch (window_pane_start_input(new_wp, item, &cause)) { 162d110efb0Snicm case -1: 163249e1654Snicm server_client_remove_pane(new_wp); 164aab3c1a6Snicm layout_close_pane(new_wp); 165aab3c1a6Snicm window_remove_pane(wp->window, new_wp); 166aab3c1a6Snicm cmdq_error(item, "%s", cause); 167aab3c1a6Snicm free(cause); 1681693b10bSnicm if (sc.argv != NULL) 1691693b10bSnicm cmd_free_argv(sc.argc, sc.argv); 17005b80794Snicm environ_free(sc.environ); 171aab3c1a6Snicm return (CMD_RETURN_ERROR); 172d110efb0Snicm case 1: 173d110efb0Snicm input = 0; 174d110efb0Snicm break; 175d110efb0Snicm } 176aab3c1a6Snicm } 177c26c4f79Snicm if (!args_has(args, 'd')) 178c26c4f79Snicm cmd_find_from_winlink_pane(current, wl, new_wp, 0); 179baddd6b2Snicm window_pop_zoom(wp->window); 180c26c4f79Snicm server_redraw_window(wp->window); 181311827fbSnicm server_status_session(s); 182311827fbSnicm 183ca7befccSnicm if (args_has(args, 'P')) { 184cc9e5b00Snicm if ((template = args_get(args, 'F')) == NULL) 18561e1d212Snicm template = SPLIT_WINDOW_TEMPLATE; 186035dc73dSnicm cp = format_single(item, template, tc, s, wl, new_wp); 18768e0a7f2Snicm cmdq_print(item, "%s", cp); 1887d053cf9Snicm free(cp); 1892c3a3119Snicm } 190e1803d63Snicm 1910772530eSnicm cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); 192844b9093Snicm cmdq_insert_hook(s, item, &fs, "after-split-window"); 193765b9a58Snicm 1941693b10bSnicm if (sc.argv != NULL) 1951693b10bSnicm cmd_free_argv(sc.argc, sc.argv); 196d0772b58Snicm environ_free(sc.environ); 197aab3c1a6Snicm if (input) 198aab3c1a6Snicm return (CMD_RETURN_WAIT); 199a224d0d3Snicm return (CMD_RETURN_NORMAL); 200311827fbSnicm } 201