Skip to content

Commit d1cddb8

Browse files
committed
Allow configuring of SourceKit-LSP’s options using .sourcekit-lsp configuration files
The idea here is to unify the different ways in which we can currently set options on SourceKit-LSP in a scalable way: Environment variables, command line arguments to `sourcekit-lsp` and initialization options. The idea is that a user can define a `~/.sourcekit-lsp/.sourcekit-lsp` file (we store logs in `~/.sourcekit-lsp/logs` on non-Darwin platforms), which will be used as the default configuration for all SourceKit-LSP instances. They can also place a `.sourcekit-lsp` file in the root of a workspace to configure SourceKit-LSP for that project specifically, eg. setting arguments that need to be passed to `swift build` for that project and which thus also need to be set on SourceKit-LSP. For compatibility reasons, I’m mapping the existing command line options into the new options structure for now. I hope to delete the command line arguments in the future and solely rely on `.sourcekit-lsp` configuration files. Environment variable will be migrated to `.sourcekit-lsp` in a follow-up commit.
1 parent 12142c0 commit d1cddb8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+722
-674
lines changed

Documentation/Configuration File.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Configuration File
2+
3+
`.sourcekit-lsp/config.json` configuration files can be used to modify the behavior of SourceKit-LSP in various ways. The following locations are checked. Settings in later configuration files override settings in earlier configuration files
4+
- `~/.sourcekit-lsp/config.json`
5+
- On macOS: `~/Library/Application Support/org.swift.sourcekit-lsp/config.json` from the various `Library` folders on the system
6+
- If the `XDG_CONFIG_HOME` environment variable is set: `$XDG_CONFIG_HOME/org.swift.sourcekit-lsp/config.json`
7+
- A `.sourcekit-lsp/config.json` file in a workspace’s root
8+
9+
The structure of the file is currently not guaranteed to be stable. Options may be removed or renamed.
10+
11+
## Structure
12+
13+
`config.json` is a JSON file with the following structure. All keys are optional and unknown keys are ignored.
14+
15+
- `swiftPM`: Dictionary with the following keys, defining options for SwiftPM workspaces
16+
- `configuration: "debug"|"release"`: The configuration to build the project for during background indexing and the configuration whose build folder should be used for Swift modules if background indexing is disabled
17+
- `scratchPath: string`: Build artifacts directory path. If nil, the build system may choose a default value
18+
- `cCompilerFlags: string[]`: Extra arguments passed to the compiler for C files
19+
- `cxxCompilerFlags: string[]`: Extra arguments passed to the compiler for C++ files
20+
- `swiftCompilerFlags: string[]`: Extra arguments passed to the compiler for Swift files
21+
- `linkerFlags: string[]`: Extra arguments passed to the linker
22+
- `compilationDatabase`: Dictionary with the following keys, defining options for workspaces with a compilation database
23+
- `searchPaths: string[]`: Additional paths to search for a compilation database, relative to a workspace root.
24+
- `fallbackBuildSystem`: Dictionary with the following keys, defining options for files that aren't managed by any build system
25+
- `cCompilerFlags: string[]`: Extra arguments passed to the compiler for C files
26+
- `cxxCompilerFlags: string[]`: Extra arguments passed to the compiler for C++ files
27+
- `swiftCompilerFlags: string[]`: Extra arguments passed to the compiler for Swift files
28+
- `clangdOptions: string[]`: Extra command line arguments passed to `clangd` when launching it
29+
- `index`: Dictionary with the following keys, defining options related to indexing
30+
- `indexStorePath: string`: Directory in which a separate compilation stores the index store. By default, inferred from the build system.
31+
- `indexDatabasePath: string`: Directory in which the indexstore-db should be stored. By default, inferred from the build system.
32+
- `indexPrefixMap: [string: string]`: Path remappings for remapping index data for local use.
33+
- `maxCoresPercentageToUseForBackgroundIndexing: double`: A hint indicating how many cores background indexing should use at most (value between 0 and 1). Background indexing is not required to honor this setting
34+
- `updateIndexStoreTimeout: int`: Number of seconds to wait for an update index store task to finish before killing it.
35+
- `defaultWorkspaceType: "buildserver"|"compdb"|"swiftpm"`: Overrides workspace type selection logic.
36+
- `generatedFilesPath: string`: Directory in which generated interfaces and macro expansions should be stored.
37+
- `experimentalFeatures: string[]`: Experimental features to enable
38+
- `swiftPublishDiagnosticsDebounce`: The time that `SwiftLanguageService` should wait after an edit before starting to compute diagnostics and sending a `PublishDiagnosticsNotification`.

Documentation/LSP Extensions.md

-22
Original file line numberDiff line numberDiff line change
@@ -73,28 +73,6 @@ Added case
7373
identifier = 'identifier'
7474
```
7575
76-
## `textDocument/completion`
77-
78-
Added field:
79-
80-
```ts
81-
/**
82-
* Options to control code completion behavior in Swift
83-
*/
84-
sourcekitlspOptions?: SKCompletionOptions
85-
```
86-
87-
with
88-
89-
```ts
90-
interface SKCompletionOptions {
91-
/**
92-
* The maximum number of completion results to return, or `null` for unlimited.
93-
*/
94-
maxResults?: int
95-
}
96-
```
97-
9876
## `textDocument/interface`
9977
10078
New request that request a textual interface of a module to display in the IDE. Used internally within SourceKit-LSP

Sources/Diagnose/IndexCommand.swift

+2-4
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ public struct IndexCommand: AsyncParsableCommand {
8282
public init() {}
8383

8484
public func run() async throws {
85-
var serverOptions = SourceKitLSPServer.Options()
86-
serverOptions.experimentalFeatures = Set(experimentalFeatures)
87-
serverOptions.experimentalFeatures.insert(.backgroundIndexing)
85+
let options = SourceKitLSPOptions(experimentalFeatures: Set(experimentalFeatures).union([.backgroundIndexing]))
8886

8987
let installPath =
9088
if let toolchainOverride, let toolchain = Toolchain(try AbsolutePath(validating: toolchainOverride)) {
@@ -96,7 +94,7 @@ public struct IndexCommand: AsyncParsableCommand {
9694
let messageHandler = IndexLogMessageHandler()
9795
let inProcessClient = try await InProcessSourceKitLSPClient(
9896
toolchainRegistry: ToolchainRegistry(installPath: installPath),
99-
serverOptions: serverOptions,
97+
options: options,
10098
workspaceFolders: [WorkspaceFolder(uri: DocumentURI(URL(fileURLWithPath: project)))],
10199
messageHandler: messageHandler
102100
)

Sources/InProcessClient/InProcessSourceKitLSPClient.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public final class InProcessSourceKitLSPClient: Sendable {
2626
/// `messageHandler` handles notifications and requests sent from the SourceKit-LSP server to the client.
2727
public init(
2828
toolchainRegistry: ToolchainRegistry,
29-
serverOptions: SourceKitLSPServer.Options = SourceKitLSPServer.Options(),
29+
options: SourceKitLSPOptions = SourceKitLSPOptions(),
30+
testHooks: TestHooks = TestHooks(),
3031
capabilities: ClientCapabilities = ClientCapabilities(),
3132
workspaceFolders: [WorkspaceFolder],
3233
messageHandler: any MessageHandler
@@ -35,7 +36,8 @@ public final class InProcessSourceKitLSPClient: Sendable {
3536
self.server = SourceKitLSPServer(
3637
client: serverToClientConnection,
3738
toolchainRegistry: toolchainRegistry,
38-
options: serverOptions,
39+
options: options,
40+
testHooks: testHooks,
3941
onExit: {
4042
serverToClientConnection.close()
4143
}

Sources/LanguageServerProtocol/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ add_library(LanguageServerProtocol STATIC
124124
SupportTypes/SemanticTokens.swift
125125
SupportTypes/SemanticTokenTypes.swift
126126
SupportTypes/ServerCapabilities.swift
127-
SupportTypes/SKCompletionOptions.swift
128127
SupportTypes/StringOrMarkupContent.swift
129128
SupportTypes/SymbolKind.swift
130129
SupportTypes/TestItem.swift

Sources/LanguageServerProtocol/Requests/CompletionRequest.swift

+1-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
/// - textDocument: The document to perform completion in.
2424
/// - position: The location to perform completion at.
2525
/// - context: Optional code-completion context.
26-
/// - sourcekitlspOptions: **(LSP Extension)** code-completion options for sourcekit-lsp.
2726
///
2827
/// - Returns: A list of completion items to complete the code at the given position.
2928
public struct CompletionRequest: TextDocumentRequest, Hashable {
@@ -36,18 +35,14 @@ public struct CompletionRequest: TextDocumentRequest, Hashable {
3635

3736
public var context: CompletionContext?
3837

39-
public var sourcekitlspOptions: SKCompletionOptions?
40-
4138
public init(
4239
textDocument: TextDocumentIdentifier,
4340
position: Position,
44-
context: CompletionContext? = nil,
45-
sourcekitlspOptions: SKCompletionOptions? = nil
41+
context: CompletionContext? = nil
4642
) {
4743
self.textDocument = textDocument
4844
self.position = position
4945
self.context = context
50-
self.sourcekitlspOptions = sourcekitlspOptions
5146
}
5247
}
5348

Sources/LanguageServerProtocol/Requests/PollIndexRequest.swift

-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212

1313
/// Poll the index for unit changes and wait for them to be registered.
1414
/// **LSP Extension, For Testing**.
15-
///
16-
/// Users of PollIndex should set `"initializationOptions": { "listenToUnitEvents": false }` during
17-
/// the `initialize` request.
1815
public struct PollIndexRequest: RequestType {
1916
public static let method: String = "workspace/_pollIndex"
2017
public typealias Response = VoidResponse

Sources/LanguageServerProtocol/SupportTypes/SKCompletionOptions.swift

-31
This file was deleted.

Sources/SKCore/BuildConfiguration.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
public enum BuildConfiguration: String, Sendable {
13+
public enum BuildConfiguration: String, Codable, Sendable {
1414
case debug
1515
case release
1616
}

Sources/SKCore/BuildServerBuildSystem.swift

+3-6
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func executable(_ name: String) -> String {
4545
/// `buildServer.json` configuration file provided in the repo root.
4646
public actor BuildServerBuildSystem: MessageHandler {
4747
public let projectRoot: AbsolutePath
48-
let buildFolder: AbsolutePath?
4948
let serverConfig: BuildServerConfig
5049

5150
var buildServer: JSONRPCConnection?
@@ -82,7 +81,6 @@ public actor BuildServerBuildSystem: MessageHandler {
8281

8382
public init(
8483
projectRoot: AbsolutePath,
85-
buildFolder: AbsolutePath?,
8684
fileSystem: FileSystem = localFileSystem
8785
) async throws {
8886
let configPath = projectRoot.appending(component: "buildServer.json")
@@ -100,7 +98,6 @@ public actor BuildServerBuildSystem: MessageHandler {
10098
currentWorkingDirectory: fileSystem.currentWorkingDirectory
10199
)
102100
#endif
103-
self.buildFolder = buildFolder
104101
self.projectRoot = projectRoot
105102
self.serverConfig = config
106103
try await self.initializeBuildServer()
@@ -109,11 +106,11 @@ public actor BuildServerBuildSystem: MessageHandler {
109106
/// Creates a build system using the Build Server Protocol config.
110107
///
111108
/// - Returns: nil if `projectRoot` has no config or there is an error parsing it.
112-
public init?(projectRoot: AbsolutePath?, buildSetup: BuildSetup) async {
113-
if projectRoot == nil { return nil }
109+
public init?(projectRoot: AbsolutePath?) async {
110+
guard let projectRoot else { return nil }
114111

115112
do {
116-
try await self.init(projectRoot: projectRoot!, buildFolder: buildSetup.path)
113+
try await self.init(projectRoot: projectRoot)
117114
} catch is FileSystemError {
118115
// config file was missing, no build server for this workspace
119116
return nil

Sources/SKCore/BuildSetup.swift

-67
This file was deleted.

Sources/SKCore/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
add_library(SKCore STATIC
33
BuildConfiguration.swift
44
BuildServerBuildSystem.swift
5-
BuildSetup.swift
65
BuildSystem.swift
76
BuildSystemDelegate.swift
87
BuildSystemManager.swift
@@ -13,6 +12,7 @@ add_library(SKCore STATIC
1312
IndexTaskID.swift
1413
MainFilesProvider.swift
1514
PathPrefixMapping.swift
15+
SourceKitLSPOptions.swift
1616
SplitShellCommand.swift
1717
Toolchain.swift
1818
ToolchainRegistry.swift

Sources/SKCore/FallbackBuildSystem.swift

+6-7
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ import class TSCBasic.Process
2222

2323
/// A simple BuildSystem suitable as a fallback when accurate settings are unknown.
2424
public actor FallbackBuildSystem {
25+
private let options: SourceKitLSPOptions.FallbackBuildSystemOptions
2526

26-
let buildSetup: BuildSetup
27-
28-
public init(buildSetup: BuildSetup) {
29-
self.buildSetup = buildSetup
27+
public init(options: SourceKitLSPOptions.FallbackBuildSystemOptions) {
28+
self.options = options
3029
}
3130

3231
/// The path to the SDK.
@@ -71,7 +70,7 @@ public actor FallbackBuildSystem {
7170

7271
func settingsSwift(_ file: String) -> FileBuildSettings {
7372
var args: [String] = []
74-
args.append(contentsOf: self.buildSetup.flags.swiftCompilerFlags)
73+
args.append(contentsOf: self.options.swiftCompilerFlags ?? [])
7574
if let sdkpath = sdkpath, !args.contains("-sdk") {
7675
args += [
7776
"-sdk",
@@ -86,9 +85,9 @@ public actor FallbackBuildSystem {
8685
var args: [String] = []
8786
switch language {
8887
case .c:
89-
args.append(contentsOf: self.buildSetup.flags.cCompilerFlags)
88+
args.append(contentsOf: self.options.cCompilerFlags ?? [])
9089
case .cpp:
91-
args.append(contentsOf: self.buildSetup.flags.cxxCompilerFlags)
90+
args.append(contentsOf: self.options.cxxCompilerFlags ?? [])
9291
default:
9392
break
9493
}

0 commit comments

Comments
 (0)