Skip to content

Commit 3421d7d

Browse files
committed
Window(feat): add next_layout, previous_layout wrapping real tmux commands
why: next-layout and previous-layout are real tmux commands (since 1.0) with their own cmd_entry structs. Invoke them directly instead of routing through select-layout flags. what: - Add Window.next_layout() calling tmux next-layout directly - Add Window.previous_layout() calling tmux previous-layout directly - Add tests verifying layout changes and round-trip cycling
1 parent ff56aa5 commit 3421d7d

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

src/libtmux/window.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,50 @@ def select_layout(
496496

497497
return self
498498

499+
def next_layout(self) -> Window:
500+
"""Cycle to the next layout via ``$ tmux next-layout``.
501+
502+
Returns
503+
-------
504+
:class:`Window`
505+
Self, for method chaining.
506+
507+
Examples
508+
--------
509+
>>> pane1 = window.active_pane
510+
>>> pane2 = window.split()
511+
>>> window.next_layout()
512+
Window(...)
513+
"""
514+
proc = self.cmd("next-layout")
515+
516+
if proc.stderr:
517+
raise exc.LibTmuxException(proc.stderr)
518+
519+
return self
520+
521+
def previous_layout(self) -> Window:
522+
"""Cycle to the previous layout via ``$ tmux previous-layout``.
523+
524+
Returns
525+
-------
526+
:class:`Window`
527+
Self, for method chaining.
528+
529+
Examples
530+
--------
531+
>>> pane1 = window.active_pane
532+
>>> pane2 = window.split()
533+
>>> window.previous_layout()
534+
Window(...)
535+
"""
536+
proc = self.cmd("previous-layout")
537+
538+
if proc.stderr:
539+
raise exc.LibTmuxException(proc.stderr)
540+
541+
return self
542+
499543
def link(
500544
self,
501545
target_session: str | Session,

tests/test_window.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,45 @@ def test_select_layout_next_previous(session: Session) -> None:
814814
assert layout_after_prev == layout_before
815815

816816

817+
def test_next_layout(session: Session) -> None:
818+
"""Test Window.next_layout() cycles to the next layout."""
819+
window = session.new_window(window_name="test_next_layout")
820+
window.resize(height=40, width=80)
821+
pane = window.active_pane
822+
assert pane is not None
823+
pane.split()
824+
825+
window.select_layout("even-horizontal")
826+
window.refresh()
827+
layout_before = window.window_layout
828+
829+
window.next_layout()
830+
window.refresh()
831+
layout_after = window.window_layout
832+
833+
assert layout_before != layout_after
834+
835+
836+
def test_previous_layout(session: Session) -> None:
837+
"""Test Window.previous_layout() cycles back."""
838+
window = session.new_window(window_name="test_prev_layout")
839+
window.resize(height=40, width=80)
840+
pane = window.active_pane
841+
assert pane is not None
842+
pane.split()
843+
844+
window.select_layout("even-horizontal")
845+
window.refresh()
846+
layout_before = window.window_layout
847+
848+
window.next_layout()
849+
window.previous_layout()
850+
window.refresh()
851+
layout_after = window.window_layout
852+
853+
assert layout_before == layout_after
854+
855+
817856
def test_select_layout_mutual_exclusion(session: Session) -> None:
818857
"""Test that layout string and flags are mutually exclusive."""
819858
window = session.new_window(window_name="test_layout_mutex")

0 commit comments

Comments
 (0)