Skip to content

refactor(cli/load,tests) Migrate display-message to typed wrapper#1039

Open
tony wants to merge 2 commits intomasterfrom
libtmux-v0.56-plus-api-updates
Open

refactor(cli/load,tests) Migrate display-message to typed wrapper#1039
tony wants to merge 2 commits intomasterfrom
libtmux-v0.56-plus-api-updates

Conversation

@tony
Copy link
Copy Markdown
Member

@tony tony commented May 10, 2026

Summary

  • Drop the last two cmd("display-message", "-p", ...) escape hatches in the codebase: one in production (cli/load._reattach), six in test code (the plugin-system suite).
  • Same tmux invocation under the hood, just routed through libtmux's typed Pane.display_message(cmd, get_text=True) wrapper. No behavior change.
  • Follows the libtmux 0.56.0 bump in py(deps) Bump libtmux 0.56.0 #1038 — the wrapper itself has been around since 0.55.0, but with 0.56.0 now landed there's no remaining reason to keep the cmd() escape for this particular subcommand.

Why now

PR #1038 broadened the Pane.display_message flag coverage in libtmux 0.56.0 (format_string=, verbose=, delay=, notify=, target_client=). While auditing tmuxp for spots that could move to the new typed surface, the only remaining cmd() escape in production turned out to be the post-reattach session-name echo loop in cli/load._reattach. Five of the six other usages were in tests asserting on session/window names via the same idiom — leaving them on cmd() while production migrated would split the call shape across the codebase.

The migration itself doesn't depend on a 0.56.0-only API; this is consistency cleanup that 0.56.0's broader display_message surface made an obvious moment to do.

Changes in this PR

c54893e5cli/load(refactor[_reattach]) Use Pane.display_message wrapper

Production change. Replaces:

proc = builder.session.cmd("display-message", "-p", "'#S'")
for line in proc.stdout:
    ...

with:

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:
    ...

The narrowing assert mirrors the existing assert builder.session is not None already at the top of _reattach(). tmux's display-message without -t defaults to the session's active pane, so the underlying invocation is byte-for-byte identical.

46b52f16tests(refactor[plugin_system]) Use Pane.display_message wrapper

Migrates six test sites in tests/cli/test_cli.py::test_reattach_plugins and four test_plugin_system_* checks in tests/workspace/test_builder.py to the same typed wrapper. Hoists active_pane once in the multi-query test that asserts on both '#S' and '#W' (replaces two separate cmd() roundtrips with two calls on the same pane reference).

Test plan

  • uv run ruff check . --fix --show-fixes clean before each commit
  • uv run ruff format . clean before each commit
  • uv run mypy clean before each commit (the narrowing assert was load-bearing — without it, Pane | None typing rejects the call)
  • uv run py.test --reruns 0 -vvv — 797 passed, 2 skipped, before each commit
  • just build-docs succeeds before each commit
  • No remaining cmd("display-message", ...) calls anywhere in src/ or tests/ (verified via grep -rn 'cmd("display-message"' src/ tests/)

tony added 2 commits May 10, 2026 09:59
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.
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.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.97%. Comparing base (c675892) to head (46b52f1).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1039      +/-   ##
==========================================
+ Coverage   81.96%   81.97%   +0.01%     
==========================================
  Files          28       28              
  Lines        2545     2547       +2     
  Branches      485      485              
==========================================
+ Hits         2086     2088       +2     
  Misses        328      328              
  Partials      131      131              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant