@@ -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 reusedNodeCallback : ReusedNodeCallback ?
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,30 @@ 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 parseTransition : IncrementalParseTransition ? = nil
217
+ if let previousTree = snapshot. tokens. syntaxTree,
218
+ let lookaheadRanges = documentLookaheadRanges [ documentURI] ,
219
+ let edits {
220
+ parseTransition = IncrementalParseTransition ( previousTree: previousTree, edits: edits, lookaheadRanges: lookaheadRanges, reusedNodeCallback: reusedNodeCallback)
221
+ }
222
+ let ( tree, nextLookaheadRanges) = Parser . parseIncrementally (
223
+ source: snapshot. text, parseTransition: parseTransition)
205
224
206
- docTokens. syntaxTree = Parser . parse ( source : snapshot . text )
225
+ docTokens. syntaxTree = tree
207
226
227
+ documentLookaheadRanges [ documentURI] = nextLookaheadRanges
228
+
208
229
return docTokens
209
230
}
210
231
}
@@ -520,34 +541,44 @@ extension SwiftLanguageServer {
520
541
// Clear settings that should not be cached for closed documents.
521
542
self . commandsByFile [ uri] = nil
522
543
self . currentDiagnostics [ uri] = nil
544
+ self . documentLookaheadRanges [ uri] = nil
523
545
524
546
_ = try ? self . sourcekitd. sendSync ( req)
525
547
}
526
548
}
527
549
528
550
public func changeDocument( _ note: DidChangeTextDocumentNotification ) {
529
551
let keys = self . keys
552
+ var edits : [ IncrementalEdit ] = [ ]
530
553
531
554
self . queue. async {
532
555
var lastResponse : SKDResponseDictionary ? = nil
533
556
534
- let snapshot = self . documentManager. edit ( note) { ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
557
+ let snapshot = self . documentManager. edit ( note) {
558
+ ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
535
559
let req = SKDRequestDictionary ( sourcekitd: self . sourcekitd)
536
560
req [ keys. request] = self . requests. editor_replacetext
537
561
req [ keys. name] = note. textDocument. uri. pseudoPath
538
562
539
563
if let range = edit. range {
540
- guard let offset = before. utf8Offset ( of: range. lowerBound) , let end = before. utf8Offset ( of: range. upperBound) else {
564
+ guard let offset = before. utf8Offset ( of: range. lowerBound) ,
565
+ let end = before. utf8Offset ( of: range. upperBound)
566
+ else {
541
567
fatalError ( " invalid edit \( range) " )
542
568
}
543
569
570
+ let length = end - offset
544
571
req [ keys. offset] = offset
545
- req [ keys. length] = end - offset
572
+ req [ keys. length] = length
546
573
574
+ edits. append ( IncrementalEdit ( offset: offset, length: length, replacementLength: edit. text. utf8. count) )
547
575
} else {
548
576
// Full text
577
+ let length = before. text. utf8. count
549
578
req [ keys. offset] = 0
550
- req [ keys. length] = before. text. utf8. count
579
+ req [ keys. length] = length
580
+
581
+ edits. append ( IncrementalEdit ( offset: 0 , length: length, replacementLength: edit. text. utf8. count) )
551
582
}
552
583
553
584
req [ keys. sourcetext] = edit. text
@@ -556,7 +587,7 @@ extension SwiftLanguageServer {
556
587
self . adjustDiagnosticRanges ( of: note. textDocument. uri, for: edit)
557
588
} updateDocumentTokens: { ( after: DocumentSnapshot ) in
558
589
if lastResponse != nil {
559
- return self . updateSyntaxTree ( for: after)
590
+ return self . updateSyntaxTree ( for: after, with : ConcurrentEdits ( fromSequential : edits ) )
560
591
} else {
561
592
return DocumentTokens ( )
562
593
}
0 commit comments