Skip to content

Commit 4e06b4d

Browse files
committed
Pane(feat[move]): add move() wrapping tmux move-pane directly
why: move-pane is a real tmux command (since 1.7) with its own cmd_entry. While it shares exec with join-pane, it should be invocable directly. what: - Add Pane.move() calling tmux move-pane with vertical (-v/-h), detach (-d), full_window (-f), size (-l), before (-b) parameters - Uses server.cmd with explicit -s/-t targeting - Add test verifying pane moves between windows
1 parent d8957d4 commit 4e06b4d

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

src/libtmux/pane.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,78 @@ def respawn(
16611661
if proc.stderr:
16621662
raise exc.LibTmuxException(proc.stderr)
16631663

1664+
def move(
1665+
self,
1666+
target: str | Pane | Window,
1667+
*,
1668+
vertical: bool = True,
1669+
detach: bool = True,
1670+
full_window: bool | None = None,
1671+
size: str | int | None = None,
1672+
before: bool | None = None,
1673+
) -> None:
1674+
"""Move this pane to another window via ``$ tmux move-pane``.
1675+
1676+
Similar to :meth:`join` but invokes the ``move-pane`` command directly.
1677+
1678+
Parameters
1679+
----------
1680+
target : str, Pane, or Window
1681+
Target pane or window to move into.
1682+
vertical : bool, optional
1683+
Split vertically (``-v`` flag), default True. False for
1684+
horizontal (``-h``).
1685+
detach : bool, optional
1686+
Do not switch to the target window (``-d`` flag), default True.
1687+
full_window : bool, optional
1688+
Use the full window width/height (``-f`` flag).
1689+
size : str or int, optional
1690+
Size for the moved pane (``-l`` flag).
1691+
before : bool, optional
1692+
Place the pane before the target (``-b`` flag).
1693+
1694+
Examples
1695+
--------
1696+
>>> pane_to_move = window.split(shell='sleep 1m')
1697+
>>> w2 = session.new_window(window_name='move_target')
1698+
>>> pane_to_move.move(w2)
1699+
"""
1700+
tmux_args: tuple[str, ...] = ()
1701+
1702+
if vertical:
1703+
tmux_args += ("-v",)
1704+
else:
1705+
tmux_args += ("-h",)
1706+
1707+
if detach:
1708+
tmux_args += ("-d",)
1709+
1710+
if full_window:
1711+
tmux_args += ("-f",)
1712+
1713+
if size is not None:
1714+
tmux_args += (f"-l{size}",)
1715+
1716+
if before:
1717+
tmux_args += ("-b",)
1718+
1719+
# Determine target ID
1720+
from libtmux.window import Window
1721+
1722+
if isinstance(target, Pane):
1723+
target_id = str(target.pane_id)
1724+
elif isinstance(target, Window):
1725+
target_id = str(target.window_id)
1726+
else:
1727+
target_id = target
1728+
1729+
tmux_args += ("-s", str(self.pane_id), "-t", target_id)
1730+
1731+
proc = self.server.cmd("move-pane", *tmux_args)
1732+
1733+
if proc.stderr:
1734+
raise exc.LibTmuxException(proc.stderr)
1735+
16641736
def join(
16651737
self,
16661738
target: str | Pane | Window,

tests/test_pane.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,25 @@ def test_respawn_pane_kill(session: Session) -> None:
924924
assert pane in window.panes
925925

926926

927+
def test_move_pane(session: Session) -> None:
928+
"""Test Pane.move() moves pane to another window."""
929+
w1 = session.new_window(window_name="move_src")
930+
pane = w1.active_pane
931+
assert pane is not None
932+
pane_to_move = pane.split(shell="sleep 1m")
933+
assert len(w1.panes) == 2
934+
935+
w2 = session.new_window(window_name="move_dst")
936+
initial_w2_panes = len(w2.panes)
937+
938+
pane_to_move.move(w2)
939+
940+
w1.refresh()
941+
w2.refresh()
942+
assert len(w1.panes) == 1
943+
assert len(w2.panes) == initial_w2_panes + 1
944+
945+
927946
def test_join_pane(session: Session) -> None:
928947
"""Test Pane.join() roundtrip with break_pane."""
929948
window = session.new_window(window_name="test_join")

0 commit comments

Comments
 (0)