Skip to content

Commit 9dce2c4

Browse files
committed
Window(feat[select_layout]): add spread, next, and previous flags
why: select-layout supports flags for spreading panes evenly and cycling through layouts that were not exposed in the Python API. what: - Add spread (-E), next_layout (-n), previous_layout (-o) parameters - Validate mutual exclusion between layout string and flag parameters - Add tests for spread, next/previous cycling, and mutual exclusion
1 parent b2a7923 commit 9dce2c4

2 files changed

Lines changed: 86 additions & 1 deletion

File tree

src/libtmux/window.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,14 @@ def last_pane(self) -> Pane | None:
406406
"""Return last pane."""
407407
return self.select_pane("-l")
408408

409-
def select_layout(self, layout: str | None = None) -> Window:
409+
def select_layout(
410+
self,
411+
layout: str | None = None,
412+
*,
413+
spread: bool | None = None,
414+
next_layout: bool | None = None,
415+
previous_layout: bool | None = None,
416+
) -> Window:
410417
"""Select layout for window.
411418
412419
Wrapper for ``$ tmux select-layout <layout>``.
@@ -436,6 +443,18 @@ def select_layout(self, layout: str | None = None) -> Window:
436443
both rows and columns.
437444
'custom'
438445
Custom dimensions (see :term:`tmux(1)` manpages).
446+
spread : bool, optional
447+
Spread panes out evenly (``-E`` flag).
448+
449+
.. versionadded:: 0.45
450+
next_layout : bool, optional
451+
Move to the next layout (``-n`` flag).
452+
453+
.. versionadded:: 0.45
454+
previous_layout : bool, optional
455+
Move to the previous layout (``-o`` flag).
456+
457+
.. versionadded:: 0.45
439458
440459
Returns
441460
-------
@@ -446,9 +465,26 @@ def select_layout(self, layout: str | None = None) -> Window:
446465
------
447466
:exc:`libtmux.exc.LibTmuxException`
448467
If tmux returns an error.
468+
ValueError
469+
If both *layout* and a flag (*spread*, *next_layout*,
470+
*previous_layout*) are specified.
449471
"""
472+
flags = (spread, next_layout, previous_layout)
473+
if layout and any(flags):
474+
msg = "Cannot specify both layout and spread/next_layout/previous_layout"
475+
raise ValueError(msg)
476+
450477
cmd = ["select-layout"]
451478

479+
if spread:
480+
cmd.append("-E")
481+
482+
if next_layout:
483+
cmd.append("-n")
484+
485+
if previous_layout:
486+
cmd.append("-o")
487+
452488
if layout: # tmux allows select-layout without args
453489
cmd.append(layout)
454490

tests/test_window.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,3 +770,52 @@ def test_deprecated_window_methods_emit_warning(
770770

771771
with pytest.warns(DeprecationWarning, match=test_case.expected_error_match):
772772
method(*test_case.args, **test_case.kwargs)
773+
774+
775+
def test_select_layout_spread(session: Session) -> None:
776+
"""Test Window.select_layout() with spread flag."""
777+
window = session.new_window(window_name="test_layout_spread")
778+
window.resize(height=40, width=80)
779+
pane = window.active_pane
780+
assert pane is not None
781+
pane.split()
782+
pane.split()
783+
assert len(window.panes) == 3
784+
785+
# Spread panes evenly — verify no error
786+
window.select_layout(spread=True)
787+
788+
789+
def test_select_layout_next_previous(session: Session) -> None:
790+
"""Test Window.select_layout() with next/previous flags."""
791+
window = session.new_window(window_name="test_layout_cycle")
792+
window.resize(height=40, width=80)
793+
pane = window.active_pane
794+
assert pane is not None
795+
pane.split()
796+
797+
# Set a known layout
798+
window.select_layout("even-horizontal")
799+
window.refresh()
800+
layout_before = window.window_layout
801+
802+
# Cycle to next layout
803+
window.select_layout(next_layout=True)
804+
window.refresh()
805+
layout_after_next = window.window_layout
806+
807+
assert layout_before != layout_after_next
808+
809+
# Cycle back to previous
810+
window.select_layout(previous_layout=True)
811+
window.refresh()
812+
layout_after_prev = window.window_layout
813+
814+
assert layout_after_prev == layout_before
815+
816+
817+
def test_select_layout_mutual_exclusion(session: Session) -> None:
818+
"""Test that layout string and flags are mutually exclusive."""
819+
window = session.new_window(window_name="test_layout_mutex")
820+
with pytest.raises(ValueError, match="Cannot specify both"):
821+
window.select_layout("tiled", spread=True)

0 commit comments

Comments
 (0)