@@ -24,32 +24,83 @@ import TSCBasic
24
24
/// like witholding diagnostics when fallback build settings are being used.
25
25
final class ClangLanguageServerShim : LanguageServer , ToolchainLanguageServer {
26
26
27
- /// The connection to the clangd LSP.
28
- let clangd : Connection
27
+ /// The connection to the clangd LSP. `nil` until `startClangdProcesss` has been called.
28
+ var clangd : Connection !
29
29
30
30
/// Capabilities of the clangd LSP, if received.
31
31
var capabilities : ServerCapabilities ? = nil
32
32
33
33
/// Path to the clang binary.
34
34
let clangPath : AbsolutePath ?
35
+
36
+ /// Path to the `clangd` binary.
37
+ let clangdPath : AbsolutePath
38
+
39
+ let clangdOptions : [ String ]
35
40
36
41
/// Resolved build settings by file. Must be accessed with the `lock`.
37
42
private var buildSettingsByFile : [ DocumentURI : ClangBuildSettings ] = [ : ]
38
43
39
44
/// Lock protecting `buildSettingsByFile`.
40
- private var lock : Lock
45
+ private var lock : Lock = Lock ( )
41
46
42
47
/// Creates a language server for the given client referencing the clang binary at the given path.
43
48
public init (
44
- client: LocalConnection ,
45
- clangd: Connection ,
46
- clangPath: AbsolutePath ?
49
+ client: Connection ,
50
+ clangPath: AbsolutePath ? ,
51
+ clangdPath: AbsolutePath ,
52
+ clangdOptions: [ String ]
47
53
) throws {
48
- self . clangd = clangd
49
54
self . clangPath = clangPath
50
- self . lock = Lock ( )
55
+ self . clangdPath = clangdPath
56
+ self . clangdOptions = clangdOptions
51
57
super. init ( client: client)
52
58
}
59
+
60
+ func startClangdProcesss( ) throws {
61
+ let usToClangd : Pipe = Pipe ( )
62
+ let clangdToUs : Pipe = Pipe ( )
63
+
64
+ let connectionToClangd = JSONRPCConnection (
65
+ protocol: MessageRegistry . lspProtocol,
66
+ inFD: clangdToUs. fileHandleForReading,
67
+ outFD: usToClangd. fileHandleForWriting
68
+ )
69
+ self . clangd = connectionToClangd
70
+
71
+ connectionToClangd. start ( receiveHandler: self ) {
72
+ // FIXME: keep the pipes alive until we close the connection. This
73
+ // should be fixed systemically.
74
+ withExtendedLifetime ( ( usToClangd, clangdToUs) ) { }
75
+ }
76
+
77
+ let process = Foundation . Process ( )
78
+
79
+ if #available( OSX 10 . 13 , * ) {
80
+ process. executableURL = clangdPath. asURL
81
+ } else {
82
+ process. launchPath = clangdPath. pathString
83
+ }
84
+
85
+ process. arguments = [
86
+ " -compile_args_from=lsp " , // Provide compiler args programmatically.
87
+ " -background-index=false " , // Disable clangd indexing, we use the build
88
+ " -index=false " // system index store instead.
89
+ ] + clangdOptions
90
+
91
+ process. standardOutput = clangdToUs
92
+ process. standardInput = usToClangd
93
+ process. terminationHandler = { process in
94
+ log ( " clangd exited: \( process. terminationReason) \( process. terminationStatus) " )
95
+ connectionToClangd. close ( )
96
+ }
97
+
98
+ if #available( OSX 10 . 13 , * ) {
99
+ try process. run ( )
100
+ } else {
101
+ process. launch ( )
102
+ }
103
+ }
53
104
54
105
public override func _registerBuiltinHandlers( ) {
55
106
_register ( ClangLanguageServerShim . publishDiagnostics)
@@ -284,60 +335,21 @@ func makeJSONRPCClangServer(
284
335
toolchain: Toolchain ,
285
336
clangdOptions: [ String ]
286
337
) throws -> ToolchainLanguageServer {
287
- guard let clangd = toolchain. clangd else {
338
+ guard let clangdPath = toolchain. clangd else {
288
339
preconditionFailure ( " missing clang from toolchain \( toolchain. identifier) " )
289
340
}
290
341
291
- let usToClangd : Pipe = Pipe ( )
292
- let clangdToUs : Pipe = Pipe ( )
293
-
294
- let connection = JSONRPCConnection (
295
- protocol: MessageRegistry . lspProtocol,
296
- inFD: clangdToUs. fileHandleForReading,
297
- outFD: usToClangd. fileHandleForWriting
298
- )
299
-
300
342
let connectionToClient = LocalConnection ( )
301
-
343
+ connectionToClient. start ( handler: client)
344
+
302
345
let shim = try ClangLanguageServerShim (
303
346
client: connectionToClient,
304
- clangd: connection,
305
- clangPath: toolchain. clang)
306
-
307
- connectionToClient. start ( handler: client)
308
- connection. start ( receiveHandler: shim) {
309
- // FIXME: keep the pipes alive until we close the connection. This
310
- // should be fixed systemically.
311
- withExtendedLifetime ( ( usToClangd, clangdToUs) ) { }
312
- }
313
-
314
- let process = Foundation . Process ( )
315
-
316
- if #available( OSX 10 . 13 , * ) {
317
- process. executableURL = clangd. asURL
318
- } else {
319
- process. launchPath = clangd. pathString
320
- }
321
-
322
- process. arguments = [
323
- " -compile_args_from=lsp " , // Provide compiler args programmatically.
324
- " -background-index=false " , // Disable clangd indexing, we use the build
325
- " -index=false " // system index store instead.
326
- ] + clangdOptions
327
-
328
- process. standardOutput = clangdToUs
329
- process. standardInput = usToClangd
330
- process. terminationHandler = { process in
331
- log ( " clangd exited: \( process. terminationReason) \( process. terminationStatus) " )
332
- connection. close ( )
333
- }
334
-
335
- if #available( OSX 10 . 13 , * ) {
336
- try process. run ( )
337
- } else {
338
- process. launch ( )
339
- }
340
-
347
+ clangPath: toolchain. clang,
348
+ clangdPath: clangdPath,
349
+ clangdOptions: clangdOptions
350
+ )
351
+ try shim. startClangdProcesss ( )
352
+
341
353
return shim
342
354
}
343
355
0 commit comments