mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
Allow specification of SourceKitLSPOptions in the initialize request
This allows editors to provide UI elements to toggle SourceKit-LSP options. # Conflicts: # Sources/SourceKitLSP/Swift/SwiftLanguageService.swift
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
- `~/.sourcekit-lsp/config.json`
|
||||
- On macOS: `~/Library/Application Support/org.swift.sourcekit-lsp/config.json` from the various `Library` folders on the system
|
||||
- If the `XDG_CONFIG_HOME` environment variable is set: `$XDG_CONFIG_HOME/org.swift.sourcekit-lsp/config.json`
|
||||
- Initialization options passed in the initialize request
|
||||
- A `.sourcekit-lsp/config.json` file in a workspace’s root
|
||||
|
||||
The structure of the file is currently not guaranteed to be stable. Options may be removed or renamed.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import Foundation
|
||||
import LSPLogging
|
||||
import SKCore
|
||||
import LanguageServerProtocol
|
||||
import SKSupport
|
||||
|
||||
import struct TSCBasic.AbsolutePath
|
||||
@@ -250,6 +250,21 @@ public struct SourceKitLSPOptions: Sendable, Codable {
|
||||
self.workDoneProgressDebounceDuration = workDoneProgressDebounceDuration
|
||||
}
|
||||
|
||||
public init?(fromLSPAny lspAny: LSPAny?) throws {
|
||||
guard let lspAny else {
|
||||
return nil
|
||||
}
|
||||
let jsonEncoded = try JSONEncoder().encode(lspAny)
|
||||
self = try JSONDecoder().decode(Self.self, from: jsonEncoded)
|
||||
}
|
||||
|
||||
public var asLSPAny: LSPAny {
|
||||
get throws {
|
||||
let jsonEncoded = try JSONEncoder().encode(self)
|
||||
return try JSONDecoder().decode(LSPAny.self, from: jsonEncoded)
|
||||
}
|
||||
}
|
||||
|
||||
public init?(path: URL?) {
|
||||
guard let path, let contents = try? String(contentsOf: path, encoding: .utf8) else {
|
||||
return nil
|
||||
|
||||
@@ -80,6 +80,7 @@ public class MultiFileTestProject {
|
||||
public init(
|
||||
files: [RelativeFileLocation: String],
|
||||
workspaces: (URL) async throws -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
|
||||
initializationOptions: LSPAny? = nil,
|
||||
capabilities: ClientCapabilities = ClientCapabilities(),
|
||||
options: SourceKitLSPOptions = .testDefault(),
|
||||
testHooks: TestHooks = TestHooks(),
|
||||
@@ -118,6 +119,7 @@ public class MultiFileTestProject {
|
||||
self.testClient = try await TestSourceKitLSPClient(
|
||||
options: options,
|
||||
testHooks: testHooks,
|
||||
initializationOptions: initializationOptions,
|
||||
capabilities: capabilities,
|
||||
usePullDiagnostics: usePullDiagnostics,
|
||||
enableBackgroundIndexing: enableBackgroundIndexing,
|
||||
|
||||
@@ -150,6 +150,7 @@ public class SwiftPMTestProject: MultiFileTestProject {
|
||||
files: [RelativeFileLocation: String],
|
||||
manifest: String = SwiftPMTestProject.defaultPackageManifest,
|
||||
workspaces: (URL) async throws -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
|
||||
initializationOptions: LSPAny? = nil,
|
||||
capabilities: ClientCapabilities = ClientCapabilities(),
|
||||
options: SourceKitLSPOptions = .testDefault(),
|
||||
testHooks: TestHooks = TestHooks(),
|
||||
@@ -190,6 +191,7 @@ public class SwiftPMTestProject: MultiFileTestProject {
|
||||
try await super.init(
|
||||
files: filesByPath,
|
||||
workspaces: workspaces,
|
||||
initializationOptions: initializationOptions,
|
||||
capabilities: capabilities,
|
||||
options: options,
|
||||
testHooks: testHooks,
|
||||
|
||||
@@ -104,7 +104,7 @@ public actor SourceKitLSPServer {
|
||||
/// This ensures that we only inform the user about background indexing not being supported for these projects once.
|
||||
private var didSendBackgroundIndexingNotSupportedNotification = false
|
||||
|
||||
let options: SourceKitLSPOptions
|
||||
var options: SourceKitLSPOptions
|
||||
|
||||
let testHooks: TestHooks
|
||||
|
||||
@@ -959,6 +959,10 @@ extension SourceKitLSPServer {
|
||||
|
||||
func initialize(_ req: InitializeRequest) async throws -> InitializeResult {
|
||||
capabilityRegistry = CapabilityRegistry(clientCapabilities: req.capabilities)
|
||||
self.options = SourceKitLSPOptions.merging(
|
||||
base: self.options,
|
||||
override: orLog("Parsing SourceKitLSPOptions", { try SourceKitLSPOptions(fromLSPAny: req.initializationOptions) })
|
||||
)
|
||||
|
||||
await workspaceQueue.async { [testHooks] in
|
||||
if let workspaceFolders = req.workspaceFolders {
|
||||
@@ -983,12 +987,13 @@ extension SourceKitLSPServer {
|
||||
if self.workspaces.isEmpty {
|
||||
logger.error("No workspace found")
|
||||
|
||||
let options = self.options
|
||||
let workspace = await Workspace(
|
||||
documentManager: self.documentManager,
|
||||
rootUri: req.rootURI,
|
||||
capabilityRegistry: self.capabilityRegistry!,
|
||||
toolchainRegistry: self.toolchainRegistry,
|
||||
options: self.options,
|
||||
options: options,
|
||||
testHooks: testHooks,
|
||||
underlyingBuildSystem: nil,
|
||||
index: nil,
|
||||
|
||||
@@ -861,4 +861,68 @@ final class WorkspaceTests: XCTestCase {
|
||||
}
|
||||
XCTAssertEqual(diagnostics.items.map(\.message), ["Cannot convert value of type 'Int' to specified type 'String'"])
|
||||
}
|
||||
|
||||
func testOptionsInInitializeRequest() async throws {
|
||||
let project = try await SwiftPMTestProject(
|
||||
files: [
|
||||
"Test.swift": """
|
||||
func test() {
|
||||
#if TEST
|
||||
let x: String = 1
|
||||
#endif
|
||||
}
|
||||
"""
|
||||
],
|
||||
initializationOptions: SourceKitLSPOptions(
|
||||
swiftPM: SourceKitLSPOptions.SwiftPMOptions(swiftCompilerFlags: ["-D", "TEST"])
|
||||
).asLSPAny
|
||||
)
|
||||
|
||||
let (uri, _) = try project.openDocument("Test.swift")
|
||||
let diagnostics = try await project.testClient.send(
|
||||
DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri))
|
||||
)
|
||||
guard case .full(let diagnostics) = diagnostics else {
|
||||
XCTFail("Expected full diagnostics")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(diagnostics.items.map(\.message), ["Cannot convert value of type 'Int' to specified type 'String'"])
|
||||
}
|
||||
|
||||
func testWorkspaceOptionsOverrideGlobalOptions() async throws {
|
||||
let project = try await SwiftPMTestProject(
|
||||
files: [
|
||||
"/.sourcekit-lsp/config.json": """
|
||||
{
|
||||
"swiftPM": {
|
||||
"swiftCompilerFlags": ["-D", "TEST"]
|
||||
}
|
||||
}
|
||||
""",
|
||||
"Test.swift": """
|
||||
func test() {
|
||||
#if TEST
|
||||
let x: String = 1
|
||||
#endif
|
||||
#if OTHER
|
||||
let x: String = 1.0
|
||||
#endif
|
||||
}
|
||||
""",
|
||||
],
|
||||
initializationOptions: SourceKitLSPOptions(
|
||||
swiftPM: SourceKitLSPOptions.SwiftPMOptions(swiftCompilerFlags: ["-D", "OTHER"])
|
||||
).asLSPAny
|
||||
)
|
||||
|
||||
let (uri, _) = try project.openDocument("Test.swift")
|
||||
let diagnostics = try await project.testClient.send(
|
||||
DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri))
|
||||
)
|
||||
guard case .full(let diagnostics) = diagnostics else {
|
||||
XCTFail("Expected full diagnostics")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(diagnostics.items.map(\.message), ["Cannot convert value of type 'Int' to specified type 'String'"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user