Context folding as outlines, fold guides and streamed file slots in the TUI - #84
Merged
Merged
Conversation
Patch the pinned TSX grammar so imported-type arrays parse without tolerating syntax errors. AI-assisted implementation and verification with Codex. Agent-Session: dca03de1-4350-4b24-b376-cb54c86fcc2d Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a103d9-eefe-7d11-9db3-da97527a7db7 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
Keep changes and useful context visible, wrap each hidden interval once, and retain nested AST folds for gradual expansion. Add file-wide plugin edits and keep unchanged TUI folds neutral. AI-assisted implementation and verification with Codex. Agent-Session: dca03de1-4350-4b24-b376-cb54c86fcc2d Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a103d9-eefe-7d11-9db3-da97527a7db7 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
Revert the file-phase visit, cursor.regions() and wrap_range from the previous commit; the host, wit, SDK and cursor are back to their prior API. The group plugin is removed and its job moves into context, which now runs last: - Each sibling list is shaped when the walk enters it: leaves are cut at kept/hidden edges and every run of hidden siblings of two or more lines becomes one collapsed row, linked across sides. - An unchanged fold hides whole when the other side holds its partner. - Opening a row reads as an outline: scopes keep their first and last line with the body closed as one row, comments stay open, and folds holding another plugin's collapsed region stay open. - Header lines of a changed scope, such as a doc comment above the signature, win over hiding an unchanged fold. - New context queries: bindings to arrays, objects and closures, callback statements, if/while/do/try blocks, Rust function bodies and comment runs. Not done: rows adjacent across levels where no closing line can separate them (Python blocks), which needs join to move folds between neighbours. AI-assisted with Claude Code; reviewed and directed by the author. Claude-Session: https://claude.ai/code/session_01DS7xVM7t9KBr33aGFeTFqb Agent-Session: a21f1781-9b0d-47f6-a269-e93bb179c266 Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
The shared Python and Rust queries folded single comments while the context plugin folded the whole run above code. The first comment of a run then had two fold ranges, a query conflict that kept the file from being diffed. The shared queries now fold the run, and context tags it. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
A fold query with @fold.open must now also capture @fold.indent: the node the body's indent is read from, usually its first statement. In Go the capture skips a leading label, which gofmt outdents. Each fold keeps that position and, for a fold with an opener, its exact span between the opener and the closer. Two patterns on one node must agree on both. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
Each fold now carries `indent`, where its content starts, and `syntax`, its span from the opener to the closer before rounding to lines. A client can then place a collapsed row at its body's column without reading the source text. A fold made by a plugin's join takes its parent fold's indent. The plugin interface does not change. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
`./pprint.sh <base> <head>` prints the rows the TUI would draw, as plain text. Collapsed rows sit at their fold's indent. `--mock-summaries` runs the summarizer against a local stand-in for Gemini. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a
Each side's tree now has one root: a fold over the whole file. Both roots share a fold_state_id, and the root's visibility replaces the file record's own, so a hidden file is a collapsed root. Plugins visit the root like any fold. The removed-runs plugin no longer treats the root as a removed run's owner. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
Entering an unchanged fold hides it. Entering a leaf cuts it where kept lines start and stop. Leaving a fold folds each run of hidden children into one row. The root makes the top level one more fold, so no node shapes its siblings ahead of the walk. AI-assisted with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
Project syntax openers, fold labels, closing suffixes and enclosing guides from existing wire metadata. Preserve leaf correspondence while masking folded cells, and tint only changed lines within paired leaves. Add Paper-style projection fixtures and scope hover accents. AI-assisted: implemented and validated with Codex. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1084c-5827-7552-b4d8-d53dd96563af
The store places each streamed file in its manifest slot and rejects a file outside the manifest or one that arrives twice. The viewer keys all state by manifest index, so a pending file has a scrollable slot with a spinner, and previous/next buttons skip to loaded files. The scroll position is one anchor: a row key and offset, plus the fold and source line it showed. Geometry changes resolve the anchor again instead of writing corrective state. Fold toggles read the current state, so quick repeated clicks alternate. Add a saved-stream visual review script. AI-assisted: implemented with Codex, simplified with Claude Code. Agent-Session: a366aa2e-0bed-4e42-9097-1917231c9f0a Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1084c-5827-7552-b4d8-d53dd96563af
AI-assisted with Claude Code. Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1084c-5827-7552-b4d8-d53dd96563af
The engine parses each side once. With `syntax` set it collects highlight captures from that tree, before the match runs, so a file that falls back to a line diff still has its syntax as well as its folds. The CLI no longer parses a second time to highlight. AI-assisted with Claude Code. Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1084c-5827-7552-b4d8-d53dd96563af
TypeScript used the JavaScript queries, which have no rule for type declarations, so an interface had no fold and its closing brace joined the unchanged lines after it. A shared TypeScript query adds the JavaScript structure plus interface, object type and enum bodies. Context makes those declarations scopes, matched on their export when exported, so a change inside keeps the header and the closing brace. AI-assisted with Claude Code. Agent-Session: 01a1061e-c424-7fa2-8db0-b8e0c93f5d16 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8 Agent-Session: 01a1084c-5827-7552-b4d8-d53dd96563af
A file diffed by line had no fold pairs, so context could not hide any fold whole and left one-line headers and closers between nested rows. A left and a right fold now pair when both lie inside one run of unchanged rows over the same lines of it: the two sides of such a run are the same text, so the folds are twins. AI-assisted with Claude Code. Claude-Session: https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
The bare declaration starts after `export `, mid-line, so its fold began a line late and merged with the body. Bare declarations are now matched only where they are not exported; the export rule covers the rest. AI-assisted with Claude Code. Claude-Session: https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
An unchanged fold is one item: its signature and closer show and its body folds, with every fold inside folded too, so opening it shows one more level. Near a change it stays on screen; otherwise it joins its neighbours' row. A changed scope opens its body even when the body is unchanged. Only a fold with a twin on the other side folds as an item, so rows stay aligned. AI-assisted with Claude Code. Claude-Session: https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
AI-assisted with Claude Code. Claude-Session: https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
paired, opens_with_scope, near_change and fold_once each had one caller, so reading the rule meant jumping between them. hidden also re-checked the root and a changed scope's header, which item and kept already cover. No behaviour change. AI-assisted with Claude Code. Claude-Session: https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8 Agent-Session: b7f96806-2bcb-4ee8-aca4-c5bedad0939a Agent-Session: 82924cb5-dcfa-42e4-abb0-ef40393249f8
sidkmenon
enabled auto-merge (squash)
October 5, 2026 06:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context now shows unchanged code as an outline, the TUI draws fold guides and gives every streamed file a slot, and files that fall back to a line diff keep their folds and colours.
Context plugin
linesof a change stays on screen. Other unchanged folds join their neighbours in one row. A row never crosses a fold edge.Rewrite the context plugin as one walk), and the oldgroupplugin is merged into it.Engine and wire
indentandsyntaxon the wire.fold_state_id.DiffOptionsgainssyntax,DiffResultgainslhs_highlights/rhs_highlights, andproject::Inputs::syntaxis gone. The wire shape does not change.Queries
exportline.diffr-grammarsas a vendored grammar.TUI
+/-sign column is gone.Tools
pprint.shprints a comparison with the TUI's own row model.Testing
cargo fmt --check(both workspaces),typos,cargo test --locked,cargo test -- --ignored,cargo xtask test-pluginsdiffr-ts: typecheck, build, 23 testsAI-assisted: implemented with Codex and Claude Code; the folding rule was worked out with the author through examples.
https://claude.ai/code/session_018Yz1XeLzfXEQkaRvKZ6LN8