@@ -45,9 +45,14 @@ public final class IncrementalParseReusedNodeCollector:
45
45
/// Keeps track of a previously parsed syntax tree and the source edits that
46
46
/// occurred since it was created.
47
47
public 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 ] = [ : ]
51
56
52
57
/// - Parameters:
53
58
/// - previousTree: The previous tree to do lookups on.
@@ -56,14 +61,30 @@ public final class IncrementalParseTransition {
56
61
/// - reusedNodeDelegate: Optional delegate to accept information about the
57
62
/// reused regions and nodes.
58
63
public init (
59
- previousTree: SourceFileSyntax ,
60
- edits: ConcurrentEdits ,
64
+ previousTree: SourceFileSyntax ? = nil ,
65
+ edits: ConcurrentEdits ? = nil ,
61
66
reusedNodeDelegate: IncrementalParseReusedNodeDelegate ? = nil
62
67
) {
63
68
self . previousTree = previousTree
64
69
self . edits = edits
65
70
self . reusedDelegate = reusedNodeDelegate
66
71
}
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
+ }
67
88
}
68
89
69
90
fileprivate extension Sequence where Element: Comparable {
@@ -204,16 +225,14 @@ public struct ConcurrentEdits {
204
225
/// updated source that was already parsed during a previous parse invocation.
205
226
public struct IncrementalParseLookup {
206
227
fileprivate let transition : IncrementalParseTransition
207
- fileprivate var cursor : SyntaxCursor
208
228
209
229
/// Create a new ``IncrementalParseLookup`` that can look nodes up based on the
210
230
/// given ``IncrementalParseTransition``.
211
231
public init ( transition: IncrementalParseTransition ) {
212
232
self . transition = transition
213
- self . cursor = . init( root: transition. previousTree. data)
214
233
}
215
234
216
- fileprivate var edits : ConcurrentEdits {
235
+ fileprivate var edits : ConcurrentEdits ? {
217
236
return transition. edits
218
237
}
219
238
@@ -242,7 +261,7 @@ public struct IncrementalParseLookup {
242
261
let node = cursorLookup ( prevPosition: prevPosition, kind: kind)
243
262
if let delegate = reusedDelegate, let node {
244
263
delegate. parserReusedNode (
245
- range: ByteSourceRange ( offset: newOffset , length: node. byteSizeAfterTrimmingTrivia) ,
264
+ range: ByteSourceRange ( offset: node . positionAfterSkippingLeadingTrivia . utf8Offset , length: node. byteSizeAfterTrimmingTrivia) ,
246
265
previousNode: node
247
266
)
248
267
}
@@ -253,20 +272,28 @@ public struct IncrementalParseLookup {
253
272
prevPosition: AbsolutePosition ,
254
273
kind: SyntaxKind
255
274
) -> Syntax ? {
275
+ guard let data = transition. previousTree? . data else {
276
+ return nil
277
+ }
278
+
279
+ var cursor = SyntaxCursor ( root: data)
256
280
guard !cursor. finished else { return nil }
257
281
258
282
while true {
259
- if nodeAtCursorCanBeReused ( prevPosition: prevPosition, kind: kind) {
283
+ if nodeAtCursorCanBeReused ( cursor , prevPosition: prevPosition, kind: kind) {
260
284
return cursor. asSyntaxNode
261
285
}
262
286
guard cursor. advanceToNextNode ( at: prevPosition) else { return nil }
263
287
}
264
288
}
265
289
266
290
fileprivate func nodeAtCursorCanBeReused(
291
+ _ cursor: SyntaxCursor ,
267
292
prevPosition: AbsolutePosition ,
268
293
kind: SyntaxKind
269
294
) -> Bool {
295
+ guard let edits = edits else { return false }
296
+
270
297
let node = cursor. node
271
298
if node. position != prevPosition {
272
299
return false
@@ -298,7 +325,7 @@ public struct IncrementalParseLookup {
298
325
}
299
326
let nodeAffectRange = ByteSourceRange (
300
327
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)
302
329
)
303
330
304
331
for edit in edits. edits {
@@ -317,6 +344,8 @@ public struct IncrementalParseLookup {
317
344
}
318
345
319
346
fileprivate func translateToPreEditOffset( _ postEditOffset: Int ) -> Int ? {
347
+ guard let edits = edits else { return nil }
348
+
320
349
var offset = postEditOffset
321
350
for edit in edits. edits {
322
351
if edit. range. offset > offset {
@@ -332,6 +361,21 @@ public struct IncrementalParseLookup {
332
361
}
333
362
return offset
334
363
}
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
+ }
335
379
}
336
380
337
381
/// Functions as an iterator that walks the tree looking for nodes with a
0 commit comments