Skip to content

Commit 252f6c1

Browse files
committed
fix(tools): Route select_pane next/previous via absolute pane_id for older tmux
why: CI exposed that the prior fix (server.cmd with target= f"{window.window_id}.+") still fails on tmux 3.2a: targeting a non-active window routes focus back to the client's current window. The relative-pane-offset parser for scoped window targets like @window_id.+ behaves differently across tmux releases — 3.6-alpha resolves it correctly; 3.2a falls back to client curw. The CI trace shows a returned pane with window_id='@1' when the call targeted '@2', confirming the same class of misrouting the earlier fix was meant to eliminate. Sidestep the tmux-version variation by skipping relative-target syntax entirely: enumerate the targeted window's panes, find the currently-active one, compute next/previous by index with wrap-around, and select by absolute pane_id. tmux accepts absolute pane_ids uniformly across every version, and `pane_active` on the target window is set regardless of whether the client is focused on that window. what: - Collapse the `next` and `previous` branches into a single compute-by-index block. `window.refresh()` ensures `pane_active` reflects current state; then walk window.panes, locate the active one, advance by ±1 (mod len), and dispatch `server.cmd("select-pane", target=target_pane.pane_id)`. - Replace the two previous comment blocks with a single one that explains both portability concerns (bare +/- uses client curw, scoped @id.+ is version-dependent). - No test change needed — test_select_pane_next_previous_respects_target_window already verifies the correct behavior; it was failing only on older tmux versions because the previous fix was version-specific.
1 parent b5bd00d commit 252f6c1

1 file changed

Lines changed: 20 additions & 9 deletions

File tree

src/libtmux_mcp/tools/pane_tools.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -875,15 +875,26 @@ def select_pane(
875875
assert direction is not None
876876
if direction in _DIRECTION_FLAGS:
877877
window.select_pane(_DIRECTION_FLAGS[direction])
878-
elif direction == "next":
879-
# Anchor the relative target to the requested window. A bare
880-
# `-t +` resolves against the attached client's current window
881-
# (tmux cmd-find.c), NOT the window we're targeting.
882-
# `@window_id.+` forces tmux to resolve the `+` offset against
883-
# the explicit window's active pane.
884-
server.cmd("select-pane", target=f"{window.window_id}.+")
885-
elif direction == "previous":
886-
server.cmd("select-pane", target=f"{window.window_id}.-")
878+
elif direction in ("next", "previous"):
879+
# Compute the target pane by absolute pane_id rather than using
880+
# tmux's relative pane-target syntax. Two portability issues
881+
# motivate this approach:
882+
# 1. A bare `-t +` / `-t -1` resolves against the attached
883+
# client's current window (tmux cmd-find.c), not the window
884+
# we're targeting.
885+
# 2. The scoped form `@window_id.+` / `.-` works on tmux 3.6+
886+
# but the relative-offset parser's behavior for prefixed
887+
# window targets varies on older releases (tmux 3.2a still
888+
# falls back to client curw for `@id.+`). Enumerating
889+
# panes and selecting by absolute pane_id sidesteps
890+
# tmux-version variation entirely.
891+
window.refresh()
892+
panes = list(window.panes)
893+
active = next((p for p in panes if p.pane_active == "1"), panes[0])
894+
idx = panes.index(active)
895+
step = 1 if direction == "next" else -1
896+
target_pane = panes[(idx + step) % len(panes)]
897+
server.cmd("select-pane", target=target_pane.pane_id)
887898

888899
# Query the active pane ID directly from tmux to avoid stale cache
889900
target = window.window_id or ""

0 commit comments

Comments
 (0)