Skip to content

Commit a402132

Browse files
committed
Window(feat[move_window]): add after, before, no-select, kill, and renumber flags
why: move-window supports flags for positioning, conflict resolution, and renumbering that were not exposed in the Python API. what: - Add after (-a), before (-b), no_select (-d), kill_target (-k), renumber (-r) parameters to move_window() - Add tests for kill_target, renumber, and no_select behaviors
1 parent 9dce2c4 commit a402132

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

src/libtmux/window.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,12 @@ def move_window(
602602
self,
603603
destination: str = "",
604604
session: str | None = None,
605+
*,
606+
after: bool | None = None,
607+
before: bool | None = None,
608+
no_select: bool | None = None,
609+
kill_target: bool | None = None,
610+
renumber: bool | None = None,
605611
) -> Window:
606612
"""Move current :class:`Window` object ``$ tmux move-window``.
607613
@@ -613,6 +619,26 @@ def move_window(
613619
session : str, optional
614620
The ``target session`` or index to move the window to, default:
615621
current session.
622+
after : bool, optional
623+
Insert after the target window (``-a`` flag).
624+
625+
.. versionadded:: 0.45
626+
before : bool, optional
627+
Insert before the target window (``-b`` flag).
628+
629+
.. versionadded:: 0.45
630+
no_select : bool, optional
631+
Do not make the moved window the current window (``-d`` flag).
632+
633+
.. versionadded:: 0.45
634+
kill_target : bool, optional
635+
Kill the target window if it exists (``-k`` flag).
636+
637+
.. versionadded:: 0.45
638+
renumber : bool, optional
639+
Renumber all windows after moving (``-r`` flag).
640+
641+
.. versionadded:: 0.45
616642
617643
Returns
618644
-------
@@ -624,9 +650,27 @@ def move_window(
624650
:exc:`libtmux.exc.LibTmuxException`
625651
If tmux returns an error.
626652
"""
653+
tmux_args: tuple[str, ...] = ()
654+
655+
if after:
656+
tmux_args += ("-a",)
657+
658+
if before:
659+
tmux_args += ("-b",)
660+
661+
if no_select:
662+
tmux_args += ("-d",)
663+
664+
if kill_target:
665+
tmux_args += ("-k",)
666+
667+
if renumber:
668+
tmux_args += ("-r",)
669+
627670
session = session or self.session_id
628671
proc = self.cmd(
629672
"move-window",
673+
*tmux_args,
630674
f"-s{self.session_id}:{self.window_index}",
631675
target=f"{session}:{destination}",
632676
)

tests/test_window.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,55 @@ def test_select_layout_mutual_exclusion(session: Session) -> None:
819819
window = session.new_window(window_name="test_layout_mutex")
820820
with pytest.raises(ValueError, match="Cannot specify both"):
821821
window.select_layout("tiled", spread=True)
822+
823+
824+
def test_move_window_kill_target(session: Session) -> None:
825+
"""Test Window.move_window() with kill_target flag."""
826+
session.new_window(window_name="move_w1")
827+
w2 = session.new_window(window_name="move_w2")
828+
assert w2.window_index is not None
829+
w2_index = w2.window_index
830+
initial_count = len(session.windows)
831+
832+
# Move first extra window to w2's index, killing w2
833+
extra_windows = [w for w in session.windows if w.window_name == "move_w1"]
834+
assert len(extra_windows) == 1
835+
extra_windows[0].move_window(destination=w2_index, kill_target=True)
836+
session.refresh()
837+
assert len(session.windows) == initial_count - 1
838+
839+
840+
def test_move_window_renumber(session: Session) -> None:
841+
"""Test Window.move_window() with renumber flag."""
842+
session.new_window(window_name="ren_w1")
843+
w2 = session.new_window(window_name="ren_w2")
844+
w3 = session.new_window(window_name="ren_w3")
845+
846+
# Kill middle window to create gap
847+
w2.kill()
848+
849+
# Move w3 with renumber
850+
w3.move_window(renumber=True)
851+
session.refresh()
852+
853+
# Verify indices are contiguous
854+
indices = sorted(
855+
int(w.window_index) for w in session.windows if w.window_index is not None
856+
)
857+
for i in range(len(indices) - 1):
858+
assert indices[i + 1] - indices[i] == 1
859+
860+
861+
def test_move_window_no_select(session: Session) -> None:
862+
"""Test Window.move_window() with no_select flag."""
863+
w1 = session.new_window(window_name="nosel_w1", attach=True)
864+
w2 = session.new_window(window_name="nosel_w2", attach=False)
865+
866+
# w1 is active
867+
session.refresh()
868+
assert session.active_window.window_id == w1.window_id
869+
870+
# Move w2 with no_select — active window should not change
871+
w2.move_window(destination="99", no_select=True)
872+
session.refresh()
873+
assert session.active_window.window_id == w1.window_id

0 commit comments

Comments
 (0)