Skip to content

feat(tui): preview the highlighted widget live while picking - #755

Merged
sirmalloc merged 2 commits into
sirmalloc:mainfrom
eric-engberg:feat/widget-picker-preview
Oct 29, 2026
Merged

sirmalloc merged 2 commits into
sirmalloc:mainfrom
eric-engberg:feat/widget-picker-preview

Conversation

@eric-engberg

Copy link
Copy Markdown
Contributor

Demo

Opening the picker after the last widget, browsing the full list (note the ↓ 72 more marker), and applying the highlighted widget. Each highlighted widget appears in the preview at the top, and Enter leaves the line exactly as previewed.

Powerline

Widget picker preview in Powerline mode

Plain

Widget picker preview in plain mode

Summary

Finding out what a widget looks like used to take several key presses: add it, look at the preview, then delete it. Repeating that across the catalog took a long time.

Now, while the add, insert, or change-type picker highlights a widget, the status line preview at the top of the TUI shows the line exactly as pressing Enter would leave it.

  • Add/insert: the highlighted widget appears where it would be placed.
  • Change type: the selected widget is shown with its type swapped.
  • Arrowing through the list, or through top-level search results, updates the preview live.
  • ESC, or browsing the category list where no widget is highlighted, restores the line. Nothing is saved until Enter.
  • In powerline mode, the new widget's background color is picked once when the picker opens. It doesn't change on every keypress, and Enter adds the same color that was previewed. Previously the color was picked at random when Enter was pressed.
  • Widgets render with the existing TUI sample data, so the preview runs nothing new.

Windowed picker lists

The picker used to render every entry. The All category has about 90 widgets, so it, and broad searches, ran past the bottom of the terminal and scrolled the status line preview off the top. Picker lists now show only the entries around the selection, with ↑ N more / ↓ N more markers.

  • The number of entries shown depends on the terminal height and the number of status lines: 7 on a standard 80×24 terminal with one line, more on taller terminals.
  • Entry numbers are still counted across the full list, so you can see your position in it.

Implementation

  • items-editor/picker-selection.ts: placePickerSelection() builds the resulting line for add, insert, or change. The preview and the final Enter both use it, so they can't drift apart.
  • items-editor/list-window.ts: getListWindow() keeps the selection centered once the list scrolls. getPickerMaxVisible() sizes the list to fit the terminal.
  • ItemsEditor: the picker reports its candidate line, or null, through the existing onPreviewChange prop that label drafts already use, so App swaps it into what StatusLinePreview renders with no changes of its own. Picker lists render through the windowed list.

Testing

  • New unit tests for placePickerSelection, getListWindow, and getPickerMaxVisible.
  • New Ink render tests:
    • category browsing shows no preview
    • search highlights a widget, and the preview shows it in place
    • change-type swaps the widget in place
    • ESC restores the line
    • Enter applies exactly the previewed line, including the powerline background
    • unmounting clears the preview
    • a long list is windowed, and the shown entries plus the hidden count add up to the total
    • the window follows the selection when it wraps to the end
  • bun test: 2380 pass. bun run lint: clean.
  • Manual run in tmux:
    • preview: add via search updates live, ESC restores the line, change-type works, and Enter applies the previewed widget
    • powerline: the new widget keeps the same background while arrowing
    • windowing at 80×24 and 120×45: the preview stays on screen; with a long --config path wrapping onto two extra lines, only the title scrolls off
  • Rebuilt as one commit on today's main, after feat(tui): opt-in dev reload that restarts the TUI in place #700 merged: bun test 3276 pass, 0 fail; bun run lint clean. Built CLI under Bun 1.4.2 and Node 26.10.0: piped renders match main in plain and Powerline modes, and the TUI opens and exits cleanly under both.

Seeing what a widget looks like used to mean adding it, looking, and
removing it again. While the add/insert/change picker highlights a
widget, the status line preview now shows the line exactly as Enter
would leave it; ESC or browsing categories restores the line.

The new widget's id and powerline background are fixed when the picker
opens, so the preview doesn't change color on every keypress and Enter
adds exactly what was shown. Preview and apply share one placement
helper. A type change drops the widget's label there, as the label
editor (sirmalloc#601) does, so the preview shows the line without the old
label, as Enter applies it.

The picker rendered every entry, so the All category (~90 widgets) or a
broad search ran past the bottom of the terminal and scrolled the
preview off the top. Picker lists now show only the entries around the
selection, sized to the terminal height, the number of status lines and
the list's tallest description (wrapped at the terminal width as Ink
wraps it), with "↑ N more" / "↓ N more" markers. Entry numbers stay
absolute, so position in the full list is still visible.
The category list holds plain strings, so finding the highlighted one
needs no callback; a picker with no categories has none highlighted.
@sirmalloc
sirmalloc merged commit bf8e2bc into sirmalloc:main Oct 29, 2026
3 checks passed
axisrow added a commit to axisrow/ccstatusline that referenced this pull request Oct 29, 2026
sirmalloc#755 live picker preview, sirmalloc#754 fast mode widget, sirmalloc#753 thinking-effort test stub, sirmalloc#752 transcript block fallback fixes, sirmalloc#751 editor keys no longer pause on global install lookup, sirmalloc#750 git cache TTL starts after the run, sirmalloc#749 npx cache skip, sirmalloc#747 Block Usage hides at 100% and swaps with Block Reset Timer)

Conflict policy: upstream infra wins, fork features ported on top. Joins:
sirmalloc#750 stamps the git cache after the run while keeping the fork's execGit
hardening/env snapshot and daemon prefetch bookkeeping; sirmalloc#752's
isApiErrorMessage guard lands in the fork's shared collectTimestampFromLine
(sync + async twins), upstream's duplicate getActivityTimestamp dropped;
sirmalloc#747 adds SESSION_AT_LIMIT alongside the fork's zero hide state
(BlockResetTimer keeps zero + under-limit via isAtSessionLimit, SessionUsage
is no-data/zero/at-limit); sirmalloc#755 replaces the fork's picker window + "Showing
X-Y of N" note with upstream's renderWindowedList/getPickerMaxVisible and
live preview (markers ↑/↓ N more cover the counts); sirmalloc#751's installationState
useMemo replaces the fork's inline lookups, the fork's mainMenuIndex helper
is kept.

Co-Authored-By: Claude Code <noreply@anthropic.com>
pcvelz added a commit to pcvelz/ccstatusline-usage that referenced this pull request Oct 29, 2026
Upstream: Extra Usage Limit widget (sirmalloc#756), live widget preview while picking (sirmalloc#755), Fast Mode widget (sirmalloc#754), transcript block fallback fixes (sirmalloc#752), editor keys on a global install (sirmalloc#751), git cache TTL (sirmalloc#750), npx cached copy skip (sirmalloc#749), Block Usage hide at 100% (sirmalloc#747), Block Reset Timer hide until 100% (sirmalloc#697), fish-style branch abbreviation (sirmalloc#614), jj detached HEAD (sirmalloc#705), hooks save warning (sirmalloc#703), dev reload (sirmalloc#700), merge ends at a hidden widget (sirmalloc#698), Block Forecast and Block Limit Timer widgets (sirmalloc#699), contributor guide (sirmalloc#706), POSIX path case fix (sirmalloc#707), whitespace-distinct conflict filenames (sirmalloc#709), Quick Start reorder (sirmalloc#715), bunx launch guidance (sirmalloc#714), jj diff summary counts (sirmalloc#711), powerline manual separators (sirmalloc#713), keychain credential by account (sirmalloc#532), Keychain probe timeout (sirmalloc#760), usage cache scoped per CLAUDE_CONFIG_DIR (sirmalloc#266), test isolation (sirmalloc#717, sirmalloc#753), dev-dependency bumps (sirmalloc#745)

Conflicts resolved per the standard-resolution table; fork deletions re-applied.

Hand edits outside conflicts:
- src/utils/global-command-resolution.ts: fork-rename (ccstatusline@ -> ccstatusline-usage@ in upstream's new bunx pattern)
- src/utils/__tests__/global-package-manager.test.ts: fork-rename (package dir ccstatusline-usage in upstream's new tests)
- src/utils/usage-fetch.ts: compat fix - cacheUsageData gained a fetchedAtMs arg (upstream sirmalloc#266); adapted the fork-only fetchFreshUsageData call site
- src/utils/__tests__/usage-fetch.test.ts: compat fixes - cache/lock now hashed per CLAUDE_CONFIG_DIR (usageFilePath helper) in four fork tests; upstream fableUsage renamed to fork's weeklyFableUsage; seedUsageCache takes TokenHome
- src/utils/__tests__/usage-prefetch.test.ts: compat fix - mockFetchUsageData renamed to upstream's mockFetchUsage in cleanly-merged tests
- README.md: took upstream's Quick Start move (sirmalloc#715) and dropped the fork's old copy; fork-rename of its ccstatusline@ specifiers; links to fork-deleted docs (docs/USAGE.md, docs/WINDOWS.md) replaced with the fork's inline text
- CONTRIBUTING.md: links to the fork-deleted docs/DEVELOPMENT.md pointed at the README Development section
- docs/test-retirements.md: ledger entries for the 12 upstream test renames (sirmalloc#697, sirmalloc#698, sirmalloc#700, sirmalloc#705, sirmalloc#713, sirmalloc#760)
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.

2 participants