Skip to content

Commit 7cda7b3

Browse files
committed
Fixed the language server crashing upon a go to definition request on untracked file
1 parent 9945da3 commit 7cda7b3

File tree

3 files changed

+89
-11
lines changed

3 files changed

+89
-11
lines changed

ls/ls.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ type INOLanguageServer struct {
6868
sketchRebuilder *sketchRebuilder
6969
}
7070

71+
type TranslationOpts struct {
72+
loadRelToIde bool
73+
}
74+
7175
// Config describes the language server configuration.
7276
type Config struct {
7377
Fqbn string
@@ -83,6 +87,13 @@ type Config struct {
8387
Jobs int
8488
}
8589

90+
var extToFileType = map[string]string{
91+
".ino": "arduino",
92+
".cpp": "cpp",
93+
".h": "cpp",
94+
".c": "c",
95+
}
96+
8697
var yellow = color.New(color.FgHiYellow)
8798

8899
func (ls *INOLanguageServer) writeLock(logger jsonrpc.FunctionLogger, requireClangd bool) {
@@ -603,7 +614,8 @@ func (ls *INOLanguageServer) textDocumentDefinitionReqFromIDE(ctx context.Contex
603614

604615
var ideLocations []lsp.Location
605616
if clangLocations != nil {
606-
ideLocations, err = ls.clang2IdeLocationsArray(logger, clangLocations)
617+
opts := TranslationOpts{loadRelToIde: true}
618+
ideLocations, err = ls.clang2IdeLocationsArray2(logger, clangLocations, &opts)
607619
if err != nil {
608620
logger.Logf("Error: %v", err)
609621
ls.Close()
@@ -989,15 +1001,13 @@ func (ls *INOLanguageServer) exitNotifFromIDE(logger jsonrpc.FunctionLogger) {
9891001
ls.Close()
9901002
}
9911003

992-
func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) {
993-
ls.writeLock(logger, true)
994-
defer ls.writeUnlock(logger)
1004+
func (ls *INOLanguageServer) implTextDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam lsp.TextDocumentItem) *jsonrpc.ResponseError {
9951005

996-
ideTextDocItem := ideParam.TextDocument
1006+
ideTextDocItem := ideParam
9971007
clangURI, _, err := ls.ide2ClangDocumentURI(logger, ideTextDocItem.URI)
9981008
if err != nil {
9991009
logger.Logf("Error: %s", err)
1000-
return
1010+
return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()}
10011011
}
10021012

10031013
if ls.ideURIIsPartOfTheSketch(ideTextDocItem.URI) {
@@ -1017,7 +1027,7 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
10171027
// Notify clangd that sketchCpp has been opened only once
10181028
if ls.sketchTrackedFilesCount != 1 {
10191029
logger.Logf("Clang already notified, do not notify it anymore")
1020-
return
1030+
return nil
10211031
}
10221032
}
10231033

@@ -1045,7 +1055,17 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
10451055
logger.Logf("Error sending notification to clangd server: %v", err)
10461056
logger.Logf("Please restart the language server.")
10471057
ls.Close()
1058+
return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()}
1059+
10481060
}
1061+
return nil
1062+
1063+
}
1064+
1065+
func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) {
1066+
ls.writeLock(logger, true)
1067+
defer ls.writeUnlock(logger)
1068+
ls.implTextDocumentDidOpenNotifFromIDE(logger, ideParam.TextDocument)
10491069
}
10501070

10511071
func (ls *INOLanguageServer) textDocumentDidChangeNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidChangeTextDocumentParams) {

ls/ls_clang_to_ide.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@ func (ls *INOLanguageServer) clangURIRefersToIno(clangURI lsp.DocumentURI) bool
2727
return clangURI.AsPath().EquivalentTo(ls.buildSketchCpp)
2828
}
2929

30+
func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range) (lsp.DocumentURI, lsp.Range, bool, error) {
31+
return ls.clang2IdeRangeAndDocumentURI2(logger, clangURI, clangRange, nil)
32+
}
33+
3034
// Convert Range and DocumentURI from Clang to IDE.
3135
// Returns:
3236
// - The IDE DocumentURI and Range
3337
// - a boolean that is true if the clang range is in the preprocessed area of the sketch
3438
// - an error
35-
func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range) (lsp.DocumentURI, lsp.Range, bool, error) {
39+
func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI2(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range, opts *TranslationOpts) (lsp.DocumentURI, lsp.Range, bool, error) {
3640
// Sketchbook/Sketch/Sketch.ino <-> build-path/sketch/Sketch.ino.cpp
3741
// Sketchbook/Sketch/AnotherTab.ino <-> build-path/sketch/Sketch.ino.cpp (different section from above)
3842
if ls.clangURIRefersToIno(clangURI) {
@@ -80,7 +84,25 @@ func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.Functio
8084
return lsp.NilURI, lsp.NilRange, false, err
8185
}
8286
idePath := ls.sketchRoot.JoinPath(rel).String()
83-
ideURI, err := ls.idePathToIdeURI(logger, idePath)
87+
88+
var ideURI lsp.DocumentURI
89+
if opts == nil || !opts.loadRelToIde {
90+
ideURI, err = ls.idePathToIdeURI(logger, idePath)
91+
} else {
92+
doc, ok := ls.trackedIdeDocs[idePath]
93+
if !ok {
94+
var shouldOpen bool
95+
doc, shouldOpen, err = makeTextDocumentItem(logger, idePath)
96+
if err != nil {
97+
logger.Logf("ERROR: could not open '%s': %s", idePath, err)
98+
}
99+
if shouldOpen {
100+
ls.implTextDocumentDidOpenNotifFromIDE(logger, doc)
101+
}
102+
103+
}
104+
ideURI = doc.URI
105+
}
84106
if ideRange.End.Line > 0 {
85107
ideRange.End.Line--
86108
}
@@ -296,9 +318,12 @@ func (ls *INOLanguageServer) cland2IdeTextEdits(logger jsonrpc.FunctionLogger, c
296318
}
297319

298320
func (ls *INOLanguageServer) clang2IdeLocationsArray(logger jsonrpc.FunctionLogger, clangLocations []lsp.Location) ([]lsp.Location, error) {
321+
return ls.clang2IdeLocationsArray2(logger, clangLocations, nil)
322+
}
323+
func (ls *INOLanguageServer) clang2IdeLocationsArray2(logger jsonrpc.FunctionLogger, clangLocations []lsp.Location, opts *TranslationOpts) ([]lsp.Location, error) {
299324
ideLocations := []lsp.Location{}
300325
for _, clangLocation := range clangLocations {
301-
ideLocation, inPreprocessed, err := ls.clang2IdeLocation(logger, clangLocation)
326+
ideLocation, inPreprocessed, err := ls.clang2IdeLocation2(logger, clangLocation, opts)
302327
if err != nil {
303328
logger.Logf("ERROR converting location %s: %s", clangLocation, err)
304329
return nil, err
@@ -313,7 +338,10 @@ func (ls *INOLanguageServer) clang2IdeLocationsArray(logger jsonrpc.FunctionLogg
313338
}
314339

315340
func (ls *INOLanguageServer) clang2IdeLocation(logger jsonrpc.FunctionLogger, clangLocation lsp.Location) (lsp.Location, bool, error) {
316-
ideURI, ideRange, inPreprocessed, err := ls.clang2IdeRangeAndDocumentURI(logger, clangLocation.URI, clangLocation.Range)
341+
return ls.clang2IdeLocation2(logger, clangLocation, nil)
342+
}
343+
func (ls *INOLanguageServer) clang2IdeLocation2(logger jsonrpc.FunctionLogger, clangLocation lsp.Location, opts *TranslationOpts) (lsp.Location, bool, error) {
344+
ideURI, ideRange, inPreprocessed, err := ls.clang2IdeRangeAndDocumentURI2(logger, clangLocation.URI, clangLocation.Range, opts)
317345
return lsp.Location{
318346
URI: ideURI,
319347
Range: ideRange,

ls/ls_ide_to_clang.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,43 @@ package ls
1717

1818
import (
1919
"fmt"
20+
"os"
21+
"path/filepath"
2022

2123
"github.com/arduino/arduino-language-server/sourcemapper"
2224
"go.bug.st/lsp"
2325
"go.bug.st/lsp/jsonrpc"
2426
)
2527

28+
func getFileType(filename string) string {
29+
ext := filepath.Ext(filename)
30+
if fileType, ok := extToFileType[ext]; ok {
31+
return fileType
32+
}
33+
return "unknown"
34+
}
2635
func (ls *INOLanguageServer) idePathToIdeURI(logger jsonrpc.FunctionLogger, inoPath string) (lsp.DocumentURI, error) {
36+
return ls.idePathToIdeURI2(logger, inoPath, nil)
37+
}
38+
39+
func makeTextDocumentItem(logger jsonrpc.FunctionLogger, path string) (lsp.TextDocumentItem, bool, error) {
40+
filetype := getFileType(path)
41+
if filetype == "unknown" {
42+
return lsp.TextDocumentItem{}, false, nil
43+
}
44+
uri := lsp.NewDocumentURI(path)
45+
languageId := filetype
46+
version := 0
47+
48+
text, err := os.ReadFile(path)
49+
if err != nil {
50+
logger.Logf("Could not read file: %v", err)
51+
return lsp.TextDocumentItem{}, false, err
52+
}
53+
return lsp.TextDocumentItem{URI: uri, LanguageID: languageId, Version: version, Text: string(text)}, true, nil
54+
55+
}
56+
func (ls *INOLanguageServer) idePathToIdeURI2(logger jsonrpc.FunctionLogger, inoPath string, opts *TranslationOpts) (lsp.DocumentURI, error) {
2757
if inoPath == sourcemapper.NotIno.File {
2858
return sourcemapper.NotInoURI, nil
2959
}

0 commit comments

Comments
 (0)