Skip to content

Commit 0ce1169

Browse files
committed
detach clangd initialization from arduino LS initialization
1 parent d7969be commit 0ce1169

File tree

2 files changed

+101
-27
lines changed

2 files changed

+101
-27
lines changed

Diff for: handler/handler.go

+100-26
Original file line numberDiff line numberDiff line change
@@ -126,32 +126,38 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
126126
params = req.Params
127127
}
128128

129-
needsWriteLock := map[string]bool{
130-
"initialize": true,
131-
"textDocument/didOpen": true,
132-
"textDocument/didChange": true,
133-
"textDocument/didClose": true,
134-
}
135129
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":
137136
handler.dataMux.Lock()
138137
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
140144
handler.dataMux.RLock()
141145
defer handler.dataMux.RUnlock()
142146
}
143147

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
152154
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+
}
155161
}
156162
}
157163

@@ -163,7 +169,51 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
163169
switch p := params.(type) {
164170
case *lsp.InitializeParams:
165171
// 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
167217

168218
case *lsp.InitializedParams:
169219
// method "initialized"
@@ -366,12 +416,12 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr
366416
if err == nil && handler.buildSketchSymbolsLoad {
367417
handler.buildSketchSymbolsLoad = false
368418
log.Println(prefix + "Queued resfreshing document symbols")
369-
err = handler.refreshCppDocumentSymbols()
419+
go handler.refreshCppDocumentSymbols()
370420
}
371421
if err == nil && handler.buildSketchSymbolsCheck {
372422
handler.buildSketchSymbolsCheck = false
373423
log.Println(prefix + "Queued check document symbols")
374-
err = handler.checkCppDocumentSymbols()
424+
go handler.checkCppDocumentSymbols()
375425
}
376426
if err != nil {
377427
// 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
431481

432482
if params == nil {
433483
// If we are restarting re-synchronize clangd
434-
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
435-
defer cancel()
436-
437484
cppURI := lsp.NewDocumentURIFromPath(handler.buildSketchCpp)
438485
cppTextDocumentIdentifier := lsp.TextDocumentIdentifier{URI: cppURI}
439486

@@ -447,6 +494,8 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
447494
},
448495
}
449496

497+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
498+
defer cancel()
450499
if err := handler.ClangdConn.Notify(ctx, "textDocument/didChange", syncEvent); err != nil {
451500
log.Println(" error reinitilizing clangd:", err)
452501
return err
@@ -465,6 +514,20 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
465514
clangdStream := jsonrpc2.NewBufferedStream(clangdStdio, jsonrpc2.VSCodeObjectCodec{})
466515
clangdHandler := jsonrpc2.AsyncHandler(jsonrpc2.HandlerWithError(handler.FromClangd))
467516
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+
}
468531
}
469532

470533
return nil
@@ -1373,8 +1436,19 @@ func (handler *InoHandler) FromClangd(ctx context.Context, connection *jsonrpc2.
13731436
defer log.Printf(prefix + "(done)")
13741437

13751438
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+
}
13781452
log.Printf(prefix + "(running)")
13791453

13801454
params, err := lsp.ReadParams(req.Method, req.Params)

Diff for: lsp/service.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ const (
221221
// support JSON-(un)marshaling both).
222222
type TextDocumentSyncKind int
223223

224-
const (
224+
var (
225225
TDSKNone TextDocumentSyncKind = 0
226226
TDSKFull TextDocumentSyncKind = 1
227227
TDSKIncremental TextDocumentSyncKind = 2

0 commit comments

Comments
 (0)