@@ -666,6 +666,8 @@ extension SourceKitLSPServer: QueueBasedMessageHandler {
666
666
logger. log ( " Received notification: \( notification. forLogging) " )
667
667
668
668
switch notification {
669
+ case let notification as DidChangeActiveDocumentNotification :
670
+ await self . didChangeActiveDocument ( notification)
669
671
case let notification as DidChangeTextDocumentNotification :
670
672
await self . changeDocument ( notification)
671
673
case let notification as DidChangeWorkspaceFoldersNotification :
@@ -752,15 +754,7 @@ extension SourceKitLSPServer: QueueBasedMessageHandler {
752
754
logger. log ( " Received request \( id) : \( params. forLogging) " )
753
755
754
756
if let textDocumentRequest = params as? any TextDocumentRequest {
755
- // When we are requesting information from a document, poke preparation of its target. We don't want to wait for
756
- // the preparation to finish because that would cause too big a delay.
757
- // In practice, while the user is working on a file, we'll get a text document request for it on a regular basis,
758
- // which prepares the files. For files that are open but aren't being worked on (eg. a different tab), we don't
759
- // get requests, ensuring that we don't unnecessarily prepare them.
760
- let workspace = await self . workspaceForDocument ( uri: textDocumentRequest. textDocument. uri)
761
- await workspace? . semanticIndexManager? . schedulePreparationForEditorFunctionality (
762
- of: textDocumentRequest. textDocument. uri
763
- )
757
+ await self . clientInteractedWithDocument ( textDocumentRequest. textDocument. uri)
764
758
}
765
759
766
760
switch request {
@@ -949,25 +943,22 @@ extension SourceKitLSPServer {
949
943
//
950
944
// The below is a workaround for the vscode-swift extension since it cannot set client capabilities.
951
945
// It passes "workspace/peekDocuments" through the `initializationOptions`.
952
- //
953
- // Similarly, for "workspace/getReferenceDocument".
954
946
var clientCapabilities = req. capabilities
955
947
if case . dictionary( let initializationOptions) = req. initializationOptions {
956
- if let peekDocuments = initializationOptions [ " workspace/peekDocuments " ] {
957
- if case . dictionary( var experimentalCapabilities) = clientCapabilities. experimental {
958
- experimentalCapabilities [ " workspace/peekDocuments " ] = peekDocuments
959
- clientCapabilities. experimental = . dictionary( experimentalCapabilities)
960
- } else {
961
- clientCapabilities. experimental = . dictionary( [ " workspace/peekDocuments " : peekDocuments] )
948
+ let experimentalClientCapabilities = [
949
+ PeekDocumentsRequest . method,
950
+ GetReferenceDocumentRequest . method,
951
+ DidChangeActiveDocumentNotification . method,
952
+ ]
953
+ for capabilityName in experimentalClientCapabilities {
954
+ guard let experimentalCapability = initializationOptions [ capabilityName] else {
955
+ continue
962
956
}
963
- }
964
-
965
- if let getReferenceDocument = initializationOptions [ " workspace/getReferenceDocument " ] {
966
957
if case . dictionary( var experimentalCapabilities) = clientCapabilities. experimental {
967
- experimentalCapabilities [ " workspace/getReferenceDocument " ] = getReferenceDocument
958
+ experimentalCapabilities [ capabilityName ] = experimentalCapability
968
959
clientCapabilities. experimental = . dictionary( experimentalCapabilities)
969
960
} else {
970
- clientCapabilities. experimental = . dictionary( [ " workspace/getReferenceDocument " : getReferenceDocument ] )
961
+ clientCapabilities. experimental = . dictionary( [ capabilityName : experimentalCapability ] )
971
962
}
972
963
}
973
964
@@ -1099,10 +1090,11 @@ extension SourceKitLSPServer {
1099
1090
: ExecuteCommandOptions ( commands: builtinSwiftCommands)
1100
1091
1101
1092
var experimentalCapabilities : [ String : LSPAny ] = [
1102
- " workspace/tests " : . dictionary( [ " version " : . int( 2 ) ] ) ,
1103
- " textDocument/tests " : . dictionary( [ " version " : . int( 2 ) ] ) ,
1104
- " workspace/triggerReindex " : . dictionary( [ " version " : . int( 1 ) ] ) ,
1105
- " workspace/getReferenceDocument " : . dictionary( [ " version " : . int( 1 ) ] ) ,
1093
+ WorkspaceTestsRequest . method: . dictionary( [ " version " : . int( 2 ) ] ) ,
1094
+ DocumentTestsRequest . method: . dictionary( [ " version " : . int( 2 ) ] ) ,
1095
+ TriggerReindexRequest . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1096
+ GetReferenceDocumentRequest . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1097
+ DidChangeActiveDocumentNotification . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1106
1098
]
1107
1099
#if canImport(SwiftDocC)
1108
1100
experimentalCapabilities [ " textDocument/doccDocumentation " ] = . dictionary( [ " version " : . int( 1 ) ] )
@@ -1286,7 +1278,7 @@ extension SourceKitLSPServer {
1286
1278
)
1287
1279
return
1288
1280
}
1289
- await workspace . semanticIndexManager ? . schedulePreparationForEditorFunctionality ( of : uri)
1281
+ await self . clientInteractedWithDocument ( uri)
1290
1282
await openDocument ( notification, workspace: workspace)
1291
1283
}
1292
1284
@@ -1370,7 +1362,7 @@ extension SourceKitLSPServer {
1370
1362
)
1371
1363
return
1372
1364
}
1373
- await workspace . semanticIndexManager ? . schedulePreparationForEditorFunctionality ( of : uri)
1365
+ await self . clientInteractedWithDocument ( uri)
1374
1366
1375
1367
// If the document is ready, we can handle the change right now.
1376
1368
let editResult = orLog ( " Editing document " ) {
@@ -1392,6 +1384,30 @@ extension SourceKitLSPServer {
1392
1384
)
1393
1385
}
1394
1386
1387
+ /// If the client doesn't support the `window/didChangeActiveDocument` notification, when the client interacts with a
1388
+ /// document, infer that this is the currently active document and poke preparation of its target. We don't want to
1389
+ /// wait for the preparation to finish because that would cause too big a delay.
1390
+ ///
1391
+ /// In practice, while the user is working on a file, we'll get a text document request for it on a regular basis,
1392
+ /// which prepares the files. For files that are open but aren't being worked on (eg. a different tab), we don't
1393
+ /// get requests, ensuring that we don't unnecessarily prepare them.
1394
+ func clientInteractedWithDocument( _ uri: DocumentURI ) async {
1395
+ if self . capabilityRegistry? . clientHasExperimentalCapability ( DidChangeActiveDocumentNotification . method) ?? false {
1396
+ // The client actively notifies us about the currently active document, so we shouldn't infer the active document
1397
+ // based on other requests that the client sends us.
1398
+ return
1399
+ }
1400
+ await self . didChangeActiveDocument (
1401
+ DidChangeActiveDocumentNotification ( textDocument: TextDocumentIdentifier ( uri) )
1402
+ )
1403
+ }
1404
+
1405
+ func didChangeActiveDocument( _ notification: DidChangeActiveDocumentNotification ) async {
1406
+ let workspace = await self . workspaceForDocument ( uri: notification. textDocument. uri)
1407
+ await workspace? . semanticIndexManager?
1408
+ . schedulePreparationForEditorFunctionality ( of: notification. textDocument. uri)
1409
+ }
1410
+
1395
1411
func willSaveDocument(
1396
1412
_ notification: WillSaveTextDocumentNotification ,
1397
1413
languageService: LanguageService
0 commit comments