@@ -11,6 +11,7 @@ import (
1111 "strconv"
1212 "strings"
1313 "sync"
14+ "sync/atomic"
1415 "time"
1516
1617 "github.com/arduino/arduino-cli/arduino/builder"
@@ -43,6 +44,9 @@ type InoHandler struct {
4344 StdioConn * jsonrpc2.Conn
4445 ClangdConn * jsonrpc2.Conn
4546
47+ stdioNotificationCount int64
48+ clangdNotificationCount int64
49+
4650 clangdStarted * sync.Cond
4751 dataMux sync.RWMutex
4852 lspInitializeParams * lsp.InitializeParams
@@ -105,12 +109,30 @@ func (handler *InoHandler) StopClangd() {
105109func (handler * InoHandler ) HandleMessageFromIDE (ctx context.Context , conn * jsonrpc2.Conn , req * jsonrpc2.Request ) (interface {}, error ) {
106110 defer streams .CatchAndLogPanic ()
107111
112+ prefix := "IDE --> "
113+ if req .Notif {
114+ n := atomic .AddInt64 (& handler .stdioNotificationCount , 1 )
115+ prefix += fmt .Sprintf ("%s notif%d " , req .Method , n )
116+ } else {
117+ prefix += fmt .Sprintf ("%s %v " , req .Method , req .ID )
118+ }
119+ defer log .Printf (prefix + "(done)" )
120+
121+ params , err := lsp .ReadParams (req .Method , req .Params )
122+ if err != nil {
123+ return nil , err
124+ }
125+ if params == nil {
126+ params = req .Params
127+ }
128+
108129 needsWriteLock := map [string ]bool {
109130 "initialize" : true ,
110131 "textDocument/didOpen" : true ,
111132 "textDocument/didChange" : true ,
112133 "textDocument/didClose" : true ,
113134 }
135+ log .Printf (prefix + "(queued)" )
114136 if needsWriteLock [req .Method ] {
115137 handler .dataMux .Lock ()
116138 defer handler .dataMux .Unlock ()
@@ -125,44 +147,42 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
125147 "initialized" : true ,
126148 }
127149 if handler .ClangdConn == nil && ! doNotNeedClangd [req .Method ] {
150+ log .Printf (prefix + "(throttled: waiting for clangd)" )
128151 handler .clangdStarted .Wait ()
129152 if handler .ClangdConn == nil {
153+ log .Printf ("Clangd startup failed: aborting call" )
130154 return nil , errors .New ("could not run clangd, aborted" )
131155 }
132156 }
133157
158+ log .Printf (prefix + "(running)" )
159+
134160 // Handle LSP methods: transform parameters and send to clangd
135161 var inoURI , cppURI lsp.DocumentURI
136162
137- params , err := lsp .ReadParams (req .Method , req .Params )
138- if err != nil {
139- return nil , err
140- }
141- if params == nil {
142- params = req .Params
143- }
144163 switch p := params .(type ) {
145164 case * lsp.InitializeParams :
146165 // method "initialize"
147166 err = handler .initializeWorkbench (p )
148167
149168 case * lsp.InitializedParams :
150169 // method "initialized"
151- log .Println ("--> initialized" )
170+ log .Println (prefix + "notification is not propagated to clangd" )
171+ return nil , nil // Do not propagate to clangd
152172
153173 case * lsp.DidOpenTextDocumentParams :
154174 // method "textDocument/didOpen"
155175 inoURI = p .TextDocument .URI
156- log .Printf ("--> didOpen (%s@%d as '%s')" , p .TextDocument .URI , p .TextDocument .Version , p .TextDocument .LanguageID )
176+ log .Printf (prefix + " (%s@%d as '%s')" , p .TextDocument .URI , p .TextDocument .Version , p .TextDocument .LanguageID )
157177
158178 if res , e := handler .didOpen (p ); e != nil {
159179 params = nil
160180 err = e
161181 } else if res == nil {
162- log .Println (" --X notification is not propagated to clangd" )
182+ log .Println (prefix + " notification is not propagated to clangd" )
163183 return nil , nil // do not propagate to clangd
164184 } else {
165- log .Printf (" --> didOpen(%s@%d as '%s')" , res .TextDocument .URI , res .TextDocument .Version , p .TextDocument .LanguageID )
185+ log .Printf (prefix + "to clang: didOpen(%s@%d as '%s')" , res .TextDocument .URI , res .TextDocument .Version , p .TextDocument .LanguageID )
166186 params = res
167187 }
168188
@@ -329,38 +349,39 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
329349 err = handler .ino2cppExecuteCommand (p )
330350 }
331351 if err != nil {
332- log .Printf (" --E %s" , err )
352+ log .Printf (prefix + "Error: %s" , err )
333353 return nil , err
334354 }
335355
336356 var result interface {}
337357 if req .Notif {
358+ log .Printf (prefix + "sent to Clang" )
338359 err = handler .ClangdConn .Notify (ctx , req .Method , params )
339- // log.Println(" sent", req.Method, "notification to clangd")
340360 } else {
361+ log .Printf (prefix + "sent to Clang" )
341362 ctx , cancel := context .WithTimeout (ctx , 800 * time .Millisecond )
342363 defer cancel ()
343364 result , err = lsp .SendRequest (ctx , handler .ClangdConn , req .Method , params )
344- // log.Println(" sent", req.Method, "request id", req.ID, " to clangd")
345365 }
346366 if err == nil && handler .buildSketchSymbolsLoad {
347367 handler .buildSketchSymbolsLoad = false
348- log .Println ("--! Resfreshing document symbols" )
368+ log .Println (prefix + "Queued resfreshing document symbols" )
349369 err = handler .refreshCppDocumentSymbols ()
350370 }
351371 if err == nil && handler .buildSketchSymbolsCheck {
352372 handler .buildSketchSymbolsCheck = false
353- log .Println ("--! Resfreshing document symbols" )
373+ log .Println (prefix + "Queued check document symbols" )
354374 err = handler .checkCppDocumentSymbols ()
355375 }
356376 if err != nil {
357377 // Exit the process and trigger a restart by the client in case of a severe error
358378 if err .Error () == "context deadline exceeded" {
359- log .Println ("Timeout exceeded while waiting for a reply from clangd." )
379+ log .Println (prefix + "Timeout exceeded while waiting for a reply from clangd." )
360380 handler .exit ()
361381 }
362382 if strings .Contains (err .Error (), "non-added document" ) || strings .Contains (err .Error (), "non-added file" ) {
363- log .Println ("The clangd process has lost track of the open document." )
383+ log .Printf (prefix + "The clangd process has lost track of the open document." )
384+ log .Printf (prefix + " %s" , err )
364385 handler .exit ()
365386 }
366387 }
@@ -381,13 +402,13 @@ func (handler *InoHandler) exit() {
381402func (handler * InoHandler ) initializeWorkbench (params * lsp.InitializeParams ) error {
382403 currCppTextVersion := 0
383404 if params != nil {
384- log .Printf ("--> initialize(%s)\n " , params .RootURI )
405+ log .Printf (" --> initialize(%s)\n " , params .RootURI )
385406 handler .lspInitializeParams = params
386407 handler .sketchRoot = params .RootURI .AsPath ()
387408 handler .sketchName = handler .sketchRoot .Base ()
388409 } else {
410+ log .Printf (" --> RE-initialize()\n " )
389411 currCppTextVersion = handler .sketchMapper .CppText .Version
390- log .Printf ("--> RE-initialize()\n " )
391412 }
392413
393414 if buildPath , err := handler .generateBuildEnvironment (); err == nil {
@@ -450,18 +471,27 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
450471}
451472
452473func (handler * InoHandler ) refreshCppDocumentSymbols () error {
474+ prefix := "LS --- "
475+ defer log .Printf (prefix + "(done)" )
476+ log .Printf (prefix + "(queued)" )
477+ handler .dataMux .Lock ()
478+ defer handler .dataMux .Unlock ()
479+ log .Printf (prefix + "(running)" )
480+
453481 // Query source code symbols
454482 cppURI := lsp .NewDocumentURIFromPath (handler .buildSketchCpp )
455- log .Printf (" --> documentSymbol(%s)" , cppURI )
483+ log .Printf (prefix + "sent to clangd: documentSymbol(%s)" , cppURI )
456484 result , err := lsp .SendRequest (context .Background (), handler .ClangdConn , "textDocument/documentSymbol" , & lsp.DocumentSymbolParams {
457485 TextDocument : lsp.TextDocumentIdentifier {URI : cppURI },
458486 })
459487 if err != nil {
488+ log .Printf (prefix + "error: %s" , err )
460489 return errors .WithMessage (err , "quering source code symbols" )
461490 }
462491 result = handler .transformClangdResult ("textDocument/documentSymbol" , cppURI , lsp .NilURI , result )
463492 if symbols , ok := result .([]lsp.DocumentSymbol ); ! ok {
464- return errors .WithMessage (err , "quering source code symbols (2)" )
493+ log .Printf (prefix + "error: invalid response from clangd" )
494+ return errors .New ("invalid response from clangd" )
465495 } else {
466496 // Filter non-functions symbols
467497 i := 0
@@ -474,26 +504,27 @@ func (handler *InoHandler) refreshCppDocumentSymbols() error {
474504 }
475505 symbols = symbols [:i ]
476506 for _ , symbol := range symbols {
477- log .Printf (" symbol: %s %s" , symbol .Kind , symbol .Name )
507+ log .Printf (prefix + " symbol: %s %s" , symbol .Kind , symbol .Name )
478508 }
479509 handler .buildSketchSymbols = symbols
480510 }
481511 return nil
482512}
483513
484514func (handler * InoHandler ) checkCppDocumentSymbols () error {
515+ prefix := "LS --- "
485516 oldSymbols := handler .buildSketchSymbols
486517 if err := handler .refreshCppDocumentSymbols (); err != nil {
487518 return err
488519 }
489520 if len (oldSymbols ) != len (handler .buildSketchSymbols ) {
490- log .Println ("--! new symbols detected, triggering sketch rebuild!" )
521+ log .Println (prefix + " new symbols detected, triggering sketch rebuild!" )
491522 handler .scheduleRebuildEnvironment ()
492523 return nil
493524 }
494525 for i , old := range oldSymbols {
495526 if newName := handler .buildSketchSymbols [i ].Name ; old .Name != newName {
496- log .Printf ("--! symbols changed, triggering sketch rebuild: '%s' -> '%s'" , old .Name , newName )
527+ log .Printf (prefix + " symbols changed, triggering sketch rebuild: '%s' -> '%s'" , old .Name , newName )
497528 handler .scheduleRebuildEnvironment ()
498529 return nil
499530 }
@@ -1332,23 +1363,32 @@ func (handler *InoHandler) cpp2inoDiagnostics(cppDiags *lsp.PublishDiagnosticsPa
13321363func (handler * InoHandler ) FromClangd (ctx context.Context , connection * jsonrpc2.Conn , req * jsonrpc2.Request ) (interface {}, error ) {
13331364 defer streams .CatchAndLogPanic ()
13341365
1366+ prefix := "CLG <-- "
1367+ if req .Notif {
1368+ n := atomic .AddInt64 (& handler .clangdNotificationCount , 1 )
1369+ prefix += fmt .Sprintf ("%s notif%d " , req .Method , n )
1370+ } else {
1371+ prefix += fmt .Sprintf ("%s %v " , req .Method , req .ID )
1372+ }
1373+ defer log .Printf (prefix + "(done)" )
1374+
1375+ log .Printf (prefix + "(queued)" )
13351376 handler .synchronizer .DataMux .RLock ()
13361377 defer handler .synchronizer .DataMux .RUnlock ()
1378+ log .Printf (prefix + "(running)" )
13371379
13381380 params , err := lsp .ReadParams (req .Method , req .Params )
13391381 if err != nil {
1382+ log .Println (prefix + "parsing clang message:" , err )
13401383 return nil , errors .WithMessage (err , "parsing JSON message from clangd" )
13411384 }
1342- if params == nil {
1343- // passthrough
1344- params = req .Params
1345- }
1385+
13461386 switch p := params .(type ) {
13471387 case * lsp.PublishDiagnosticsParams :
13481388 // "textDocument/publishDiagnostics"
1349- log .Printf (" <-- publishDiagnostics(%s):" , p .URI )
1389+ log .Printf (prefix + " publishDiagnostics(%s):" , p .URI )
13501390 for _ , diag := range p .Diagnostics {
1351- log .Printf (" > %d:%d - %v: %s" , diag .Range .Start .Line , diag .Range .Start .Character , diag .Severity , diag .Code )
1391+ log .Printf (prefix + " > %d:%d - %v: %s" , diag .Range .Start .Line , diag .Range .Start .Character , diag .Severity , diag .Code )
13521392 }
13531393
13541394 // the diagnostics on sketch.cpp.ino once mapped into their
@@ -1370,13 +1410,6 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
13701410 continue
13711411 }
13721412
1373- if enableLogging {
1374- log .Printf ("<-- publishDiagnostics(%s):" , inoDiag .URI )
1375- for _ , diag := range inoDiag .Diagnostics {
1376- log .Printf (" > %d:%d - %v: %s" , diag .Range .Start .Line , diag .Range .Start .Character , diag .Severity , diag .Code )
1377- }
1378- }
1379-
13801413 // If we have an "undefined reference" in the .ino code trigger a
13811414 // check for newly created symbols (that in turn may trigger a
13821415 // new arduino-preprocessing of the sketch).
@@ -1390,6 +1423,10 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
13901423 }
13911424 }
13921425
1426+ log .Printf (prefix + "to IDE: publishDiagnostics(%s):" , inoDiag .URI )
1427+ for _ , diag := range inoDiag .Diagnostics {
1428+ log .Printf (prefix + "> %d:%d - %v: %s" , diag .Range .Start .Line , diag .Range .Start .Character , diag .Severity , diag .Code )
1429+ }
13931430 if err := handler .StdioConn .Notify (ctx , "textDocument/publishDiagnostics" , inoDiag ); err != nil {
13941431 return nil , err
13951432 }
@@ -1407,9 +1444,7 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
14071444 URI : lsp .NewDocumentURI (sourcePath ),
14081445 Diagnostics : []lsp.Diagnostic {},
14091446 }
1410- if enableLogging {
1411- log .Printf ("<-- publishDiagnostics(%s):" , msg .URI )
1412- }
1447+ log .Printf (prefix + "to IDE: publishDiagnostics(%s):" , msg .URI )
14131448 if err := handler .StdioConn .Notify (ctx , "textDocument/publishDiagnostics" , msg ); err != nil {
14141449 return nil , err
14151450 }
@@ -1423,22 +1458,24 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
14231458 // "workspace/applyEdit"
14241459 p .Edit = * handler .cpp2inoWorkspaceEdit (& p .Edit )
14251460 }
1426-
14271461 if err != nil {
14281462 log .Println ("From clangd: Method:" , req .Method , "Error:" , err )
14291463 return nil , err
14301464 }
1465+
1466+ if params == nil {
1467+ // passthrough
1468+ log .Printf (prefix + "passing through message" )
1469+ params = req .Params
1470+ }
1471+
14311472 var result interface {}
14321473 if req .Notif {
1474+ log .Println (prefix + "to IDE" )
14331475 err = handler .StdioConn .Notify (ctx , req .Method , params )
1434- if enableLogging {
1435- log .Println ("From clangd:" , req .Method )
1436- }
14371476 } else {
1477+ log .Println (prefix + "to IDE" )
14381478 result , err = lsp .SendRequest (ctx , handler .StdioConn , req .Method , params )
1439- if enableLogging {
1440- log .Println ("From clangd:" , req .Method , "id" , req .ID )
1441- }
14421479 }
14431480 return result , err
14441481}
0 commit comments