@@ -32,6 +32,27 @@ extension NSLock {
32
32
}
33
33
}
34
34
35
+ /// Gathers data from clangd's stderr pipe. When it has accumulated a full line, writes the the line to the logger.
36
+ fileprivate class ClangdStderrLogForwarder {
37
+ private var buffer = Data ( )
38
+
39
+ func handle( _ newData: Data ) {
40
+ self . buffer += newData
41
+ if newData. contains ( UInt8 ( ascii: " \n " ) ) {
42
+ self . flushBuffer ( )
43
+ }
44
+ }
45
+
46
+ private func flushBuffer( ) {
47
+ guard let newlineIndex = self . buffer. firstIndex ( of: UInt8 ( ascii: " \n " ) ) else {
48
+ return
49
+ }
50
+ let logger = Logger ( subsystem: subsystem, category: " clangd-stderr " )
51
+ logger. info ( " \( String ( data: self . buffer [ ... newlineIndex] , encoding: . utf8) ?? " <invalid UTF-8> " ) " )
52
+ buffer = buffer [ buffer. index ( after: newlineIndex) ... ]
53
+ }
54
+ }
55
+
35
56
/// A thin wrapper over a connection to a clangd server providing build setting handling.
36
57
///
37
58
/// In addition, it also intercepts notifications and replies from clangd in order to do things
@@ -203,6 +224,17 @@ actor ClangLanguageServerShim: ToolchainLanguageServer, MessageHandler {
203
224
204
225
process. standardOutput = clangdToUs
205
226
process. standardInput = usToClangd
227
+ let logForwarder = ClangdStderrLogForwarder ( )
228
+ let stderrHandler = Pipe ( )
229
+ stderrHandler. fileHandleForReading. readabilityHandler = { fileHandle in
230
+ let newData = fileHandle. readData ( ofLength: 1 )
231
+ if newData. count == 0 {
232
+ stderrHandler. fileHandleForReading. readabilityHandler = nil
233
+ } else {
234
+ logForwarder. handle ( newData)
235
+ }
236
+ }
237
+ process. standardError = stderrHandler
206
238
process. terminationHandler = { [ weak self] process in
207
239
logger. log (
208
240
level: process. terminationReason == . exit ? . default : . error,
0 commit comments