@@ -126,32 +126,38 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
126
126
params = req .Params
127
127
}
128
128
129
- needsWriteLock := map [string ]bool {
130
- "initialize" : true ,
131
- "textDocument/didOpen" : true ,
132
- "textDocument/didChange" : true ,
133
- "textDocument/didClose" : true ,
134
- }
135
129
log .Printf (prefix + "(queued)" )
136
- if needsWriteLock [req .Method ] {
130
+ switch req .Method {
131
+ case // Write lock
132
+ "initialize" ,
133
+ "textDocument/didOpen" ,
134
+ "textDocument/didChange" ,
135
+ "textDocument/didClose" :
137
136
handler .dataMux .Lock ()
138
137
defer handler .dataMux .Unlock ()
139
- } else {
138
+ case // Read lock
139
+ "textDocument/publishDiagnostics" ,
140
+ "workspace/applyEdit" :
141
+ handler .dataMux .RLock ()
142
+ defer handler .dataMux .RUnlock ()
143
+ default : // Default to read lock
140
144
handler .dataMux .RLock ()
141
145
defer handler .dataMux .RUnlock ()
142
146
}
143
147
144
- // Wait for clangd start-up
145
- doNotNeedClangd := map [string ]bool {
146
- "initialize" : true ,
147
- "initialized" : true ,
148
- }
149
- if handler .ClangdConn == nil && ! doNotNeedClangd [req .Method ] {
150
- log .Printf (prefix + "(throttled: waiting for clangd)" )
151
- handler .clangdStarted .Wait ()
148
+ switch req .Method {
149
+ case // Do not need clangd
150
+ "initialize" ,
151
+ "initialized" :
152
+ default : // Default to clangd required
153
+ // Wait for clangd start-up
152
154
if handler .ClangdConn == nil {
153
- log .Printf ("Clangd startup failed: aborting call" )
154
- return nil , errors .New ("could not run clangd, aborted" )
155
+ log .Printf (prefix + "(throttled: waiting for clangd)" )
156
+ handler .clangdStarted .Wait ()
157
+ if handler .ClangdConn == nil {
158
+ log .Printf (prefix + "clangd startup failed: aborting call" )
159
+ return nil , errors .New ("could not start clangd, aborted" )
160
+ }
155
161
}
156
162
}
157
163
@@ -163,7 +169,51 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
163
169
switch p := params .(type ) {
164
170
case * lsp.InitializeParams :
165
171
// method "initialize"
166
- err = handler .initializeWorkbench (p )
172
+
173
+ go func () {
174
+ // Start clangd asynchronously
175
+ log .Printf ("LS --- initializing workbench (queued)" )
176
+ handler .dataMux .Lock ()
177
+ defer handler .dataMux .Unlock ()
178
+
179
+ log .Printf ("LS --- initializing workbench (running)" )
180
+ handler .initializeWorkbench (p )
181
+
182
+ // clangd should be running now...
183
+ handler .clangdStarted .Broadcast ()
184
+
185
+ log .Printf ("LS --- initializing workbench (done)" )
186
+ }()
187
+
188
+ T := true
189
+ F := false
190
+ return & lsp.InitializeResult {
191
+ Capabilities : lsp.ServerCapabilities {
192
+ TextDocumentSync : & lsp.TextDocumentSyncOptionsOrKind {Kind : & lsp .TDSKIncremental },
193
+ HoverProvider : true ,
194
+ CompletionProvider : & lsp.CompletionOptions {
195
+ TriggerCharacters : []string {"." , "\u003e " , ":" },
196
+ },
197
+ SignatureHelpProvider : & lsp.SignatureHelpOptions {
198
+ TriggerCharacters : []string {"(" , "," },
199
+ },
200
+ DefinitionProvider : true ,
201
+ ReferencesProvider : false , // TODO: true
202
+ DocumentHighlightProvider : true ,
203
+ DocumentSymbolProvider : true ,
204
+ WorkspaceSymbolProvider : true ,
205
+ CodeActionProvider : & lsp.BoolOrCodeActionOptions {IsProvider : & T },
206
+ DocumentFormattingProvider : true ,
207
+ DocumentRangeFormattingProvider : true ,
208
+ DocumentOnTypeFormattingProvider : & lsp.DocumentOnTypeFormattingOptions {
209
+ FirstTriggerCharacter : "\n " ,
210
+ },
211
+ RenameProvider : & lsp.BoolOrRenameOptions {IsProvider : & F }, // TODO: &T
212
+ ExecuteCommandProvider : & lsp.ExecuteCommandOptions {
213
+ Commands : []string {"clangd.applyFix" , "clangd.applyTweak" },
214
+ },
215
+ },
216
+ }, nil
167
217
168
218
case * lsp.InitializedParams :
169
219
// method "initialized"
@@ -366,12 +416,12 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
366
416
if err == nil && handler .buildSketchSymbolsLoad {
367
417
handler .buildSketchSymbolsLoad = false
368
418
log .Println (prefix + "Queued resfreshing document symbols" )
369
- err = handler .refreshCppDocumentSymbols ()
419
+ go handler .refreshCppDocumentSymbols ()
370
420
}
371
421
if err == nil && handler .buildSketchSymbolsCheck {
372
422
handler .buildSketchSymbolsCheck = false
373
423
log .Println (prefix + "Queued check document symbols" )
374
- err = handler .checkCppDocumentSymbols ()
424
+ go handler .checkCppDocumentSymbols ()
375
425
}
376
426
if err != nil {
377
427
// Exit the process and trigger a restart by the client in case of a severe error
@@ -431,9 +481,6 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
431
481
432
482
if params == nil {
433
483
// If we are restarting re-synchronize clangd
434
- ctx , cancel := context .WithTimeout (context .Background (), time .Second )
435
- defer cancel ()
436
-
437
484
cppURI := lsp .NewDocumentURIFromPath (handler .buildSketchCpp )
438
485
cppTextDocumentIdentifier := lsp.TextDocumentIdentifier {URI : cppURI }
439
486
@@ -447,6 +494,8 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
447
494
},
448
495
}
449
496
497
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second )
498
+ defer cancel ()
450
499
if err := handler .ClangdConn .Notify (ctx , "textDocument/didChange" , syncEvent ); err != nil {
451
500
log .Println (" error reinitilizing clangd:" , err )
452
501
return err
@@ -465,6 +514,20 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
465
514
clangdStream := jsonrpc2 .NewBufferedStream (clangdStdio , jsonrpc2.VSCodeObjectCodec {})
466
515
clangdHandler := jsonrpc2 .AsyncHandler (jsonrpc2 .HandlerWithError (handler .FromClangd ))
467
516
handler .ClangdConn = jsonrpc2 .NewConn (context .Background (), clangdStream , clangdHandler )
517
+
518
+ // Send initialization command to clangd
519
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second )
520
+ defer cancel ()
521
+ var resp lsp.InitializeResult
522
+ if err := handler .ClangdConn .Call (ctx , "initialize" , handler .lspInitializeParams , & resp ); err != nil {
523
+ log .Println (" error initilizing clangd:" , err )
524
+ return err
525
+ }
526
+
527
+ if err := handler .ClangdConn .Notify (ctx , "initialized" , lsp.InitializedParams {}); err != nil {
528
+ log .Println (" error sending initialize to clangd:" , err )
529
+ return err
530
+ }
468
531
}
469
532
470
533
return nil
@@ -1373,8 +1436,19 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
1373
1436
defer log .Printf (prefix + "(done)" )
1374
1437
1375
1438
log .Printf (prefix + "(queued)" )
1376
- handler .synchronizer .DataMux .RLock ()
1377
- defer handler .synchronizer .DataMux .RUnlock ()
1439
+ switch req .Method {
1440
+ case // No locking required
1441
+ "$/progress" ,
1442
+ "window/workDoneProgress/create" :
1443
+ case // Read lock
1444
+ "textDocument/publishDiagnostics" ,
1445
+ "workspace/applyEdit" :
1446
+ handler .dataMux .RLock ()
1447
+ defer handler .dataMux .RUnlock ()
1448
+ default : // Default to read lock
1449
+ handler .dataMux .RLock ()
1450
+ defer handler .dataMux .RUnlock ()
1451
+ }
1378
1452
log .Printf (prefix + "(running)" )
1379
1453
1380
1454
params , err := lsp .ReadParams (req .Method , req .Params )
0 commit comments