Skip to content

feat(ide): expand folding coverage and fix selection in preprocessor regions - #325

Merged
hongjr03 merged 4 commits into
masterfrom
feat/folding-selection
Aug 4, 2026
Merged

feat(ide): expand folding coverage and fix selection in preprocessor regions#325
hongjr03 merged 4 commits into
masterfrom
feat/folding-selection

Conversation

@hongjr03

@hongjr03 hongjr03 commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

Four commits improving folding and selection, driven by the review goals of correctness, cleanliness, and efficiency:

  1. Expand folding coverage (crates/ide/src/folding_ranges.rs, LSP layer)

    • Fold function/task bodies (Subroutine) at file, module, and generate-block level, recursing into their statement arenas like blocks.
    • Recurse into generate blocks: instances, subroutines, assigns, and declarations inside generate now fold individually.
    • Fold runs of consecutive single-line items into one group fold: package imports (Imports), continuous assigns, and declarations.
    • Fold multi-line argument lists and concatenations/assignment patterns syntactically, like rust-analyzer's ArgList/Array folds.
    • Rewrite comment folding as a single syntax walk over token trivia; drop the memchr scan and the ineffective visited_ranges set.
    • Remove FoldingConfig from the ide API (line_fold_only is purely a client-capability concern at the LSP layer) and the never-populated collapsed_text field.
  2. Selection inside preprocessor directives and inactive ifdef branches

    • Directive trivia is zero-width in the syntax tree and disabled code is absent from it entirely. Recover exact ranges from the preprocessor trace (root buffer offsets are the file's own offsets): directive keyword/name ranges for ifdef/define/include lines, and disabled_ranges for inactive branch bodies.
    • Drop the duplicate selection range that appeared for trivia-only files.
  3. Fold fixture matrix + region fix

    • rust-analyzer style <fold kind> fixture harness covering every fold kind.
    • Fix a pre-existing ordering bug in RegionTreeBuilder::stage: the closing token's trivia was scanned only after open regions were force-closed, so an endregion marker attached to endmodule/EOF was lost and the region stretched to the end of the container.
  4. Single-item group fold fix

    • collect_item_groups folded a lone multi-line item as a one-element group, duplicating the item fold; require at least two items per group.

Validation

  • cargo test --workspace green (540+ tests, including 18 new folding fixtures and an extended selection matrix).
  • cargo fmt --check clean for all touched files.

Follow-up

Opened separately: library declarations in .sv files (library-map syntax) recover into misleading multi-line declaration folds (see issue).

- Fold function/task bodies (Subroutine) at file, module, and generate
  block level, recursing into their statement arenas like blocks.
- Recurse into generate blocks: instances, subroutines, assigns, and
  declarations inside generate now fold individually.
- Fold runs of consecutive single-line items into one group fold:
  package imports (Imports), continuous assigns, and declarations.
- Fold multi-line argument lists and concatenations/assignment patterns
  syntactically, like rust-analyzer's ArgList/Array folds.
- Rewrite comment folding as a single syntax walk over token trivia;
  drop the memchr scan and the ineffective visited_ranges set.
- Remove FoldingConfig from the ide API (line_fold_only is purely a
  client-capability concern at the LSP layer) and the never-populated
  collapsed_text field.
Selection inside a preprocessor directive used to degenerate to the
bare cursor range: directive trivia is zero-width in the syntax tree,
so no range could be found. Selection inside an inactive `ifdef branch
was impossible altogether, since the disabled code is absent from the
tree.

Recover both from the preprocessor trace, whose root buffer offsets are
the file's own offsets:

- directive keyword/name ranges give exact selection steps for
  `ifdef/`define/`include/... lines;
- disabled ranges make the whole inactive branch selectable, which is
  the natural expand-selection unit for dead code.

Also drop the duplicate selection range that appeared for trivia-only
files (the comment range and the trivia-to-token range coincided).
Add a rust-analyzer style fixture harness for folding ranges
(<fold kind>...</fold> tags) and cover every fold kind: comment
runs, block comments, regions, module/port-list split, subroutines
(module- and file-level), instances (single and multi), generate
blocks, import/assign/declaration groups, pseudo regions, argument
lists, concatenations, and config declarations.

While writing the region fixtures a pre-existing ordering bug in
RegionTreeBuilder::stage surfaced: the closing token's trivia was
scanned only after open regions had been force-closed, so an
endregion marker attached to endmodule/EOF was silently lost and the
region stretched to the end of the container. Scan the trivia first.
collect_item_groups folded a lone multi-line item (e.g. a declaration
recovered from a parse error) as a one-element group, duplicating the
item fold produced by collect_folds. Require at least two items per
group.
@hongjr03
hongjr03 merged commit 0e73c4d into master Aug 4, 2026
17 of 18 checks passed
@hongjr03
hongjr03 deleted the feat/folding-selection branch August 4, 2026 17:46
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.

1 participant