Skip to content

Commit 26de915

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

File tree

3 files changed

+97
-11
lines changed

3 files changed

+97
-11
lines changed

ls/ls.go

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ type Config struct {
8383
Jobs int
8484
}
8585

86+
var extToFileType = map[string]string{
87+
".h": "cpp",
88+
".hpp": "cpp",
89+
}
90+
91+
type translationOpts struct {
92+
loadRelToIde bool
93+
}
94+
8695
var yellow = color.New(color.FgHiYellow)
8796

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

604613
var ideLocations []lsp.Location
605614
if clangLocations != nil {
606-
ideLocations, err = ls.clang2IdeLocationsArray(logger, clangLocations)
615+
opts := translationOpts{loadRelToIde: true}
616+
ideLocations, err = ls.clang2IdeLocationsArray2(logger, clangLocations, &opts)
607617
if err != nil {
608618
logger.Logf("Error: %v", err)
609619
ls.Close()
@@ -989,15 +999,13 @@ func (ls *INOLanguageServer) exitNotifFromIDE(logger jsonrpc.FunctionLogger) {
989999
ls.Close()
9901000
}
9911001

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

996-
ideTextDocItem := ideParam.TextDocument
1004+
ideTextDocItem := ideParam
9971005
clangURI, _, err := ls.ide2ClangDocumentURI(logger, ideTextDocItem.URI)
9981006
if err != nil {
9991007
logger.Logf("Error: %s", err)
1000-
return
1008+
return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()}
10011009
}
10021010

10031011
if ls.ideURIIsPartOfTheSketch(ideTextDocItem.URI) {
@@ -1017,7 +1025,7 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
10171025
// Notify clangd that sketchCpp has been opened only once
10181026
if ls.sketchTrackedFilesCount != 1 {
10191027
logger.Logf("Clang already notified, do not notify it anymore")
1020-
return
1028+
return nil
10211029
}
10221030
}
10231031

@@ -1045,7 +1053,17 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
10451053
logger.Logf("Error sending notification to clangd server: %v", err)
10461054
logger.Logf("Please restart the language server.")
10471055
ls.Close()
1056+
return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()}
1057+
10481058
}
1059+
return nil
1060+
1061+
}
1062+
1063+
func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) {
1064+
ls.writeLock(logger, true)
1065+
defer ls.writeUnlock(logger)
1066+
ls.implTextDocumentDidOpenNotifFromIDE(logger, ideParam.TextDocument)
10491067
}
10501068

10511069
func (ls *INOLanguageServer) textDocumentDidChangeNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidChangeTextDocumentParams) {
@@ -1619,6 +1637,16 @@ type UnknownURIError struct {
16191637
URI lsp.DocumentURI
16201638
}
16211639

1640+
// UnknownFileExtensionError when a file extension isn't recognized
1641+
// and a file with it has to be opened.
1642+
type UnknownFileExtensionError struct {
1643+
extension string
1644+
}
1645+
16221646
func (e *UnknownURIError) Error() string {
16231647
return "Document is not available: " + e.URI.String()
16241648
}
1649+
1650+
func (e *UnknownFileExtensionError) Error() string {
1651+
return "Unknown file extension " + e.extension
1652+
}

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(ext string) string {
29+
if fileType, ok := extToFileType[ext]; ok {
30+
return fileType
31+
}
32+
return "unknown"
33+
}
2634
func (ls *INOLanguageServer) idePathToIdeURI(logger jsonrpc.FunctionLogger, inoPath string) (lsp.DocumentURI, error) {
35+
return ls.idePathToIdeURI2(logger, inoPath)
36+
}
37+
38+
func makeTextDocumentItem(logger jsonrpc.FunctionLogger, path string) (lsp.TextDocumentItem, bool, error) {
39+
ext := filepath.Ext(path)
40+
filetype := getFileType(path)
41+
uri := lsp.NewDocumentURI(path)
42+
if filetype == "unknown" {
43+
return lsp.TextDocumentItem{URI: uri, LanguageID: filetype}, false, &UnknownFileExtensionError{ext}
44+
}
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) (lsp.DocumentURI, error) {
2757
if inoPath == sourcemapper.NotIno.File {
2858
return sourcemapper.NotInoURI, nil
2959
}

0 commit comments

Comments
 (0)