LSP: add syntax-backed folding ranges in full mode
- Dominant language
- C#
- Stars
- 154
- Forks
- 4
- Avg merge
- 2h 46m
- Merged PRs (30d)
- 189
Description
Parent epic: #1390. Deferred from #1306. This can proceed in parallel with the semantic/member work and may use existing statement/declaration spans plus delimiter tokens.
## Goal
Provide deterministic `textDocument/foldingRange` results for standalone `full` mode, including TypeScript/TSX constructs that minimal editors cannot always derive themselves.
## Work
- [ ] Register folding ranges in `full` mode only and honor client `lineFoldingOnly` and `rangeLimit` capabilities.
- [ ] Produce ranges for multiline functions/methods/arrows, classes/interfaces/enums/namespaces, blocks/control flow, switch bodies/cases where useful, object/array/type literals, multiline parameter/type-argument lists, JSX elements/fragments, template literals, and multiline comments.
- [ ] Add import-group and region folding only when the source syntax makes the boundary deterministic.
- [ ] Reuse source spans/delimiter tokens rather than reparsing source with ad hoc regular expressions; use #1391 if a claimed range cannot be made exact from existing provenance.
- [ ] Exclude single-line, empty, invalid, duplicate, and crossing ranges; preserve legitimate nesting and deterministic ordering.
- [ ] Define fold kinds (`comment`, `imports`, `region`) and collapsed text only where protocol/client support is reliable.
- [ ] Remain resilient under parser recovery and incomplete edits, using document snapshots and cancellation.
- [ ] Document supported constructs and the intentional absence from `interop-only`.
## Verification
- [ ] Exact line/character tests cover every supported construct, deep nesting, adjacent ranges, same-line braces, Allman braces, CRLF/LF, Unicode, comments, templates, TSX, decorators, and generic/type literals.
- [ ] Structural invariant tests assert start precedes end, no single-line folds, ranges are within the document, duplicates are absent, and ranges are either nested or disjoint rather than crossing.
- [ ] Malformed and half-typed source returns best-effort valid ranges without exceptions.
- [ ] `lineFoldingOnly` and small `rangeLimit` requests return deterministic valid subsets.
- [ ] Stale-version and cancellation tests do not publish obsolete ranges.
- [ ] Real initialize handshakes advertise folding only in `full`; `interop-only` remains unchanged.
- [ ] Add an end-to-end JSON-RPC snapshot for a representative TSX/module file.
- [ ] Benchmark a large generated/nested file and document latency and allocation impact.
- [ ] Full unit, language-server pack, extension compile, Test262, and TypeScript conformance validation is green.
## Success criteria
Supported multiline constructs fold at the intended boundaries in standalone clients, all ranges satisfy LSP structural invariants under valid and recovered syntax, client limits are honored, and coexistence mode is unaffected.
## Non-goals
- Competing with an editor's richer native Tree-sitter folds.
- Heuristic folding whose boundaries are not source-structurally defensible.
- Folding runtime/generated compiler structures.
Contributor guide
Research direction
The issue names no source files or test paths. Start by locating standalone `full`-mode registration, existing statement/declaration spans, and delimiter-token provenance; done means deterministic valid folding ranges, capability limits, recovery behavior, and the listed unit, JSON-RPC, handshake, and benchmark verification pass without changing `interop-only`.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, typescript
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100