Skip to content

Commit d8e0fff

Browse files
committed
Make background indexing a proper option in SourceKitLSPOptions
This allows us to flip the default in the future more easily. It also allows users to disable background indexing when it’s enabled by default. rdar://130280855
1 parent abfe5e9 commit d8e0fff

15 files changed

+141
-128
lines changed

Sources/Diagnose/IndexCommand.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public struct IndexCommand: AsyncParsableCommand {
8282
public init() {}
8383

8484
public func run() async throws {
85-
let options = SourceKitLSPOptions(experimentalFeatures: Set(experimentalFeatures).union([.backgroundIndexing]))
85+
let options = SourceKitLSPOptions(
86+
backgroundIndexing: true,
87+
experimentalFeatures: Set(experimentalFeatures)
88+
)
8689

8790
let installPath =
8891
if let toolchainOverride, let toolchain = Toolchain(try AbsolutePath(validating: toolchainOverride)) {

Sources/SKCore/SourceKitLSPOptions.swift

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ public struct SourceKitLSPOptions: Sendable, Codable {
111111
public var maxCoresPercentageToUseForBackgroundIndexing: Double?
112112
public var updateIndexStoreTimeout: Int?
113113

114+
public var maxCoresPercentageToUseForBackgroundIndexingOrDefault: Double {
115+
return maxCoresPercentageToUseForBackgroundIndexing ?? 1
116+
}
117+
118+
public var updateIndexStoreTimeoutOrDefault: Duration {
119+
if let updateIndexStoreTimeout {
120+
.seconds(updateIndexStoreTimeout)
121+
} else {
122+
.seconds(120)
123+
}
124+
}
125+
114126
public init(
115127
indexStorePath: String? = nil,
116128
indexDatabasePath: String? = nil,
@@ -137,16 +149,19 @@ public struct SourceKitLSPOptions: Sendable, Codable {
137149
}
138150
}
139151

140-
public var swiftPM: SwiftPMOptions?
141-
public var compilationDatabase: CompilationDatabaseOptions?
142-
public var fallbackBuildSystem: FallbackBuildSystemOptions?
152+
public var swiftPM: SwiftPMOptions
153+
public var compilationDatabase: CompilationDatabaseOptions
154+
public var fallbackBuildSystem: FallbackBuildSystemOptions
143155
public var clangdOptions: [String]?
144-
public var index: IndexOptions?
156+
public var index: IndexOptions
145157

146158
/// Default workspace type (buildserver|compdb|swiftpm). Overrides workspace type selection logic.
147159
public var defaultWorkspaceType: WorkspaceType?
148160
public var generatedFilesPath: String?
149161

162+
/// Whether background indexing is enabled.
163+
public var backgroundIndexing: Bool?
164+
150165
/// Experimental features that are enabled.
151166
public var experimentalFeatures: Set<ExperimentalFeature>? = nil
152167

@@ -155,25 +170,29 @@ public struct SourceKitLSPOptions: Sendable, Codable {
155170
///
156171
/// This is mostly intended for testing purposes so we don't need to wait the debouncing time to get a diagnostics
157172
/// notification when running unit tests.
158-
public var swiftPublishDiagnosticsDebounce: Double? = nil
173+
public var swiftPublishDiagnosticsDebounceDuration: Double? = nil
159174

160-
public var swiftPublishDiagnosticsDebounceDuration: TimeInterval {
161-
if let workDoneProgressDebounce {
162-
return workDoneProgressDebounce
175+
public var swiftPublishDiagnosticsDebounceDurationOrDefault: Duration {
176+
if let swiftPublishDiagnosticsDebounceDuration {
177+
return .seconds(swiftPublishDiagnosticsDebounceDuration)
163178
}
164-
return 2 /* seconds */
179+
return .seconds(2)
165180
}
166181

167182
/// When a task is started that should be displayed to the client as a work done progress, how many milliseconds to
168183
/// wait before actually starting the work done progress. This prevents flickering of the work done progress in the
169184
/// client for short-lived index tasks which end within this duration.
170-
public var workDoneProgressDebounce: Double? = nil
185+
public var workDoneProgressDebounceDuration: Double? = nil
171186

172-
public var workDoneProgressDebounceDuration: Duration {
173-
if let workDoneProgressDebounce {
174-
return .seconds(workDoneProgressDebounce)
187+
public var workDoneProgressDebounceDurationOrDefault: Duration {
188+
if let workDoneProgressDebounceDuration {
189+
return .seconds(workDoneProgressDebounceDuration)
175190
}
176-
return .seconds(0)
191+
return .seconds(1)
192+
}
193+
194+
public var backgroundIndexingOrDefault: Bool {
195+
return backgroundIndexing ?? false
177196
}
178197

179198
public init(
@@ -184,9 +203,10 @@ public struct SourceKitLSPOptions: Sendable, Codable {
184203
index: IndexOptions = .init(),
185204
defaultWorkspaceType: WorkspaceType? = nil,
186205
generatedFilesPath: String? = nil,
206+
backgroundIndexing: Bool? = nil,
187207
experimentalFeatures: Set<ExperimentalFeature>? = nil,
188-
swiftPublishDiagnosticsDebounce: Double? = nil,
189-
workDoneProgressDebounce: Double? = nil
208+
swiftPublishDiagnosticsDebounceDuration: Double? = nil,
209+
workDoneProgressDebounceDuration: Double? = nil
190210
) {
191211
self.swiftPM = swiftPM
192212
self.fallbackBuildSystem = fallbackBuildSystem
@@ -195,9 +215,10 @@ public struct SourceKitLSPOptions: Sendable, Codable {
195215
self.index = index
196216
self.generatedFilesPath = generatedFilesPath
197217
self.defaultWorkspaceType = defaultWorkspaceType
218+
self.backgroundIndexing = backgroundIndexing
198219
self.experimentalFeatures = experimentalFeatures
199-
self.swiftPublishDiagnosticsDebounce = swiftPublishDiagnosticsDebounce
200-
self.workDoneProgressDebounce = workDoneProgressDebounce
220+
self.swiftPublishDiagnosticsDebounceDuration = swiftPublishDiagnosticsDebounceDuration
221+
self.workDoneProgressDebounceDuration = workDoneProgressDebounceDuration
201222
}
202223

203224
public init?(path: URL?) {
@@ -207,7 +228,7 @@ public struct SourceKitLSPOptions: Sendable, Codable {
207228
guard
208229
let decoded = orLog(
209230
"Parsing config.json",
210-
{ try JSONDecoder().decode(SourceKitLSPOptions.self, from: contents) }
231+
{ try JSONDecoder().decode(Self.self, from: contents) }
211232
)
212233
else {
213234
return nil
@@ -217,23 +238,25 @@ public struct SourceKitLSPOptions: Sendable, Codable {
217238

218239
public static func merging(base: SourceKitLSPOptions, override: SourceKitLSPOptions?) -> SourceKitLSPOptions {
219240
return SourceKitLSPOptions(
220-
swiftPM: SwiftPMOptions.merging(base: base.swiftPM ?? .init(), override: override?.swiftPM),
241+
swiftPM: SwiftPMOptions.merging(base: base.swiftPM, override: override?.swiftPM),
221242
fallbackBuildSystem: FallbackBuildSystemOptions.merging(
222-
base: base.fallbackBuildSystem ?? .init(),
243+
base: base.fallbackBuildSystem,
223244
override: override?.fallbackBuildSystem
224245
),
225246
compilationDatabase: CompilationDatabaseOptions.merging(
226-
base: base.compilationDatabase ?? .init(),
247+
base: base.compilationDatabase,
227248
override: override?.compilationDatabase
228249
),
229250
clangdOptions: override?.clangdOptions ?? base.clangdOptions,
230-
index: IndexOptions.merging(base: base.index ?? .init(), override: override?.index),
251+
index: IndexOptions.merging(base: base.index, override: override?.index),
231252
defaultWorkspaceType: override?.defaultWorkspaceType ?? base.defaultWorkspaceType,
232253
generatedFilesPath: override?.generatedFilesPath ?? base.generatedFilesPath,
254+
backgroundIndexing: override?.backgroundIndexing ?? base.backgroundIndexing,
233255
experimentalFeatures: override?.experimentalFeatures ?? base.experimentalFeatures,
234-
swiftPublishDiagnosticsDebounce: override?.swiftPublishDiagnosticsDebounce
235-
?? base.swiftPublishDiagnosticsDebounce,
236-
workDoneProgressDebounce: override?.workDoneProgressDebounce ?? base.workDoneProgressDebounce
256+
swiftPublishDiagnosticsDebounceDuration: override?.swiftPublishDiagnosticsDebounceDuration
257+
?? base.swiftPublishDiagnosticsDebounceDuration,
258+
workDoneProgressDebounceDuration: override?.workDoneProgressDebounceDuration
259+
?? base.workDoneProgressDebounceDuration
237260
)
238261
}
239262

@@ -250,4 +273,34 @@ public struct SourceKitLSPOptions: Sendable, Codable {
250273
}
251274
return experimentalFeatures.contains(feature)
252275
}
276+
277+
public init(from decoder: any Decoder) throws {
278+
let container = try decoder.container(keyedBy: CodingKeys.self)
279+
280+
self.swiftPM = try container.decodeIfPresent(SwiftPMOptions.self, forKey: CodingKeys.swiftPM) ?? .init()
281+
self.compilationDatabase =
282+
try container.decodeIfPresent(CompilationDatabaseOptions.self, forKey: CodingKeys.compilationDatabase) ?? .init()
283+
self.fallbackBuildSystem =
284+
try container.decodeIfPresent(FallbackBuildSystemOptions.self, forKey: CodingKeys.fallbackBuildSystem) ?? .init()
285+
self.clangdOptions = try container.decodeIfPresent([String].self, forKey: CodingKeys.clangdOptions)
286+
self.index = try container.decodeIfPresent(IndexOptions.self, forKey: CodingKeys.index) ?? .init()
287+
self.defaultWorkspaceType = try container.decodeIfPresent(
288+
WorkspaceType.self,
289+
forKey: CodingKeys.defaultWorkspaceType
290+
)
291+
self.generatedFilesPath = try container.decodeIfPresent(String.self, forKey: CodingKeys.generatedFilesPath)
292+
self.backgroundIndexing = try container.decodeIfPresent(Bool.self, forKey: CodingKeys.backgroundIndexing)
293+
self.experimentalFeatures = try container.decodeIfPresent(
294+
Set<ExperimentalFeature>.self,
295+
forKey: CodingKeys.experimentalFeatures
296+
)
297+
self.swiftPublishDiagnosticsDebounceDuration = try container.decodeIfPresent(
298+
Double.self,
299+
forKey: CodingKeys.swiftPublishDiagnosticsDebounceDuration
300+
)
301+
self.workDoneProgressDebounceDuration = try container.decodeIfPresent(
302+
Double.self,
303+
forKey: CodingKeys.workDoneProgressDebounceDuration
304+
)
305+
}
253306
}

Sources/SKSupport/ExperimentalFeatures.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
/// An experimental feature that can be enabled by passing `--experimental-feature` to `sourcekit-lsp` on the command
1414
/// line. The raw value of this feature is how it is named on the command line.
1515
public enum ExperimentalFeature: String, Codable, Sendable, CaseIterable {
16-
/// Enable background indexing.
17-
case backgroundIndexing = "background-indexing"
18-
1916
/// Add `--experimental-prepare-for-indexing` to the `swift build` command run to prepare a target for indexing.
2017
case swiftpmPrepareForIndexing = "swiftpm-prepare-for-indexing"
2118

Sources/SKSwiftPMWorkspace/SwiftPMBuildSystem.swift

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public actor SwiftPMBuildSystem {
131131
private let workspacePath: TSCAbsolutePath
132132

133133
/// Options that allow the user to pass extra compiler flags.
134-
private let options: SourceKitLSPOptions.SwiftPMOptions
134+
private let options: SourceKitLSPOptions
135135

136136
/// The directory containing `Package.swift`.
137137
@_spi(Testing)
@@ -175,12 +175,9 @@ public actor SwiftPMBuildSystem {
175175
logger.log(level: diagnostic.severity.asLogLevel, "SwiftPM log: \(diagnostic.description)")
176176
})
177177

178-
/// Whether to pass `--experimental-prepare-for-indexing` to `swift build` as part of preparation.
179-
private let experimentalFeatures: Set<ExperimentalFeature>
180-
181178
/// Whether the `SwiftPMBuildSystem` is pointed at a `.index-build` directory that's independent of the
182179
/// user's build.
183-
private var isForIndexBuild: Bool { experimentalFeatures.contains(.backgroundIndexing) }
180+
private var isForIndexBuild: Bool { options.backgroundIndexingOrDefault }
184181

185182
private let testHooks: SwiftPMTestHooks
186183

@@ -196,8 +193,7 @@ public actor SwiftPMBuildSystem {
196193
workspacePath: TSCAbsolutePath,
197194
toolchainRegistry: ToolchainRegistry,
198195
fileSystem: FileSystem = localFileSystem,
199-
options: SourceKitLSPOptions.SwiftPMOptions,
200-
experimentalFeatures: Set<ExperimentalFeature>,
196+
options: SourceKitLSPOptions,
201197
reloadPackageStatusCallback: @escaping (ReloadPackageStatus) async -> Void = { _ in },
202198
testHooks: SwiftPMTestHooks
203199
) async throws {
@@ -209,7 +205,6 @@ public actor SwiftPMBuildSystem {
209205
}
210206

211207
self.toolchain = toolchain
212-
self.experimentalFeatures = experimentalFeatures
213208
self.testHooks = testHooks
214209

215210
guard let packageRoot = findPackageDirectory(containing: workspacePath, fileSystem) else {
@@ -229,9 +224,9 @@ public actor SwiftPMBuildSystem {
229224
forRootPackage: AbsolutePath(packageRoot),
230225
fileSystem: fileSystem
231226
)
232-
if experimentalFeatures.contains(.backgroundIndexing) {
227+
if options.backgroundIndexingOrDefault {
233228
location.scratchDirectory = AbsolutePath(packageRoot.appending(component: ".index-build"))
234-
} else if let scratchDirectory = options.scratchPath,
229+
} else if let scratchDirectory = options.swiftPM.scratchPath,
235230
let scratchDirectoryPath = try? AbsolutePath(validating: scratchDirectory)
236231
{
237232
location.scratchDirectory = scratchDirectoryPath
@@ -248,18 +243,18 @@ public actor SwiftPMBuildSystem {
248243
)
249244

250245
let buildConfiguration: PackageModel.BuildConfiguration
251-
switch options.configuration {
246+
switch options.swiftPM.configuration {
252247
case .debug, nil:
253248
buildConfiguration = .debug
254249
case .release:
255250
buildConfiguration = .release
256251
}
257252

258253
let buildFlags = BuildFlags(
259-
cCompilerFlags: options.cCompilerFlags ?? [],
260-
cxxCompilerFlags: options.cxxCompilerFlags ?? [],
261-
swiftCompilerFlags: options.swiftCompilerFlags ?? [],
262-
linkerFlags: options.linkerFlags ?? []
254+
cCompilerFlags: options.swiftPM.cCompilerFlags ?? [],
255+
cxxCompilerFlags: options.swiftPM.cxxCompilerFlags ?? [],
256+
swiftCompilerFlags: options.swiftPM.swiftCompilerFlags ?? [],
257+
linkerFlags: options.swiftPM.linkerFlags ?? []
263258
)
264259

265260
self.toolsBuildParameters = try BuildParameters(
@@ -312,8 +307,7 @@ public actor SwiftPMBuildSystem {
312307
public init?(
313308
uri: DocumentURI,
314309
toolchainRegistry: ToolchainRegistry,
315-
options: SourceKitLSPOptions.SwiftPMOptions,
316-
experimentalFeatures: Set<ExperimentalFeature>,
310+
options: SourceKitLSPOptions,
317311
reloadPackageStatusCallback: @escaping (ReloadPackageStatus) async -> Void,
318312
testHooks: SwiftPMTestHooks
319313
) async {
@@ -326,7 +320,6 @@ public actor SwiftPMBuildSystem {
326320
toolchainRegistry: toolchainRegistry,
327321
fileSystem: localFileSystem,
328322
options: options,
329-
experimentalFeatures: experimentalFeatures,
330323
reloadPackageStatusCallback: reloadPackageStatusCallback,
331324
testHooks: testHooks
332325
)
@@ -613,14 +606,14 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
613606
"--disable-index-store",
614607
"--target", target.targetID,
615608
]
616-
if let configuration = options.configuration {
609+
if let configuration = options.swiftPM.configuration {
617610
arguments += ["-c", configuration.rawValue]
618611
}
619-
arguments += options.cCompilerFlags?.flatMap { ["-Xcc", $0] } ?? []
620-
arguments += options.cxxCompilerFlags?.flatMap { ["-Xcxx", $0] } ?? []
621-
arguments += options.swiftCompilerFlags?.flatMap { ["-Xswiftc", $0] } ?? []
622-
arguments += options.linkerFlags?.flatMap { ["-Xlinker", $0] } ?? []
623-
if experimentalFeatures.contains(.swiftpmPrepareForIndexing) {
612+
arguments += options.swiftPM.cCompilerFlags?.flatMap { ["-Xcc", $0] } ?? []
613+
arguments += options.swiftPM.cxxCompilerFlags?.flatMap { ["-Xcxx", $0] } ?? []
614+
arguments += options.swiftPM.swiftCompilerFlags?.flatMap { ["-Xswiftc", $0] } ?? []
615+
arguments += options.swiftPM.linkerFlags?.flatMap { ["-Xlinker", $0] } ?? []
616+
if options.hasExperimentalFeature(.swiftpmPrepareForIndexing) {
624617
arguments.append("--experimental-prepare-for-indexing")
625618
}
626619
if Task.isCancelled {

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import XCTest
2424

2525
extension SourceKitLSPOptions {
2626
public static func testDefault(experimentalFeatures: Set<ExperimentalFeature>? = nil) -> SourceKitLSPOptions {
27-
return SourceKitLSPOptions(experimentalFeatures: experimentalFeatures, swiftPublishDiagnosticsDebounce: 0)
27+
return SourceKitLSPOptions(experimentalFeatures: experimentalFeatures, swiftPublishDiagnosticsDebounceDuration: 0)
2828
}
2929
}
3030

@@ -108,13 +108,10 @@ public final class TestSourceKitLSPClient: MessageHandler, Sendable {
108108
) async throws {
109109
var options = options
110110
if let globalModuleCache {
111-
options.swiftPM = options.swiftPM ?? SourceKitLSPOptions.SwiftPMOptions()
112-
options.swiftPM!.swiftCompilerFlags =
113-
(options.swiftPM!.swiftCompilerFlags ?? []) + ["-module-cache-path", globalModuleCache.path]
114-
}
115-
if enableBackgroundIndexing {
116-
options.experimentalFeatures = (options.experimentalFeatures ?? []).union([.backgroundIndexing])
111+
options.swiftPM.swiftCompilerFlags =
112+
(options.swiftPM.swiftCompilerFlags ?? []) + ["-module-cache-path", globalModuleCache.path]
117113
}
114+
options.backgroundIndexing = enableBackgroundIndexing
118115

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

Sources/SourceKitLSP/CreateBuildSystem.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ func createBuildSystem(
3838
return await SwiftPMBuildSystem(
3939
uri: rootUri,
4040
toolchainRegistry: toolchainRegistry,
41-
options: options.swiftPM ?? .init(),
42-
experimentalFeatures: options.experimentalFeatures ?? [],
41+
options: options,
4342
reloadPackageStatusCallback: reloadPackageStatusCallback,
4443
testHooks: testHooks.swiftpmTestHooks
4544
)
@@ -48,7 +47,7 @@ func createBuildSystem(
4847
func createCompilationDatabaseBuildSystem(rootPath: AbsolutePath) -> CompilationDatabaseBuildSystem? {
4948
return CompilationDatabaseBuildSystem(
5049
projectRoot: rootPath,
51-
searchPaths: (options.compilationDatabase?.searchPaths ?? []).compactMap { try? RelativePath(validating: $0) }
50+
searchPaths: (options.compilationDatabase.searchPaths ?? []).compactMap { try? RelativePath(validating: $0) }
5251
)
5352
}
5453

Sources/SourceKitLSP/IndexProgressManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ actor IndexProgressManager {
128128
workDoneProgress = await WorkDoneProgressManager(
129129
server: sourceKitLSPServer,
130130
tokenPrefix: "indexing",
131-
initialDebounce: sourceKitLSPServer.options.workDoneProgressDebounceDuration,
131+
initialDebounce: sourceKitLSPServer.options.workDoneProgressDebounceDurationOrDefault,
132132
title: "Indexing",
133133
message: message,
134134
percentage: percentage

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ public actor SourceKitLSPServer {
214214

215215
self.client = client
216216
let processorCount = ProcessInfo.processInfo.processorCount
217-
let lowPriorityCores = (options.index?.maxCoresPercentageToUseForBackgroundIndexing ?? 1) * Double(processorCount)
217+
let lowPriorityCores = options.index.maxCoresPercentageToUseForBackgroundIndexingOrDefault * Double(processorCount)
218218
self.indexTaskScheduler = TaskScheduler(maxConcurrentTasksByPriority: [
219219
(TaskPriority.medium, processorCount),
220220
(TaskPriority.low, max(Int(lowPriorityCores), 1)),
@@ -940,7 +940,7 @@ extension SourceKitLSPServer {
940940
self?.indexProgressManager.indexProgressStatusDidChange()
941941
}
942942
)
943-
if let workspace, options.hasExperimentalFeature(.backgroundIndexing), workspace.semanticIndexManager == nil,
943+
if let workspace, options.backgroundIndexingOrDefault, workspace.semanticIndexManager == nil,
944944
!self.didSendBackgroundIndexingNotSupportedNotification
945945
{
946946
self.sendNotificationToClient(

0 commit comments

Comments
 (0)