@@ -52,6 +52,10 @@ struct ExecutableNotFoundError: Error {
52
52
let executableName : String
53
53
}
54
54
55
+ enum BuildServerNotFoundError : Error {
56
+ case fileNotFound
57
+ }
58
+
55
59
private struct BuildServerConfig : Codable {
56
60
/// The name of the build tool.
57
61
let name : String
@@ -142,7 +146,10 @@ actor ExternalBuildSystemAdapter {
142
146
143
147
/// Create a new JSONRPCConnection to the build server.
144
148
private func createConnectionToBspServer( ) async throws -> JSONRPCConnection {
145
- let configPath = projectRoot. appending ( component: " buildServer.json " )
149
+ guard let configPath = getConfigPath ( ) else {
150
+ throw BuildServerNotFoundError . fileNotFound
151
+ }
152
+
146
153
let serverConfig = try BuildServerConfig . load ( from: configPath)
147
154
var serverPath = try AbsolutePath ( validating: serverConfig. argv [ 0 ] , relativeTo: projectRoot)
148
155
var serverArgs = Array ( serverConfig. argv [ 1 ... ] )
@@ -178,6 +185,48 @@ actor ExternalBuildSystemAdapter {
178
185
) . connection
179
186
}
180
187
188
+ private func getConfigPath( ) -> AbsolutePath ? {
189
+ var buildServerConfigLocations : [ AbsolutePath ? ] = [ ]
190
+
191
+ let workspacePath = projectRoot. appending ( component: " .bsp " )
192
+ buildServerConfigLocations. append ( workspacePath)
193
+
194
+ #if os(Windows)
195
+ let localAppDataPath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " LOCALAPPDATA " ] )
196
+ let programDataPath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " PROGRAMDATA " ] )
197
+
198
+ buildServerConfigLocations. append ( contentsOf: [ localAppDataPath, programDataPath] )
199
+ #else
200
+ let xdgDataHomePath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " XDG_DATA_HOME " ] )
201
+ let xdgDataDirsPath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " XDG_DATA_DIRS " ] )
202
+
203
+ buildServerConfigLocations. append ( contentsOf: [ xdgDataHomePath, xdgDataDirsPath] )
204
+
205
+ if let libraryUrl = FileManager . default. urls ( for: . applicationSupportDirectory, in: . userDomainMask) . first {
206
+ let libraryPath = AbsolutePath ( validatingOrNil: libraryUrl. absoluteString)
207
+ buildServerConfigLocations. append ( libraryPath)
208
+ }
209
+ #endif
210
+
211
+ for buildServerConfigLocation in buildServerConfigLocations {
212
+ guard let buildServerConfigLocation else {
213
+ continue
214
+ }
215
+ let fileManager = FileManager . default
216
+ do {
217
+ let items = try fileManager. contentsOfDirectory ( atPath: buildServerConfigLocation. pathString)
218
+ let jsonFiles = items. filter { $0. hasSuffix ( " .json " ) }
219
+
220
+ if let configFilePath = jsonFiles. sorted ( ) . first {
221
+ return buildServerConfigLocation. appending ( component: configFilePath)
222
+ }
223
+ } catch {
224
+ logger. error ( " Failed to read build server config file at \( buildServerConfigLocation) : \( error) " )
225
+ }
226
+ }
227
+ return nil
228
+ }
229
+
181
230
/// Restart the BSP server after it has crashed.
182
231
private func handleBspServerCrash( ) async throws {
183
232
// Set `connectionToBuildServer` to `nil` to indicate that there is currently no BSP server running.
0 commit comments