Skip to content

feat(tui): sort tables and collapse trees in visualizations - #2120

Merged
LHagfoss merged 2 commits into
mainfrom
feat/tui-interactive-viz
Oct 18, 2026
Merged

LHagfoss merged 2 commits into
mainfrom
feat/tui-interactive-viz

Conversation

@LHagfoss

Copy link
Copy Markdown
Owner

Closes #2088

Finishes the scope left open after #2094: interactive rustcode-viz widgets in the TUI, matching the macOS app.

Behavior

  • Table: click a header to sort ascending, click again to flip. Numeric columns sort by value, text lexically. The sorted header shows ▲/▼. A click overrides the payload's sort_by, which gets the same marker. Every row is sorted before the 50-row cap. Narrow key/value tables have no header row, so they can't be re-sorted.
  • Tree: nodes with children show ▾/▸. Clicking the marker or label folds or unfolds the node, and a folded node shows N hidden. Every node starts open, as in the current render. Nodes cut off by the depth limit get no marker.
  • Targets are lit on hover. A click is a press and release on the same cell, the same rule tool rows use, so dragging still selects. A reader who is scrolled up keeps the clicked row in place.

Design

  • VizView { source, sort, toggled } is stored in TranscriptState.viz_views, keyed by (history index, viz ordinal). source is a hash of the fence body, so state made for another body is ignored. It exists only in terminal UI state: it is not persisted, not sent to the provider, and does not touch /copy or export. The canonical text is unchanged.
  • The renderer (render_visualization_with_view) returns clickable spans with the rows. Table header columns are read from the Markdown grid's span structure, and anything that doesn't match that shape yields no targets. Tree node ids are preorder ids over the whole tree, so they stay stable when nodes above them fold.
  • committed_block renders assistant messages through render_committed_history_block_interactive. The committed block cache key hashes that message's view state, so a toggle redraws and nothing stale is left on screen. Hits are cached next to the rows, the same way as tool_owner_cache. The projection maps hits to painted cells next to tool and message rows (viz_line_flags, then set_viz_rows, then viz_target_at).
  • Live streams, open fences and terminal scrollback stay non-interactive and always use the default view. Streaming and scrollback contracts are unchanged.

Deferred

  • Keyboard access. The transcript has no focus model for items inside a message (ctrl+shift+o steps tool output only), so this stays mouse-first. It is documented as a follow-up in docs/visualizations.md.
  • New widget types (sparkline, key_value).

Tests

  • Unit: numeric and text sorting with markers, sort_by override, header targets covering their columns and picking the next direction, no targets for narrow tables, tree folding with hidden counts and stable ids, message-level targets offset past the gutter, stale state ignored, live stream not interactive.
  • Frame: visualization_headers_and_tree_nodes_are_click_targets_that_redraw renders a real frame, resolves targets from painted cells, applies them, and checks that the redraw sorts, flips, folds and unfolds while the history text stays unchanged.

🤖 Generated with Claude Code

LHagfoss and others added 2 commits October 18, 2026 15:52
Table headers in a finished `rustcode-viz` widget sort on click (again to
flip, numeric columns by value, ▲/▼ marker), and tree nodes with children
fold on click (▾/▸, "N hidden" hint), mirroring the macOS app.

The view state lives only in TranscriptState, keyed by (history index, viz
ordinal) plus a hash of the fence body. It is never persisted, sent to the
provider, or applied to /copy or export. The committed block cache keys on
it, the renderer reports clickable spans next to the rows, and the
projection maps them to painted cells like tool rows. Live streams, open
fences, and terminal scrollback stay non-interactive. Keyboard access is
left for a follow-up: the transcript has no focus model inside messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the feature New feature or request label Oct 18, 2026
@LHagfoss
LHagfoss merged commit 36bd0ba into main Oct 18, 2026
7 checks passed
@LHagfoss
LHagfoss deleted the feat/tui-interactive-viz branch October 18, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(tui): render agent-generated visualizations in chat

1 participant