@@ -11,6 +11,7 @@ import (
11
11
"strconv"
12
12
"strings"
13
13
"sync"
14
+ "sync/atomic"
14
15
"time"
15
16
16
17
"github.com/arduino/arduino-cli/arduino/builder"
@@ -43,6 +44,9 @@ type InoHandler struct {
43
44
StdioConn * jsonrpc2.Conn
44
45
ClangdConn * jsonrpc2.Conn
45
46
47
+ stdioNotificationCount int64
48
+ clangdNotificationCount int64
49
+
46
50
clangdStarted * sync.Cond
47
51
dataMux sync.RWMutex
48
52
lspInitializeParams * lsp.InitializeParams
@@ -105,12 +109,30 @@ func (handler *InoHandler) StopClangd() {
105
109
func (handler * InoHandler ) HandleMessageFromIDE (ctx context.Context , conn * jsonrpc2.Conn , req * jsonrpc2.Request ) (interface {}, error ) {
106
110
defer streams .CatchAndLogPanic ()
107
111
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
+
108
129
needsWriteLock := map [string ]bool {
109
130
"initialize" : true ,
110
131
"textDocument/didOpen" : true ,
111
132
"textDocument/didChange" : true ,
112
133
"textDocument/didClose" : true ,
113
134
}
135
+ log .Printf (prefix + "(queued)" )
114
136
if needsWriteLock [req .Method ] {
115
137
handler .dataMux .Lock ()
116
138
defer handler .dataMux .Unlock ()
@@ -125,44 +147,42 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
125
147
"initialized" : true ,
126
148
}
127
149
if handler .ClangdConn == nil && ! doNotNeedClangd [req .Method ] {
150
+ log .Printf (prefix + "(throttled: waiting for clangd)" )
128
151
handler .clangdStarted .Wait ()
129
152
if handler .ClangdConn == nil {
153
+ log .Printf ("Clangd startup failed: aborting call" )
130
154
return nil , errors .New ("could not run clangd, aborted" )
131
155
}
132
156
}
133
157
158
+ log .Printf (prefix + "(running)" )
159
+
134
160
// Handle LSP methods: transform parameters and send to clangd
135
161
var inoURI , cppURI lsp.DocumentURI
136
162
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
- }
144
163
switch p := params .(type ) {
145
164
case * lsp.InitializeParams :
146
165
// method "initialize"
147
166
err = handler .initializeWorkbench (p )
148
167
149
168
case * lsp.InitializedParams :
150
169
// 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
152
172
153
173
case * lsp.DidOpenTextDocumentParams :
154
174
// method "textDocument/didOpen"
155
175
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 )
157
177
158
178
if res , e := handler .didOpen (p ); e != nil {
159
179
params = nil
160
180
err = e
161
181
} else if res == nil {
162
- log .Println (" --X notification is not propagated to clangd" )
182
+ log .Println (prefix + " notification is not propagated to clangd" )
163
183
return nil , nil // do not propagate to clangd
164
184
} 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 )
166
186
params = res
167
187
}
168
188
@@ -329,38 +349,39 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
329
349
err = handler .ino2cppExecuteCommand (p )
330
350
}
331
351
if err != nil {
332
- log .Printf (" --E %s" , err )
352
+ log .Printf (prefix + "Error: %s" , err )
333
353
return nil , err
334
354
}
335
355
336
356
var result interface {}
337
357
if req .Notif {
358
+ log .Printf (prefix + "sent to Clang" )
338
359
err = handler .ClangdConn .Notify (ctx , req .Method , params )
339
- // log.Println(" sent", req.Method, "notification to clangd")
340
360
} else {
361
+ log .Printf (prefix + "sent to Clang" )
341
362
ctx , cancel := context .WithTimeout (ctx , 800 * time .Millisecond )
342
363
defer cancel ()
343
364
result , err = lsp .SendRequest (ctx , handler .ClangdConn , req .Method , params )
344
- // log.Println(" sent", req.Method, "request id", req.ID, " to clangd")
345
365
}
346
366
if err == nil && handler .buildSketchSymbolsLoad {
347
367
handler .buildSketchSymbolsLoad = false
348
- log .Println ("--! Resfreshing document symbols" )
368
+ log .Println (prefix + "Queued resfreshing document symbols" )
349
369
err = handler .refreshCppDocumentSymbols ()
350
370
}
351
371
if err == nil && handler .buildSketchSymbolsCheck {
352
372
handler .buildSketchSymbolsCheck = false
353
- log .Println ("--! Resfreshing document symbols" )
373
+ log .Println (prefix + "Queued check document symbols" )
354
374
err = handler .checkCppDocumentSymbols ()
355
375
}
356
376
if err != nil {
357
377
// Exit the process and trigger a restart by the client in case of a severe error
358
378
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." )
360
380
handler .exit ()
361
381
}
362
382
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 )
364
385
handler .exit ()
365
386
}
366
387
}
@@ -381,13 +402,13 @@ func (handler *InoHandler) exit() {
381
402
func (handler * InoHandler ) initializeWorkbench (params * lsp.InitializeParams ) error {
382
403
currCppTextVersion := 0
383
404
if params != nil {
384
- log .Printf ("--> initialize(%s)\n " , params .RootURI )
405
+ log .Printf (" --> initialize(%s)\n " , params .RootURI )
385
406
handler .lspInitializeParams = params
386
407
handler .sketchRoot = params .RootURI .AsPath ()
387
408
handler .sketchName = handler .sketchRoot .Base ()
388
409
} else {
410
+ log .Printf (" --> RE-initialize()\n " )
389
411
currCppTextVersion = handler .sketchMapper .CppText .Version
390
- log .Printf ("--> RE-initialize()\n " )
391
412
}
392
413
393
414
if buildPath , err := handler .generateBuildEnvironment (); err == nil {
@@ -450,18 +471,27 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
450
471
}
451
472
452
473
func (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
+
453
481
// Query source code symbols
454
482
cppURI := lsp .NewDocumentURIFromPath (handler .buildSketchCpp )
455
- log .Printf (" --> documentSymbol(%s)" , cppURI )
483
+ log .Printf (prefix + "sent to clangd: documentSymbol(%s)" , cppURI )
456
484
result , err := lsp .SendRequest (context .Background (), handler .ClangdConn , "textDocument/documentSymbol" , & lsp.DocumentSymbolParams {
457
485
TextDocument : lsp.TextDocumentIdentifier {URI : cppURI },
458
486
})
459
487
if err != nil {
488
+ log .Printf (prefix + "error: %s" , err )
460
489
return errors .WithMessage (err , "quering source code symbols" )
461
490
}
462
491
result = handler .transformClangdResult ("textDocument/documentSymbol" , cppURI , lsp .NilURI , result )
463
492
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" )
465
495
} else {
466
496
// Filter non-functions symbols
467
497
i := 0
@@ -474,26 +504,27 @@ func (handler *InoHandler) refreshCppDocumentSymbols() error {
474
504
}
475
505
symbols = symbols [:i ]
476
506
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 )
478
508
}
479
509
handler .buildSketchSymbols = symbols
480
510
}
481
511
return nil
482
512
}
483
513
484
514
func (handler * InoHandler ) checkCppDocumentSymbols () error {
515
+ prefix := "LS --- "
485
516
oldSymbols := handler .buildSketchSymbols
486
517
if err := handler .refreshCppDocumentSymbols (); err != nil {
487
518
return err
488
519
}
489
520
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!" )
491
522
handler .scheduleRebuildEnvironment ()
492
523
return nil
493
524
}
494
525
for i , old := range oldSymbols {
495
526
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 )
497
528
handler .scheduleRebuildEnvironment ()
498
529
return nil
499
530
}
@@ -1332,23 +1363,32 @@ func (handler *InoHandler) cpp2inoDiagnostics(cppDiags *lsp.PublishDiagnosticsPa
1332
1363
func (handler * InoHandler ) FromClangd (ctx context.Context , connection * jsonrpc2.Conn , req * jsonrpc2.Request ) (interface {}, error ) {
1333
1364
defer streams .CatchAndLogPanic ()
1334
1365
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)" )
1335
1376
handler .synchronizer .DataMux .RLock ()
1336
1377
defer handler .synchronizer .DataMux .RUnlock ()
1378
+ log .Printf (prefix + "(running)" )
1337
1379
1338
1380
params , err := lsp .ReadParams (req .Method , req .Params )
1339
1381
if err != nil {
1382
+ log .Println (prefix + "parsing clang message:" , err )
1340
1383
return nil , errors .WithMessage (err , "parsing JSON message from clangd" )
1341
1384
}
1342
- if params == nil {
1343
- // passthrough
1344
- params = req .Params
1345
- }
1385
+
1346
1386
switch p := params .(type ) {
1347
1387
case * lsp.PublishDiagnosticsParams :
1348
1388
// "textDocument/publishDiagnostics"
1349
- log .Printf (" <-- publishDiagnostics(%s):" , p .URI )
1389
+ log .Printf (prefix + " publishDiagnostics(%s):" , p .URI )
1350
1390
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 )
1352
1392
}
1353
1393
1354
1394
// the diagnostics on sketch.cpp.ino once mapped into their
@@ -1370,13 +1410,6 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1370
1410
continue
1371
1411
}
1372
1412
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
-
1380
1413
// If we have an "undefined reference" in the .ino code trigger a
1381
1414
// check for newly created symbols (that in turn may trigger a
1382
1415
// new arduino-preprocessing of the sketch).
@@ -1390,6 +1423,10 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1390
1423
}
1391
1424
}
1392
1425
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
+ }
1393
1430
if err := handler .StdioConn .Notify (ctx , "textDocument/publishDiagnostics" , inoDiag ); err != nil {
1394
1431
return nil , err
1395
1432
}
@@ -1407,9 +1444,7 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1407
1444
URI : lsp .NewDocumentURI (sourcePath ),
1408
1445
Diagnostics : []lsp.Diagnostic {},
1409
1446
}
1410
- if enableLogging {
1411
- log .Printf ("<-- publishDiagnostics(%s):" , msg .URI )
1412
- }
1447
+ log .Printf (prefix + "to IDE: publishDiagnostics(%s):" , msg .URI )
1413
1448
if err := handler .StdioConn .Notify (ctx , "textDocument/publishDiagnostics" , msg ); err != nil {
1414
1449
return nil , err
1415
1450
}
@@ -1423,22 +1458,24 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1423
1458
// "workspace/applyEdit"
1424
1459
p .Edit = * handler .cpp2inoWorkspaceEdit (& p .Edit )
1425
1460
}
1426
-
1427
1461
if err != nil {
1428
1462
log .Println ("From clangd: Method:" , req .Method , "Error:" , err )
1429
1463
return nil , err
1430
1464
}
1465
+
1466
+ if params == nil {
1467
+ // passthrough
1468
+ log .Printf (prefix + "passing through message" )
1469
+ params = req .Params
1470
+ }
1471
+
1431
1472
var result interface {}
1432
1473
if req .Notif {
1474
+ log .Println (prefix + "to IDE" )
1433
1475
err = handler .StdioConn .Notify (ctx , req .Method , params )
1434
- if enableLogging {
1435
- log .Println ("From clangd:" , req .Method )
1436
- }
1437
1476
} else {
1477
+ log .Println (prefix + "to IDE" )
1438
1478
result , err = lsp .SendRequest (ctx , handler .StdioConn , req .Method , params )
1439
- if enableLogging {
1440
- log .Println ("From clangd:" , req .Method , "id" , req .ID )
1441
- }
1442
1479
}
1443
1480
return result , err
1444
1481
}
0 commit comments