Skip to content

Commit 6a1d923

Browse files
committed
Add a request to check if SourceKit-LSP is currently performing any indexing
1 parent f4e015b commit 6a1d923

File tree

11 files changed

+101
-4
lines changed

11 files changed

+101
-4
lines changed

Contributor Documentation/LSP Extensions.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,27 @@ export interface DocumentTestsParams {
434434
}
435435
```
436436
437+
## `sourceKit/_isIndexing`
438+
439+
Request from the client to the server querying whether SourceKit-LSP is currently performing an background indexing tasks, including target preparation.
440+
441+
> [!IMPORTANT]
442+
> This request is experimental and may be modified or removed in future versions of SourceKit-LSP without notice. Do not rely on it.
443+
444+
- params: `IsIndexingParams`
445+
- result: `IsIndexingResult`
446+
447+
```ts
448+
export interface IsIndexingParams {}
449+
450+
export interface IsIndexingResult {
451+
/**
452+
* Whether SourceKit-LSP is currently performing an indexing task.
453+
*/
454+
indexing: boolean;
455+
}
456+
```
457+
437458
## `window/didChangeActiveDocument`
438459
439460
New notification from the client to the server, telling SourceKit-LSP which document is the currently active primary document.

Documentation/Configuration File.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ The structure of the file is currently not guaranteed to be stable. Options may
5353
- `noLazy`: Prepare a target without generating object files but do not do lazy type checking and function body skipping. This uses SwiftPM's `--experimental-prepare-for-indexing-no-lazy` flag.
5454
- `enabled`: Prepare a target without generating object files.
5555
- `cancelTextDocumentRequestsOnEditAndClose: boolean`: Whether sending a `textDocument/didChange` or `textDocument/didClose` notification for a document should cancel all pending requests for that document.
56-
- `experimentalFeatures: ("on-type-formatting"|"set-options-request"|"sourcekit-options-request")[]`: Experimental features that are enabled.
56+
- `experimentalFeatures: ("on-type-formatting"|"set-options-request"|"sourcekit-options-request"|"is-indexing-request")[]`: Experimental features that are enabled.
5757
- `swiftPublishDiagnosticsDebounceDuration: number`: The time that `SwiftLanguageService` should wait after an edit before starting to compute diagnostics and sending a `PublishDiagnosticsNotification`.
5858
- `workDoneProgressDebounceDuration: number`: When a task is started that should be displayed to the client as a work done progress, how many milliseconds to wait before actually starting the work done progress. This prevents flickering of the work done progress in the client for short-lived index tasks which end within this duration.
5959
- `sourcekitdRequestTimeout: number`: The maximum duration that a sourcekitd request should be allowed to execute before being declared as timed out. In general, editors should cancel requests that they are no longer interested in, but in case editors don't cancel requests, this ensures that a long-running non-cancelled request is not blocking sourcekitd and thus most semantic functionality. In particular, VS Code does not cancel the semantic tokens request, which can cause a long-running AST build that blocks sourcekitd.

Sources/LanguageServerProtocol/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ add_library(LanguageServerProtocol STATIC
6767
Requests/InlayHintResolveRequest.swift
6868
Requests/InlineValueRefreshRequest.swift
6969
Requests/InlineValueRequest.swift
70+
Requests/IsIndexingRequest.swift
7071
Requests/LinkedEditingRangeRequest.swift
7172
Requests/MonikersRequest.swift
7273
Requests/PeekDocumentsRequest.swift

Sources/LanguageServerProtocol/Messages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public let builtinRequests: [_RequestType.Type] = [
5858
InlayHintResolveRequest.self,
5959
InlineValueRefreshRequest.self,
6060
InlineValueRequest.self,
61+
IsIndexingRequest.self,
6162
LinkedEditingRangeRequest.self,
6263
MonikersRequest.self,
6364
PeekDocumentsRequest.self,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
public struct IsIndexingRequest: RequestType {
14+
public static let method: String = "sourceKit/_isIndexing"
15+
public typealias Response = IsIndexingResponse
16+
17+
public init() {}
18+
}
19+
20+
public struct IsIndexingResponse: ResponseType {
21+
/// Whether SourceKit-LSP is currently performing an indexing task.
22+
public var indexing: Bool
23+
24+
public init(indexing: Bool) {
25+
self.indexing = indexing
26+
}
27+
}

Sources/SKOptions/ExperimentalFeatures.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@ public enum ExperimentalFeature: String, Codable, Sendable, CaseIterable {
2222

2323
/// Enable the `workspace/_sourceKitOptions` request.
2424
case sourceKitOptionsRequest = "sourcekit-options-request"
25+
26+
/// Enable the `sourceKit/_isIndexing` request.
27+
case isIndexingRequest = "is-indexing-request"
2528
}

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ package enum IndexTaskStatus: Comparable {
9393
/// In reality, these status are not exclusive. Eg. the index might be preparing one target for editor functionality,
9494
/// re-generating the build graph and indexing files at the same time. To avoid showing too many concurrent status
9595
/// messages to the user, we only show the highest priority task.
96-
package enum IndexProgressStatus: Sendable {
96+
package enum IndexProgressStatus: Sendable, Equatable {
9797
case preparingFileForEditorFunctionality
9898
case schedulingIndexing
9999
case indexing(preparationTasks: [BuildTargetIdentifier: IndexTaskStatus], indexTasks: [DocumentURI: IndexTaskStatus])

Sources/SourceKitLSP/MessageHandlingDependencyTracker.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ package enum MessageHandlingDependencyTracker: QueueBasedMessageHandlerDependenc
206206
self = .freestanding
207207
case is InlineValueRefreshRequest:
208208
self = .freestanding
209+
case is IsIndexingRequest:
210+
self = .freestanding
209211
case is PollIndexRequest:
210212
self = .globalConfigurationChange
211213
case is RenameRequest:

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ extension SourceKitLSPServer: QueueBasedMessageHandler {
824824
initialized = true
825825
case let request as RequestAndReply<InlayHintRequest>:
826826
await self.handleRequest(for: request, requestHandler: self.inlayHint)
827+
case let request as RequestAndReply<IsIndexingRequest>:
828+
await request.reply { try await self.isIndexing(request.params) }
827829
case let request as RequestAndReply<PollIndexRequest>:
828830
await request.reply { try await pollIndex(request.params) }
829831
case let request as RequestAndReply<PrepareRenameRequest>:
@@ -1270,6 +1272,17 @@ extension SourceKitLSPServer {
12701272
)
12711273
}
12721274

1275+
func isIndexing(_ request: IsIndexingRequest) async throws -> IsIndexingResponse {
1276+
guard self.options.hasExperimentalFeature(.isIndexingRequest) else {
1277+
throw ResponseError.unknown("\(IsIndexingRequest.method) indexing is an experimental request")
1278+
}
1279+
let isIndexing =
1280+
await workspaces
1281+
.compactMap(\.semanticIndexManager)
1282+
.asyncContains { await $0.progressStatus != .upToDate }
1283+
return IsIndexingResponse(indexing: isIndexing)
1284+
}
1285+
12731286
// MARK: - Text synchronization
12741287

12751288
func openDocument(_ notification: DidOpenTextDocumentNotification) async {

Tests/SourceKitLSPTests/BackgroundIndexingTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,33 @@ final class BackgroundIndexingTests: XCTestCase {
18831883
) != nil
18841884
}
18851885
}
1886+
1887+
func testIsIndexingRequest() async throws {
1888+
let checkedIsIndexStatus = AtomicBool(initialValue: false)
1889+
let hooks = Hooks(
1890+
indexHooks: IndexHooks(updateIndexStoreTaskDidStart: { task in
1891+
while !checkedIsIndexStatus.value {
1892+
try? await Task.sleep(for: .seconds(0.1))
1893+
}
1894+
})
1895+
)
1896+
let project = try await SwiftPMTestProject(
1897+
files: [
1898+
"Test.swift": ""
1899+
],
1900+
options: .testDefault(experimentalFeatures: [.isIndexingRequest]),
1901+
hooks: hooks,
1902+
enableBackgroundIndexing: true,
1903+
pollIndex: false
1904+
)
1905+
let isIndexingResponseWhileIndexing = try await project.testClient.send(IsIndexingRequest())
1906+
XCTAssert(isIndexingResponseWhileIndexing.indexing)
1907+
checkedIsIndexStatus.value = true
1908+
1909+
try await repeatUntilExpectedResult {
1910+
try await project.testClient.send(IsIndexingRequest()).indexing == false
1911+
}
1912+
}
18861913
}
18871914

18881915
extension HoverResponseContents {

config.schema.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@
7171
"enum" : [
7272
"on-type-formatting",
7373
"set-options-request",
74-
"sourcekit-options-request"
74+
"sourcekit-options-request",
75+
"is-indexing-request"
7576
],
7677
"markdownEnumDescriptions" : [
7778
"Enable support for the `textDocument\/onTypeFormatting` request.",
7879
"Enable support for the `workspace\/_setOptions` request.",
79-
"Enable the `workspace\/_sourceKitOptions` request."
80+
"Enable the `workspace\/_sourceKitOptions` request.",
81+
"Enable the `sourceKit\/_isIndexing` request."
8082
],
8183
"type" : "string"
8284
},

0 commit comments

Comments
 (0)