@@ -119,6 +119,11 @@ public final class SwiftLanguageServer: ToolchainLanguageServer {
119
119
120
120
var commandsByFile : [ DocumentURI : SwiftCompileCommand ] = [ : ]
121
121
122
+ var documentLookaheadRanges : [ DocumentURI : LookaheadRanges ] = [ : ]
123
+
124
+ /// *For Testing*
125
+ public var documentReusedNodeCollector : [ DocumentURI : IncrementalParseReusedNodeCollector ] = [ : ]
126
+
122
127
var keys : sourcekitd_keys { return sourcekitd. keys }
123
128
var requests : sourcekitd_requests { return sourcekitd. requests }
124
129
var values : sourcekitd_values { return sourcekitd. values }
@@ -197,14 +202,36 @@ public final class SwiftLanguageServer: ToolchainLanguageServer {
197
202
}
198
203
199
204
/// Returns the updated lexical tokens for the given `snapshot`.
205
+ ///
206
+ /// - Parameters:
207
+ /// - edits: If we are in the context of editing the contents of a file, i.e. calling ``SwiftLanguageServer/changeDocument(_:)``, we should pass `edits` to enable incremental parse. Otherwise, `edits` should be `nil`.
200
208
private func updateSyntaxTree(
201
- for snapshot: DocumentSnapshot
209
+ for snapshot: DocumentSnapshot ,
210
+ with edits: ConcurrentEdits ? = nil
202
211
) -> DocumentTokens {
203
212
logExecutionTime ( level: . debug) {
204
213
var docTokens = snapshot. tokens
214
+ let documentURI = snapshot. document. uri
215
+
216
+ var reusedNodeCollector = documentReusedNodeCollector [ documentURI]
217
+ if reusedNodeCollector == nil {
218
+ documentReusedNodeCollector [ documentURI] = IncrementalParseReusedNodeCollector ( )
219
+ reusedNodeCollector = documentReusedNodeCollector [ documentURI]
220
+ }
221
+
222
+ var parseTransition : IncrementalParseTransition ? = nil
223
+ if let previousTree = snapshot. tokens. syntaxTree,
224
+ let lookaheadRanges = documentLookaheadRanges [ documentURI] ,
225
+ let edits {
226
+ parseTransition = IncrementalParseTransition ( previousTree: previousTree, edits: edits, lookaheadRanges: lookaheadRanges, reusedNodeDelegate: reusedNodeCollector)
227
+ }
228
+ let ( tree, nextLookaheadRanges) = Parser . parseIncrementally (
229
+ source: snapshot. text, parseTransition: parseTransition)
205
230
206
- docTokens. syntaxTree = Parser . parse ( source : snapshot . text )
231
+ docTokens. syntaxTree = tree
207
232
233
+ documentLookaheadRanges [ documentURI] = nextLookaheadRanges
234
+
208
235
return docTokens
209
236
}
210
237
}
@@ -520,34 +547,45 @@ extension SwiftLanguageServer {
520
547
// Clear settings that should not be cached for closed documents.
521
548
self . commandsByFile [ uri] = nil
522
549
self . currentDiagnostics [ uri] = nil
550
+ self . documentLookaheadRanges [ uri] = nil
551
+ self . documentReusedNodeCollector [ uri] = nil
523
552
524
553
_ = try ? self . sourcekitd. sendSync ( req)
525
554
}
526
555
}
527
556
528
557
public func changeDocument( _ note: DidChangeTextDocumentNotification ) {
529
558
let keys = self . keys
559
+ var edits : [ IncrementalEdit ] = [ ]
530
560
531
561
self . queue. async {
532
562
var lastResponse : SKDResponseDictionary ? = nil
533
563
534
- let snapshot = self . documentManager. edit ( note) { ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
564
+ let snapshot = self . documentManager. edit ( note) {
565
+ ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
535
566
let req = SKDRequestDictionary ( sourcekitd: self . sourcekitd)
536
567
req [ keys. request] = self . requests. editor_replacetext
537
568
req [ keys. name] = note. textDocument. uri. pseudoPath
538
569
539
570
if let range = edit. range {
540
- guard let offset = before. utf8Offset ( of: range. lowerBound) , let end = before. utf8Offset ( of: range. upperBound) else {
571
+ guard let offset = before. utf8Offset ( of: range. lowerBound) ,
572
+ let end = before. utf8Offset ( of: range. upperBound)
573
+ else {
541
574
fatalError ( " invalid edit \( range) " )
542
575
}
543
576
577
+ let length = end - offset
544
578
req [ keys. offset] = offset
545
- req [ keys. length] = end - offset
579
+ req [ keys. length] = length
546
580
581
+ edits. append ( IncrementalEdit ( offset: offset, length: length, replacementLength: edit. text. utf8. count) )
547
582
} else {
548
583
// Full text
584
+ let length = before. text. utf8. count
549
585
req [ keys. offset] = 0
550
- req [ keys. length] = before. text. utf8. count
586
+ req [ keys. length] = length
587
+
588
+ edits. append ( IncrementalEdit ( offset: 0 , length: length, replacementLength: edit. text. utf8. count) )
551
589
}
552
590
553
591
req [ keys. sourcetext] = edit. text
@@ -556,7 +594,7 @@ extension SwiftLanguageServer {
556
594
self . adjustDiagnosticRanges ( of: note. textDocument. uri, for: edit)
557
595
} updateDocumentTokens: { ( after: DocumentSnapshot ) in
558
596
if lastResponse != nil {
559
- return self . updateSyntaxTree ( for: after)
597
+ return self . updateSyntaxTree ( for: after, with : ConcurrentEdits ( fromSequential : edits ) )
560
598
} else {
561
599
return DocumentTokens ( )
562
600
}
0 commit comments