@@ -650,6 +650,8 @@ extension SourceKitLSPServer: QueueBasedMessageHandler {
650
650
logger. log ( " Received notification: \( notification. forLogging) " )
651
651
652
652
switch notification {
653
+ case let notification as DidChangeActiveDocumentNotification :
654
+ await self . didChangeActiveDocument ( notification)
653
655
case let notification as DidChangeTextDocumentNotification :
654
656
await self . changeDocument ( notification)
655
657
case let notification as DidChangeWorkspaceFoldersNotification :
@@ -736,15 +738,7 @@ extension SourceKitLSPServer: QueueBasedMessageHandler {
736
738
logger. log ( " Received request \( id) : \( params. forLogging) " )
737
739
738
740
if let textDocumentRequest = params as? any TextDocumentRequest {
739
- // When we are requesting information from a document, poke preparation of its target. We don't want to wait for
740
- // the preparation to finish because that would cause too big a delay.
741
- // In practice, while the user is working on a file, we'll get a text document request for it on a regular basis,
742
- // which prepares the files. For files that are open but aren't being worked on (eg. a different tab), we don't
743
- // get requests, ensuring that we don't unnecessarily prepare them.
744
- let workspace = await self . workspaceForDocument ( uri: textDocumentRequest. textDocument. uri)
745
- await workspace? . semanticIndexManager? . schedulePreparationForEditorFunctionality (
746
- of: textDocumentRequest. textDocument. uri
747
- )
741
+ await self . clientInteractedWithDocument ( textDocumentRequest. textDocument. uri)
748
742
}
749
743
750
744
switch request {
@@ -931,25 +925,22 @@ extension SourceKitLSPServer {
931
925
//
932
926
// The below is a workaround for the vscode-swift extension since it cannot set client capabilities.
933
927
// It passes "workspace/peekDocuments" through the `initializationOptions`.
934
- //
935
- // Similarly, for "workspace/getReferenceDocument".
936
928
var clientCapabilities = req. capabilities
937
929
if case . dictionary( let initializationOptions) = req. initializationOptions {
938
- if let peekDocuments = initializationOptions [ " workspace/peekDocuments " ] {
939
- if case . dictionary( var experimentalCapabilities) = clientCapabilities. experimental {
940
- experimentalCapabilities [ " workspace/peekDocuments " ] = peekDocuments
941
- clientCapabilities. experimental = . dictionary( experimentalCapabilities)
942
- } else {
943
- clientCapabilities. experimental = . dictionary( [ " workspace/peekDocuments " : peekDocuments] )
930
+ let experimentalClientCapabilities = [
931
+ PeekDocumentsRequest . method,
932
+ GetReferenceDocumentRequest . method,
933
+ DidChangeActiveDocumentNotification . method,
934
+ ]
935
+ for capabilityName in experimentalClientCapabilities {
936
+ guard let experimentalCapability = initializationOptions [ capabilityName] else {
937
+ continue
944
938
}
945
- }
946
-
947
- if let getReferenceDocument = initializationOptions [ " workspace/getReferenceDocument " ] {
948
939
if case . dictionary( var experimentalCapabilities) = clientCapabilities. experimental {
949
- experimentalCapabilities [ " workspace/getReferenceDocument " ] = getReferenceDocument
940
+ experimentalCapabilities [ capabilityName ] = experimentalCapability
950
941
clientCapabilities. experimental = . dictionary( experimentalCapabilities)
951
942
} else {
952
- clientCapabilities. experimental = . dictionary( [ " workspace/getReferenceDocument " : getReferenceDocument ] )
943
+ clientCapabilities. experimental = . dictionary( [ capabilityName : experimentalCapability ] )
953
944
}
954
945
}
955
946
@@ -1081,10 +1072,11 @@ extension SourceKitLSPServer {
1081
1072
: ExecuteCommandOptions ( commands: builtinSwiftCommands)
1082
1073
1083
1074
var experimentalCapabilities : [ String : LSPAny ] = [
1084
- " workspace/tests " : . dictionary( [ " version " : . int( 2 ) ] ) ,
1085
- " textDocument/tests " : . dictionary( [ " version " : . int( 2 ) ] ) ,
1086
- " workspace/triggerReindex " : . dictionary( [ " version " : . int( 1 ) ] ) ,
1087
- " workspace/getReferenceDocument " : . dictionary( [ " version " : . int( 1 ) ] ) ,
1075
+ WorkspaceTestsRequest . method: . dictionary( [ " version " : . int( 2 ) ] ) ,
1076
+ DocumentTestsRequest . method: . dictionary( [ " version " : . int( 2 ) ] ) ,
1077
+ TriggerReindexRequest . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1078
+ GetReferenceDocumentRequest . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1079
+ DidChangeActiveDocumentNotification . method: . dictionary( [ " version " : . int( 1 ) ] ) ,
1088
1080
]
1089
1081
#if canImport(SwiftDocC)
1090
1082
experimentalCapabilities [ " textDocument/doccDocumentation " ] = . dictionary( [ " version " : . int( 1 ) ] )
@@ -1268,7 +1260,7 @@ extension SourceKitLSPServer {
1268
1260
)
1269
1261
return
1270
1262
}
1271
- await workspace . semanticIndexManager ? . schedulePreparationForEditorFunctionality ( of : uri)
1263
+ await self . clientInteractedWithDocument ( uri)
1272
1264
await openDocument ( notification, workspace: workspace)
1273
1265
}
1274
1266
@@ -1352,7 +1344,7 @@ extension SourceKitLSPServer {
1352
1344
)
1353
1345
return
1354
1346
}
1355
- await workspace . semanticIndexManager ? . schedulePreparationForEditorFunctionality ( of : uri)
1347
+ await self . clientInteractedWithDocument ( uri)
1356
1348
1357
1349
// If the document is ready, we can handle the change right now.
1358
1350
let editResult = orLog ( " Editing document " ) {
@@ -1374,6 +1366,30 @@ extension SourceKitLSPServer {
1374
1366
)
1375
1367
}
1376
1368
1369
+ /// If the client doesn't support the `window/didChangeActiveDocument` notification, when the client interacts with a
1370
+ /// document, infer that this is the currently active document and poke preparation of its target. We don't want to
1371
+ /// wait for the preparation to finish because that would cause too big a delay.
1372
+ ///
1373
+ /// In practice, while the user is working on a file, we'll get a text document request for it on a regular basis,
1374
+ /// which prepares the files. For files that are open but aren't being worked on (eg. a different tab), we don't
1375
+ /// get requests, ensuring that we don't unnecessarily prepare them.
1376
+ func clientInteractedWithDocument( _ uri: DocumentURI ) async {
1377
+ if self . capabilityRegistry? . clientHasExperimentalCapability ( DidChangeActiveDocumentNotification . method) ?? false {
1378
+ // The client actively notifies us about the currently active document, so we shouldn't infer the active document
1379
+ // based on other requests that the client sends us.
1380
+ return
1381
+ }
1382
+ await self . didChangeActiveDocument (
1383
+ DidChangeActiveDocumentNotification ( textDocument: TextDocumentIdentifier ( uri) )
1384
+ )
1385
+ }
1386
+
1387
+ func didChangeActiveDocument( _ notification: DidChangeActiveDocumentNotification ) async {
1388
+ let workspace = await self . workspaceForDocument ( uri: notification. textDocument. uri)
1389
+ await workspace? . semanticIndexManager?
1390
+ . schedulePreparationForEditorFunctionality ( of: notification. textDocument. uri)
1391
+ }
1392
+
1377
1393
func willSaveDocument(
1378
1394
_ notification: WillSaveTextDocumentNotification ,
1379
1395
languageService: LanguageService
0 commit comments