From c54893e5d99f26a619c6ab9d3c5947848d0d9773 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 10 May 2026 09:59:20 -0500 Subject: [PATCH 1/2] cli/load(refactor[_reattach]) Use Pane.display_message wrapper why: The reattach loop reached for libtmux's `Server.cmd()` escape hatch to invoke `tmux display-message -p '#S'` for the session name, even though libtmux has exposed a typed `Pane.display_message()` wrapper for this exact subcommand for several releases. With libtmux 0.56.0 now in the dependency tree (it broadens `display_message`'s flag coverage on top of the existing get_text path), there's no remaining reason to keep this particular cmd() escape. what: - Replace `builder.session.cmd("display-message", "-p", "'#S'")` in `_reattach()` with `active_pane.display_message("'#S'", get_text=True)` against `builder.session.active_pane`. Same tmux invocation under the hood; typed call site instead of stringly-typed positional args. - Add a narrowing assert on `active_pane` (returns `Pane | None` in libtmux's typing) so mypy can prove the call site is well-typed. Mirrors the existing `assert builder.session is not None` pattern at the top of `_reattach()`. - Iterate the returned `list[str]` directly. Previously the loop consumed `proc.stdout` (a list), so the iteration shape is identical and the per-line `tmuxp_echo` / `logger.debug` body is unchanged. No behavior change: the active pane is what tmux's display-message defaults to anyway when no `-t` is passed, so the underlying tmux invocation is byte-for-byte identical. --- src/tmuxp/cli/load.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tmuxp/cli/load.py b/src/tmuxp/cli/load.py index 375cdb1b22..5c84b30b61 100644 --- a/src/tmuxp/cli/load.py +++ b/src/tmuxp/cli/load.py @@ -216,8 +216,10 @@ def _reattach(builder: WorkspaceBuilder, colors: Colors | None = None) -> None: assert builder.session is not None for plugin in builder.plugins: plugin.reattach(builder.session) - proc = builder.session.cmd("display-message", "-p", "'#S'") - for line in proc.stdout: + active_pane = builder.session.active_pane + assert active_pane is not None + lines = active_pane.display_message("'#S'", get_text=True) + for line in lines: tmuxp_echo(colors.info(line) if colors else line) logger.debug( "reattach display-message output", From 46b52f1673025ec660851417d2505767047bb4b1 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 10 May 2026 10:02:45 -0500 Subject: [PATCH 2/2] tests(refactor[plugin_system]) Use Pane.display_message wrapper why: Six tests in the plugin-system suite were querying tmux for session/window names via the same `session.cmd("display-message", "-p", "'#S'")` escape hatch that production just migrated away from in `cli/load.py:_reattach`. Keeping the tests on the typed wrapper that production now uses keeps the call shape consistent across the codebase and removes the last `cmd("display-message", ...)` site from the repo. what: - `tests/cli/test_cli.py::test_reattach_plugins`: replace the `cmd()` call with `active_pane.display_message("'#S'", get_text=True)` so the post-reattach assertion uses the typed wrapper. - `tests/workspace/test_builder.py`: migrate four `test_plugin_system_*` checks (`before_workspace_builder`, `on_window_create`, `after_window_finished`, and the multi-window variant covering both `before_script` and `after_window_finished`) onto `active_pane.display_message()`. The multi-window variant hoists the active_pane lookup once and reuses it for both the `'#S'` and `'#W'` queries. - Each call site adds a narrowing assert on `active_pane` (libtmux types it as `Pane | None`) so mypy can prove the call is well-typed. Mirrors the production assert added in `_reattach()`. No behavior change: tmux's `display-message` defaults to the session's active pane when no `-t` is passed, so the underlying tmux invocations are byte-for-byte identical to the prior `session.cmd(...)` calls. --- tests/cli/test_cli.py | 6 ++++-- tests/workspace/test_builder.py | 29 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index 34524946d4..2f4617e91e 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -170,6 +170,8 @@ def test_reattach_plugins( _reattach(builder) assert builder.session is not None - proc = builder.session.cmd("display-message", "-p", "'#S'") + active_pane = builder.session.active_pane + assert active_pane is not None + lines = active_pane.display_message("'#S'", get_text=True) - assert proc.stdout[0] == "'plugin_test_r'" + assert lines[0] == "'plugin_test_r'" diff --git a/tests/workspace/test_builder.py b/tests/workspace/test_builder.py index da95168f46..4307747be8 100644 --- a/tests/workspace/test_builder.py +++ b/tests/workspace/test_builder.py @@ -824,8 +824,10 @@ def test_plugin_system_before_workspace_builder( builder.build(session=session) - proc = session.cmd("display-message", "-p", "'#S'") - assert proc.stdout[0] == "'plugin_test_bwb'" + active_pane = session.active_pane + assert active_pane is not None + lines = active_pane.display_message("'#S'", get_text=True) + assert lines[0] == "'plugin_test_bwb'" def test_plugin_system_on_window_create( @@ -847,8 +849,10 @@ def test_plugin_system_on_window_create( builder.build(session=session) - proc = session.cmd("display-message", "-p", "'#W'") - assert proc.stdout[0] == "'plugin_test_owc'" + active_pane = session.active_pane + assert active_pane is not None + lines = active_pane.display_message("'#W'", get_text=True) + assert lines[0] == "'plugin_test_owc'" def test_plugin_system_after_window_finished( @@ -870,8 +874,10 @@ def test_plugin_system_after_window_finished( builder.build(session=session) - proc = session.cmd("display-message", "-p", "'#W'") - assert proc.stdout[0] == "'plugin_test_awf'" + active_pane = session.active_pane + assert active_pane is not None + lines = active_pane.display_message("'#W'", get_text=True) + assert lines[0] == "'plugin_test_awf'" def test_plugin_system_on_window_create_multiple_windows( @@ -946,15 +952,18 @@ def test_plugin_system_multiple_plugins( builder.build(session=session) + active_pane = session.active_pane + assert active_pane is not None + # Drop through to the before_script plugin hook - proc = session.cmd("display-message", "-p", "'#S'") - assert proc.stdout[0] == "'plugin_test_bwb'" + lines = active_pane.display_message("'#S'", get_text=True) + assert lines[0] == "'plugin_test_bwb'" # Drop through to the after_window_finished. This won't succeed # unless on_window_create succeeds because of how the test plugin # override methods are currently written - proc = session.cmd("display-message", "-p", "'#W'") - assert proc.stdout[0] == "'mp_test_awf'" + lines = active_pane.display_message("'#W'", get_text=True) + assert lines[0] == "'mp_test_awf'" def test_load_configs_same_session(