Skip to content

Releases: atomicstack/tmux-popup-control

v0.12.1

09 Jun 21:49

Choose a tag to compare

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

  • SessionOption now reads session options via show-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 (were 0644) and the capture dir 0700 — 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/Restore respect context cancellation on every progress send (a stalled consumer can no longer leak the producer goroutine).
  • pane:join no 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 TestMain teardown to the menu package and fixed a test-ordering hazard under -shuffle=on.

v0.12.0

02 Jun 17:18

Choose a tag to compare

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 renderYNPrompt helper 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 the window-pane-status-format pair.
  • the tmux_command and format_string shared domains are now typed structs (TmuxCommandDomain, FormatStringDomain) instead of untyped maps.
  • new accessors: Catalog.TmuxCommands() returns 91 tmux commands with aliases sorted by name, and Catalog.FormatVariables() returns the 192 default format variables from format.c with their value types.

housekeeping

  • gofmt sweep across internal/menu, internal/ui, internal/cmdparse, and internal/testutil — whitespace only, no behaviour changes.

v0.11.0

07 May 00:51

Choose a tag to compare

highlights

  • new top-level resurrect submenu — save / save-as / restore / restore-from / delete-saved all live here now, hoisted out of the session submenu 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 the last symlink 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, y green bold, n red bold. applies to both the per-plugin uninstall prompt and the post-completion "Reload plugins?" prompt.

menu changes

  • session:saveresurrect:save
  • session:save-asresurrect:save-as
  • session:restoreresurrect:restore
  • session:restore-fromresurrect:restore-from
  • new: resurrect:delete-saved
  • main.tmux hotkey vars rename to TMUX_POPUP_CONTROL_KEY_RESURRECT_*; the legacy KEY_SESSION_SAVE / KEY_SESSION_RESTORE_FROM names 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 the last symlink as appropriate.

v0.10.0

05 May 01:16

Choose a tag to compare

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 -p at 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 maxVisibleItemsmaxVisibleItems reserved rows for an inline preview that viewVertical then refused to render, shrinking the tree's viewport and dragging the auto-selected cursor off the top in --no-preview configs.
  • 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 parallel make test load that hung for 5+ minutes per run.

performance

  • tmux: cut redundant tmux commands per backend poll — cache ShowOption results per (socket, option) for the binary's lifetime; skip ListSessionsFormat when no custom session label format is configured. Drops FetchSessions from 6 commands to 3 on the first cycle, cheaper still after.
  • testutil: pool one tmux server per test binary — sampling concurrent tmux processes during make test showed 11–13 servers alive at peak from cleanup-overlap stacking. New pool runs one server per package via sync.Once/TestMain and tears down only per-test sessions in cleanup. Tests that genuinely need an isolated server (cross-server save/restore round-trip) opt into StartIsolatedTmuxServer.

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).
  • attachFilterCursor clamping modernized; dead form-cursor path removed.

v0.9.5

16 Apr 22:47

Choose a tag to compare

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

14 Apr 14:06

Choose a tag to compare

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

13 Apr 21:17

Choose a tag to compare

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

12 Apr 17:50

Choose a tag to compare

improvements

  • inline colour rendering — colour values (colour33, color196, #ff5500, etc.) in show-options output 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,bold now render their colour components in the actual colour
  • exported cmdparse helpersSchemaHasArgFlag and PositionalAt are 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 handlingshow-options -A output with *-suffixed inherited names (e.g. display-panes-active-colour*) is now correctly recognised and coloured
  • show-hooks empty outputshow-hooks with empty output now shows [no hooks found] (or [no hooks found in scope -g]) instead of silently hiding the popup

v0.9.1

12 Apr 03:21

Choose a tag to compare

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, colourN forms, and #rrggbb hex.
  • show-options / show-window-options / show-hooks results 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-hooks queries 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

11 Apr 22:57

Choose a tag to compare

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 parsing show-options -a at 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 ^/v indicator rows. the completion popup renders it via lipgloss.JoinHorizontal as a separate column so selection highlighting can never bleed into the scrollbar glyph; the main menu and session tree pick it up through a new styledLine.suffix field.
  • 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 the window:switch menu 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, and show-hooks now 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_PANE from TMUX_POPUP_CONTROL_PANE_ID when running inside a display-popup, which clears TMUX_PANE and broke tmux commands that rely on it to resolve the current pane context (e.g. move-window -r).
  • integration tests now strip TMUX_PANE and all TMUX_POPUP_CONTROL_* vars from the subprocess environment alongside the existing TMUX= clearing, preventing the user's live tmux session context from leaking into tests when make test runs inside tmux.

Full Changelog: v0.8.0...v0.9.0