99 "regexp"
1010 "strconv"
1111 "strings"
12+ "sync"
1213 "time"
1314
1415 "github.com/arduino/arduino-cli/arduino/builder"
@@ -59,26 +60,30 @@ func NewInoHandler(stdio io.ReadWriteCloser, board lsp.Board) *InoHandler {
5960 if enableLogging {
6061 log .Println ("Initial board configuration:" , board )
6162 }
63+
64+ go handler .rebuildEnvironmentLoop ()
6265 return handler
6366}
6467
6568// InoHandler is a JSON-RPC handler that delegates messages to clangd.
6669type InoHandler struct {
67- StdioConn * jsonrpc2.Conn
68- ClangdConn * jsonrpc2.Conn
69- lspInitializeParams * lsp.InitializeParams
70- buildPath * paths.Path
71- buildSketchRoot * paths.Path
72- buildSketchCpp * paths.Path
73- buildSketchCppVersion int
74- buildSketchSymbols []lsp.DocumentSymbol
75- buildSketchSymbolsLoad bool
76- buildSketchSymbolsCheck bool
77- sketchRoot * paths.Path
78- sketchName string
79- sketchMapper * sourcemapper.InoMapper
80- sketchTrackedFilesCount int
81- trackedFiles map [lsp.DocumentURI ]* lsp.TextDocumentItem
70+ StdioConn * jsonrpc2.Conn
71+ ClangdConn * jsonrpc2.Conn
72+ lspInitializeParams * lsp.InitializeParams
73+ buildPath * paths.Path
74+ buildSketchRoot * paths.Path
75+ buildSketchCpp * paths.Path
76+ buildSketchCppVersion int
77+ buildSketchSymbols []lsp.DocumentSymbol
78+ buildSketchSymbolsLoad bool
79+ buildSketchSymbolsCheck bool
80+ rebuildSketchDeadline * time.Time
81+ rebuildSketchDeadlineMutex sync.Mutex
82+ sketchRoot * paths.Path
83+ sketchName string
84+ sketchMapper * sourcemapper.InoMapper
85+ sketchTrackedFilesCount int
86+ trackedFiles map [lsp.DocumentURI ]* lsp.TextDocumentItem
8287
8388 config lsp.BoardConfig
8489 synchronizer Synchronizer
@@ -324,13 +329,18 @@ func (handler *InoHandler) exit() {
324329}
325330
326331func (handler * InoHandler ) initializeWorkbench (params * lsp.InitializeParams ) error {
327- rootURI := params .RootURI
328- log .Printf ("--> initializeWorkbench(%s)\n " , rootURI )
332+ currCppTextVersion := 0
333+ if params != nil {
334+ log .Printf ("--> initialize(%s)\n " , params .RootURI )
335+ handler .lspInitializeParams = params
336+ handler .sketchRoot = params .RootURI .AsPath ()
337+ handler .sketchName = handler .sketchRoot .Base ()
338+ } else {
339+ currCppTextVersion = handler .sketchMapper .CppText .Version
340+ log .Printf ("--> RE-initialize()\n " )
341+ }
329342
330- handler .lspInitializeParams = params
331- handler .sketchRoot = rootURI .AsPath ()
332- handler .sketchName = handler .sketchRoot .Base ()
333- if buildPath , err := generateBuildEnvironment (handler .sketchRoot , handler .config .SelectedBoard .Fqbn ); err == nil {
343+ if buildPath , err := handler .generateBuildEnvironment (); err == nil {
334344 handler .buildPath = buildPath
335345 handler .buildSketchRoot = buildPath .Join ("sketch" )
336346 } else {
@@ -343,22 +353,48 @@ func (handler *InoHandler) initializeWorkbench(params *lsp.InitializeParams) err
343353
344354 if cppContent , err := handler .buildSketchCpp .ReadFile (); err == nil {
345355 handler .sketchMapper = sourcemapper .CreateInoMapper (cppContent )
356+ handler .sketchMapper .CppText .Version = currCppTextVersion + 1
346357 } else {
347358 return errors .WithMessage (err , "reading generated cpp file from sketch" )
348359 }
349360
350- clangdStdout , clangdStdin , clangdStderr := startClangd (handler .buildPath , handler .buildSketchCpp )
351- clangdStdio := streams .NewReadWriteCloser (clangdStdin , clangdStdout )
352- if enableLogging {
353- clangdStdio = streams .LogReadWriteCloserAs (clangdStdio , "inols-clangd.log" )
354- go io .Copy (streams .OpenLogFileAs ("inols-clangd-err.log" ), clangdStderr )
361+ if params == nil {
362+ // If we are restarting re-synchronize clangd
363+ ctx , cancel := context .WithTimeout (context .Background (), time .Second )
364+ defer cancel ()
365+
366+ cppURI := lsp .NewDocumenteURIFromPath (handler .buildSketchCpp )
367+ cppTextDocumentIdentifier := lsp.TextDocumentIdentifier {URI : cppURI }
368+
369+ syncEvent := & lsp.DidChangeTextDocumentParams {
370+ TextDocument : lsp.VersionedTextDocumentIdentifier {
371+ TextDocumentIdentifier : cppTextDocumentIdentifier ,
372+ Version : handler .sketchMapper .CppText .Version ,
373+ },
374+ ContentChanges : []lsp.TextDocumentContentChangeEvent {
375+ {Text : handler .sketchMapper .CppText .Text }, // Full text change
376+ },
377+ }
378+
379+ if err := handler .ClangdConn .Notify (ctx , "textDocument/didChange" , syncEvent ); err != nil {
380+ log .Println (" error reinitilizing clangd:" , err )
381+ return err
382+ }
355383 } else {
356- go io .Copy (os .Stderr , clangdStderr )
357- }
384+ // Otherwise start clangd!
385+ clangdStdout , clangdStdin , clangdStderr := startClangd (handler .buildPath , handler .buildSketchCpp )
386+ clangdStdio := streams .NewReadWriteCloser (clangdStdin , clangdStdout )
387+ if enableLogging {
388+ clangdStdio = streams .LogReadWriteCloserAs (clangdStdio , "inols-clangd.log" )
389+ go io .Copy (streams .OpenLogFileAs ("inols-clangd-err.log" ), clangdStderr )
390+ } else {
391+ go io .Copy (os .Stderr , clangdStderr )
392+ }
358393
359- clangdStream := jsonrpc2 .NewBufferedStream (clangdStdio , jsonrpc2.VSCodeObjectCodec {})
360- clangdHandler := jsonrpc2 .AsyncHandler (jsonrpc2 .HandlerWithError (handler .FromClangd ))
361- handler .ClangdConn = jsonrpc2 .NewConn (context .Background (), clangdStream , clangdHandler )
394+ clangdStream := jsonrpc2 .NewBufferedStream (clangdStdio , jsonrpc2.VSCodeObjectCodec {})
395+ clangdHandler := jsonrpc2 .AsyncHandler (jsonrpc2 .HandlerWithError (handler .FromClangd ))
396+ handler .ClangdConn = jsonrpc2 .NewConn (context .Background (), clangdStream , clangdHandler )
397+ }
362398
363399 return nil
364400}
@@ -483,6 +519,7 @@ func (handler *InoHandler) didChange(ctx context.Context, req *lsp.DidChangeText
483519 // and trigger arduino-preprocessing + clangd restart.
484520
485521 log .Println (" uh oh DIRTY CHANGE!" )
522+ handler .scheduleRebuildEnvironment ()
486523 }
487524
488525 // log.Println("New version:----------")
0 commit comments