Type hints for tmux 3.4+ format tokens#674
Draft
tony wants to merge 8 commits into
Draft
Conversation
This was referenced May 17, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #674 +/- ##
==========================================
- Coverage 52.44% 51.79% -0.65%
==========================================
Files 26 26
Lines 3726 3726
Branches 747 747
==========================================
- Hits 1954 1930 -24
- Misses 1468 1482 +14
- Partials 304 314 +10 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tony
force-pushed
the
parity-pt-2
branch
6 times, most recently
from
May 18, 2026 02:31
d886138 to
61688af
Compare
why: The 0.57.x section claimed list-clients "emits the client_*
tokens but never pane_* ones" — backwards: tmux's format_defaults
cascades downward through c->session, the session's current window,
and that window's active pane, so list-clients (and list-sessions
and list-windows) all hydrate pane fields via cascade. Pinned by the
strengthened cascade tests on this branch and by upstream
cmd-list-clients.c calling format_defaults(ft, l[i], NULL, NULL,
NULL). Two adjacent overclaims compounded the issue: a fixed token
count ("twelve client_* tokens") that didn't match the typed Client
surface, and a "every wrapper uses raise_if_stderr" claim that didn't
match the supported surface in practice.
what:
- Rewrite the cascade paragraph in the typed format-token entry to
describe the actual downward cascade (Client/Session/Window rows
hydrate active-pane/window fields; client_* resolves only under
list-clients because tmux has no reverse cascade).
- Drop number slop: "twelve client_* tokens", "~45 additional format
tokens", the explicit list of eight forward-looking tokens, and
the embedded token-name catalogs that belong in autodoc.
- Replace "every wrapper" with "shared helper used across the
supported surface". Trim "matching the rest of the typed wrappers"
to "matching the rest of the supported surface".
- Add the Client snapshot caveat (session_id/window_id/pane_id are
attached-view, not identity) into the Client entry.
- Add the malformed-predicate caveat to the C-side filter entry.
- Add a Fixes bullet for Server.clients and Server.search_sessions
propagating tmux errors instead of swallowing them.
- Add a Documentation bullet for the Obj cascade-semantics
docstring.
- Tighten the lead paragraph: drop "closes wrapper gaps" and the
token count.
Carry the wrapper-to-tmux-support pattern from the earlier 0.56-section copy-improvements commit into the 0.57.x section.
why: In 0.57 the typed wrappers migrated to raise_if_stderr, which attaches a LibTmuxException.subcommand attribute and prefixes str(exc) with "<subcommand>: ". The release entry framed this purely as additive — there was no breaking-change subheading for upgraders who pattern-match on str(exc) exactly or anchor a regex with ^. The wrapped stderr is still in exc.args[0]; the subcommand name is exposed as a typed attribute. Substring containment and unanchored regex matches keep working. what: - CHANGES: new ### Breaking changes subsection under 0.57 with three migration paths (exc.subcommand, exc.args[0], substring match). - MIGRATION: new ## libtmux 0.57.0 section covering the same contract from the upgrader's perspective, with before/after code for each migration path.
why: client.session_id / window_id / pane_id are hydrated from tmux's downward format cascade at the moment the Client dataclass is built and go stale as soon as the client switches view. The existing class-level docstring warning isn't enough on its own — users iterating over server.clients still reach for the raw fields and treat them as identity. what: - Add Client.attached_session / .attached_window / .attached_pane. Each property re-reads list-clients before resolving and returns the live typed Session / Window / Pane (or None), mirroring the Session.active_window fresh-lookup convention. - Tighten the Client class-level warning to point at the new properties as the safe accessors. - Tests: typed resolution, fresh window tracking (selects a new active window post-hydration and asserts the property reflects it — proves the property re-queries rather than returning the snapshot), pane resolution, None propagation when session_id is absent. - CHANGES: extend the Client what's-new entry to mention the attached_* accessors. - MIGRATION: 0.57 section gains a "snapshots, not identity" subheading covering the snapshot vs. live access pattern.
why: The Client documentation should distinguish attached_* convenience behavior from explicit refresh lookups. what: - Clarify None behavior for missing live client rows - Preserve refresh/from_client_name missing-object semantics
…stead of raising
why: tmux's stderr from display-message conflates genuine argument-parser
errors (e.g. -F-with-positional rejection) with operational quirks like
3.2a's control-mode dispatch path silently failing without emitting stderr
at all. Raising LibTmuxException on every stderr forced an in-branch
workaround — pytest.skip patches gated on has_gte_version("3.3") — that
masked the underlying mismatch instead of solving it. Switch to
warnings.warn so callers see the stderr without losing the return value,
and the eventual raise/per-call-opt-in contract can land in a follow-up
shipment that exercises real tmux versions end-to-end.
what:
- src/libtmux/server.py, src/libtmux/window.py, src/libtmux/pane.py:
replace raise_if_stderr(proc, "display-message") with
warnings.warn("display-message: …", stacklevel=2). Wrapper return
value unchanged on success and on warn paths.
- All three display_message docstrings gain a Notes block describing
the warn-not-raise contract and showing the
warnings.catch_warnings/filterwarnings("error") escalation pattern.
- tests/test_pane.py, tests/test_window.py, tests/test_server.py:
rename test_*_display_message_raises_on_tmux_error to
test_*_display_message_warns_on_tmux_error and switch to
pytest.warns(UserWarning, match=…). Drop the 3.2a control-mode skip
added by the prior commit on test_server_display_message_no_text_returns_none —
with warn-not-raise the 3.2a control-mode stderr no longer fails the
test (the test only asserts result is None on get_text=False).
- CHANGES: rewrite the display_message Fixes entry to describe the
warn contract and how to escalate.
- MIGRATION: add a new section under 0.57.0 documenting the warn
contract and the warnings.catch_warnings escalation pattern.
- MIGRATION: add a section noting that Pane.reset now dispatches via
self.server.cmd; mocks targeting pane.cmd no longer intercept reset.
- docs/topics/pane_interaction.md: tighten the capture_pane(pending=True)
wording to describe tmux's parser pending buffer rather than "slow
consumer / paused program" (the latter framing implies a PTY/app
buffering issue that pending= doesn't address).
- docs/topics/filtering.md: note that there is no search_clients();
filter via Server.clients and Python-side QueryList.filter.
why: tmux master (post-3.6a) registers eight new format tokens that the next tmux release will ship: pane_zoomed_flag, pane_floating_flag, pane_flags, pane_pb_state, pane_pb_progress, pane_pipe_pid, synchronized_output_flag, bracket_paste_flag. Declaring them now means libtmux is ready when the tag lands; older tmux releases expand unknown tokens to empty strings, so the fields stay None until the user upgrades tmux. what: - src/libtmux/neo.py: add the fields alphabetically within the existing Obj layout (pane_* tokens among the pane_* block, bracket_paste_flag near buffer_*, synchronized_output_flag near start_time). - tests/test_pane.py: parametrized test asserts each field is declared on the dataclass and hydrates either as None or as a string after refresh(). No runtime-value assertions — those will activate when the shipping tmux release exposes the tokens.
why: with the scope+version gating in place, the format string sent to older
tmux versions automatically excludes tokens that those versions don't
recognize. The tokens below first registered in tmux 3.4-3.6 — tagging them
with FIELD_VERSION makes them appear on supported tmux releases that include
them, and absent on older tmux without sending unknown tokens that bloat the
format string or trigger crashes.
what:
- src/libtmux/neo.py:
- Re-add fields to Obj alphabetically: pane_key_mode,
pane_unseen_changes, session_active, session_activity_flag,
session_alert, session_bell_flag, session_silence_flag, client_theme.
- Populate FIELD_VERSION with each token's minimum tmux release
(3.4 for pane_unseen_changes, 3.5 for pane_key_mode, 3.6 for the
five session_* tokens and client_theme).
- tests/test_pane.py: restore pane_key_mode and pane_unseen_changes in
PANE_FORMAT_FIELDS (the parametrized declaration+hydration test).
- tests/test_session.py: restore the new session_* entries in
SESSION_FORMAT_FIELDS.
Verification:
- On tmux 3.6a (local), all tokens hydrate via refresh(); tests
pass.
- On tmux 3.2a, FIELD_VERSION skips all 8 — the -F template stays at
its pre--rollback shape for that version.
Version anchors verified via: rg '"<token>"'
https://github.com/tmux/tmux/blob/<TAG>/format.c across 3.2a, 3.3a, 3.4,
3.5, 3.5a, 3.6, 3.6a.
tony
force-pushed
the
typed-format-fields-tmux-3-4-plus
branch
from
July 18, 2026 11:02
8db405d to
9e927a4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds typed Python attributes for format tokens tmux added in releases
after 3.2a — covering 3.4 (`pane_unseen_changes`), 3.5
(`pane_key_mode`), 3.6 (`session_active`, `session_activity_flag`,
`session_alert`, `session_bell_flag`, `session_silence_flag`,
`client_theme`), and the forward-looking set expected to land with
tmux 3.7+ (`bracket_paste_flag`, `pane_flags`, `pane_floating_flag`,
`pane_pb_progress`, `pane_pb_state`, `pane_pipe_pid`,
`pane_zoomed_flag`, `synchronized_output_flag`).
Problem solved
IDE autocomplete and `mypy` awareness for newer tmux format tokens.
Today users can read these via raw `display-message -p`, but the
typed surface saves the field-name lookup and centralizes the
version gate.
Why this is its own shipment
The forward-looking tokens can't be validated in CI until tmux 3.7
reaches a tagged release. Holding the shipment lets the typed
declarations land alongside real version-checked tests instead of
declarations gated by a version number that doesn't yet exist.
Status
Draft, gated on tmux 3.7 reaching a tagged release. This branch is
parented on `parity-pt-2` (#672); once #672 merges, rebase onto
`master` and revisit. The 3.4 / 3.5 / 3.6 tokens are already
validatable today and could land sooner if needed — but the
forward-looking set drives the held-back timing.
Acceptance criteria for merge
returns the correct field set for every combination of
`list_cmd ∈ {list-sessions, list-windows, list-panes, list-clients}`
\× `version ∈ {3.2a, 3.3, 3.4, 3.5, 3.6a, 3.7}`
fields hydrate as expected
Test plan
pre-existing 3.2a control-mode skips)
after the rebase target merges
Refs
and core typed surface land in Increase tmux coverage: Client, typed fields, Native filtering #672; the forward-looking expansion
lands here.