diff --git a/ls/ls.go b/ls/ls.go index b487f087..40b497e 100644 --- a/ls/ls.go +++ b/ls/ls.go @@ -83,6 +83,15 @@ type Config struct { Jobs int } +var extToFileType = map[string]string{ + ".h": "cpp", + ".hpp": "cpp", +} + +type translationOpts struct { + loadRelToIde bool +} + var yellow = color.New(color.FgHiYellow) func (ls *INOLanguageServer) writeLock(logger jsonrpc.FunctionLogger, requireClangd bool) { @@ -603,7 +612,8 @@ func (ls *INOLanguageServer) textDocumentDefinitionReqFromIDE(ctx context.Contex var ideLocations []lsp.Location if clangLocations != nil { - ideLocations, err = ls.clang2IdeLocationsArray(logger, clangLocations) + opts := translationOpts{loadRelToIde: true} + ideLocations, err = ls.clang2IdeLocationsArray2(logger, clangLocations, &opts) if err != nil { logger.Logf("Error: %v", err) ls.Close() @@ -989,15 +999,13 @@ func (ls *INOLanguageServer) exitNotifFromIDE(logger jsonrpc.FunctionLogger) { ls.Close() } -func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) { - ls.writeLock(logger, true) - defer ls.writeUnlock(logger) +func (ls *INOLanguageServer) implTextDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam lsp.TextDocumentItem) *jsonrpc.ResponseError { - ideTextDocItem := ideParam.TextDocument + ideTextDocItem := ideParam clangURI, _, err := ls.ide2ClangDocumentURI(logger, ideTextDocItem.URI) if err != nil { logger.Logf("Error: %s", err) - return + return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()} } if ls.ideURIIsPartOfTheSketch(ideTextDocItem.URI) { @@ -1017,7 +1025,7 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func // Notify clangd that sketchCpp has been opened only once if ls.sketchTrackedFilesCount != 1 { logger.Logf("Clang already notified, do not notify it anymore") - return + return nil } } @@ -1045,7 +1053,17 @@ func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.Func logger.Logf("Error sending notification to clangd server: %v", err) logger.Logf("Please restart the language server.") ls.Close() + return &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()} + } + return nil + +} + +func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) { + ls.writeLock(logger, true) + defer ls.writeUnlock(logger) + ls.implTextDocumentDidOpenNotifFromIDE(logger, ideParam.TextDocument) } func (ls *INOLanguageServer) textDocumentDidChangeNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidChangeTextDocumentParams) { @@ -1619,6 +1637,16 @@ type UnknownURIError struct { URI lsp.DocumentURI } +// UnknownFileExtensionError when a file extension isn't recognized +// and a file with it has to be opened. +type UnknownFileExtensionError struct { + extension string +} + func (e *UnknownURIError) Error() string { return "Document is not available: " + e.URI.String() } + +func (e *UnknownFileExtensionError) Error() string { + return "Unknown file extension " + e.extension +} diff --git a/ls/ls_clang_to_ide.go b/ls/ls_clang_to_ide.go index 882d1b5..d8ef4ca 100644 --- a/ls/ls_clang_to_ide.go +++ b/ls/ls_clang_to_ide.go @@ -27,12 +27,16 @@ func (ls *INOLanguageServer) clangURIRefersToIno(clangURI lsp.DocumentURI) bool return clangURI.AsPath().EquivalentTo(ls.buildSketchCpp) } +func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range) (lsp.DocumentURI, lsp.Range, bool, error) { + return ls.clang2IdeRangeAndDocumentURI2(logger, clangURI, clangRange, nil) +} + // Convert Range and DocumentURI from Clang to IDE. // Returns: // - The IDE DocumentURI and Range // - a boolean that is true if the clang range is in the preprocessed area of the sketch // - an error -func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range) (lsp.DocumentURI, lsp.Range, bool, error) { +func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI2(logger jsonrpc.FunctionLogger, clangURI lsp.DocumentURI, clangRange lsp.Range, opts *translationOpts) (lsp.DocumentURI, lsp.Range, bool, error) { // Sketchbook/Sketch/Sketch.ino <-> build-path/sketch/Sketch.ino.cpp // Sketchbook/Sketch/AnotherTab.ino <-> build-path/sketch/Sketch.ino.cpp (different section from above) if ls.clangURIRefersToIno(clangURI) { @@ -80,7 +84,25 @@ func (ls *INOLanguageServer) clang2IdeRangeAndDocumentURI(logger jsonrpc.Functio return lsp.NilURI, lsp.NilRange, false, err } idePath := ls.sketchRoot.JoinPath(rel).String() - ideURI, err := ls.idePathToIdeURI(logger, idePath) + + var ideURI lsp.DocumentURI + if opts == nil || !opts.loadRelToIde { + ideURI, err = ls.idePathToIdeURI(logger, idePath) + } else { + doc, ok := ls.trackedIdeDocs[idePath] + if !ok { + var shouldOpen bool + doc, shouldOpen, err = makeTextDocumentItem(logger, idePath) + if err != nil { + logger.Logf("ERROR: could not open '%s': %s", idePath, err) + } + if shouldOpen { + ls.implTextDocumentDidOpenNotifFromIDE(logger, doc) + } + + } + ideURI = doc.URI + } if ideRange.End.Line > 0 { ideRange.End.Line-- } @@ -296,9 +318,12 @@ func (ls *INOLanguageServer) cland2IdeTextEdits(logger jsonrpc.FunctionLogger, c } func (ls *INOLanguageServer) clang2IdeLocationsArray(logger jsonrpc.FunctionLogger, clangLocations []lsp.Location) ([]lsp.Location, error) { + return ls.clang2IdeLocationsArray2(logger, clangLocations, nil) +} +func (ls *INOLanguageServer) clang2IdeLocationsArray2(logger jsonrpc.FunctionLogger, clangLocations []lsp.Location, opts *translationOpts) ([]lsp.Location, error) { ideLocations := []lsp.Location{} for _, clangLocation := range clangLocations { - ideLocation, inPreprocessed, err := ls.clang2IdeLocation(logger, clangLocation) + ideLocation, inPreprocessed, err := ls.clang2IdeLocation2(logger, clangLocation, opts) if err != nil { logger.Logf("ERROR converting location %s: %s", clangLocation, err) return nil, err @@ -313,7 +338,10 @@ func (ls *INOLanguageServer) clang2IdeLocationsArray(logger jsonrpc.FunctionLogg } func (ls *INOLanguageServer) clang2IdeLocation(logger jsonrpc.FunctionLogger, clangLocation lsp.Location) (lsp.Location, bool, error) { - ideURI, ideRange, inPreprocessed, err := ls.clang2IdeRangeAndDocumentURI(logger, clangLocation.URI, clangLocation.Range) + return ls.clang2IdeLocation2(logger, clangLocation, nil) +} +func (ls *INOLanguageServer) clang2IdeLocation2(logger jsonrpc.FunctionLogger, clangLocation lsp.Location, opts *translationOpts) (lsp.Location, bool, error) { + ideURI, ideRange, inPreprocessed, err := ls.clang2IdeRangeAndDocumentURI2(logger, clangLocation.URI, clangLocation.Range, opts) return lsp.Location{ URI: ideURI, Range: ideRange, diff --git a/ls/ls_ide_to_clang.go b/ls/ls_ide_to_clang.go index e6ccc11..73b8cf6 100644 --- a/ls/ls_ide_to_clang.go +++ b/ls/ls_ide_to_clang.go @@ -17,13 +17,43 @@ package ls import ( "fmt" + "os" + "path/filepath" "github.com/arduino/arduino-language-server/sourcemapper" "go.bug.st/lsp" "go.bug.st/lsp/jsonrpc" ) +func getFileType(ext string) string { + if fileType, ok := extToFileType[ext]; ok { + return fileType + } + return "unknown" +} func (ls *INOLanguageServer) idePathToIdeURI(logger jsonrpc.FunctionLogger, inoPath string) (lsp.DocumentURI, error) { + return ls.idePathToIdeURI2(logger, inoPath) +} + +func makeTextDocumentItem(logger jsonrpc.FunctionLogger, path string) (lsp.TextDocumentItem, bool, error) { + ext := filepath.Ext(path) + filetype := getFileType(path) + uri := lsp.NewDocumentURI(path) + if filetype == "unknown" { + return lsp.TextDocumentItem{URI: uri, LanguageID: filetype}, false, &UnknownFileExtensionError{ext} + } + languageID := filetype + version := 0 + + text, err := os.ReadFile(path) + if err != nil { + logger.Logf("Could not read file: %v", err) + return lsp.TextDocumentItem{}, false, err + } + return lsp.TextDocumentItem{URI: uri, LanguageID: languageID, Version: version, Text: string(text)}, true, nil + +} +func (ls *INOLanguageServer) idePathToIdeURI2(logger jsonrpc.FunctionLogger, inoPath string) (lsp.DocumentURI, error) { if inoPath == sourcemapper.NotIno.File { return sourcemapper.NotInoURI, nil }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: