Skip to content

Commit f794220

Browse files
committed
Language server now skips libraries detection while editing
A full build is made only at language server startup. Other full builds are performed by the IDE and build_path should be passed to the LS with a custom command "ino/didCompleteBuild". Co-authored-by: [email protected]
1 parent 27011c9 commit f794220

File tree

3 files changed

+68
-13
lines changed

3 files changed

+68
-13
lines changed

Diff for: ls/builder.go

+22-12
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (r *SketchRebuilder) rebuilderLoop() {
9292
r.cancel = cancel
9393
r.mutex.Unlock()
9494

95-
if err := r.doRebuild(ctx, logger); err != nil {
95+
if err := r.doRebuildArduinoPreprocessedSketch(ctx, logger); err != nil {
9696
logger.Logf("Error: %s", err)
9797
}
9898

@@ -104,10 +104,9 @@ func (r *SketchRebuilder) rebuilderLoop() {
104104
}
105105
}
106106

107-
func (r *SketchRebuilder) doRebuild(ctx context.Context, logger jsonrpc.FunctionLogger) error {
107+
func (r *SketchRebuilder) doRebuildArduinoPreprocessedSketch(ctx context.Context, logger jsonrpc.FunctionLogger) error {
108108
ls := r.ls
109-
110-
if success, err := ls.generateBuildEnvironment(ctx, logger); err != nil {
109+
if success, err := ls.generateBuildEnvironment(ctx, false, logger); err != nil {
111110
return err
112111
} else if !success {
113112
return fmt.Errorf("build failed")
@@ -123,10 +122,6 @@ func (r *SketchRebuilder) doRebuild(ctx context.Context, logger jsonrpc.Function
123122
default:
124123
}
125124

126-
if err := ls.buildPath.Join("compile_commands.json").CopyTo(ls.compileCommandsDir.Join("compile_commands.json")); err != nil {
127-
logger.Logf("ERROR: updating compile_commands: %s", err)
128-
}
129-
130125
if cppContent, err := ls.buildSketchCpp.ReadFile(); err == nil {
131126
oldVersion := ls.sketchMapper.CppText.Version
132127
ls.sketchMapper = sourcemapper.CreateInoMapper(cppContent)
@@ -166,11 +161,17 @@ func (r *SketchRebuilder) doRebuild(ctx context.Context, logger jsonrpc.Function
166161
return nil
167162
}
168163

169-
func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, logger jsonrpc.FunctionLogger) (bool, error) {
164+
func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, fullBuild bool, logger jsonrpc.FunctionLogger) (bool, error) {
165+
var buildPath *paths.Path
166+
if fullBuild {
167+
buildPath = ls.fullBuildPath
168+
} else {
169+
buildPath = ls.buildPath
170+
}
171+
170172
// Extract all build information from language server status
171173
ls.readLock(logger, false)
172174
sketchRoot := ls.sketchRoot
173-
buildPath := ls.buildPath
174175
config := ls.config
175176
type overridesFile struct {
176177
Overrides map[string]string `json:"overrides"`
@@ -204,6 +205,7 @@ func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, logge
204205
BuildPath: buildPath.String(),
205206
CreateCompilationDatabaseOnly: true,
206207
Verbose: true,
208+
SkipLibrariesDiscovery: !fullBuild,
207209
}
208210
compileReqJson, _ := json.MarshalIndent(compileReq, "", " ")
209211
logger.Logf("Running build with: %s", string(compileReqJson))
@@ -264,9 +266,12 @@ func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, logge
264266
"--source-override", overridesJSON.String(),
265267
"--build-path", buildPath.String(),
266268
"--format", "json",
267-
//"--clean",
268-
sketchRoot.String(),
269269
}
270+
if !fullBuild {
271+
args = append(args, "--skip-libraries-discovery")
272+
}
273+
args = append(args, sketchRoot.String())
274+
270275
cmd, err := executils.NewProcess(nil, args...)
271276
if err != nil {
272277
return false, errors.Errorf("running %s: %s", strings.Join(args, " "), err)
@@ -298,6 +303,11 @@ func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, logge
298303
success = res.Success
299304
}
300305

306+
if fullBuild {
307+
ls.CopyFullBuildResults(logger, buildPath)
308+
return ls.generateBuildEnvironment(ctx, false, logger)
309+
}
310+
301311
// TODO: do canonicalization directly in `arduino-cli`
302312
canonicalizeCompileCommandsJSON(buildPath.Join("compile_commands.json"))
303313

Diff for: ls/ls.go

+31-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type INOLanguageServer struct {
3939
buildPath *paths.Path
4040
buildSketchRoot *paths.Path
4141
buildSketchCpp *paths.Path
42+
fullBuildPath *paths.Path
4243
sketchRoot *paths.Path
4344
sketchName string
4445
sketchMapper *sourcemapper.SketchMapper
@@ -129,9 +130,16 @@ func NewINOLanguageServer(stdin io.Reader, stdout io.Writer, config *Config) *IN
129130
ls.buildSketchRoot = ls.buildPath.Join("sketch")
130131
}
131132

133+
if tmp, err := paths.MkTempDir("", "arduino-language-server"); err != nil {
134+
log.Fatalf("Could not create temp folder: %s", err)
135+
} else {
136+
ls.fullBuildPath = tmp.Canonical()
137+
}
138+
132139
logger.Logf("Initial board configuration: %s", ls.config.Fqbn)
133140
logger.Logf("Language server build path: %s", ls.buildPath)
134141
logger.Logf("Language server build sketch root: %s", ls.buildSketchRoot)
142+
logger.Logf("Language server FULL build path: %s", ls.fullBuildPath)
135143

136144
ls.IDE = NewIDELSPServer(logger, stdin, stdout, ls)
137145
ls.progressHandler = NewProgressProxy(ls.IDE.conn)
@@ -158,7 +166,7 @@ func (ls *INOLanguageServer) InitializeReqFromIDE(ctx context.Context, logger js
158166
ls.sketchName = ls.sketchRoot.Base()
159167
ls.buildSketchCpp = ls.buildSketchRoot.Join(ls.sketchName + ".ino.cpp")
160168

161-
if success, err := ls.generateBuildEnvironment(context.Background(), logger); err != nil {
169+
if success, err := ls.generateBuildEnvironment(context.Background(), true, logger); err != nil {
162170
logger.Logf("error starting clang: %s", err)
163171
return
164172
} else if !success {
@@ -1160,6 +1168,24 @@ func (ls *INOLanguageServer) TextDocumentDidCloseNotifFromIDE(logger jsonrpc.Fun
11601168
}
11611169
}
11621170

1171+
func (ls *INOLanguageServer) FullBuildCompletedFromIDE(logger jsonrpc.FunctionLogger, params *DidCompleteBuildParams) {
1172+
ls.writeLock(logger, true)
1173+
defer ls.writeUnlock(logger)
1174+
1175+
ls.CopyFullBuildResults(logger, params.BuildOutputUri.AsPath())
1176+
ls.triggerRebuild()
1177+
}
1178+
1179+
func (ls *INOLanguageServer) CopyFullBuildResults(logger jsonrpc.FunctionLogger, buildPath *paths.Path) {
1180+
fromCache := buildPath.Join("libraries.cache")
1181+
toCache := ls.buildPath.Join("libraries.cache")
1182+
if err := fromCache.CopyTo(toCache); err != nil {
1183+
logger.Logf("ERROR: updating libraries.cache: %s", err)
1184+
} else {
1185+
logger.Logf("Updated 'libraries.cache'. Copied: %v to %v", fromCache, toCache)
1186+
}
1187+
}
1188+
11631189
func (ls *INOLanguageServer) PublishDiagnosticsNotifFromClangd(logger jsonrpc.FunctionLogger, clangParams *lsp.PublishDiagnosticsParams) {
11641190
ls.readLock(logger, false)
11651191
defer ls.readUnlock(logger)
@@ -1343,6 +1369,10 @@ func (ls *INOLanguageServer) CleanUp() {
13431369
ls.buildPath.RemoveAll()
13441370
ls.buildPath = nil
13451371
}
1372+
if ls.fullBuildPath != nil {
1373+
ls.fullBuildPath.RemoveAll()
1374+
ls.fullBuildPath = nil
1375+
}
13461376
}
13471377

13481378
func (ls *INOLanguageServer) extractDataFolderFromArduinoCLI(logger jsonrpc.FunctionLogger) (*paths.Path, error) {

Diff for: ls/lsp_server_ide.go

+15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func NewIDELSPServer(logger jsonrpc.FunctionLogger, in io.Reader, out io.Writer,
2020
ls: ls,
2121
}
2222
server.conn = lsp.NewServer(in, out, server)
23+
server.conn.RegisterCustomNotification("ino/didCompleteBuild", server.ArduinoBuildCompleted)
2324
server.conn.SetLogger(&LSPLogger{
2425
IncomingPrefix: "IDE --> LS",
2526
OutgoingPrefix: "IDE <-- LS",
@@ -274,3 +275,17 @@ func (server *IDELSPServer) TextDocumentDidSave(logger jsonrpc.FunctionLogger, p
274275
func (server *IDELSPServer) TextDocumentDidClose(logger jsonrpc.FunctionLogger, params *lsp.DidCloseTextDocumentParams) {
275276
server.ls.TextDocumentDidCloseNotifFromIDE(logger, params)
276277
}
278+
279+
// DidCompleteBuildParams is a custom notification from the Arduino IDE, sent
280+
type DidCompleteBuildParams struct {
281+
BuildOutputUri *lsp.DocumentURI `json:"buildOutputUri"`
282+
}
283+
284+
func (server *IDELSPServer) ArduinoBuildCompleted(logger jsonrpc.FunctionLogger, raw json.RawMessage) {
285+
var params DidCompleteBuildParams
286+
if err := json.Unmarshal(raw, &params); err != nil {
287+
logger.Logf("ERROR decoding DidCompleteBuildParams: %s", err)
288+
} else {
289+
server.ls.FullBuildCompletedFromIDE(logger, &params)
290+
}
291+
}

0 commit comments

Comments
 (0)