Releases: atomicstack/tmux-popup-control
Releases · atomicstack/tmux-popup-control
v0.12.1
v0.12.1
a maintenance release: a broad internal code-quality pass plus security and test-infrastructure hardening. no user-facing feature or keybinding changes.
security
SessionOptionnow reads session options viashow-options -qv(option name passed as data) instead of interpolating an untrusted, save-file-derived session name into a tmux#{...}format string.- save files are now validated on read: session/window names containing control characters or format-significant
#/}are rejected. - pane-capture files are written
0600(were0644) and the capture dir0700— pane scrollback can contain secrets.
fixes
- shutdown no longer races the shared control-mode client: the backend watcher is fully drained before the client closes.
- the throttle in the backend poller is now cancellable, so quitting is prompt.
Save/Restorerespect context cancellation on every progress send (a stalled consumer can no longer leak the producer goroutine).pane:joinno longer emits a trace event for a join that never happens.- multi-select id parsing unified — the previous space-splitting could corrupt names containing spaces.
internal / quality
- modernized to go 1.25 idioms (min/max, slices/maps helpers, strings.Cut, cmp.Or, sync.OnceValues, sync.WaitGroup.Go, errors.Is/Join).
- large de-duplication across the menu, ui-render, tmux-snapshot, and state-store layers; the resurrect package decomposed.
- gradient progress bars now use the vendored lipgloss blending API instead of a hand-rolled per-cell implementation.
tests
- fixed
AssertNoServerCrash, which was a silent no-op (tmux verbose logs were written outside the directory it inspected) — integration crash detection now actually works. - added the missing
TestMainteardown to the menu package and fixed a test-ordering hazard under-shuffle=on.
v0.12.0
highlights
bugfixes
- restore: restore now matches against tmux identity and layouts correctly, fixing cases where resurrect-saved sessions failed to rebuild faithfully.
- pane:join: the menu no longer drops the target argument, so the joined pane actually disappears from the source instead of staying behind.
ui safety
- destructive plugin actions (uninstall, reload) and the resurrect "delete saved" action now route through a shared y/n confirmation prompt before doing anything irreversible.
- internal refactor: a single
renderYNPrompthelper backs every confirmation, so y/n prompts stay visually consistent across the app.
tmuxopts catalog
- refreshed the embedded tmux option catalog from upstream. new options surfaced:
copy-mode-line-numbers,copy-mode-line-number-style,copy-mode-current-line-number-style,tree-mode-preview-format,tree-mode-preview-style, and thewindow-pane-status-formatpair. - the
tmux_commandandformat_stringshared domains are now typed structs (TmuxCommandDomain,FormatStringDomain) instead of untyped maps. - new accessors:
Catalog.TmuxCommands()returns 91 tmux commands with aliases sorted by name, andCatalog.FormatVariables()returns the 192 default format variables fromformat.cwith their value types.
housekeeping
- gofmt sweep across
internal/menu,internal/ui,internal/cmdparse, andinternal/testutil— whitespace only, no behaviour changes.
v0.11.0
highlights
- new top-level
resurrectsubmenu — save / save-as / restore / restore-from / delete-saved all live here now, hoisted out of thesessionsubmenu where they always felt out of place. delete-saved presents the same listing as restore-from but removes the chosen save (plus its companion pane archive) and re-points thelastsymlink at the next-newest remaining save. - plugin uninstall now reuses the install/update progress UI: bordered cells per plugin with status pills (
asking/pending removal/skipped/removing/done/failed), gradient progress bar (red→white for uninstall), and a single y/n prompt above the progress bar instead of one per cell. install/update behaviour unchanged. - y/n confirmation prompts coloured consistently: surrounding text yellow,
ygreen bold,nred bold. applies to both the per-plugin uninstall prompt and the post-completion "Reload plugins?" prompt.
menu changes
session:save→resurrect:savesession:save-as→resurrect:save-assession:restore→resurrect:restoresession:restore-from→resurrect:restore-from- new:
resurrect:delete-saved - main.tmux hotkey vars rename to
TMUX_POPUP_CONTROL_KEY_RESURRECT_*; the legacyKEY_SESSION_SAVE/KEY_SESSION_RESTORE_FROMnames are honoured as fallbacks so existing tmux.conf entries keep working.
bugfix
ui: count level Subtitle row in maxVisibleItems— the restore-from / delete-saved listings render the save-dir path as a subtitle, but the visible-items budget didn't reserve a row for it. on small popup heights the cursor could land past the last viewport-visible row and never scroll back into view.
new APIs
resurrect.DeleteSave(dir, path)— removes a save file and its companion pane-archive, repointing or clearing thelastsymlink as appropriate.
v0.10.0
highlights
- make test 7× faster on cold cache, ~80× faster on warm cache (49s → 7s cold, 25s → 0.6s warm) via three layered fixes: pool tmux servers per test binary instead of spawn-per-test, drop gotmuxcc tracing from the default test env, cap
go test -pat 4 to avoid the four integration packages all hammering tmux at once. - eliminated the load-induced flake set in the integration tests (
TestFilterNarrowsSessionList,TestNavigationOpensSubmenuAndEscapeReturns,TestEscapeExitsFromRootMenu, etc.) by addressing the contention that caused them, not by bumping timeouts. - filter cursor migration to tea.View.Cursor: form text inputs now surface their cursor via Bubble Tea's first-class cursor API instead of in-string block rendering, fixing positioning in the prompt row and aligning with the rest of the v2 input model.
fixes
ui: respect noPreview in maxVisibleItems—maxVisibleItemsreserved rows for an inline preview thatviewVerticalthen refused to render, shrinking the tree's viewport and dragging the auto-selected cursor off the top in--no-previewconfigs.cmdparse: replace golden_schemas.txt with schema-aware assertions— the previous full-output golden broke deterministically every time tmux added a command or flag; new assertions cover the commands the codebase actually consumes for completion.resurrect: mock tmux fetch fns in TestRunAutoSaveCommandReturnsBlankWhenIconDisabled— the test was attempting real save+fetch against whatever tmux server was reachable from the test environment; under parallelmake testload that hung for 5+ minutes per run.
performance
tmux: cut redundant tmux commands per backend poll— cacheShowOptionresults per (socket, option) for the binary's lifetime; skipListSessionsFormatwhen no custom session label format is configured. DropsFetchSessionsfrom 6 commands to 3 on the first cycle, cheaper still after.testutil: pool one tmux server per test binary— sampling concurrent tmux processes duringmake testshowed 11–13 servers alive at peak from cleanup-overlap stacking. New pool runs one server per package viasync.Once/TestMainand tears down only per-test sessions in cleanup. Tests that genuinely need an isolated server (cross-server save/restore round-trip) opt intoStartIsolatedTmuxServer.
diagnostics
backend: emit poll.start / poll.done trace events— now visible in the JSON trace log, not only in the SQLite sink. Useful for tracing first-fetch latency under load.
ui polish
- form text input cursors render via
tea.View.Cursor, with positioning bound to the actual prompt row (f9d7e5b,3a460f9,104b621,f59deac,6a3910c,f290cb5,68161cc,8c5233b,a472c52,ed56ff7). attachFilterCursorclamping modernized; dead form-cursor path removed.
v0.9.5
fixed
- autosave: don't snapshot freshly-started empty sessions. when the last autosave predated the current tmux server's start time — e.g., starting a new tmux server more than the autosave interval after the previous one exited — the status-line worker would save immediately, capturing a near-empty session and wasting an autosave slot. the worker now detects "first save of a new tmux server lifetime" via
#{start_time}and waits the full interval before the first save, so freshly-started sessions have a chance to be populated before being captured.
full changelog: v0.9.4...v0.9.5
v0.9.4
improvements
- show seconds in session restore timestamps so saves taken in quick succession can be told apart
- include the queried scope in show-options / show-hooks empty placeholder messages (e.g. "in scope -g", "in session scope") so it's clear which scope was searched
fixes
- resolve the active pane/window per preview level via a live tmux topology fetch, so switch and tree previews target the correct active pane even when the cached backend state is stale
- focus the session tree on the current session/window/pane when it opens, for both direct loads and root-menu startup hydration
- treat show-options "invalid option" responses (e.g. querying an unset user option) as empty output and render the placeholder instead of surfacing an error
- suppress macOS xattr and metadata headers in release tarballs so extraction on linux no longer warns about
LIBARCHIVE.xattr.com.apple.provenance
v0.9.3
improvements
- replace the static scope legend underneath the autocomplete popup with the currently selected item's full help text; colour scope names in both the popup's description column and the help text below
fixes
- parse quoted strings in command input using tmux lexer rules — previously quote characters were passed literally to tmux and double-quoted strings with spaces were split into multiple arguments
- trigger completion when the cursor is mid-text — previously the popup only appeared when the cursor was at the end of the filter input
v0.9.2
improvements
- inline colour rendering — colour values (
colour33,color196,#ff5500, etc.) inshow-optionsoutput are now rendered in their actual colour instead of a swatch block preceding the name - hook scope colour — hooks have their own dedicated scope colour (muted purple), visible in
show-options,show-hooks, and the scope legend - scope-coloured help text — command summaries for
set-option,show-options, and related commands now highlight scope words (server, session, window, pane, user, hook) in their scope colour, including plural forms - style attribute colour rendering — compound style values like
fg=colour33,bg=red,boldnow render their colour components in the actual colour - exported cmdparse helpers —
SchemaHasArgFlagandPositionalAtare now exported for use outside the cmdparse package
fixes
- option scope colour persistence — scope colour on option names in the fuzzy filter no longer disappears when the cursor moves away or a space is pressed; the colour now persists regardless of cursor position
- inherited option name handling —
show-options -Aoutput with*-suffixed inherited names (e.g.display-panes-active-colour*) is now correctly recognised and coloured - show-hooks empty output —
show-hookswith empty output now shows[no hooks found](or[no hooks found in scope -g]) instead of silently hiding the popup
v0.9.1
improvements
- live user-defined options (
@plugin …) are now queried from the running tmux server via control mode and merged into the option-name completion catalog. - the option completion popup colours each candidate by scope (server / session / window / pane / user) and shows a one-line scope legend underneath the bordered popup.
- the option token inside the filter input follows the highlighted candidate live and falls back to a catalog lookup once the dropdown dismisses on exact match.
- value completion for colour-typed options (
status-fg,cursor-colour, …) now decorates each candidate with a coloured swatch for basic names,colourNforms, and#rrggbbhex. show-options/show-window-options/show-hooksresults render each option name in its scope colour, and colour-typed values get a swatch prepended when the value resolves to a known tmux colour.
fixes
- scope-only
show-options/show-window-options/show-hooksqueries with empty output now show a[no options found in scope -g]placeholder instead of silently hiding the result popup, so it is clear the command actually ran.
v0.9.0
improvements
- added a dedicated tmux option/hook/value catalog (
internal/tmuxopts) embedded at build time, covering every documented tmux option, hook, and enumerated value with descriptions, so completions no longer depend on parsingshow-options -aat runtime. - the command submenu now offers completion for option names, hook names, and enumerated option values, wiring
set-option,set-window-option,set-hook,show-options, and related commands into the existing completion dropdown with fuzzy filtering and description hints. - lists across the ui now draw a proper scrollbar column (thin
│thumb in the same grey as list trimmings), replacing the previous^/vindicator rows. the completion popup renders it vialipgloss.JoinHorizontalas a separate column so selection highlighting can never bleed into the scrollbar glyph; the main menu and session tree pick it up through a newstyledLine.suffixfield. - the completion popup no longer reflows while scrolling — width measurement now iterates the entire filtered candidate set and is hard-capped at 50 visible columns so a single very long candidate cannot blow the popup across the screen.
- page up and page down now step the completion popup cursor by a full viewport when the popup is focused, instead of leaking through to the background menu level.
- the session tree marks the currently-attached window with a " (current)" suffix and renders single-pane windows as "1 pane" instead of "1 panes".
- added a dedicated window-switcher keybinding (prefix+w by default, overridable via
TMUX_POPUP_CONTROL_KEY_WINDOW_SWITCHER/@tmux-popup-control-key-window-switcher) that launches thewindow:switchmenu directly, matching the existing shortcut style used for the pane switcher and session tree. - the restore progress bar now lerps toward the real step at ~60fps, eliminating visual jerkiness when restore events arrive in bursts while still reporting the true step/total in the counter text.
fixes
show-options,show-window-options, andshow-hooksnow synthesise a[option name has no value]/[hook name has no value]placeholder when tmux returns empty output for a single-target query, instead of silently showing nothing. list-all queries still render as empty.- restore
TMUX_PANEfromTMUX_POPUP_CONTROL_PANE_IDwhen running inside adisplay-popup, which clearsTMUX_PANEand broke tmux commands that rely on it to resolve the current pane context (e.g.move-window -r). - integration tests now strip
TMUX_PANEand allTMUX_POPUP_CONTROL_*vars from the subprocess environment alongside the existingTMUX=clearing, preventing the user's live tmux session context from leaking into tests whenmake testruns inside tmux.
Full Changelog: v0.8.0...v0.9.0