Repository navigation
v0.10
Release Notes: v0.10.0
Release Date: January 6, 2026
Previous Version: v0.9 (January 4, 2026)
Overview
This release contains significant improvements to the SyntaxEditor and Query system, fixing fundamental issues with multi-node replacements and range queries. The internal architecture has been refactored to properly handle queries that match multiple consecutive siblings.
🚀 New Features
Query Region System
A new internal QueryRegion abstraction enables queries to correctly resolve to contiguous ranges of slots within parent containers. This powers correct behavior for:
Query.Between(start, end)- Now correctly replaces/removes/inserts around entire matched ranges- Block boundary queries (
.Start(),.End(),.Inner()) - Properly resolve to slot positions for accurate editing - Sequence queries - Multi-node matches are handled atomically
Block Boundary API Improvements
The IBlockContainerNode interface now uses a cleaner API:
// Old API (removed)
Query.Syntax<FunctionSyntax>().InnerStart("body")
Query.Syntax<FunctionSyntax>().InnerEnd("body")
// New API
Query.Syntax<FunctionSyntax>().Block("body").Start()
Query.Syntax<FunctionSyntax>().Block("body").End()
Query.Syntax<FunctionSyntax>().Block("body").Inner()Green Node Trivia Access
New methods on GreenNode for efficient trivia access:
GetLeadingTrivia()/GetTrailingTrivia()- Access trivia via first/last leaf descendantGetLeadingTriviaWidth()/GetTrailingTriviaWidth()- Precomputed width accessGetFirstLeaf()/GetLastLeaf()- Navigate to boundary leaves in O(depth)
⚡ Performance Improvements
PathTrackingWalker
A new internal PathTrackingWalker tracks paths incrementally during tree traversal:
- O(1) per step instead of O(depth) for
NodePath.FromNode() - Pushes sibling index on descent, pops on ascent
- Used by all
SelectRegionsimplementations
Lazy Path Resolution
QueryRegion.ParentPath is computed lazily on first access, avoiding tree-walking overhead when regions are enumerated but not all are used for editing.
Optimized Trivia Extraction
SyntaxEditor.GetTrivia()now delegates to green node methods (2 lines vs 30+ lines)- Uses precomputed
LeadingTriviaWidth/TrailingTriviaWidthinstead of runtime summation GetContentWithoutTrivia()uses span-based slicing
Inlined Query Matching
KindNodeQuery.SelectRegionsinlines Kind check and predicate evaluationBlockNodeQuery.SelectRegionsinlines block type check- Avoids virtual
TryMatchdispatch in hot loops
🐛 Bug Fixes
Fixed: Query.Between with SyntaxEditor.Replace()
Previously, Replace() with range queries like Query.Between(start, end) would only replace the first node. Now the entire matched range is replaced atomically.
Fixed: Block Inner Content Replacement
Replacing content inside empty blocks (e.g., { }) now works correctly. The zero-width inner region is properly resolved.
Fixed: Multi-Position Insertions
InsertAfter and InsertBefore with queries matching multiple positions now correctly insert at all matched positions.
📊 New Benchmarks
Added SyntaxEditorBenchmarks.cs with comprehensive benchmarks:
| Category | Benchmarks |
|---|---|
| Replace | Replace_SingleToken, Replace_MultipleTokens, Replace_AllIdents |
| BlockInner | Replace_BlockInner_Empty, Replace_BlockInner_WithContent, Replace_BlockInner_Larger |
| Insert | InsertAfter_SinglePosition, InsertAfter_ManyPositions, InsertBefore_ManyPositions |
| SelectRegions | SelectRegions_DeepTree (20/50 levels), SelectRegions_DeepTree_Blocks, SelectRegions_DeepTree_First |
| Transform | Edit_Transform_SingleToken, Replace_WithNodeTransformer |
| UndoRedo | Edit_ThenUndo, MultipleEdits_ThenUndoAll |
🔧 Breaking Changes
None for public API. All changes are internal implementation details.
Internal API Changes (for library contributors)
- Removed
InsertionQueryandInsertionPointenum - replaced byBoundaryQuery+IRegionQuery IBlockContainerNode.InnerStart()/InnerEnd()replaced by.Block().Start()/.End()- Query types now implement
IRegionQueryinterface
📁 Files Changed
+2,751 / -891 lines across 21 files
New Files:
QueryRegion.cs (245 lines)
SyntaxEditorBenchmarks.cs (375 lines)
Major Changes:
SyntaxEditor.cs (+530 lines refactored)
NodeQueryTypes.cs (+386 lines)
QueryCombinators.cs (+181 lines)
GreenBlock.cs (+203 lines)
IBlockContainerNode.cs (+171 lines)
GreenNode.cs (+88 lines)
🧪 Test Coverage
- 15+ new tests for
Query.Betweenwith all editor operations - Block inner content replacement tests (empty and non-empty)
- Deep tree traversal tests (20-50 levels)
- Multi-position insertion tests
Upgrade Guide
No action required for most users. If you were using internal APIs:
// If you implemented IBlockContainerNode, update usage:
// Before:
editor.InsertAfter(query.InnerStart("body"), "code")
// After:
editor.InsertAfter(query.Block("body").Start(), "code")