diff --git a/Documentation/Configuration File.md b/Documentation/Configuration File.md index 48b84eb30..ae96a1768 100644 --- a/Documentation/Configuration File.md +++ b/Documentation/Configuration File.md @@ -43,7 +43,7 @@ The structure of the file is currently not guaranteed to be stable. Options may - `logLevel: "debug"|"info"|"default"|"error"|"fault"`: The level from which one onwards log messages should be written. - `privacyLevel: "public"|"private"|"sensitive"`: Whether potentially sensitive information should be redacted. Default is `public`, which redacts potentially sensitive information. - `inputMirrorDirectory: string`: Write all input received by SourceKit-LSP on stdin to a file in this directory. Useful to record and replay an entire SourceKit-LSP session. -- `defaultWorkspaceType: "buildserver"|"compdb"|"swiftpm"`: Overrides workspace type selection logic. +- `defaultWorkspaceType: "swiftPM"|"compilationDatabase"|"buildServer"`: Overrides workspace type selection logic. - `generatedFilesPath: string`: Directory in which generated interfaces and macro expansions should be stored. - `backgroundIndexing: bool`: Explicitly enable or disable background indexing. - `backgroundPreparationMode: "build"|"noLazy"|"enabled"`: Determines how background indexing should prepare a target. Possible values are: diff --git a/Sources/SKOptions/SourceKitLSPOptions.swift b/Sources/SKOptions/SourceKitLSPOptions.swift index 124452586..aa171d52f 100644 --- a/Sources/SKOptions/SourceKitLSPOptions.swift +++ b/Sources/SKOptions/SourceKitLSPOptions.swift @@ -280,7 +280,7 @@ public struct SourceKitLSPOptions: Sendable, Codable, Equatable { set { logging = newValue } } - /// Default workspace type (buildserver|compdb|swiftpm). Overrides workspace type selection logic. + /// Default workspace type (swiftPM|compilationDatabase|buildServer). Overrides workspace type selection logic. public var defaultWorkspaceType: WorkspaceType? public var generatedFilesPath: String? @@ -444,6 +444,17 @@ public struct SourceKitLSPOptions: Sendable, Codable, Equatable { ) } + public static func merging(base: SourceKitLSPOptions, workspaceFolder: DocumentURI) -> SourceKitLSPOptions { + return SourceKitLSPOptions.merging( + base: base, + override: SourceKitLSPOptions( + path: workspaceFolder.fileURL? + .appendingPathComponent(".sourcekit-lsp") + .appendingPathComponent("config.json") + ) + ) + } + public var generatedFilesAbsolutePath: URL { if let generatedFilesPath { return URL(fileURLWithPath: generatedFilesPath) diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift index 323d6fb12..8c6020d44 100644 --- a/Sources/SourceKitLSP/SourceKitLSPServer.swift +++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift @@ -222,6 +222,8 @@ package actor SourceKitLSPServer { // was added to it and thus currently doesn't know that it can handle that file. In that case, we shouldn't open // a new workspace for the same root. Instead, the existing workspace's build system needs to be reloaded. let uri = DocumentURI(url) + + let options = SourceKitLSPOptions.merging(base: self.options, workspaceFolder: uri) guard let buildSystemSpec = determineBuildSystem(forWorkspaceFolder: uri, options: self.options) else { continue } @@ -231,7 +233,7 @@ package actor SourceKitLSPServer { guard let workspace = await orLog( "Creating workspace", - { try await createWorkspace(workspaceFolder: uri, buildSystemSpec: buildSystemSpec) } + { try await createWorkspace(workspaceFolder: uri, options: options, buildSystemSpec: buildSystemSpec) } ) else { continue @@ -821,6 +823,7 @@ extension SourceKitLSPServer { /// If the build system that was determined for the workspace does not satisfy `condition`, `nil` is returned. private func createWorkspace( workspaceFolder: DocumentURI, + options: SourceKitLSPOptions, buildSystemSpec: BuildSystemSpec? ) async throws -> Workspace { guard let capabilityRegistry = capabilityRegistry else { @@ -828,15 +831,7 @@ extension SourceKitLSPServer { logger.log("Cannot open workspace before server is initialized") throw NoCapabilityRegistryError() } - let testHooks = self.testHooks - let options = SourceKitLSPOptions.merging( - base: self.options, - override: SourceKitLSPOptions( - path: workspaceFolder.fileURL? - .appendingPathComponent(".sourcekit-lsp") - .appendingPathComponent("config.json") - ) - ) + logger.log("Creating workspace at \(workspaceFolder.forLogging) with options: \(options.forLogging)") logger.logFullObjectInMultipleLogMessages(header: "Options for workspace", options.loggingProxy) @@ -848,7 +843,7 @@ extension SourceKitLSPServer { buildSystemSpec: buildSystemSpec, toolchainRegistry: self.toolchainRegistry, options: options, - testHooks: testHooks, + testHooks: self.testHooks, indexTaskScheduler: indexTaskScheduler ) return workspace @@ -857,9 +852,12 @@ extension SourceKitLSPServer { /// Determines the build system for the given workspace folder and creates a `Workspace` that uses this inferred build /// system. private func createWorkspaceWithInferredBuildSystem(workspaceFolder: DocumentURI) async throws -> Workspace { + let options = SourceKitLSPOptions.merging(base: self.options, workspaceFolder: workspaceFolder) + let buildSystemSpec = determineBuildSystem(forWorkspaceFolder: workspaceFolder, options: options) return try await self.createWorkspace( workspaceFolder: workspaceFolder, - buildSystemSpec: determineBuildSystem(forWorkspaceFolder: workspaceFolder, options: self.options) + options: options, + buildSystemSpec: buildSystemSpec ) } diff --git a/Tests/SourceKitLSPTests/WorkspaceTests.swift b/Tests/SourceKitLSPTests/WorkspaceTests.swift index 84a1187bc..0101e90c5 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import BuildSystemIntegration import Foundation import LanguageServerProtocol import SKLogging @@ -967,4 +968,60 @@ final class WorkspaceTests: XCTestCase { ["Cannot convert value of type 'Int' to specified type 'String'"] ) } + + func testWorkspaceOptionsOverrideBuildSystem() async throws { + let swiftc = try await unwrap(ToolchainRegistry.forTesting.default?.swiftc) + let sdkArgs = + if let defaultSDKPath { + """ + -sdk '\(defaultSDKPath)' + """ + } else { + "" + } + + let project = try await MultiFileTestProject(files: [ + ".sourcekit-lsp/config.json": """ + { + "defaultWorkspaceType": "compilationDatabase" + } + """, + "Foo.swift": """ + #if HAVE_SETTINGS + #error("Have settings") + #endif + """, + "Sources/MyLib/Bar.swift": "", + "build/compile_commands.json": """ + [ + { + "directory": "$TEST_DIR", + "command": "\(swiftc.filePath) $TEST_DIR/Foo.swift -DHAVE_SETTINGS \(sdkArgs)", + "file": "Foo.swift", + "output": "build/Foo.swift.o" + }, + ] + """, + "Package.swift": """ + // swift-tools-version: 5.7 + + import PackageDescription + + let package = Package( + name: "MyLib", + targets: [ + .target(name: "MyLib"), + ] + ) + """, + ]) + let (uri, _) = try project.openDocument("Foo.swift") + let diagnostics = try await project.testClient.send( + DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri)) + ) + XCTAssertEqual( + diagnostics.fullReport?.items.map(\.message), + ["Have settings"] + ) + } }