Skip to content

Commit eb304c4

Browse files
committed
Add a general notion of experimental features to sourcekit-lsp
Background indexing probably won’t be the last experimental feature in sourcekit-lsp that we want to gate behind a feature flag. Instead of adding new parameters ad-hoc, introduce a general notion of experimental features.
1 parent d6a72ef commit eb304c4

10 files changed

+52
-33
lines changed

Sources/Diagnose/IndexCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public struct IndexCommand: AsyncParsableCommand {
7575

7676
public func run() async throws {
7777
var serverOptions = SourceKitLSPServer.Options()
78-
serverOptions.indexOptions.enableBackgroundIndexing = true
78+
serverOptions.experimentalFeatures.append(.backgroundIndexing)
7979

8080
let installPath =
8181
if let toolchainOverride, let toolchain = Toolchain(try AbsolutePath(validating: toolchainOverride)) {

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ public final class TestSourceKitLSPClient: MessageHandler {
117117
if let moduleCache {
118118
serverOptions.buildSetup.flags.swiftCompilerFlags += ["-module-cache-path", moduleCache.path]
119119
}
120-
serverOptions.indexOptions.enableBackgroundIndexing = enableBackgroundIndexing
120+
if enableBackgroundIndexing {
121+
serverOptions.experimentalFeatures.append(.backgroundIndexing)
122+
}
121123

122124
var notificationYielder: AsyncStream<any NotificationType>.Continuation!
123125
self.notifications = AsyncStream { continuation in

Sources/SourceKitLSP/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_library(SourceKitLSP STATIC
44
CreateBuildSystem.swift
55
DocumentManager.swift
66
DocumentSnapshot+FromFileContents.swift
7+
ExperimentalFeatures.swift
78
IndexProgressManager.swift
89
IndexStoreDB+MainFilesProvider.swift
910
LanguageServerType.swift

Sources/SourceKitLSP/CreateBuildSystem.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func createBuildSystem(
3838
url: rootUrl,
3939
toolchainRegistry: toolchainRegistry,
4040
buildSetup: options.buildSetup,
41-
isForIndexBuild: options.indexOptions.enableBackgroundIndexing,
41+
isForIndexBuild: options.experimentalFeatures.contains(.backgroundIndexing),
4242
reloadPackageStatusCallback: reloadPackageStatusCallback
4343
)
4444
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 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+
/// An experimental feature that can be enabled by passing `--experimental-feature` to `sourcekit-lsp` on the command
14+
/// line. The raw value of this feature is how it is named on the command line.
15+
public enum ExperimentalFeature: String, Codable, Sendable, CaseIterable {
16+
/// Enable background indexing.
17+
case backgroundIndexing = "background-indexing"
18+
19+
/// Show the files that are currently being indexed / the targets that are currently being prepared in the work done
20+
/// progress.
21+
///
22+
/// This is an option because VS Code tries to render a multi-line work done progress into a single line text field in
23+
/// the status bar, which looks broken. But at the same time, it is very useful to get a feeling about what's
24+
/// currently happening indexing-wise.
25+
case showActivePreparationTasksInProgress = "show-active-preparation-tasks-in-progress"
26+
}

Sources/SourceKitLSP/IndexProgressManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ actor IndexProgressManager {
9999
// Clip the finished tasks to 0 because showing a negative number there looks stupid.
100100
let finishedTasks = max(queuedIndexTasks - indexTasks.count, 0)
101101
message = "\(finishedTasks) / \(queuedIndexTasks)"
102-
if await sourceKitLSPServer.options.indexOptions.showActivePreparationTasksInProgress {
102+
if await sourceKitLSPServer.options.experimentalFeatures.contains(.showActivePreparationTasksInProgress) {
103103
var inProgressTasks: [String] = []
104104
inProgressTasks += preparationTasks.filter { $0.value == .executing }
105105
.map { "- Preparing \($0.key.targetID)" }

Sources/SourceKitLSP/SourceKitLSPServer+Options.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ extension SourceKitLSPServer {
4949
/// notification when running unit tests.
5050
public var swiftPublishDiagnosticsDebounceDuration: TimeInterval
5151

52+
/// Experimental features that are enabled.
53+
public var experimentalFeatures: [ExperimentalFeature]
54+
5255
public var indexTestHooks: IndexTestHooks
5356

5457
public init(
@@ -59,6 +62,7 @@ extension SourceKitLSPServer {
5962
completionOptions: SKCompletionOptions = .init(),
6063
generatedInterfacesPath: AbsolutePath = defaultDirectoryForGeneratedInterfaces,
6164
swiftPublishDiagnosticsDebounceDuration: TimeInterval = 2, /* 2s */
65+
experimentalFeatures: [ExperimentalFeature] = [],
6266
indexTestHooks: IndexTestHooks = IndexTestHooks()
6367
) {
6468
self.buildSetup = buildSetup
@@ -68,6 +72,7 @@ extension SourceKitLSPServer {
6872
self.completionOptions = completionOptions
6973
self.generatedInterfacesPath = generatedInterfacesPath
7074
self.swiftPublishDiagnosticsDebounceDuration = swiftPublishDiagnosticsDebounceDuration
75+
self.experimentalFeatures = experimentalFeatures
7176
self.indexTestHooks = indexTestHooks
7277
}
7378
}

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ extension SourceKitLSPServer {
941941
self?.indexProgressManager.indexProgressStatusDidChange()
942942
}
943943
)
944-
if let workspace, options.indexOptions.enableBackgroundIndexing, workspace.semanticIndexManager == nil,
944+
if let workspace, options.experimentalFeatures.contains(.backgroundIndexing), workspace.semanticIndexManager == nil,
945945
!self.didSendBackgroundIndexingNotSupportedNotification
946946
{
947947
self.sendNotificationToClient(

Sources/SourceKitLSP/Workspace.swift

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public final class Workspace: Sendable {
108108
mainFilesProvider: uncheckedIndex,
109109
toolchainRegistry: toolchainRegistry
110110
)
111-
if options.indexOptions.enableBackgroundIndexing,
111+
if options.experimentalFeatures.contains(.backgroundIndexing),
112112
let uncheckedIndex,
113113
await buildSystemManager.supportsPreparation
114114
{
@@ -247,37 +247,22 @@ public struct IndexOptions: Sendable {
247247
/// explicit calls to pollForUnitChangesAndWait().
248248
public var listenToUnitEvents: Bool
249249

250-
/// Whether background indexing should be enabled.
251-
public var enableBackgroundIndexing: Bool
252-
253250
/// The percentage of the machine's cores that should at most be used for background indexing.
254251
///
255252
/// Setting this to a value < 1 ensures that background indexing doesn't use all CPU resources.
256253
public var maxCoresPercentageToUseForBackgroundIndexing: Double
257254

258-
/// Whether to show the files that are currently being indexed / the targets that are currently being prepared in the
259-
/// work done progress.
260-
///
261-
/// This is an option because VS Code tries to render a multi-line work done progress into a single line text field in
262-
/// the status bar, which looks broken. But at the same time, it is very useful to get a feeling about what's
263-
/// currently happening indexing-wise.
264-
public var showActivePreparationTasksInProgress: Bool
265-
266255
public init(
267256
indexStorePath: AbsolutePath? = nil,
268257
indexDatabasePath: AbsolutePath? = nil,
269258
indexPrefixMappings: [PathPrefixMapping]? = nil,
270259
listenToUnitEvents: Bool = true,
271-
enableBackgroundIndexing: Bool = false,
272-
maxCoresPercentageToUseForBackgroundIndexing: Double = 1,
273-
showActivePreparationTasksInProgress: Bool = false
260+
maxCoresPercentageToUseForBackgroundIndexing: Double = 1
274261
) {
275262
self.indexStorePath = indexStorePath
276263
self.indexDatabasePath = indexDatabasePath
277264
self.indexPrefixMappings = indexPrefixMappings
278265
self.listenToUnitEvents = listenToUnitEvents
279-
self.enableBackgroundIndexing = enableBackgroundIndexing
280266
self.maxCoresPercentageToUseForBackgroundIndexing = maxCoresPercentageToUseForBackgroundIndexing
281-
self.showActivePreparationTasksInProgress = showActivePreparationTasksInProgress
282267
}
283268
}

Sources/sourcekit-lsp/SourceKitLSP.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,14 @@ struct SourceKitLSP: AsyncParsableCommand {
201201
)
202202
var completionMaxResults = 200
203203

204-
@Flag(
205-
help: "Enable background indexing. This feature is still under active development and may be incomplete."
206-
)
207-
var experimentalEnableBackgroundIndexing = false
208-
209-
@Flag(
204+
@Option(
205+
name: .customLong("experimental-feature"),
210206
help: """
211-
When reporting index progress, show the currently running index tasks in addition to the task's count. \
212-
This produces a multi-line work done progress, which might render incorrectly, depending on the editor.
207+
Enable an experimental sourcekit-lsp feature.
208+
Available features are: \(ExperimentalFeature.allCases.map(\.rawValue).joined(separator: ", "))
213209
"""
214210
)
215-
var experimentalShowActivePreparationTasksInProgress = false
211+
var experimentalFeatures: [ExperimentalFeature]
216212

217213
func mapOptions() -> SourceKitLSPServer.Options {
218214
var serverOptions = SourceKitLSPServer.Options()
@@ -229,8 +225,6 @@ struct SourceKitLSP: AsyncParsableCommand {
229225
serverOptions.indexOptions.indexStorePath = indexStorePath
230226
serverOptions.indexOptions.indexDatabasePath = indexDatabasePath
231227
serverOptions.indexOptions.indexPrefixMappings = indexPrefixMappings
232-
serverOptions.indexOptions.enableBackgroundIndexing = experimentalEnableBackgroundIndexing
233-
serverOptions.indexOptions.showActivePreparationTasksInProgress = experimentalShowActivePreparationTasksInProgress
234228
serverOptions.completionOptions.maxResults = completionMaxResults
235229
serverOptions.generatedInterfacesPath = generatedInterfacesPath
236230

@@ -285,3 +279,9 @@ struct SourceKitLSP: AsyncParsableCommand {
285279
try await Task.sleep(for: .seconds(60 * 60 * 24 * 365 * 10))
286280
}
287281
}
282+
283+
#if compiler(>=6)
284+
extension ExperimentalFeature: @retroactive ExpressibleByArgument {}
285+
#else
286+
extension ExperimentalFeature: ExpressibleByArgument {}
287+
#endif

0 commit comments

Comments
 (0)