@@ -45,9 +45,14 @@ public final class IncrementalParseReusedNodeCollector:
4545/// Keeps track of a previously parsed syntax tree and the source edits that
4646/// occurred since it was created.
4747public final class IncrementalParseTransition {
48- fileprivate let previousTree : SourceFileSyntax
49- fileprivate let edits : ConcurrentEdits
50- fileprivate let reusedDelegate : IncrementalParseReusedNodeDelegate ?
48+ fileprivate var previousTree : SourceFileSyntax ?
49+ fileprivate var edits : ConcurrentEdits ?
50+ fileprivate var reusedDelegate : IncrementalParseReusedNodeDelegate ?
51+
52+ fileprivate var previousLookaheadRange : [ Int : Int ] = [ : ]
53+ /// Keep track of how far we would look when calling ``Lookahead``
54+ /// Key is offset to buffer start and value is the length of we lookahead
55+ fileprivate var cursorLookaheadRange : [ Int : Int ] = [ : ]
5156
5257 /// - Parameters:
5358 /// - previousTree: The previous tree to do lookups on.
@@ -56,14 +61,30 @@ public final class IncrementalParseTransition {
5661 /// - reusedNodeDelegate: Optional delegate to accept information about the
5762 /// reused regions and nodes.
5863 public init (
59- previousTree: SourceFileSyntax ,
60- edits: ConcurrentEdits ,
64+ previousTree: SourceFileSyntax ? = nil ,
65+ edits: ConcurrentEdits ? = nil ,
6166 reusedNodeDelegate: IncrementalParseReusedNodeDelegate ? = nil
6267 ) {
6368 self . previousTree = previousTree
6469 self . edits = edits
6570 self . reusedDelegate = reusedNodeDelegate
6671 }
72+
73+ public func setupTransition( tree: SourceFileSyntax , edits: ConcurrentEdits , delegate: IncrementalParseReusedNodeDelegate ? = nil ) {
74+ self . previousTree = tree
75+ self . edits = edits
76+ self . reusedDelegate = delegate
77+ self . previousLookaheadRange = cursorLookaheadRange
78+ self . cursorLookaheadRange = [ : ]
79+ }
80+
81+ public func registerAffectRange( at offset: Int , length: Int ) {
82+ self . cursorLookaheadRange [ offset] = length
83+ }
84+
85+ public func isValidTransition( ) -> Bool {
86+ return previousTree != nil
87+ }
6788}
6889
6990fileprivate extension Sequence where Element: Comparable {
@@ -204,16 +225,14 @@ public struct ConcurrentEdits {
204225/// updated source that was already parsed during a previous parse invocation.
205226public struct IncrementalParseLookup {
206227 fileprivate let transition : IncrementalParseTransition
207- fileprivate var cursor : SyntaxCursor
208228
209229 /// Create a new ``IncrementalParseLookup`` that can look nodes up based on the
210230 /// given ``IncrementalParseTransition``.
211231 public init ( transition: IncrementalParseTransition ) {
212232 self . transition = transition
213- self . cursor = . init( root: transition. previousTree. data)
214233 }
215234
216- fileprivate var edits : ConcurrentEdits {
235+ fileprivate var edits : ConcurrentEdits ? {
217236 return transition. edits
218237 }
219238
@@ -242,7 +261,7 @@ public struct IncrementalParseLookup {
242261 let node = cursorLookup ( prevPosition: prevPosition, kind: kind)
243262 if let delegate = reusedDelegate, let node {
244263 delegate. parserReusedNode (
245- range: ByteSourceRange ( offset: newOffset , length: node. byteSizeAfterTrimmingTrivia) ,
264+ range: ByteSourceRange ( offset: node . positionAfterSkippingLeadingTrivia . utf8Offset , length: node. byteSizeAfterTrimmingTrivia) ,
246265 previousNode: node
247266 )
248267 }
@@ -253,20 +272,28 @@ public struct IncrementalParseLookup {
253272 prevPosition: AbsolutePosition ,
254273 kind: SyntaxKind
255274 ) -> Syntax ? {
275+ guard let data = transition. previousTree? . data else {
276+ return nil
277+ }
278+
279+ var cursor = SyntaxCursor ( root: data)
256280 guard !cursor. finished else { return nil }
257281
258282 while true {
259- if nodeAtCursorCanBeReused ( prevPosition: prevPosition, kind: kind) {
283+ if nodeAtCursorCanBeReused ( cursor , prevPosition: prevPosition, kind: kind) {
260284 return cursor. asSyntaxNode
261285 }
262286 guard cursor. advanceToNextNode ( at: prevPosition) else { return nil }
263287 }
264288 }
265289
266290 fileprivate func nodeAtCursorCanBeReused(
291+ _ cursor: SyntaxCursor ,
267292 prevPosition: AbsolutePosition ,
268293 kind: SyntaxKind
269294 ) -> Bool {
295+ guard let edits = edits else { return false }
296+
270297 let node = cursor. node
271298 if node. position != prevPosition {
272299 return false
@@ -298,7 +325,7 @@ public struct IncrementalParseLookup {
298325 }
299326 let nodeAffectRange = ByteSourceRange (
300327 offset: node. position. utf8Offset,
301- length: ( node. raw. totalLength + nextLeafNodeLength) . utf8Length
328+ length: max ( mergeLookaheadRange ( at : node. position . utf8Offset , length : node . raw. totalLength. utf8Length ) , ( node . raw . totalLength + nextLeafNodeLength) . utf8Length)
302329 )
303330
304331 for edit in edits. edits {
@@ -317,6 +344,8 @@ public struct IncrementalParseLookup {
317344 }
318345
319346 fileprivate func translateToPreEditOffset( _ postEditOffset: Int ) -> Int ? {
347+ guard let edits = edits else { return nil }
348+
320349 var offset = postEditOffset
321350 for edit in edits. edits {
322351 if edit. range. offset > offset {
@@ -332,6 +361,21 @@ public struct IncrementalParseLookup {
332361 }
333362 return offset
334363 }
364+
365+ fileprivate func mergeLookaheadRange( at start: Int , length: Int ) -> Int {
366+ var totalLength = start + length
367+
368+ let targetRanges = transition. previousLookaheadRange. filter { $0. key >= totalLength } . sorted ( by: { $0. key < $1. key } )
369+
370+ for targetRange in targetRanges {
371+ if targetRange. key != totalLength {
372+ break
373+ }
374+ totalLength += targetRange. value
375+ }
376+
377+ return totalLength
378+ }
335379}
336380
337381/// Functions as an iterator that walks the tree looking for nodes with a
0 commit comments