Skip to content

Shape reading mode: fold function bodies in the whole-file view - #26

Draft
davegaeddert wants to merge 4 commits into
masterfrom
claude/code-symbol-mode-3bfh4e
Draft

Shape reading mode: fold function bodies in the whole-file view#26
davegaeddert wants to merge 4 commits into
masterfrom
claude/code-symbol-mode-3bfh4e

Conversation

@davegaeddert

@davegaeddert davegaeddert commented Jul 30, 2026

Copy link
Copy Markdown
Member

Spike of the reading-modes arc's first future (futures: review/reading-modes/shape-view.md): a "Shape" toggle for the whole-file view that folds every function/method body to a faint marker — signatures, docstrings, fields, and imports stay literal — with per-fold expand/collapse and real line numbers preserved.

Approach

Deliberately without forking @pierre/diffs (which has no fold/hidden-range API and recycles rows while virtualizing): shape mode synthesizes a smaller real document — collapsed bodies removed, one indent-matched marker line each — so pierre's virtualization stays correct. Pierre's line numbers are disabled (disableLineNumbers) and a custom self-virtualized gutter (ShapeGutter) renders real line numbers + fold chevrons; on scroll it translates one wrapper instead of rebuilding rows. A collapsed fold's marker occupies the same row its first body line takes when expanded, so single toggles never shift content above the click point. Read-only by design: token/selection/annotation interactions are inert in shape mode, and line-addressed features that speak real-file coordinates (in-file search, go-to-line, outline active-tracking/clicks) are explicitly suppressed while shape is on rather than silently mis-mapped.

Backing data: Symbol gains optional bodyStartLine (1-based first interior line; the signature including its trailing { line stays visible), populated at all 66 construction sites in the tree-sitter extractor. None for one-liners, expression-bodied functions, and bodyless declarations.

Shape state and derivation live in hooks/useShapeMode.ts (component state by design, like svgViewMode/markdownViewMode — promoting to a slice is required only if this ever becomes a palette command). A /simplify four-angle cleanup pass (2a15ea9) shrank the model to the two fields the renderer consumes, hoisted per-toggle hashing/splitting to once per file, and reused ToggleButtonGroup for the fold controls.

Status

  • bodyStartLine in core/src/symbols/ (+3 extractor tests: Rust incl. multi-line signatures, Python incl. docstring-as-interior, TypeScript incl. arrow consts)
  • Synthesized-document fold view + custom gutter (shape-model.ts pure + 16 unit tests, ShapeGutter.tsx, useShapeMode.ts, toolbar toggle + expand/collapse-all, gated to plain whole-file mode)
  • Frontend validation: tsc clean, 628 vitest tests pass
  • Visual verification in a browser harness against core/src/symbols/extractor.rs (3.5k lines → 598 rows / 97 folds), re-verified after the cleanup pass: fold markers, multi-line signatures intact, gutter alignment deep mid-file, in-place expand with no scroll shift, expand-all/collapse-all, raw toggle
  • Needs a local run: this cloud environment's network policy blocks static.crates.io, so cargo check/cargo test could not run here (Rust code is rustfmt-parse-clean and structurally audited, but the 3 new extractor tests are unrun). Please run scripts/test locally, then scripts/dev-web → open a repo → an unchanged file in whole-file view → the Shape toggle in the toolbar.

Known follow-ups (deliberate spike scope)

  • Real-line remapping: search/go-to-line/outline are suppressed in shape mode; buildShapeDocument's rows can carry a real↔doc mapping when someone closes this properly (the suppression site documents the path).
  • Deferred Rust refactors from the cleanup review (need a compiler): a Symbol::from_node constructor to collapse the 66 mechanical field initializations; passing precomputed line bounds into body_interior_start; replacing its starts_with('{') text test with the tree-sitter-structural body.named_child(0) answer.
  • Outline rows still look clickable in shape mode though clicks are inert; marker rows are syntax-highlighted as plain text.

🤖 Generated with Claude Code

https://claude.ai/code/session_013mVGpFa5b6ZNMVaXE7bQQq

claude added 4 commits July 30, 2026 20:33
Groundwork for the shape reading-mode spike (fold function bodies in the
whole-file view). Implementation lands in follow-up commits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013mVGpFa5b6ZNMVaXE7bQQq
1-based first interior line of a symbol's body — the first line a fold
may hide while the whole signature, including a trailing brace, stays
visible. Populated wherever the grammar exposes a body node; None for
one-liners, expression-bodied functions, and bodyless declarations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013mVGpFa5b6ZNMVaXE7bQQq
A toolbar toggle folds every function/method body to an elision marker
so the file reads as its outline; markers (and gutter chevrons) expand
and collapse individual bodies in place.

Pierre has no fold API and recycles rows while virtualizing, so shape
mode hands it a smaller real document — collapsed bodies removed, one
indent-matched marker line each — keeping virtualization correct, and
renders real line numbers from a custom self-virtualized gutter with
pierre's own numbers disabled. A collapsed fold's marker occupies the
same row its first body line takes when expanded, so single toggles
never shift content above the click point. Read-only: token, selection,
and annotation interactions are inert in shape mode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013mVGpFa5b6ZNMVaXE7bQQq
ShapeDocument shrinks to the two fields the renderer consumes; the
test-only exports and parallel fold maps are gone. Shape derivation
moves into hooks/useShapeMode.ts, which also hoists the per-toggle
file split and content hash to once per file (the synthesized doc's
cache key replaces re-hashing the whole document on every fold click).
The gutter now translates one wrapper on scroll instead of rebuilding
every visible row, and only shape mode pays the scroll-node state that
previously cost every file view a second CodeView render. Toolbar fold
controls reuse ToggleButtonGroup; the six shape props are required.

Line-addressed features (in-file search, go-to-line, outline tracking)
speak real-file coordinates, which the synthesized document does not
share — they are now explicitly suppressed while shape mode is on
rather than silently mis-mapped, with the mapping path documented for
whoever closes the gap properly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013mVGpFa5b6ZNMVaXE7bQQq
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