@@ -118,6 +118,9 @@ public final class SwiftLanguageServer: ToolchainLanguageServer {
118
118
var currentCompletionSession : CodeCompletionSession ? = nil
119
119
120
120
var commandsByFile : [ DocumentURI : SwiftCompileCommand ] = [ : ]
121
+
122
+ /// *For Testing*
123
+ public var reusedNodeCallback : ReusedNodeCallback ?
121
124
122
125
var keys : sourcekitd_keys { return sourcekitd. keys }
123
126
var requests : sourcekitd_requests { return sourcekitd. requests }
@@ -197,13 +200,27 @@ public final class SwiftLanguageServer: ToolchainLanguageServer {
197
200
}
198
201
199
202
/// Returns the updated lexical tokens for the given `snapshot`.
203
+ ///
204
+ /// - Parameters:
205
+ /// - 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
206
private func updateSyntaxTree(
201
- for snapshot: DocumentSnapshot
207
+ for snapshot: DocumentSnapshot ,
208
+ with edits: ConcurrentEdits ? = nil
202
209
) -> DocumentTokens {
203
210
logExecutionTime ( level: . debug) {
204
211
var docTokens = snapshot. tokens
212
+
213
+ var parseTransition : IncrementalParseTransition ? = nil
214
+ if let previousTree = snapshot. tokens. syntaxTree,
215
+ let lookaheadRanges = snapshot. tokens. lookaheadRanges,
216
+ let edits {
217
+ parseTransition = IncrementalParseTransition ( previousTree: previousTree, edits: edits, lookaheadRanges: lookaheadRanges, reusedNodeCallback: reusedNodeCallback)
218
+ }
219
+ let ( tree, nextLookaheadRanges) = Parser . parseIncrementally (
220
+ source: snapshot. text, parseTransition: parseTransition)
205
221
206
- docTokens. syntaxTree = Parser . parse ( source: snapshot. text)
222
+ docTokens. syntaxTree = tree
223
+ docTokens. lookaheadRanges = nextLookaheadRanges
207
224
208
225
return docTokens
209
226
}
@@ -527,27 +544,36 @@ extension SwiftLanguageServer {
527
544
528
545
public func changeDocument( _ note: DidChangeTextDocumentNotification ) {
529
546
let keys = self . keys
547
+ var edits : [ IncrementalEdit ] = [ ]
530
548
531
549
self . queue. async {
532
550
var lastResponse : SKDResponseDictionary ? = nil
533
551
534
- let snapshot = self . documentManager. edit ( note) { ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
552
+ let snapshot = self . documentManager. edit ( note) {
553
+ ( before: DocumentSnapshot , edit: TextDocumentContentChangeEvent ) in
535
554
let req = SKDRequestDictionary ( sourcekitd: self . sourcekitd)
536
555
req [ keys. request] = self . requests. editor_replacetext
537
556
req [ keys. name] = note. textDocument. uri. pseudoPath
538
557
539
558
if let range = edit. range {
540
- guard let offset = before. utf8Offset ( of: range. lowerBound) , let end = before. utf8Offset ( of: range. upperBound) else {
559
+ guard let offset = before. utf8Offset ( of: range. lowerBound) ,
560
+ let end = before. utf8Offset ( of: range. upperBound)
561
+ else {
541
562
fatalError ( " invalid edit \( range) " )
542
563
}
543
564
565
+ let length = end - offset
544
566
req [ keys. offset] = offset
545
- req [ keys. length] = end - offset
567
+ req [ keys. length] = length
546
568
569
+ edits. append ( IncrementalEdit ( offset: offset, length: length, replacementLength: edit. text. utf8. count) )
547
570
} else {
548
571
// Full text
572
+ let length = before. text. utf8. count
549
573
req [ keys. offset] = 0
550
- req [ keys. length] = before. text. utf8. count
574
+ req [ keys. length] = length
575
+
576
+ edits. append ( IncrementalEdit ( offset: 0 , length: length, replacementLength: edit. text. utf8. count) )
551
577
}
552
578
553
579
req [ keys. sourcetext] = edit. text
@@ -556,7 +582,7 @@ extension SwiftLanguageServer {
556
582
self . adjustDiagnosticRanges ( of: note. textDocument. uri, for: edit)
557
583
} updateDocumentTokens: { ( after: DocumentSnapshot ) in
558
584
if lastResponse != nil {
559
- return self . updateSyntaxTree ( for: after)
585
+ return self . updateSyntaxTree ( for: after, with : ConcurrentEdits ( fromSequential : edits ) )
560
586
} else {
561
587
return DocumentTokens ( )
562
588
}
0 commit comments