From 950194fb636e575fc0f3cbbe46a9c26006f61014 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Mon, 6 Apr 2026 20:10:15 -0700 Subject: [PATCH 1/8] Migrated cmd-split-window.c into cmd-new-pane.c for code reuse. --- Makefile.am | 1 - cmd-new-pane.c | 292 +++++++++++++++++++++++++++++++++------------ cmd-split-window.c | 204 ------------------------------- 3 files changed, 216 insertions(+), 281 deletions(-) delete mode 100644 cmd-split-window.c diff --git a/Makefile.am b/Makefile.am index a956035e..c22a9dab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -145,7 +145,6 @@ dist_tmux_SOURCES = \ cmd-show-options.c \ cmd-show-prompt-history.c \ cmd-source-file.c \ - cmd-split-window.c \ cmd-swap-pane.c \ cmd-tile-float-pane.c \ cmd-swap-window.c \ diff --git a/cmd-new-pane.c b/cmd-new-pane.c index 82a600e2..6db42f2a 100644 --- a/cmd-new-pane.c +++ b/cmd-new-pane.c @@ -26,16 +26,19 @@ #include "tmux.h" +/* + * Split a window (add a new pane). + */ + #define NEW_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" -static enum cmd_retval cmd_new_pane_exec(struct cmd *, - struct cmdq_item *); +static enum cmd_retval cmd_new_pane_exec(struct cmd *, struct cmdq_item *); const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:fF:h:Iklm:p:PR:s:S:t:w:x:y:Z", 0, -1, NULL }, + .args = { "bc:de:fF:h:Iklm:p:PR:s:S:t:T:w:x:y:Z", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-l size] [-m message] " "[-R inactive-border-style] [-s style] [-S active-border-style] " @@ -47,26 +50,45 @@ const struct cmd_entry cmd_new_pane_entry = { .exec = cmd_new_pane_exec }; +const struct cmd_entry cmd_split_window_entry = { + .name = "split-window", + .alias = "splitw", -static enum cmd_retval -cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) + .args = { "bc:de:fF:hIl:p:Pt:T:vZ", 0, -1, NULL }, + .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " + "[-F format] [-l size] " CMD_TARGET_PANE_USAGE + " [shell-command [argument ...]]", + + .target = { 't', CMD_FIND_PANE, 0 }, + + .flags = 0, + .exec = cmd_new_pane_exec +}; + +enum new_pane_type { + FLOATING, + TILED, + NONE, +}; + +static enum new_pane_type +cmd_new_pane_get_type(const char* val) { - struct args *args = cmd_get_args(self); - struct cmd_find_state *current = cmdq_get_current(item); - struct cmd_find_state *target = cmdq_get_target(item); - struct spawn_context sc = { 0 }; - struct client *tc = cmdq_get_target_client(item); - struct session *s = target->s; - struct winlink *wl = target->wl; - struct window *w = wl->window; - struct window_pane *wp = target->wp, *new_wp; - struct layout_cell *lc; - struct cmd_find_state fs; - int flags, input; - const char *template, *style; - char *cause = NULL, *cp; - struct args_value *av; - u_int count = args_count(args); + if (strncmp(val, "floating", (sizeof "floating") - 1) == 0 || + strncmp(val, "f", (sizeof "f") - 1) == 0) + return FLOATING; + if (strncmp(val, "tiled", (sizeof "tiled") - 1) == 0 || + strncmp(val, "t", (sizeof "t") - 1) == 0) + return TILED; + return NONE; +} + +static struct layout_cell * +cmd_new_pane_get_float_layout_cell(struct cmdq_item *item, struct args *args, + struct window *w) +{ + struct layout_cell *lc = NULL; + char *cause = NULL; int x, y; u_int sx, sy, pct; static int last_x = 0, last_y = 0; @@ -94,7 +116,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); - return (CMD_RETURN_ERROR); + return (NULL); } } if (args_has(args, 'w')) { @@ -103,7 +125,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); - return (CMD_RETURN_ERROR); + return (NULL); } } if (args_has(args, 'h')) { @@ -112,7 +134,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); - return (CMD_RETURN_ERROR); + return (NULL); } } if (args_has(args, 'x')) { @@ -121,7 +143,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); - return (CMD_RETURN_ERROR); + return (NULL); } } else { if (last_x == 0) { @@ -138,7 +160,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); - return (CMD_RETURN_ERROR); + return (NULL); } } else { if (last_y == 0) { @@ -150,22 +172,6 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) } } - input = (args_has(args, 'I') && count == 0); - - flags = SPAWN_FLOATING; - if (args_has(args, 'b')) - flags |= SPAWN_BEFORE; - if (args_has(args, 'f')) - flags |= SPAWN_FULLSIZE; - if (input || (count == 1 && *args_string(args, 0) == '\0')) - flags |= SPAWN_EMPTY; - - sc.item = item; - sc.s = s; - sc.wl = wl; - - sc.wp0 = wp; - /* Floating panes sit in layout cells which are not in the layout_root * tree so we call it with parent == NULL. */ @@ -174,11 +180,171 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) lc->yoff = y; lc->sx = sx; lc->sy = sy; - sc.lc = lc; - last_x = x; /* Statically save last xoff & yoff so that new */ last_y = y; /* floating panes offset so they don't overlap. */ + return (lc); +} + +static int +cmd_new_pane_style_floating_pane(struct cmdq_item *item, struct args *args, + struct window_pane *new_wp) +{ + const char *style; + + style = args_get(args, 's'); + if (style != NULL) { + if (options_set_string(new_wp->options, "window-style", 0, + "%s", style) == NULL) { + cmdq_error(item, "bad style: %s", style); + return (-1); + } + options_set_string(new_wp->options, "window-active-style", 0, + "%s", style); + new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); + } + style = args_get(args, 'S'); + if (style != NULL) { + if (options_set_string(new_wp->options, + "pane-active-border-style", 0, "%s", style) == NULL) { + cmdq_error(item, "bad active border style: %s", style); + return (-1); + } + } + style = args_get(args, 'R'); + if (style != NULL) { + if (options_set_string(new_wp->options, "pane-border-style", 0, + "%s", style) == NULL) { + cmdq_error(item, "bad inactive border style: %s", style); + return (-1); + } + } + if (args_has(args, 'k') || args_has(args, 'm')) { + options_set_number(new_wp->options, "remain-on-exit", 3); + if (args_has(args, 'm')) + options_set_string(new_wp->options, "remain-on-exit-format", + 0, "%s", args_get(args, 'm')); + } + return (0); +} + +static struct layout_cell * +cmd_new_pane_get_split_layout_cell(struct cmdq_item *item, struct args *args, + struct window *w, struct window_pane *wp, int flags) +{ + enum layout_type type; + struct layout_cell *lc = NULL; + char *cause = NULL; + int size; + u_int curval = 0; + + if (wp->flags & PANE_FLOATING) { + cmdq_error(item, "can't split a floating pane"); + return (NULL); + } + + type = LAYOUT_TOPBOTTOM; + if (args_has(args, 'h')) + type = LAYOUT_LEFTRIGHT; + + /* If the 'p' flag is dropped then this bit can be moved into 'l'. */ + if (args_has(args, 'l') || args_has(args, 'p')) { + if (args_has(args, 'f')) { + if (type == LAYOUT_TOPBOTTOM) + curval = w->sy; + else + curval = w->sx; + } else { + if (type == LAYOUT_TOPBOTTOM) + curval = wp->sy; + else + curval = wp->sx; + } + } + + size = -1; + if (args_has(args, 'l')) { + size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, + item, &cause); + } else if (args_has(args, 'p')) { + size = args_strtonum_and_expand(args, 'p', 0, 100, item, + &cause); + if (cause == NULL) + size = curval * size / 100; + } + if (cause != NULL) { + cmdq_error(item, "size %s", cause); + free(cause); + return (NULL); + } + + window_push_zoom(wp->window, 1, args_has(args, 'Z')); + lc = layout_split_pane(wp, type, size, flags); + if (lc == NULL) + cmdq_error(item, "no space for new pane"); + + return (lc); +} + +static enum cmd_retval +cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) +{ + struct args *args = cmd_get_args(self); + struct cmd_find_state *current = cmdq_get_current(item); + struct cmd_find_state *target = cmdq_get_target(item); + struct spawn_context sc = { 0 }; + struct client *tc = cmdq_get_target_client(item); + struct session *s = target->s; + struct winlink *wl = target->wl; + struct window *w = wl->window; + struct window_pane *wp = target->wp, *new_wp; + struct layout_cell *lc = NULL; + struct cmd_find_state fs; + int flags, input; + const char *template; + char *cause = NULL, *cp; + struct args_value *av; + u_int count = args_count(args); + enum new_pane_type pane_type = NONE; + + if (args_has(args, 'T')) { + pane_type = cmd_new_pane_get_type(args_get(args, 'T')); + } else { + if (cmd_get_entry(self) == &cmd_new_pane_entry) + pane_type = FLOATING; + else + pane_type = TILED; + } + + input = (args_has(args, 'I') && count == 0); + + flags = pane_type == FLOATING ? SPAWN_FLOATING : 0; + if (args_has(args, 'b')) + flags |= SPAWN_BEFORE; + if (args_has(args, 'f')) + flags |= SPAWN_FULLSIZE; + if (input || (count == 1 && *args_string(args, 0) == '\0')) + flags |= SPAWN_EMPTY; + + + if (pane_type == FLOATING) { + // return (cmd_new_pane_exec(self, item)); + lc = cmd_new_pane_get_float_layout_cell(item, args, w); + } else if (pane_type == TILED) + lc = cmd_new_pane_get_split_layout_cell(item, args, w, wp, + flags); + else + cmdq_error(item, "unrecognized pane type '%s'", args_get(args, 'T')); + if (lc == NULL) + return (CMD_RETURN_ERROR); + + sc.item = item; + sc.s = s; + sc.wl = wl; + + sc.wp0 = wp; + sc.lc = lc; + args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); @@ -205,43 +371,17 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) environ_free(sc.environ); return (CMD_RETURN_ERROR); } - style = args_get(args, 's'); - if (style != NULL) { - if (options_set_string(new_wp->options, "window-style", 0, - "%s", style) == NULL) { - cmdq_error(item, "bad style: %s", style); + + if (pane_type == FLOATING) + if (cmd_new_pane_style_floating_pane(item, args, new_wp) != 0) return (CMD_RETURN_ERROR); - } - options_set_string(new_wp->options, "window-active-style", 0, - "%s", style); - new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); - } - style = args_get(args, 'S'); - if (style != NULL) { - if (options_set_string(new_wp->options, - "pane-active-border-style", 0, "%s", style) == NULL) { - cmdq_error(item, "bad active border style: %s", style); - return (CMD_RETURN_ERROR); - } - } - style = args_get(args, 'R'); - if (style != NULL) { - if (options_set_string(new_wp->options, "pane-border-style", 0, - "%s", style) == NULL) { - cmdq_error(item, "bad inactive border style: %s", style); - return (CMD_RETURN_ERROR); - } - } - if (args_has(args, 'k') || args_has(args, 'm')) { - options_set_number(new_wp->options, "remain-on-exit", 3); - if (args_has(args, 'm')) - options_set_string(new_wp->options, "remain-on-exit-format", - 0, "%s", args_get(args, 'm')); - } + if (input) { switch (window_pane_start_input(new_wp, item, &cause)) { case -1: server_client_remove_pane(new_wp); + if (pane_type == TILED) + layout_close_pane(new_wp); window_remove_pane(wp->window, new_wp); cmdq_error(item, "%s", cause); free(cause); diff --git a/cmd-split-window.c b/cmd-split-window.c deleted file mode 100644 index bd2a4b48..00000000 --- a/cmd-split-window.c +++ /dev/null @@ -1,204 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2009 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#include -#include -#include -#include - -#include "tmux.h" - -/* - * Split a window (add a new pane). - */ - -#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" - -static enum cmd_retval cmd_split_window_exec(struct cmd *, - struct cmdq_item *); - -const struct cmd_entry cmd_split_window_entry = { - .name = "split-window", - .alias = "splitw", - - .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, - .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " - "[-F format] [-l size] " CMD_TARGET_PANE_USAGE - " [shell-command [argument ...]]", - - .target = { 't', CMD_FIND_PANE, 0 }, - - .flags = 0, - .exec = cmd_split_window_exec -}; - -static enum cmd_retval -cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) -{ - struct args *args = cmd_get_args(self); - struct cmd_find_state *current = cmdq_get_current(item); - struct cmd_find_state *target = cmdq_get_target(item); - struct spawn_context sc = { 0 }; - struct client *tc = cmdq_get_target_client(item); - struct session *s = target->s; - struct winlink *wl = target->wl; - struct window *w = wl->window; - struct window_pane *wp = target->wp, *new_wp; - enum layout_type type; - struct layout_cell *lc; - struct cmd_find_state fs; - int size, flags, input; - const char *template; - char *cause = NULL, *cp; - struct args_value *av; - u_int count = args_count(args), curval = 0; - - if (wp->flags & PANE_FLOATING) { - cmdq_error(item, "can't split a floating pane"); - return (CMD_RETURN_ERROR); - } - - type = LAYOUT_TOPBOTTOM; - if (args_has(args, 'h')) - type = LAYOUT_LEFTRIGHT; - - /* If the 'p' flag is dropped then this bit can be moved into 'l'. */ - if (args_has(args, 'l') || args_has(args, 'p')) { - if (args_has(args, 'f')) { - if (type == LAYOUT_TOPBOTTOM) - curval = w->sy; - else - curval = w->sx; - } else { - if (type == LAYOUT_TOPBOTTOM) - curval = wp->sy; - else - curval = wp->sx; - } - } - - size = -1; - if (args_has(args, 'l')) { - size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, - item, &cause); - } else if (args_has(args, 'p')) { - size = args_strtonum_and_expand(args, 'p', 0, 100, item, - &cause); - if (cause == NULL) - size = curval * size / 100; - } - if (cause != NULL) { - cmdq_error(item, "size %s", cause); - free(cause); - return (CMD_RETURN_ERROR); - } - - window_push_zoom(wp->window, 1, args_has(args, 'Z')); - input = (args_has(args, 'I') && count == 0); - - flags = 0; - if (args_has(args, 'b')) - flags |= SPAWN_BEFORE; - if (args_has(args, 'f')) - flags |= SPAWN_FULLSIZE; - if (input || (count == 1 && *args_string(args, 0) == '\0')) - flags |= SPAWN_EMPTY; - - lc = layout_split_pane(wp, type, size, flags); - if (lc == NULL) { - cmdq_error(item, "no space for new pane"); - return (CMD_RETURN_ERROR); - } - - sc.item = item; - sc.s = s; - sc.wl = wl; - - sc.wp0 = wp; - sc.lc = lc; - - args_to_vector(args, &sc.argc, &sc.argv); - sc.environ = environ_create(); - - av = args_first_value(args, 'e'); - while (av != NULL) { - environ_put(sc.environ, av->string, 0); - av = args_next_value(av); - } - - sc.idx = -1; - sc.cwd = args_get(args, 'c'); - - sc.flags = flags; - if (args_has(args, 'd')) - sc.flags |= SPAWN_DETACHED; - if (args_has(args, 'Z')) - sc.flags |= SPAWN_ZOOM; - - if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { - cmdq_error(item, "create pane failed: %s", cause); - free(cause); - if (sc.argv != NULL) - cmd_free_argv(sc.argc, sc.argv); - environ_free(sc.environ); - return (CMD_RETURN_ERROR); - } - if (input) { - switch (window_pane_start_input(new_wp, item, &cause)) { - case -1: - server_client_remove_pane(new_wp); - layout_close_pane(new_wp); - window_remove_pane(wp->window, new_wp); - cmdq_error(item, "%s", cause); - free(cause); - if (sc.argv != NULL) - cmd_free_argv(sc.argc, sc.argv); - environ_free(sc.environ); - return (CMD_RETURN_ERROR); - case 1: - input = 0; - break; - } - } - if (!args_has(args, 'd')) - cmd_find_from_winlink_pane(current, wl, new_wp, 0); - window_pop_zoom(wp->window); - server_redraw_window(wp->window); - server_status_session(s); - - if (args_has(args, 'P')) { - if ((template = args_get(args, 'F')) == NULL) - template = SPLIT_WINDOW_TEMPLATE; - cp = format_single(item, template, tc, s, wl, new_wp); - cmdq_print(item, "%s", cp); - free(cp); - } - - cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); - cmdq_insert_hook(s, item, &fs, "after-split-window"); - - if (sc.argv != NULL) - cmd_free_argv(sc.argc, sc.argv); - environ_free(sc.environ); - if (input) - return (CMD_RETURN_WAIT); - return (CMD_RETURN_NORMAL); -} From 4bb7a8675361c12a7a6164d759fd2a547e89e2e1 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Mon, 13 Apr 2026 13:50:13 -0700 Subject: [PATCH 2/8] Tested the new commands and updated documentation. --- cmd-find.c | 2 +- cmd-new-pane.c | 175 ++++++++++++++++++++---------------------------- tmux.1 | 176 ++++++++++++++++++++++++------------------------- 3 files changed, 159 insertions(+), 194 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 747d204a..8b747a1c 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -1030,7 +1030,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, fs->w = fs->wl->window; fs->wp = fs->w->active; } - goto found; + break; } if (fs->wp == NULL) { if (~flags & CMD_FIND_QUIET) diff --git a/cmd-new-pane.c b/cmd-new-pane.c index 6db42f2a..a2e8269a 100644 --- a/cmd-new-pane.c +++ b/cmd-new-pane.c @@ -38,11 +38,13 @@ const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:fF:h:Iklm:p:PR:s:S:t:T:w:x:y:Z", 0, -1, NULL }, + .args = { "bc:de:fF:hH:Ikl:m:p:PR:s:S:t:T:w:x:y:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " - "[-F format] [-l size] [-m message] " - "[-R inactive-border-style] [-s style] [-S active-border-style] " - CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]", + "[-F format] [-H height] [-l size] [-m message] " + "[-R inactive-border-style] [-s style] " + "[-S active-border-style] [-w width] [-x x-position] " + "[-y y-position]" CMD_TARGET_PANE_USAGE "[-T type] " + " [shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -54,9 +56,12 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:fF:hIl:p:Pt:T:vZ", 0, -1, NULL }, - .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " - "[-F format] [-l size] " CMD_TARGET_PANE_USAGE + .args = { "bc:de:fF:hH:Ikl:m:p:PR:s:S:t:T:w:x:y:vZ", 0, -1, NULL }, + .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " + "[-F format] [-H height] [-l size] [-m message] " + "[-R inactive-border-style] [-s style] " + "[-S active-border-style] [-w width] [-x x-position] " + "[-y y-position]" CMD_TARGET_PANE_USAGE "[-T type] " " [shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -84,53 +89,41 @@ cmd_new_pane_get_type(const char* val) } static struct layout_cell * -cmd_new_pane_get_float_layout_cell(struct cmdq_item *item, struct args *args, +cmd_new_pane_get_floating_layout_cell(struct cmdq_item *item, struct args *args, struct window *w) { struct layout_cell *lc = NULL; char *cause = NULL; int x, y; - u_int sx, sy, pct; + u_int sx = w->sx / 2, sy = w->sy / 2; static int last_x = 0, last_y = 0; - if (args_has(args, 'f')) { - sx = w->sx; - sy = w->sy; + if (last_x == 0) { + x = 4; } else { - if (args_has(args, 'l')) { - sx = args_percentage_and_expand(args, 'l', 0, INT_MAX, w->sx, - item, &cause); - sy = args_percentage_and_expand(args, 'l', 0, INT_MAX, w->sy, - item, &cause); - } else if (args_has(args, 'p')) { - pct = args_strtonum_and_expand(args, 'p', 0, 100, item, - &cause); - if (cause == NULL) { - sx = w->sx * pct / 100; - sy = w->sy * pct / 100; - } - } else if (cause == NULL) { - sx = w->sx / 2; - sy = w->sy / 2; - } - if (cause != NULL) { - cmdq_error(item, "size %s", cause); - free(cause); - return (NULL); - } + x = (last_x += 4); + if (last_x > (int)w->sx) + x = 4; + } + if (last_y == 0) { + y = 2; + } else { + y = (last_y += 2); + if (last_y > (int)w->sy) + y = 2; } if (args_has(args, 'w')) { - sx = args_strtonum_and_expand(args, 'w', 1, USHRT_MAX, item, - &cause); + sx = args_percentage_and_expand(args, 'w', 0, USHRT_MAX, w->sx, + item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); return (NULL); } } - if (args_has(args, 'h')) { - sy = args_strtonum_and_expand(args, 'h', 1, USHRT_MAX, item, - &cause); + if (args_has(args, 'H')) { + sy = args_percentage_and_expand(args, 'H', 0, USHRT_MAX, w->sy, + item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); @@ -138,38 +131,22 @@ cmd_new_pane_get_float_layout_cell(struct cmdq_item *item, struct args *args, } } if (args_has(args, 'x')) { - x = args_strtonum_and_expand(args, 'x', SHRT_MIN, SHRT_MAX, + x = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx, item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); return (NULL); } - } else { - if (last_x == 0) { - x = 5; - } else { - x = (last_x += 5); - if (last_x > (int)w->sx) - x = 5; - } } if (args_has(args, 'y')) { - y = args_strtonum_and_expand(args, 'y', SHRT_MIN, SHRT_MAX, + y = args_percentage_and_expand(args, 'y', 0, USHRT_MAX, w->sy, item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); free(cause); return (NULL); } - } else { - if (last_y == 0) { - y = 5; - } else { - y = (last_y += 5); - if (last_y > (int)w->sy) - y = 5; - } } /* Floating panes sit in layout cells which are not in the layout_root @@ -186,50 +163,8 @@ cmd_new_pane_get_float_layout_cell(struct cmdq_item *item, struct args *args, return (lc); } -static int -cmd_new_pane_style_floating_pane(struct cmdq_item *item, struct args *args, - struct window_pane *new_wp) -{ - const char *style; - - style = args_get(args, 's'); - if (style != NULL) { - if (options_set_string(new_wp->options, "window-style", 0, - "%s", style) == NULL) { - cmdq_error(item, "bad style: %s", style); - return (-1); - } - options_set_string(new_wp->options, "window-active-style", 0, - "%s", style); - new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); - } - style = args_get(args, 'S'); - if (style != NULL) { - if (options_set_string(new_wp->options, - "pane-active-border-style", 0, "%s", style) == NULL) { - cmdq_error(item, "bad active border style: %s", style); - return (-1); - } - } - style = args_get(args, 'R'); - if (style != NULL) { - if (options_set_string(new_wp->options, "pane-border-style", 0, - "%s", style) == NULL) { - cmdq_error(item, "bad inactive border style: %s", style); - return (-1); - } - } - if (args_has(args, 'k') || args_has(args, 'm')) { - options_set_number(new_wp->options, "remain-on-exit", 3); - if (args_has(args, 'm')) - options_set_string(new_wp->options, "remain-on-exit-format", - 0, "%s", args_get(args, 'm')); - } - return (0); -} - static struct layout_cell * -cmd_new_pane_get_split_layout_cell(struct cmdq_item *item, struct args *args, +cmd_new_pane_get_tiled_layout_cell(struct cmdq_item *item, struct args *args, struct window *w, struct window_pane *wp, int flags) { enum layout_type type; @@ -301,7 +236,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) struct layout_cell *lc = NULL; struct cmd_find_state fs; int flags, input; - const char *template; + const char *template, *style; char *cause = NULL, *cp; struct args_value *av; u_int count = args_count(args); @@ -328,10 +263,9 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) if (pane_type == FLOATING) { - // return (cmd_new_pane_exec(self, item)); - lc = cmd_new_pane_get_float_layout_cell(item, args, w); + lc = cmd_new_pane_get_floating_layout_cell(item, args, w); } else if (pane_type == TILED) - lc = cmd_new_pane_get_split_layout_cell(item, args, w, wp, + lc = cmd_new_pane_get_tiled_layout_cell(item, args, w, wp, flags); else cmdq_error(item, "unrecognized pane type '%s'", args_get(args, 'T')); @@ -372,9 +306,40 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_ERROR); } - if (pane_type == FLOATING) - if (cmd_new_pane_style_floating_pane(item, args, new_wp) != 0) + style = args_get(args, 's'); + if (style != NULL) { + if (options_set_string(new_wp->options, "window-style", 0, + "%s", style) == NULL) { + cmdq_error(item, "bad style: %s", style); return (CMD_RETURN_ERROR); + } + options_set_string(new_wp->options, "window-active-style", 0, + "%s", style); + new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); + } + style = args_get(args, 'S'); + if (style != NULL) { + if (options_set_string(new_wp->options, + "pane-active-border-style", 0, "%s", style) == NULL) { + cmdq_error(item, "bad active border style: %s", style); + return (CMD_RETURN_ERROR); + } + } + style = args_get(args, 'R'); + if (style != NULL) { + if (options_set_string(new_wp->options, "pane-border-style", 0, + "%s", style) == NULL) { + cmdq_error(item, "bad inactive border style: %s", style); + return (CMD_RETURN_ERROR); + } + } + if (args_has(args, 'k') || args_has(args, 'm')) { + options_set_number(new_wp->options, "remain-on-exit", 3); + if (args_has(args, 'm')) + options_set_string(new_wp->options, + "remain-on-exit-format", + 0, "%s", args_get(args, 'm')); + } if (input) { switch (window_pane_start_input(new_wp, item, &cause)) { diff --git a/tmux.1 b/tmux.1 index c3f0d9b2..cae20748 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3323,12 +3323,11 @@ but a different format may be specified with .Fl F . .Tg newp .It Xo Ic new-pane -.Op Fl bdefIPZ +.Op Fl bdefhIkPvZ .Op Fl c Ar start-directory .Op Fl e Ar environment .Op Fl F Ar format -.Op Fl h Ar height -.Op Fl k +.Op Fl H Ar height .Op Fl l Ar size .Op Fl m Ar message .Op Fl p Ar percentage @@ -3342,35 +3341,36 @@ but a different format may be specified with .Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic newp -Create a new floating pane. -The -.Fl w , -.Fl h , -.Fl x , -and -.Fl y -options set the width, height, and position of the pane; if not given, -the pane is sized to half the window dimensions and offset from the -previous floating pane. -The -.Fl l -and -.Fl p -options set the size in lines or as a percentage. -The -.Fl f -option uses the full window dimensions. +Create a new pane. The new pane may be floating by specifying the type with +.Fl Tf +/ +.Fl Tfloating , +or tiled into the layout by splitting an existing pane with +.Fl Tt +/ +.Fl Ttiled . +When creating a tiled pane, a target pane may be specified with +.Fl t . +Note that some options are related to dimensions/layout and so will only affect +one pane type. Those options will be in their own sections. .Pp If .Fl d is given, the session does not make the new pane the current pane. .Fl Z -zooms if the window is not zoomed. -.Pp +zooms if the window is not zoomed, or keeps it zoomed if already zoomed. +.Fl s +sets the style for the pane content. +.Fl S +sets the border style when the pane is active and +.Fl R +sets the border style when the pane is inactive (see +.Sx STYLES ) . .Fl k -keeps the pane open after the shell command exits and waits for a -keypress (any non-mouse key) before closing it. -The message shown is controlled by the +keeps the pane open after the optional +.Ar shell-command +exits and waits for a keypress (any non-mouse key) before closing it. The +message shown is controlled by the .Ic remain-on-exit-format option. .Fl m Ar message @@ -3380,7 +3380,6 @@ but also sets the .Ic remain-on-exit-format option for this pane to .Ar message . -.Pp An empty .Ar shell-command (\[aq]\[aq]) will create a pane with no command running in it. @@ -3389,15 +3388,49 @@ The flag (if .Ar shell-command is not specified or empty) -will create an empty pane and forward any output from stdin to it. +will create an empty pane and forward any output from stdin to it. For example: +.Bd -literal -offset indent +$ make 2>&1|tmux splitw \-dI & +.Ed .Pp -.Fl s -sets the style for the pane content. -.Fl S -sets the border style when the pane is active and -.Fl R -sets the border style when the pane is inactive (see -.Sx STYLES ) . +For floating panes, the following flags are availible: +The +.Fl w , +.Fl h , +.Fl x , +and +.Fl y +options set the width, height, and position of the pane; if not given, +the pane is sized to half the window dimensions and offset from the +previous floating pane. These four options may be followed by '%' to specify +a percentage of the current window dimensions. +.Pp +For tiled panes, the following flags are availible: +.Fl h +does a horizontal split and +.Fl v +a vertical split; if neither is specified, +.Fl v +is assumed. +The +.Fl l +option specifies the size of the new pane in lines (for vertical split) or in +columns (for horizontal split); +.Ar size +may be followed by +.Ql % +to specify a percentage of the available space. +The +.Fl b +option causes the new pane to be created to the left of or above +.Ar target\-pane . +The +.Fl f +option creates a new pane spanning the full window height (with +.Fl h ) +or full window width (with +.Fl v ) , +instead of splitting the active pane. .Pp All other options have the same meaning as for the .Ic new-window @@ -3726,65 +3759,32 @@ the command behaves like .Ic last\-window . .Tg splitw .It Xo Ic split\-window -.Op Fl bdfhIvPZ -.Op Fl c Ar start\-directory +.Op Fl bdefhIkPvZ +.Op Fl c Ar start-directory .Op Fl e Ar environment .Op Fl F Ar format +.Op Fl H Ar height .Op Fl l Ar size -.Op Fl t Ar target\-pane -.Op Ar shell\-command Op Ar argument ... +.Op Fl m Ar message +.Op Fl p Ar percentage +.Op Fl R Ar inactive-border-style +.Op Fl s Ar style +.Op Fl S Ar active-border-style +.Op Fl t Ar target-pane +.Op Fl T Ar type +.Op Fl w Ar width +.Op Fl x Ar x-position +.Op Fl y Ar y-position +.Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic splitw -Create a new pane by splitting -.Ar target\-pane : -.Fl h -does a horizontal split and -.Fl v -a vertical split; if neither is specified, -.Fl v -is assumed. -The -.Fl l -option specifies the size of the new pane in lines (for vertical split) or in -columns (for horizontal split); -.Ar size -may be followed by -.Ql % -to specify a percentage of the available space. -The -.Fl b -option causes the new pane to be created to the left of or above -.Ar target\-pane . -The -.Fl f -option creates a new pane spanning the full window height (with -.Fl h ) -or full window width (with -.Fl v ) , -instead of splitting the active pane. -.Fl Z -zooms if the window is not zoomed, or keeps it zoomed if already zoomed. +Creates a new pane. Default behavior is to split the pane in a tiled layout. +Shares behavior with +.Ic new-pane . .Pp -An empty -.Ar shell\-command -(\[aq]\[aq]) will create a pane with no command running in it. -Output can be sent to such a pane with the -.Ic display\-message -command. -The -.Fl I -flag (if -.Ar shell\-command -is not specified or empty) -will create an empty pane and forward any output from stdin to it. -For example: -.Bd -literal -offset indent -$ make 2>&1|tmux splitw \-dI & -.Ed -.Pp -All other options have the same meaning as for the -.Ic new\-window -command. +See +.Ic new-pane +for more details. .Tg swapp .It Xo Ic swap\-pane .Op Fl dDUZ From f992c68fd878c0d0dd7b2c0b3911d46682eeb750 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Mon, 13 Apr 2026 22:04:08 -0700 Subject: [PATCH 3/8] slight touchup --- tmux.1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index cae20748..1bf17910 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3335,13 +3335,16 @@ but a different format may be specified with .Op Fl s Ar style .Op Fl S Ar active-border-style .Op Fl t Ar target-pane +.Op Fl T Ar type .Op Fl w Ar width .Op Fl x Ar x-position .Op Fl y Ar y-position .Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic newp -Create a new pane. The new pane may be floating by specifying the type with +Create a new pane. The new pane may be floating by specifying the +.Ar type +with .Fl Tf / .Fl Tfloating , @@ -3351,8 +3354,10 @@ or tiled into the layout by splitting an existing pane with .Fl Ttiled . When creating a tiled pane, a target pane may be specified with .Fl t . -Note that some options are related to dimensions/layout and so will only affect -one pane type. Those options will be in their own sections. +Note that some options are related to dimensions/layout. Those options will +only affect one creation +.Ar type +and will be in their own sections. .Pp If .Fl d From 1bc85cb59e90df5ad1d2e4234202315114dbec3b Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Tue, 14 Apr 2026 12:40:59 -0700 Subject: [PATCH 4/8] Adjustment from feedback and slight touchups. --- Makefile.am | 2 +- cmd-find.c | 2 +- cmd-new-pane.c => cmd-split-window.c | 82 +++++++++++++--------------- tmux.1 | 58 +++++++++++--------- 4 files changed, 74 insertions(+), 70 deletions(-) rename cmd-new-pane.c => cmd-split-window.c (82%) diff --git a/Makefile.am b/Makefile.am index c22a9dab..999e9909 100644 --- a/Makefile.am +++ b/Makefile.am @@ -115,7 +115,6 @@ dist_tmux_SOURCES = \ cmd-lock-server.c \ cmd-minimise-pane.c \ cmd-move-window.c \ - cmd-new-pane.c \ cmd-new-session.c \ cmd-new-window.c \ cmd-parse.y \ @@ -145,6 +144,7 @@ dist_tmux_SOURCES = \ cmd-show-options.c \ cmd-show-prompt-history.c \ cmd-source-file.c \ + cmd-split-window.c \ cmd-swap-pane.c \ cmd-tile-float-pane.c \ cmd-swap-window.c \ diff --git a/cmd-find.c b/cmd-find.c index 8b747a1c..747d204a 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -1030,7 +1030,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, fs->w = fs->wl->window; fs->wp = fs->w->active; } - break; + goto found; } if (fs->wp == NULL) { if (~flags & CMD_FIND_QUIET) diff --git a/cmd-new-pane.c b/cmd-split-window.c similarity index 82% rename from cmd-new-pane.c rename to cmd-split-window.c index a2e8269a..0789d0dc 100644 --- a/cmd-new-pane.c +++ b/cmd-split-window.c @@ -27,70 +27,58 @@ #include "tmux.h" /* - * Split a window (add a new pane). + * Create a new pane. */ #define NEW_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" -static enum cmd_retval cmd_new_pane_exec(struct cmd *, struct cmdq_item *); +static enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmdq_item *); const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:fF:hH:Ikl:m:p:PR:s:S:t:T:w:x:y:vZ", 0, -1, NULL }, + .args = { "bc:de:fF:hH:Ikl:m:M:p:PR:s:S:t:w:x:y:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-H height] [-l size] [-m message] " - "[-R inactive-border-style] [-s style] " + "[-M mode] [-R inactive-border-style] [-s style] " "[-S active-border-style] [-w width] [-x x-position] " - "[-y y-position]" CMD_TARGET_PANE_USAGE "[-T type] " - " [shell-command [argument ...]]", + "[-y y-position]" CMD_TARGET_PANE_USAGE + "[shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, .flags = 0, - .exec = cmd_new_pane_exec + .exec = cmd_split_window_exec }; const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:fF:hH:Ikl:m:p:PR:s:S:t:T:w:x:y:vZ", 0, -1, NULL }, + .args = { "bc:de:fF:hH:Ikl:m:M:p:PR:s:S:t:w:x:y:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-H height] [-l size] [-m message] " - "[-R inactive-border-style] [-s style] " + "[-M mode] [-R inactive-border-style] [-s style] " "[-S active-border-style] [-w width] [-x x-position] " - "[-y y-position]" CMD_TARGET_PANE_USAGE "[-T type] " - " [shell-command [argument ...]]", + "[-y y-position]" CMD_TARGET_PANE_USAGE + "[shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, .flags = 0, - .exec = cmd_new_pane_exec + .exec = cmd_split_window_exec }; -enum new_pane_type { +enum new_pane_mode { FLOATING, TILED, NONE, }; -static enum new_pane_type -cmd_new_pane_get_type(const char* val) -{ - if (strncmp(val, "floating", (sizeof "floating") - 1) == 0 || - strncmp(val, "f", (sizeof "f") - 1) == 0) - return FLOATING; - if (strncmp(val, "tiled", (sizeof "tiled") - 1) == 0 || - strncmp(val, "t", (sizeof "t") - 1) == 0) - return TILED; - return NONE; -} - static struct layout_cell * -cmd_new_pane_get_floating_layout_cell(struct cmdq_item *item, struct args *args, - struct window *w) +cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, + struct args *args, struct window *w) { struct layout_cell *lc = NULL; char *cause = NULL; @@ -164,8 +152,8 @@ cmd_new_pane_get_floating_layout_cell(struct cmdq_item *item, struct args *args, } static struct layout_cell * -cmd_new_pane_get_tiled_layout_cell(struct cmdq_item *item, struct args *args, - struct window *w, struct window_pane *wp, int flags) +cmd_split_window_get_tiled_layout_cell(struct cmdq_item *item, + struct args *args, struct window *w, struct window_pane *wp, int flags) { enum layout_type type; struct layout_cell *lc = NULL; @@ -222,7 +210,7 @@ cmd_new_pane_get_tiled_layout_cell(struct cmdq_item *item, struct args *args, } static enum cmd_retval -cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) +cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *current = cmdq_get_current(item); @@ -240,20 +228,25 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) char *cause = NULL, *cp; struct args_value *av; u_int count = args_count(args); - enum new_pane_type pane_type = NONE; + enum new_pane_mode pane_mode = NONE; - if (args_has(args, 'T')) { - pane_type = cmd_new_pane_get_type(args_get(args, 'T')); + if (args_has(args, 'M')) { + if (strcasecmp(args_get(args, 'M'), "f") == 0) + pane_mode = FLOATING; + else if (strcasecmp(args_get(args, 'M'), "t") == 0) + pane_mode = TILED; + else + pane_mode = NONE; } else { if (cmd_get_entry(self) == &cmd_new_pane_entry) - pane_type = FLOATING; + pane_mode = FLOATING; else - pane_type = TILED; + pane_mode = TILED; } input = (args_has(args, 'I') && count == 0); - flags = pane_type == FLOATING ? SPAWN_FLOATING : 0; + flags = pane_mode == FLOATING ? SPAWN_FLOATING : 0; if (args_has(args, 'b')) flags |= SPAWN_BEFORE; if (args_has(args, 'f')) @@ -262,13 +255,16 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) flags |= SPAWN_EMPTY; - if (pane_type == FLOATING) { - lc = cmd_new_pane_get_floating_layout_cell(item, args, w); - } else if (pane_type == TILED) - lc = cmd_new_pane_get_tiled_layout_cell(item, args, w, wp, + if (pane_mode == FLOATING) + lc = cmd_split_window_get_floating_layout_cell(item, args, w); + else if (pane_mode == TILED) + lc = cmd_split_window_get_tiled_layout_cell(item, args, w, wp, flags); - else - cmdq_error(item, "unrecognized pane type '%s'", args_get(args, 'T')); + else { + cmdq_error(item, "unrecognized pane mode '%s'", + args_get(args, 'M')); + return (CMD_RETURN_ERROR); + } if (lc == NULL) return (CMD_RETURN_ERROR); @@ -345,7 +341,7 @@ cmd_new_pane_exec(struct cmd *self, struct cmdq_item *item) switch (window_pane_start_input(new_wp, item, &cause)) { case -1: server_client_remove_pane(new_wp); - if (pane_type == TILED) + if (pane_mode == TILED) layout_close_pane(new_wp); window_remove_pane(wp->window, new_wp); cmdq_error(item, "%s", cause); diff --git a/tmux.1 b/tmux.1 index 1bf17910..dcb15490 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3330,34 +3330,39 @@ but a different format may be specified with .Op Fl H Ar height .Op Fl l Ar size .Op Fl m Ar message +.Op Fl M Ar mode .Op Fl p Ar percentage .Op Fl R Ar inactive-border-style .Op Fl s Ar style .Op Fl S Ar active-border-style .Op Fl t Ar target-pane -.Op Fl T Ar type .Op Fl w Ar width .Op Fl x Ar x-position .Op Fl y Ar y-position .Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic newp -Create a new pane. The new pane may be floating by specifying the -.Ar type -with -.Fl Tf -/ -.Fl Tfloating , -or tiled into the layout by splitting an existing pane with -.Fl Tt -/ -.Fl Ttiled . +Create a new pane. +A +.Ar mode +may be specified with the +.Fl M +option and must be followed by one of the following special values: +.Bl -column "XXXXX" -offset indent +.It Sy "Value" Ta Sy "Meaning" +.It Li "f" Ta "floating pane above the current layout" +.It Li "t" Ta "tiled into the layout by splitting a pane" +.El +.Pp +If no +.Ar mode +is specified, +.Ic f +is assumed. When creating a tiled pane, a target pane may be specified with .Fl t . -Note that some options are related to dimensions/layout. Those options will -only affect one creation -.Ar type -and will be in their own sections. +Note that some options will only affect one +.Ar mode . .Pp If .Fl d @@ -3374,8 +3379,8 @@ sets the border style when the pane is inactive (see .Fl k keeps the pane open after the optional .Ar shell-command -exits and waits for a keypress (any non-mouse key) before closing it. The -message shown is controlled by the +exits and waits for a keypress (any non-mouse key) before closing it. +The message shown is controlled by the .Ic remain-on-exit-format option. .Fl m Ar message @@ -3393,24 +3398,26 @@ The flag (if .Ar shell-command is not specified or empty) -will create an empty pane and forward any output from stdin to it. For example: +will create an empty pane and forward any output from stdin to it. +For example: .Bd -literal -offset indent $ make 2>&1|tmux splitw \-dI & .Ed .Pp -For floating panes, the following flags are availible: +For floating panes, the following options are availible: The .Fl w , .Fl h , .Fl x , and .Fl y -options set the width, height, and position of the pane; if not given, -the pane is sized to half the window dimensions and offset from the -previous floating pane. These four options may be followed by '%' to specify -a percentage of the current window dimensions. +options set the width, height, and position of the pane. +If not given, the pane is sized to half the window dimensions and offset from +the previous floating pane. +These four options may be followed by '%' to specify a percentage of the +current window dimensions. .Pp -For tiled panes, the following flags are availible: +For tiled panes, the following options are availible: .Fl h does a horizontal split and .Fl v @@ -3783,7 +3790,8 @@ the command behaves like .Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic splitw -Creates a new pane. Default behavior is to split the pane in a tiled layout. +Creates a new pane. +Default behavior is to split the pane in a tiled layout. Shares behavior with .Ic new-pane . .Pp From 7a4e35e317f4d0d9dc9b0943bc85d75657311b79 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Tue, 14 Apr 2026 13:08:19 -0700 Subject: [PATCH 5/8] doc fix. --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index dcb15490..19bfd978 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3778,12 +3778,12 @@ the command behaves like .Op Fl H Ar height .Op Fl l Ar size .Op Fl m Ar message +.Op Fl M Ar mode .Op Fl p Ar percentage .Op Fl R Ar inactive-border-style .Op Fl s Ar style .Op Fl S Ar active-border-style .Op Fl t Ar target-pane -.Op Fl T Ar type .Op Fl w Ar width .Op Fl x Ar x-position .Op Fl y Ar y-position From 914ffc888785f4046d9a3fab59a4042871842c3d Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Wed, 15 Apr 2026 12:33:08 -0700 Subject: [PATCH 6/8] touchup. --- cmd-split-window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 0789d0dc..d2979646 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -30,7 +30,7 @@ * Create a new pane. */ -#define NEW_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" +#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" static enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmdq_item *); @@ -363,7 +363,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL) - template = NEW_PANE_TEMPLATE; + template = SPLIT_WINDOW_TEMPLATE; cp = format_single(item, template, tc, s, wl, new_wp); cmdq_print(item, "%s", cp); free(cp); From a7ad0c443408ad27125bcd70bf464be378ffa000 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Thu, 16 Apr 2026 11:38:33 -0700 Subject: [PATCH 7/8] Option flag adjustment for eventual consistency. --- cmd-split-window.c | 62 +++++++++++++++++++++++----------------------- tmux.1 | 14 +++++------ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index d2979646..46b365fc 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -38,12 +38,12 @@ const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:fF:hH:Ikl:m:M:p:PR:s:S:t:w:x:y:vZ", 0, -1, NULL }, + .args = { "bc:de:fF:hIkl:m:M:p:PR:s:S:t:x:X:y:Y:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " - "[-F format] [-H height] [-l size] [-m message] " - "[-M mode] [-R inactive-border-style] [-s style] " - "[-S active-border-style] [-w width] [-x x-position] " - "[-y y-position]" CMD_TARGET_PANE_USAGE + "[-F format] [-l size] [-m message] [-M mode] " + "[-R inactive-border-style] [-s style] " + "[-S active-border-style] [-x width] [-X x-position]" + "[-y length] [-Y y-position]" CMD_TARGET_PANE_USAGE "[shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -56,12 +56,12 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:fF:hH:Ikl:m:M:p:PR:s:S:t:w:x:y:vZ", 0, -1, NULL }, + .args = { "bc:de:fF:hIkl:m:M:p:PR:s:S:t:x:X:y:Y:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " - "[-F format] [-H height] [-l size] [-m message] " - "[-M mode] [-R inactive-border-style] [-s style] " - "[-S active-border-style] [-w width] [-x x-position] " - "[-y y-position]" CMD_TARGET_PANE_USAGE + "[-F format] [-l size] [-m message] [-M mode] " + "[-R inactive-border-style] [-s style] " + "[-S active-border-style] [-x width] [-X x-position]" + "[-y length] [-Y y-position]" CMD_TARGET_PANE_USAGE "[shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -100,8 +100,8 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, if (last_y > (int)w->sy) y = 2; } - if (args_has(args, 'w')) { - sx = args_percentage_and_expand(args, 'w', 0, USHRT_MAX, w->sx, + if (args_has(args, 'x')) { + sx = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx, item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); @@ -109,26 +109,26 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, return (NULL); } } - if (args_has(args, 'H')) { - sy = args_percentage_and_expand(args, 'H', 0, USHRT_MAX, w->sy, - item, &cause); - if (cause != NULL) { - cmdq_error(item, "size %s", cause); - free(cause); - return (NULL); - } - } - if (args_has(args, 'x')) { - x = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx, - item, &cause); - if (cause != NULL) { - cmdq_error(item, "size %s", cause); - free(cause); - return (NULL); - } - } if (args_has(args, 'y')) { - y = args_percentage_and_expand(args, 'y', 0, USHRT_MAX, w->sy, + sy = args_percentage_and_expand(args, 'y', 0, USHRT_MAX, w->sy, + item, &cause); + if (cause != NULL) { + cmdq_error(item, "size %s", cause); + free(cause); + return (NULL); + } + } + if (args_has(args, 'X')) { + x = args_percentage_and_expand(args, 'X', 0, USHRT_MAX, w->sx, + item, &cause); + if (cause != NULL) { + cmdq_error(item, "size %s", cause); + free(cause); + return (NULL); + } + } + if (args_has(args, 'Y')) { + y = args_percentage_and_expand(args, 'Y', 0, USHRT_MAX, w->sy, item, &cause); if (cause != NULL) { cmdq_error(item, "size %s", cause); diff --git a/tmux.1 b/tmux.1 index 19bfd978..7fa136d7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3327,7 +3327,6 @@ but a different format may be specified with .Op Fl c Ar start-directory .Op Fl e Ar environment .Op Fl F Ar format -.Op Fl H Ar height .Op Fl l Ar size .Op Fl m Ar message .Op Fl M Ar mode @@ -3336,9 +3335,10 @@ but a different format may be specified with .Op Fl s Ar style .Op Fl S Ar active-border-style .Op Fl t Ar target-pane -.Op Fl w Ar width -.Op Fl x Ar x-position -.Op Fl y Ar y-position +.Op Fl x Ar width +.Op Fl X Ar x-position +.Op Fl y Ar length +.Op Fl Y Ar y-position .Op Ar shell-command Op Ar argument ... .Xc .D1 Pq alias: Ic newp @@ -3406,11 +3406,11 @@ $ make 2>&1|tmux splitw \-dI & .Pp For floating panes, the following options are availible: The -.Fl w , -.Fl h , .Fl x , +.Fl y , +.Fl X , and -.Fl y +.Fl Y options set the width, height, and position of the pane. If not given, the pane is sized to half the window dimensions and offset from the previous floating pane. From 0a55e5ca541c924c4f8515e55f8db18560222801 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Fri, 17 Apr 2026 12:44:50 -0700 Subject: [PATCH 8/8] Fixed logical error in handing default cascading. --- cmd-split-window.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 46b365fc..046dc66e 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -83,23 +83,13 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, struct layout_cell *lc = NULL; char *cause = NULL; int x, y; - u_int sx = w->sx / 2, sy = w->sy / 2; + u_int sx, sy; static int last_x = 0, last_y = 0; - if (last_x == 0) { - x = 4; - } else { - x = (last_x += 4); - if (last_x > (int)w->sx) - x = 4; - } - if (last_y == 0) { - y = 2; - } else { - y = (last_y += 2); - if (last_y > (int)w->sy) - y = 2; - } + /* Default size. */ + sx = w->sx / 2; + sy = w->sy / 2; + if (args_has(args, 'x')) { sx = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx, item, &cause); @@ -118,6 +108,8 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, return (NULL); } } + + /* If a position is not defined, it defaults to cascading. */ if (args_has(args, 'X')) { x = args_percentage_and_expand(args, 'X', 0, USHRT_MAX, w->sx, item, &cause); @@ -126,6 +118,12 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, free(cause); return (NULL); } + } else if (last_x == 0) + x = 4; + else { + x = (last_x += 4); + if (last_x > (int)w->sx) + x = 4; } if (args_has(args, 'Y')) { y = args_percentage_and_expand(args, 'Y', 0, USHRT_MAX, w->sy, @@ -135,6 +133,12 @@ cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, free(cause); return (NULL); } + } else if (last_y == 0) + y = 2; + else { + y = (last_y += 2); + if (last_y > (int)w->sy) + y = 2; } /* Floating panes sit in layout cells which are not in the layout_root