Skip to content

Commit 79331a1

Browse files
committed
Session(fix[detach_client]): preserve client targeting semantics
why: tmux detach-client treats -s before -t, so always forcing a session target detached every client on the session instead of the requested client. what: - remove the unconditional session target from Session.detach_client - clarify all_clients plus target_client behavior in the docstring - add regressions for default and explicit target detach behavior
1 parent c5e737d commit 79331a1

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

src/libtmux/session.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ def detach_client(
272272
Target client to detach (``-t`` flag). If omitted, detaches
273273
the most recently active client.
274274
all_clients : bool, optional
275-
Detach all clients attached to this session (``-a`` flag).
275+
Detach all clients attached to this session (``-a`` flag). If
276+
combined with ``target_client``, tmux keeps that client attached.
276277
shell_command : str, optional
277278
Run a shell command after detaching (``-E`` flag).
278279
@@ -292,9 +293,6 @@ def detach_client(
292293
if target_client is not None:
293294
tmux_args += ("-t", target_client)
294295

295-
# Use -s for session targeting (not -t, which targets clients)
296-
tmux_args += ("-s", str(self.session_id))
297-
298296
proc = self.server.cmd("detach-client", *tmux_args)
299297

300298
if proc.stderr:

tests/test_session.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,46 @@ def test_detach_client(
595595
assert after == before - 1
596596

597597

598+
def test_detach_client_only_detaches_one_client(
599+
control_mode: t.Callable[..., t.Any],
600+
session: Session,
601+
server: Server,
602+
) -> None:
603+
"""Test Session.detach_client() without a target detaches one client."""
604+
with control_mode(), control_mode():
605+
before = server.cmd("list-clients", "-F", "#{client_name}").stdout
606+
assert len(before) == 2
607+
608+
session.detach_client()
609+
610+
after = server.cmd("list-clients", "-F", "#{client_name}").stdout
611+
assert len(after) == 1
612+
assert set(after) < set(before)
613+
614+
615+
def test_detach_client_target_client(
616+
control_mode: t.Callable[..., t.Any],
617+
session: Session,
618+
server: Server,
619+
) -> None:
620+
"""Test Session.detach_client() detaches only the requested client."""
621+
with control_mode(), control_mode():
622+
clients = server.cmd("list-clients", "-F", "#{client_name}").stdout
623+
assert len(clients) == 2
624+
625+
target_client = clients[-1]
626+
session.detach_client(target_client=target_client)
627+
628+
remaining_clients = server.cmd(
629+
"list-clients",
630+
"-F",
631+
"#{client_name}",
632+
).stdout
633+
assert remaining_clients == [
634+
client for client in clients if client != target_client
635+
]
636+
637+
598638
def test_last_window(session: Session) -> None:
599639
"""Test Session.last_window() selects previous window."""
600640
w1 = session.new_window(window_name="last_a", attach=True)

0 commit comments

Comments
 (0)