diff --git a/.github/workflows/check-go-task.yml b/.github/workflows/check-go-task.yml new file mode 100644 index 0000000..844629e --- /dev/null +++ b/.github/workflows/check-go-task.yml @@ -0,0 +1,223 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-go-task.md +name: Check Go + +env: + # See: https://github.com/actions/setup-go/tree/main#supported-version-syntax + GO_VERSION: "1.18.3" + +# See: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows +on: + create: + push: + paths: + - ".github/workflows/check-go-task.ya?ml" + - "Taskfile.ya?ml" + - "**/go.mod" + - "**/go.sum" + - "**.go" + pull_request: + paths: + - ".github/workflows/check-go-task.ya?ml" + - "Taskfile.ya?ml" + - "**/go.mod" + - "**/go.sum" + - "**.go" + schedule: + # Run periodically to catch breakage caused by external changes. + - cron: "0 7 * * WED" + workflow_dispatch: + repository_dispatch: + +jobs: + run-determination: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.determination.outputs.result }} + steps: + - name: Determine if the rest of the workflow should run + id: determination + run: | + RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x" + # The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead. + if [[ + "${{ github.event_name }}" != "create" || + "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX + ]]; then + # Run the other jobs. + RESULT="true" + else + # There is no need to run the other jobs. + RESULT="false" + fi + + echo "::set-output name=result::$RESULT" + + check-errors: + name: check-errors (${{ matrix.module.path }}) + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + module: + - path: ./ + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Check for errors + env: + GO_MODULE_PATH: ${{ matrix.module.path }} + run: task go:vet + + check-outdated: + name: check-outdated (${{ matrix.module.path }}) + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + module: + - path: ./ + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Modernize usages of outdated APIs + env: + GO_MODULE_PATH: ${{ matrix.module.path }} + run: task go:fix + + - name: Check if any fixes were needed + run: git diff --color --exit-code + + check-style: + name: check-style (${{ matrix.module.path }}) + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + module: + - path: ./ + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install golint + run: go install golang.org/x/lint/golint@latest + + - name: Check style + env: + GO_MODULE_PATH: ${{ matrix.module.path }} + run: task --silent go:lint + + check-formatting: + name: check-formatting (${{ matrix.module.path }}) + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + module: + - path: ./ + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Format code + env: + GO_MODULE_PATH: ${{ matrix.module.path }} + run: task go:format + + - name: Check formatting + run: git diff --color --exit-code + + check-config: + name: check-config (${{ matrix.module.path }}) + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + module: + - path: ./ + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Run go mod tidy + working-directory: ${{ matrix.module.path }} + run: go mod tidy + + - name: Check whether any tidying was needed + run: git diff --color --exit-code diff --git a/README.md b/README.md index 5af746e..c915192 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ # Arduino Language Server [![Check Taskfiles status](https://github.com/arduino/arduino-language-server/actions/workflows/check-taskfiles.yml/badge.svg)](https://github.com/arduino/arduino-language-server/actions/workflows/check-taskfiles.yml) +[![Check Go status](https://github.com/arduino/arduino-language-server/actions/workflows/check-go-task.yml/badge.svg)](https://github.com/arduino/arduino-language-server/actions/workflows/check-go-task.yml) The **Arduino Language Server** is the tool that powers the autocompletion of the new [Arduino IDE 2][arduino-ide-repo]. It implements the standard [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) so it can be used with other IDEs as well. diff --git a/Taskfile.yml b/Taskfile.yml index c6c6547..42aac29 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -3,6 +3,44 @@ version: "3" includes: dist: ./DistTasks.yml +vars: + PROJECT_NAME: "arduino-language-server" + DIST_DIR: "dist" + # Path of the project's primary Go module: + DEFAULT_GO_MODULE_PATH: ./ + DEFAULT_GO_PACKAGES: + sh: | + echo $(cd {{default "./" .GO_MODULE_PATH}} && go list ./... | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"') + # build vars + COMMIT: + sh: echo "$(git log --no-show-signature -n 1 --format=%h)" + TIMESTAMP: + sh: echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + TIMESTAMP_SHORT: + sh: echo "{{now | date "20060102"}}" + TAG: + sh: echo "$(git tag --points-at=HEAD 2> /dev/null | head -n1)" + VERSION: "{{if .NIGHTLY}}nightly-{{.TIMESTAMP_SHORT}}{{else if .TAG}}{{.TAG}}{{else}}{{.PACKAGE_NAME_PREFIX}}git-snapshot{{end}}" + CONFIGURATION_PACKAGE: "github.com/arduino/arduino-language-server/version" + LDFLAGS: >- + -ldflags + ' + -X {{.CONFIGURATION_PACKAGE}}.versionString={{.VERSION}} + -X {{.CONFIGURATION_PACKAGE}}.commit={{.COMMIT}} + -X {{.CONFIGURATION_PACKAGE}}.date={{.TIMESTAMP}} + ' + # test vars + GOFLAGS: "-timeout 10m -v -coverpkg=./... -covermode=atomic" + TEST_VERSION: "0.0.0-test.preview" + TEST_COMMIT: "deadbeef" + TEST_LDFLAGS: >- + -ldflags + ' + -X {{.CONFIGURATION_PACKAGE}}.versionString={{.TEST_VERSION}} + -X {{.CONFIGURATION_PACKAGE}}.commit={{.TEST_COMMIT}} + -X {{.CONFIGURATION_PACKAGE}}.date={{.TIMESTAMP}} + ' + tasks: docs:generate: desc: Create all generated documentation content @@ -320,39 +358,3 @@ tasks: - task: poetry:install-deps cmds: - poetry run mkdocs serve - -vars: - PROJECT_NAME: "arduino-language-server" - DIST_DIR: "dist" - DEFAULT_GO_PACKAGES: - sh: | - echo $(cd {{default "./" .GO_MODULE_PATH}} && go list ./... | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"') - # build vars - COMMIT: - sh: echo "$(git log --no-show-signature -n 1 --format=%h)" - TIMESTAMP: - sh: echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" - TIMESTAMP_SHORT: - sh: echo "{{now | date "20060102"}}" - TAG: - sh: echo "$(git tag --points-at=HEAD 2> /dev/null | head -n1)" - VERSION: "{{if .NIGHTLY}}nightly-{{.TIMESTAMP_SHORT}}{{else if .TAG}}{{.TAG}}{{else}}{{.PACKAGE_NAME_PREFIX}}git-snapshot{{end}}" - CONFIGURATION_PACKAGE: "github.com/arduino/arduino-language-server/version" - LDFLAGS: >- - -ldflags - ' - -X {{.CONFIGURATION_PACKAGE}}.versionString={{.VERSION}} - -X {{.CONFIGURATION_PACKAGE}}.commit={{.COMMIT}} - -X {{.CONFIGURATION_PACKAGE}}.date={{.TIMESTAMP}} - ' - # test vars - GOFLAGS: "-timeout 10m -v -coverpkg=./... -covermode=atomic" - TEST_VERSION: "0.0.0-test.preview" - TEST_COMMIT: "deadbeef" - TEST_LDFLAGS: >- - -ldflags - ' - -X {{.CONFIGURATION_PACKAGE}}.versionString={{.TEST_VERSION}} - -X {{.CONFIGURATION_PACKAGE}}.commit={{.TEST_COMMIT}} - -X {{.CONFIGURATION_PACKAGE}}.date={{.TIMESTAMP}} - ' diff --git a/ls/builder.go b/ls/builder.go index 6b0bea7..f4338bd 100644 --- a/ls/builder.go +++ b/ls/builder.go @@ -25,15 +25,16 @@ import ( "google.golang.org/grpc" ) -type SketchRebuilder struct { +type sketchRebuilder struct { ls *INOLanguageServer trigger chan chan<- bool cancel func() mutex sync.Mutex } -func NewSketchBuilder(ls *INOLanguageServer) *SketchRebuilder { - res := &SketchRebuilder{ +// newSketchBuilder makes a new SketchRebuilder and returns its pointer +func newSketchBuilder(ls *INOLanguageServer) *sketchRebuilder { + res := &sketchRebuilder{ trigger: make(chan chan<- bool, 1), cancel: func() {}, ls: ls, @@ -57,7 +58,8 @@ func (ls *INOLanguageServer) triggerRebuild() { ls.sketchRebuilder.TriggerRebuild(nil) } -func (r *SketchRebuilder) TriggerRebuild(completed chan<- bool) { +// TriggerRebuild schedule a sketch rebuild (it will be executed asynchronously) +func (r *sketchRebuilder) TriggerRebuild(completed chan<- bool) { r.mutex.Lock() defer r.mutex.Unlock() @@ -68,7 +70,7 @@ func (r *SketchRebuilder) TriggerRebuild(completed chan<- bool) { } } -func (r *SketchRebuilder) rebuilderLoop() { +func (r *sketchRebuilder) rebuilderLoop() { logger := NewLSPFunctionLogger(color.HiMagentaString, "SKETCH REBUILD: ") for { completed := <-r.trigger @@ -104,7 +106,7 @@ func (r *SketchRebuilder) rebuilderLoop() { } } -func (r *SketchRebuilder) doRebuildArduinoPreprocessedSketch(ctx context.Context, logger jsonrpc.FunctionLogger) error { +func (r *sketchRebuilder) doRebuildArduinoPreprocessedSketch(ctx context.Context, logger jsonrpc.FunctionLogger) error { ls := r.ls if success, err := ls.generateBuildEnvironment(ctx, !r.ls.config.SkipLibrariesDiscoveryOnRebuild, logger); err != nil { return err @@ -207,8 +209,8 @@ func (ls *INOLanguageServer) generateBuildEnvironment(ctx context.Context, fullB Verbose: true, SkipLibrariesDiscovery: !fullBuild, } - compileReqJson, _ := json.MarshalIndent(compileReq, "", " ") - logger.Logf("Running build with: %s", string(compileReqJson)) + compileReqJSON, _ := json.MarshalIndent(compileReq, "", " ") + logger.Logf("Running build with: %s", string(compileReqJSON)) compRespStream, err := client.Compile(context.Background(), compileReq) if err != nil { diff --git a/ls/ls.go b/ls/ls.go index f3b18ed..0ad3c1a 100644 --- a/ls/ls.go +++ b/ls/ls.go @@ -30,9 +30,9 @@ import ( type INOLanguageServer struct { config *Config IDE *IDELSPServer - Clangd *ClangdLSPClient + Clangd *clangdLSPClient - progressHandler *ProgressProxyHandler + progressHandler *progressProxyHandler closing chan bool clangdStarted *sync.Cond dataMux sync.RWMutex @@ -46,7 +46,7 @@ type INOLanguageServer struct { sketchTrackedFilesCount int trackedIdeDocs map[string]lsp.TextDocumentItem ideInoDocsWithDiagnostics map[lsp.DocumentURI]bool - sketchRebuilder *SketchRebuilder + sketchRebuilder *sketchRebuilder } // Config describes the language server configuration. @@ -123,7 +123,7 @@ func NewINOLanguageServer(stdin io.Reader, stdout io.Writer, config *Config) *IN config: config, } ls.clangdStarted = sync.NewCond(&ls.dataMux) - ls.sketchRebuilder = NewSketchBuilder(ls) + ls.sketchRebuilder = newSketchBuilder(ls) if tmp, err := paths.MkTempDir("", "arduino-language-server"); err != nil { log.Fatalf("Could not create temp folder: %s", err) @@ -144,7 +144,7 @@ func NewINOLanguageServer(stdin io.Reader, stdout io.Writer, config *Config) *IN logger.Logf("Language server FULL build path: %s", ls.fullBuildPath) ls.IDE = NewIDELSPServer(logger, stdin, stdout, ls) - ls.progressHandler = NewProgressProxy(ls.IDE.conn) + ls.progressHandler = newProgressProxy(ls.IDE.conn) go func() { defer streams.CatchAndLogPanic() ls.IDE.Run() @@ -155,7 +155,7 @@ func NewINOLanguageServer(stdin io.Reader, stdout io.Writer, config *Config) *IN return ls } -func (ls *INOLanguageServer) InitializeReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.InitializeParams) (*lsp.InitializeResult, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) initializeReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.InitializeParams) (*lsp.InitializeResult, *jsonrpc.ResponseError) { ls.writeLock(logger, false) ls.sketchRoot = ideParams.RootURI.AsPath() ls.sketchName = ls.sketchRoot.Base() @@ -195,7 +195,7 @@ func (ls *INOLanguageServer) InitializeReqFromIDE(ctx context.Context, logger js } // Start clangd - ls.Clangd = NewClangdLSPClient(logger, dataFolder, ls) + ls.Clangd = newClangdLSPClient(logger, dataFolder, ls) go func() { defer streams.CatchAndLogPanic() ls.Clangd.Run() @@ -363,7 +363,7 @@ func (ls *INOLanguageServer) InitializeReqFromIDE(ctx context.Context, logger js return resp, nil } -func (ls *INOLanguageServer) ShutdownReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger) *jsonrpc.ResponseError { +func (ls *INOLanguageServer) shutdownReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger) *jsonrpc.ResponseError { done := make(chan bool) go func() { ls.progressHandler.Shutdown() @@ -374,7 +374,7 @@ func (ls *INOLanguageServer) ShutdownReqFromIDE(ctx context.Context, logger json return nil } -func (ls *INOLanguageServer) TextDocumentCompletionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.CompletionParams) (*lsp.CompletionList, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentCompletionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.CompletionParams) (*lsp.CompletionList, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -468,7 +468,7 @@ func (ls *INOLanguageServer) TextDocumentCompletionReqFromIDE(ctx context.Contex return ideCompletionList, nil } -func (ls *INOLanguageServer) TextDocumentHoverReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.HoverParams) (*lsp.Hover, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentHoverReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.HoverParams) (*lsp.Hover, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -519,7 +519,7 @@ func (ls *INOLanguageServer) TextDocumentHoverReqFromIDE(ctx context.Context, lo return &ideResp, nil } -func (ls *INOLanguageServer) TextDocumentSignatureHelpReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.SignatureHelpParams) (*lsp.SignatureHelp, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentSignatureHelpReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.SignatureHelpParams) (*lsp.SignatureHelp, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -550,7 +550,7 @@ func (ls *INOLanguageServer) TextDocumentSignatureHelpReqFromIDE(ctx context.Con return ideSignatureHelp, nil } -func (ls *INOLanguageServer) TextDocumentDefinitionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentDefinitionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -594,7 +594,7 @@ func (ls *INOLanguageServer) TextDocumentDefinitionReqFromIDE(ctx context.Contex return ideLocations, ideLocationLinks, nil } -func (ls *INOLanguageServer) TextDocumentTypeDefinitionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.TypeDefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentTypeDefinitionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.TypeDefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { // XXX: This capability is not advertised in the initialization message (clangd // does not advertise it either, so maybe we should just not implement it) ls.readLock(logger, true) @@ -640,7 +640,7 @@ func (ls *INOLanguageServer) TextDocumentTypeDefinitionReqFromIDE(ctx context.Co return ideLocations, ideLocationLinks, nil } -func (ls *INOLanguageServer) TextDocumentImplementationReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.ImplementationParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentImplementationReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.ImplementationParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -684,7 +684,7 @@ func (ls *INOLanguageServer) TextDocumentImplementationReqFromIDE(ctx context.Co return ideLocations, inoLocationLinks, nil } -func (ls *INOLanguageServer) TextDocumentDocumentHighlightReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentDocumentHighlightReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -731,7 +731,7 @@ func (ls *INOLanguageServer) TextDocumentDocumentHighlightReqFromIDE(ctx context return ideHighlights, nil } -func (ls *INOLanguageServer) TextDocumentDocumentSymbolReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, []lsp.SymbolInformation, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentDocumentSymbolReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, []lsp.SymbolInformation, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -762,13 +762,13 @@ func (ls *INOLanguageServer) TextDocumentDocumentSymbolReqFromIDE(ctx context.Co // Convert response for IDE var ideDocSymbols []lsp.DocumentSymbol if clangDocSymbols != nil { - if s, err := ls.clang2IdeDocumentSymbols(logger, clangDocSymbols, clangParams.TextDocument.URI, ideParams.TextDocument.URI); err != nil { + s, err := ls.clang2IdeDocumentSymbols(logger, clangDocSymbols, clangParams.TextDocument.URI, ideParams.TextDocument.URI) + if err != nil { logger.Logf("Error: %s", err) ls.Close() return nil, nil, &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()} - } else { - ideDocSymbols = s } + ideDocSymbols = s } var ideSymbolsInformation []lsp.SymbolInformation if clangSymbolsInformation != nil { @@ -777,7 +777,7 @@ func (ls *INOLanguageServer) TextDocumentDocumentSymbolReqFromIDE(ctx context.Co return ideDocSymbols, ideSymbolsInformation, nil } -func (ls *INOLanguageServer) TextDocumentCodeActionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.CodeActionParams) ([]lsp.CommandOrCodeAction, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentCodeActionReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.CodeActionParams) ([]lsp.CommandOrCodeAction, *jsonrpc.ResponseError) { ls.readLock(logger, true) defer ls.readUnlock(logger) @@ -846,7 +846,7 @@ func (ls *INOLanguageServer) TextDocumentCodeActionReqFromIDE(ctx context.Contex return ideCommandsOrCodeActions, nil } -func (ls *INOLanguageServer) TextDocumentFormattingReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentFormattingReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -860,12 +860,12 @@ func (ls *INOLanguageServer) TextDocumentFormattingReqFromIDE(ctx context.Contex } clangURI := clangTextDocument.URI - if cleanup, err := ls.createClangdFormatterConfig(logger, clangURI); err != nil { + cleanup, err := ls.createClangdFormatterConfig(logger, clangURI) + if err != nil { logger.Logf("Error: %s", err) return nil, &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()} - } else { - defer cleanup() } + defer cleanup() clangParams := &lsp.DocumentFormattingParams{ WorkDoneProgressParams: ideParams.WorkDoneProgressParams, @@ -894,14 +894,14 @@ func (ls *INOLanguageServer) TextDocumentFormattingReqFromIDE(ctx context.Contex } // Edits may span over multiple .ino files, filter only the edits relative to the currently displayed file - if inoEdits, ok := ideEdits[ideURI]; !ok { + inoEdits, ok := ideEdits[ideURI] + if !ok { return []lsp.TextEdit{}, nil - } else { - return inoEdits, nil } + return inoEdits, nil } -func (ls *INOLanguageServer) TextDocumentRangeFormattingReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentRangeFormattingReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -918,12 +918,12 @@ func (ls *INOLanguageServer) TextDocumentRangeFormattingReqFromIDE(ctx context.C Range: clangRange, } - if cleanup, e := ls.createClangdFormatterConfig(logger, clangURI); e != nil { + cleanup, e := ls.createClangdFormatterConfig(logger, clangURI) + if e != nil { logger.Logf("cannot create formatter config file: %v", err) return nil, &jsonrpc.ResponseError{Code: jsonrpc.ErrorCodesInternalError, Message: err.Error()} - } else { - defer cleanup() } + defer cleanup() clangEdits, clangErr, err := ls.Clangd.conn.TextDocumentRangeFormatting(ctx, clangParams) if err != nil { @@ -947,24 +947,24 @@ func (ls *INOLanguageServer) TextDocumentRangeFormattingReqFromIDE(ctx context.C } // Edits may span over multiple .ino files, filter only the edits relative to the currently displayed file - if inoEdits, ok := sketchEdits[ideURI]; !ok { + inoEdits, ok := sketchEdits[ideURI] + if !ok { return []lsp.TextEdit{}, nil - } else { - return inoEdits, nil } + return inoEdits, nil } -func (ls *INOLanguageServer) InitializedNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.InitializedParams) { +func (ls *INOLanguageServer) initializedNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.InitializedParams) { logger.Logf("Notification is not propagated to clangd") } -func (ls *INOLanguageServer) ExitNotifFromIDE(logger jsonrpc.FunctionLogger) { +func (ls *INOLanguageServer) exitNotifFromIDE(logger jsonrpc.FunctionLogger) { ls.Clangd.conn.Exit() logger.Logf("Arduino Language Server is shutting down.") os.Exit(0) } -func (ls *INOLanguageServer) TextDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) { +func (ls *INOLanguageServer) textDocumentDidOpenNotifFromIDE(logger jsonrpc.FunctionLogger, ideParam *lsp.DidOpenTextDocumentParams) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -1023,7 +1023,7 @@ func (ls *INOLanguageServer) TextDocumentDidOpenNotifFromIDE(logger jsonrpc.Func } } -func (ls *INOLanguageServer) TextDocumentDidChangeNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidChangeTextDocumentParams) { +func (ls *INOLanguageServer) textDocumentDidChangeNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidChangeTextDocumentParams) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -1047,7 +1047,7 @@ func (ls *INOLanguageServer) TextDocumentDidChangeNotifFromIDE(logger jsonrpc.Fu // Apply the change to the tracked sketch file. trackedIdeDocID := ideTextDocIdentifier.URI.AsPath().String() if doc, ok := ls.trackedIdeDocs[trackedIdeDocID]; !ok { - logger.Logf("Error: %s", &UnknownURI{ideTextDocIdentifier.URI}) + logger.Logf("Error: %s", &UnknownURIError{ideTextDocIdentifier.URI}) return } else if updatedDoc, err := textedits.ApplyLSPTextDocumentContentChangeEvent(doc, ideParams); err != nil { logger.Logf("Error: %s", err) @@ -1119,7 +1119,7 @@ func (ls *INOLanguageServer) TextDocumentDidChangeNotifFromIDE(logger jsonrpc.Fu } } -func (ls *INOLanguageServer) TextDocumentDidSaveNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidSaveTextDocumentParams) { +func (ls *INOLanguageServer) textDocumentDidSaveNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidSaveTextDocumentParams) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -1130,7 +1130,7 @@ func (ls *INOLanguageServer) TextDocumentDidSaveNotifFromIDE(logger jsonrpc.Func ls.triggerRebuild() } -func (ls *INOLanguageServer) TextDocumentDidCloseNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidCloseTextDocumentParams) { +func (ls *INOLanguageServer) textDocumentDidCloseNotifFromIDE(logger jsonrpc.FunctionLogger, ideParams *lsp.DidCloseTextDocumentParams) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) @@ -1173,14 +1173,15 @@ func (ls *INOLanguageServer) TextDocumentDidCloseNotifFromIDE(logger jsonrpc.Fun } } -func (ls *INOLanguageServer) FullBuildCompletedFromIDE(logger jsonrpc.FunctionLogger, params *DidCompleteBuildParams) { +func (ls *INOLanguageServer) fullBuildCompletedFromIDE(logger jsonrpc.FunctionLogger, params *DidCompleteBuildParams) { ls.writeLock(logger, true) defer ls.writeUnlock(logger) - ls.CopyFullBuildResults(logger, params.BuildOutputUri.AsPath()) + ls.CopyFullBuildResults(logger, params.BuildOutputURI.AsPath()) ls.triggerRebuild() } +// CopyFullBuildResults copies the results of a full build in the LS workspace func (ls *INOLanguageServer) CopyFullBuildResults(logger jsonrpc.FunctionLogger, buildPath *paths.Path) { fromCache := buildPath.Join("libraries.cache") toCache := ls.buildPath.Join("libraries.cache") @@ -1191,7 +1192,7 @@ func (ls *INOLanguageServer) CopyFullBuildResults(logger jsonrpc.FunctionLogger, } } -func (ls *INOLanguageServer) PublishDiagnosticsNotifFromClangd(logger jsonrpc.FunctionLogger, clangParams *lsp.PublishDiagnosticsParams) { +func (ls *INOLanguageServer) publishDiagnosticsNotifFromClangd(logger jsonrpc.FunctionLogger, clangParams *lsp.PublishDiagnosticsParams) { if ls.config.DisableRealTimeDiagnostics { logger.Logf("Ignored by configuration") return @@ -1271,7 +1272,7 @@ func (ls *INOLanguageServer) PublishDiagnosticsNotifFromClangd(logger jsonrpc.Fu } } -func (ls *INOLanguageServer) TextDocumentRenameReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.RenameParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { +func (ls *INOLanguageServer) textDocumentRenameReqFromIDE(ctx context.Context, logger jsonrpc.FunctionLogger, ideParams *lsp.RenameParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { ls.writeLock(logger, false) defer ls.writeUnlock(logger) @@ -1317,7 +1318,7 @@ func (ls *INOLanguageServer) ideURIIsPartOfTheSketch(ideURI lsp.DocumentURI) boo return res } -func (ls *INOLanguageServer) ProgressNotifFromClangd(logger jsonrpc.FunctionLogger, progress *lsp.ProgressParams) { +func (ls *INOLanguageServer) progressNotifFromClangd(logger jsonrpc.FunctionLogger, progress *lsp.ProgressParams) { var token string if err := json.Unmarshal(progress.Token, &token); err != nil { logger.Logf("error decoding progress token: %s", err) @@ -1338,7 +1339,7 @@ func (ls *INOLanguageServer) ProgressNotifFromClangd(logger jsonrpc.FunctionLogg } } -func (ls *INOLanguageServer) WindowWorkDoneProgressCreateReqFromClangd(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCreateParams) *jsonrpc.ResponseError { +func (ls *INOLanguageServer) windowWorkDoneProgressCreateReqFromClangd(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCreateParams) *jsonrpc.ResponseError { var token string if err := json.Unmarshal(params.Token, &token); err != nil { logger.Logf("error decoding progress token: %s", err) @@ -1348,7 +1349,7 @@ func (ls *INOLanguageServer) WindowWorkDoneProgressCreateReqFromClangd(ctx conte return nil } -func (ls *INOLanguageServer) SetTraceNotifFromIDE(logger jsonrpc.FunctionLogger, params *lsp.SetTraceParams) { +func (ls *INOLanguageServer) setTraceNotifFromIDE(logger jsonrpc.FunctionLogger, params *lsp.SetTraceParams) { logger.Logf("Notification level set to: %s", params.Value) ls.Clangd.conn.SetTrace(params) } @@ -1574,10 +1575,11 @@ func (ls *INOLanguageServer) cpp2inoTextEdit(logger jsonrpc.FunctionLogger, cppU return inoURI, inoEdit, inPreprocessed, err } -type UnknownURI struct { +// UnknownURIError is an error when an URI is not recognized +type UnknownURIError struct { URI lsp.DocumentURI } -func (e *UnknownURI) Error() string { +func (e *UnknownURIError) Error() string { return "Document is not available: " + e.URI.String() } diff --git a/ls/ls_clang_to_ide.go b/ls/ls_clang_to_ide.go index 76e1298..95ce82c 100644 --- a/ls/ls_clang_to_ide.go +++ b/ls/ls_clang_to_ide.go @@ -87,7 +87,7 @@ func (ls *INOLanguageServer) clang2IdeDocumentURI(logger jsonrpc.FunctionLogger, return ideDoc.URI, nil } } - return lsp.DocumentURI{}, &UnknownURI{URI: clangURI} + return lsp.DocumentURI{}, &UnknownURIError{URI: clangURI} } // /another/global/path/to/source.cpp <-> /another/global/path/to/source.cpp diff --git a/ls/ls_ide_to_clang.go b/ls/ls_ide_to_clang.go index fc49771..fb3e9e4 100644 --- a/ls/ls_ide_to_clang.go +++ b/ls/ls_ide_to_clang.go @@ -20,7 +20,7 @@ func (ls *INOLanguageServer) idePathToIdeURI(logger jsonrpc.FunctionLogger, inoP logger.Logf(" !!! > %s", p) } uri := lsp.NewDocumentURI(inoPath) - return uri, &UnknownURI{uri} + return uri, &UnknownURIError{uri} } return doc.URI, nil } @@ -44,7 +44,7 @@ func (ls *INOLanguageServer) ide2ClangDocumentURI(logger jsonrpc.FunctionLogger, inside, err := idePath.IsInsideDir(ls.sketchRoot) if err != nil { logger.Logf("ERROR: could not determine if '%s' is inside '%s'", idePath, ls.sketchRoot) - return lsp.NilURI, false, &UnknownURI{ideURI} + return lsp.NilURI, false, &UnknownURIError{ideURI} } if !inside { clangURI := ideURI @@ -94,9 +94,8 @@ func (ls *INOLanguageServer) ide2ClangRange(logger jsonrpc.FunctionLogger, ideUR if ls.clangURIRefersToIno(clangURI) { if clangRange, ok := ls.sketchMapper.InoToCppLSPRangeOk(ideURI, ideRange); ok { return clangURI, clangRange, nil - } else { - return lsp.DocumentURI{}, lsp.Range{}, fmt.Errorf("invalid range %s:%s: could not be mapped to Arduino-preprocessed sketck.ino.cpp", ideURI, ideRange) } + return lsp.DocumentURI{}, lsp.Range{}, fmt.Errorf("invalid range %s:%s: could not be mapped to Arduino-preprocessed sketck.ino.cpp", ideURI, ideRange) } else if inSketch { // Convert other sketch file ranges (.cpp/.h) clangRange := ideRange diff --git a/ls/lsp_client_clangd.go b/ls/lsp_client_clangd.go index 60300af..f21f4d1 100644 --- a/ls/lsp_client_clangd.go +++ b/ls/lsp_client_clangd.go @@ -16,12 +16,13 @@ import ( "go.bug.st/lsp/jsonrpc" ) -type ClangdLSPClient struct { +type clangdLSPClient struct { conn *lsp.Client ls *INOLanguageServer } -func NewClangdLSPClient(logger jsonrpc.FunctionLogger, dataFolder *paths.Path, ls *INOLanguageServer) *ClangdLSPClient { +// newClangdLSPClient creates and returns a new client +func newClangdLSPClient(logger jsonrpc.FunctionLogger, dataFolder *paths.Path, ls *INOLanguageServer) *clangdLSPClient { clangdConfFile := ls.buildPath.Join(".clangd") clangdConf := fmt.Sprintln("Diagnostics:") clangdConf += fmt.Sprintln(" Suppress: [anon_bitfield_qualifiers]") @@ -68,11 +69,11 @@ func NewClangdLSPClient(logger jsonrpc.FunctionLogger, dataFolder *paths.Path, l go io.Copy(os.Stderr, clangdStderr) } - client := &ClangdLSPClient{ + client := &clangdLSPClient{ ls: ls, } client.conn = lsp.NewClient(clangdStdio, clangdStdio, client) - client.conn.SetLogger(&LSPLogger{ + client.conn.SetLogger(&Logger{ IncomingPrefix: "IDE LS <-- Clangd", OutgoingPrefix: "IDE LS --> Clangd", HiColor: color.HiRedString, @@ -82,73 +83,90 @@ func NewClangdLSPClient(logger jsonrpc.FunctionLogger, dataFolder *paths.Path, l return client } -func (client *ClangdLSPClient) Run() { +// Run sends a Run notification to Clangd +func (client *clangdLSPClient) Run() { client.conn.Run() } -func (client *ClangdLSPClient) Close() { +// Close sends an Exit notification to Clangd +func (client *clangdLSPClient) Close() { client.conn.Exit() // send "exit" notification to Clangd // TODO: kill client.conn } // The following are events incoming from Clangd -func (client *ClangdLSPClient) WindowShowMessageRequest(context.Context, jsonrpc.FunctionLogger, *lsp.ShowMessageRequestParams) (*lsp.MessageActionItem, *jsonrpc.ResponseError) { +// WindowShowMessageRequest is not implemented +func (client *clangdLSPClient) WindowShowMessageRequest(context.Context, jsonrpc.FunctionLogger, *lsp.ShowMessageRequestParams) (*lsp.MessageActionItem, *jsonrpc.ResponseError) { panic("unimplemented") } -func (client *ClangdLSPClient) WindowShowDocument(context.Context, jsonrpc.FunctionLogger, *lsp.ShowDocumentParams) (*lsp.ShowDocumentResult, *jsonrpc.ResponseError) { +// WindowShowDocument is not implemented +func (client *clangdLSPClient) WindowShowDocument(context.Context, jsonrpc.FunctionLogger, *lsp.ShowDocumentParams) (*lsp.ShowDocumentResult, *jsonrpc.ResponseError) { panic("unimplemented") } -func (client *ClangdLSPClient) WindowWorkDoneProgressCreate(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCreateParams) *jsonrpc.ResponseError { - return client.ls.WindowWorkDoneProgressCreateReqFromClangd(ctx, logger, params) +// WindowWorkDoneProgressCreate is not implemented +func (client *clangdLSPClient) WindowWorkDoneProgressCreate(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCreateParams) *jsonrpc.ResponseError { + return client.ls.windowWorkDoneProgressCreateReqFromClangd(ctx, logger, params) } -func (client *ClangdLSPClient) ClientRegisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.RegistrationParams) *jsonrpc.ResponseError { +// ClientRegisterCapability is not implemented +func (client *clangdLSPClient) ClientRegisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.RegistrationParams) *jsonrpc.ResponseError { panic("unimplemented") } -func (client *ClangdLSPClient) ClientUnregisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.UnregistrationParams) *jsonrpc.ResponseError { +// ClientUnregisterCapability is not implemented +func (client *clangdLSPClient) ClientUnregisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.UnregistrationParams) *jsonrpc.ResponseError { panic("unimplemented") } -func (client *ClangdLSPClient) WorkspaceWorkspaceFolders(context.Context, jsonrpc.FunctionLogger) ([]lsp.WorkspaceFolder, *jsonrpc.ResponseError) { +// WorkspaceWorkspaceFolders is not implemented +func (client *clangdLSPClient) WorkspaceWorkspaceFolders(context.Context, jsonrpc.FunctionLogger) ([]lsp.WorkspaceFolder, *jsonrpc.ResponseError) { panic("unimplemented") } -func (client *ClangdLSPClient) WorkspaceConfiguration(context.Context, jsonrpc.FunctionLogger, *lsp.ConfigurationParams) ([]json.RawMessage, *jsonrpc.ResponseError) { +// WorkspaceConfiguration is not implemented +func (client *clangdLSPClient) WorkspaceConfiguration(context.Context, jsonrpc.FunctionLogger, *lsp.ConfigurationParams) ([]json.RawMessage, *jsonrpc.ResponseError) { panic("unimplemented") } -func (client *ClangdLSPClient) WorkspaceApplyEdit(context.Context, jsonrpc.FunctionLogger, *lsp.ApplyWorkspaceEditParams) (*lsp.ApplyWorkspaceEditResult, *jsonrpc.ResponseError) { +// WorkspaceApplyEdit is not implemented +func (client *clangdLSPClient) WorkspaceApplyEdit(context.Context, jsonrpc.FunctionLogger, *lsp.ApplyWorkspaceEditParams) (*lsp.ApplyWorkspaceEditResult, *jsonrpc.ResponseError) { panic("unimplemented") } -func (client *ClangdLSPClient) WorkspaceCodeLensRefresh(context.Context, jsonrpc.FunctionLogger) *jsonrpc.ResponseError { +// WorkspaceCodeLensRefresh is not implemented +func (client *clangdLSPClient) WorkspaceCodeLensRefresh(context.Context, jsonrpc.FunctionLogger) *jsonrpc.ResponseError { panic("unimplemented") } -func (client *ClangdLSPClient) Progress(logger jsonrpc.FunctionLogger, progress *lsp.ProgressParams) { - client.ls.ProgressNotifFromClangd(logger, progress) +// Progress sends a Progress notification +func (client *clangdLSPClient) Progress(logger jsonrpc.FunctionLogger, progress *lsp.ProgressParams) { + client.ls.progressNotifFromClangd(logger, progress) } -func (client *ClangdLSPClient) LogTrace(jsonrpc.FunctionLogger, *lsp.LogTraceParams) { +// LogTrace is not implemented +func (client *clangdLSPClient) LogTrace(jsonrpc.FunctionLogger, *lsp.LogTraceParams) { panic("unimplemented") } -func (client *ClangdLSPClient) WindowShowMessage(jsonrpc.FunctionLogger, *lsp.ShowMessageParams) { +// WindowShowMessage is not implemented +func (client *clangdLSPClient) WindowShowMessage(jsonrpc.FunctionLogger, *lsp.ShowMessageParams) { panic("unimplemented") } -func (client *ClangdLSPClient) WindowLogMessage(jsonrpc.FunctionLogger, *lsp.LogMessageParams) { +// WindowLogMessage is not implemented +func (client *clangdLSPClient) WindowLogMessage(jsonrpc.FunctionLogger, *lsp.LogMessageParams) { panic("unimplemented") } -func (client *ClangdLSPClient) TelemetryEvent(jsonrpc.FunctionLogger, json.RawMessage) { +// TelemetryEvent is not implemented +func (client *clangdLSPClient) TelemetryEvent(jsonrpc.FunctionLogger, json.RawMessage) { panic("unimplemented") } -func (client *ClangdLSPClient) TextDocumentPublishDiagnostics(logger jsonrpc.FunctionLogger, params *lsp.PublishDiagnosticsParams) { - go client.ls.PublishDiagnosticsNotifFromClangd(logger, params) +// TextDocumentPublishDiagnostics sends a notification to Publish Dignostics +func (client *clangdLSPClient) TextDocumentPublishDiagnostics(logger jsonrpc.FunctionLogger, params *lsp.PublishDiagnosticsParams) { + go client.ls.publishDiagnosticsNotifFromClangd(logger, params) } diff --git a/ls/lsp_logger.go b/ls/lsp_logger.go index 4f39eff..f56c3ed 100644 --- a/ls/lsp_logger.go +++ b/ls/lsp_logger.go @@ -10,7 +10,8 @@ import ( "go.bug.st/lsp/jsonrpc" ) -type LSPLogger struct { +// Logger is a lsp logger +type Logger struct { IncomingPrefix, OutgoingPrefix string HiColor, LoColor func(format string, a ...interface{}) string ErrorColor func(format string, a ...interface{}) string @@ -20,69 +21,90 @@ func init() { log.SetFlags(log.Lmicroseconds) } -func (l *LSPLogger) LogOutgoingRequest(id string, method string, params json.RawMessage) { +// LogOutgoingRequest prints an outgoing request into the log +func (l *Logger) LogOutgoingRequest(id string, method string, params json.RawMessage) { log.Print(l.HiColor("%s REQU %s %s", l.OutgoingPrefix, method, id)) } -func (l *LSPLogger) LogOutgoingCancelRequest(id string) { + +// LogOutgoingCancelRequest prints an outgoing cancel request into the log +func (l *Logger) LogOutgoingCancelRequest(id string) { log.Print(l.LoColor("%s CANCEL %s", l.OutgoingPrefix, id)) } -func (l *LSPLogger) LogIncomingResponse(id string, method string, resp json.RawMessage, respErr *jsonrpc.ResponseError) { + +// LogIncomingResponse prints an incoming response into the log if there is no error +func (l *Logger) LogIncomingResponse(id string, method string, resp json.RawMessage, respErr *jsonrpc.ResponseError) { e := "" if respErr != nil { e = l.ErrorColor(" ERROR: %s", respErr.AsError()) } log.Print(l.LoColor("%s RESP %s %s%s", l.IncomingPrefix, method, id, e)) } -func (l *LSPLogger) LogOutgoingNotification(method string, params json.RawMessage) { + +// LogOutgoingNotification prints an outgoing notification into the log +func (l *Logger) LogOutgoingNotification(method string, params json.RawMessage) { log.Print(l.HiColor("%s NOTIF %s", l.OutgoingPrefix, method)) } -func (l *LSPLogger) LogIncomingRequest(id string, method string, params json.RawMessage) jsonrpc.FunctionLogger { +// LogIncomingRequest prints an incoming request into the log +func (l *Logger) LogIncomingRequest(id string, method string, params json.RawMessage) jsonrpc.FunctionLogger { spaces := " " log.Print(l.HiColor(fmt.Sprintf("%s REQU %s %s", l.IncomingPrefix, method, id))) - return &LSPFunctionLogger{ + return &FunctionLogger{ colorFunc: l.HiColor, prefix: fmt.Sprintf("%s %s %s", spaces[:len(l.IncomingPrefix)], method, id), } } -func (l *LSPLogger) LogIncomingCancelRequest(id string) { + +// LogIncomingCancelRequest prints an incoming cancel request into the log +func (l *Logger) LogIncomingCancelRequest(id string) { log.Print(l.LoColor("%s CANCEL %s", l.IncomingPrefix, id)) } -func (l *LSPLogger) LogOutgoingResponse(id string, method string, resp json.RawMessage, respErr *jsonrpc.ResponseError) { + +// LogOutgoingResponse prints an outgoing response into the log if there is no error +func (l *Logger) LogOutgoingResponse(id string, method string, resp json.RawMessage, respErr *jsonrpc.ResponseError) { e := "" if respErr != nil { e = l.ErrorColor(" ERROR: %s", respErr.AsError()) } log.Print(l.LoColor("%s RESP %s %s%s", l.OutgoingPrefix, method, id, e)) } -func (l *LSPLogger) LogIncomingNotification(method string, params json.RawMessage) jsonrpc.FunctionLogger { + +// LogIncomingNotification prints an incoming notification into the log +func (l *Logger) LogIncomingNotification(method string, params json.RawMessage) jsonrpc.FunctionLogger { spaces := " " log.Print(l.HiColor(fmt.Sprintf("%s NOTIF %s", l.IncomingPrefix, method))) - return &LSPFunctionLogger{ + return &FunctionLogger{ colorFunc: l.HiColor, prefix: fmt.Sprintf("%s %s", spaces[:len(l.IncomingPrefix)], method), } } -func (l *LSPLogger) LogIncomingDataDelay(delay time.Duration) { + +// LogIncomingDataDelay prints the delay of incoming data into the log +func (l *Logger) LogIncomingDataDelay(delay time.Duration) { log.Printf("IN Elapsed: %v", delay) } -func (l *LSPLogger) LogOutgoingDataDelay(delay time.Duration) { + +// LogOutgoingDataDelay prints the delay of outgoing data into the log +func (l *Logger) LogOutgoingDataDelay(delay time.Duration) { log.Printf("OUT Elapsed: %v", delay) } -type LSPFunctionLogger struct { +// FunctionLogger is a lsp function logger +type FunctionLogger struct { colorFunc func(format string, a ...interface{}) string prefix string } -func NewLSPFunctionLogger(colofFunction func(format string, a ...interface{}) string, prefix string) *LSPFunctionLogger { +// NewLSPFunctionLogger creates a new function logger +func NewLSPFunctionLogger(colofFunction func(format string, a ...interface{}) string, prefix string) *FunctionLogger { color.NoColor = false - return &LSPFunctionLogger{ + return &FunctionLogger{ colorFunc: colofFunction, prefix: prefix, } } -func (l *LSPFunctionLogger) Logf(format string, a ...interface{}) { +// Logf logs the given message +func (l *FunctionLogger) Logf(format string, a ...interface{}) { log.Print(l.colorFunc(l.prefix+": "+format, a...)) } diff --git a/ls/lsp_server_ide.go b/ls/lsp_server_ide.go index b1fd386..b5e8ff2 100644 --- a/ls/lsp_server_ide.go +++ b/ls/lsp_server_ide.go @@ -10,18 +10,20 @@ import ( "go.bug.st/lsp/jsonrpc" ) +// IDELSPServer is an IDE lsp server type IDELSPServer struct { conn *lsp.Server ls *INOLanguageServer } +// NewIDELSPServer creates and return a new server func NewIDELSPServer(logger jsonrpc.FunctionLogger, in io.Reader, out io.Writer, ls *INOLanguageServer) *IDELSPServer { server := &IDELSPServer{ ls: ls, } server.conn = lsp.NewServer(in, out, server) server.conn.RegisterCustomNotification("ino/didCompleteBuild", server.ArduinoBuildCompleted) - server.conn.SetLogger(&LSPLogger{ + server.conn.SetLogger(&Logger{ IncomingPrefix: "IDE --> LS", OutgoingPrefix: "IDE <-- LS", HiColor: color.HiGreenString, @@ -31,204 +33,254 @@ func NewIDELSPServer(logger jsonrpc.FunctionLogger, in io.Reader, out io.Writer, return server } +// Run runs the server connection func (server *IDELSPServer) Run() { server.conn.Run() } +// Initialize sends an initilize request func (server *IDELSPServer) Initialize(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.InitializeParams) (*lsp.InitializeResult, *jsonrpc.ResponseError) { - return server.ls.InitializeReqFromIDE(ctx, logger, params) + return server.ls.initializeReqFromIDE(ctx, logger, params) } +// Shutdown sends a shutdown request func (server *IDELSPServer) Shutdown(ctx context.Context, logger jsonrpc.FunctionLogger) *jsonrpc.ResponseError { - return server.ls.ShutdownReqFromIDE(ctx, logger) + return server.ls.shutdownReqFromIDE(ctx, logger) } +// WorkspaceSymbol is not implemented func (server *IDELSPServer) WorkspaceSymbol(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkspaceSymbolParams) ([]lsp.SymbolInformation, *jsonrpc.ResponseError) { panic("unimplemented") } +// WorkspaceExecuteCommand is not implemented func (server *IDELSPServer) WorkspaceExecuteCommand(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.ExecuteCommandParams) (json.RawMessage, *jsonrpc.ResponseError) { panic("unimplemented") } +// WorkspaceWillCreateFiles is not implemented func (server *IDELSPServer) WorkspaceWillCreateFiles(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CreateFilesParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { panic("unimplemented") } +// WorkspaceWillRenameFiles is not implemented func (server *IDELSPServer) WorkspaceWillRenameFiles(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.RenameFilesParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { panic("unimplemented") } +// WorkspaceWillDeleteFiles is not implemented func (server *IDELSPServer) WorkspaceWillDeleteFiles(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DeleteFilesParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentWillSaveWaitUntil is not implemented func (server *IDELSPServer) TextDocumentWillSaveWaitUntil(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WillSaveTextDocumentParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentCompletion is not implemented func (server *IDELSPServer) TextDocumentCompletion(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CompletionParams) (*lsp.CompletionList, *jsonrpc.ResponseError) { - return server.ls.TextDocumentCompletionReqFromIDE(ctx, logger, params) + return server.ls.textDocumentCompletionReqFromIDE(ctx, logger, params) } +// CompletionItemResolve is not implemented func (server *IDELSPServer) CompletionItemResolve(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CompletionItem) (*lsp.CompletionItem, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentHover sends a request to hover a text document func (server *IDELSPServer) TextDocumentHover(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.HoverParams) (*lsp.Hover, *jsonrpc.ResponseError) { - return server.ls.TextDocumentHoverReqFromIDE(ctx, logger, params) + return server.ls.textDocumentHoverReqFromIDE(ctx, logger, params) } +// TextDocumentSignatureHelp requests help for text document signature func (server *IDELSPServer) TextDocumentSignatureHelp(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.SignatureHelpParams) (*lsp.SignatureHelp, *jsonrpc.ResponseError) { - return server.ls.TextDocumentSignatureHelpReqFromIDE(ctx, logger, params) + return server.ls.textDocumentSignatureHelpReqFromIDE(ctx, logger, params) } +// TextDocumentDeclaration is not implemented func (server *IDELSPServer) TextDocumentDeclaration(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DeclarationParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentDefinition sends a request to define a text document func (server *IDELSPServer) TextDocumentDefinition(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { - return server.ls.TextDocumentDefinitionReqFromIDE(ctx, logger, params) + return server.ls.textDocumentDefinitionReqFromIDE(ctx, logger, params) } +// TextDocumentTypeDefinition sends a request to define a type for the text document func (server *IDELSPServer) TextDocumentTypeDefinition(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.TypeDefinitionParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { - return server.ls.TextDocumentTypeDefinitionReqFromIDE(ctx, logger, params) + return server.ls.textDocumentTypeDefinitionReqFromIDE(ctx, logger, params) } +// TextDocumentImplementation sends a request to implement a text document func (server *IDELSPServer) TextDocumentImplementation(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.ImplementationParams) ([]lsp.Location, []lsp.LocationLink, *jsonrpc.ResponseError) { - return server.ls.TextDocumentImplementationReqFromIDE(ctx, logger, params) + return server.ls.textDocumentImplementationReqFromIDE(ctx, logger, params) } +// TextDocumentReferences is not implemented func (server *IDELSPServer) TextDocumentReferences(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.ReferenceParams) ([]lsp.Location, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentDocumentHighlight sends a request to highlight a text document func (server *IDELSPServer) TextDocumentDocumentHighlight(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, *jsonrpc.ResponseError) { - return server.ls.TextDocumentDocumentHighlightReqFromIDE(ctx, logger, params) + return server.ls.textDocumentDocumentHighlightReqFromIDE(ctx, logger, params) } +// TextDocumentDocumentSymbol sends a request for text document symbol func (server *IDELSPServer) TextDocumentDocumentSymbol(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, []lsp.SymbolInformation, *jsonrpc.ResponseError) { - return server.ls.TextDocumentDocumentSymbolReqFromIDE(ctx, logger, params) + return server.ls.textDocumentDocumentSymbolReqFromIDE(ctx, logger, params) } +// TextDocumentCodeAction sends a request for text document code action func (server *IDELSPServer) TextDocumentCodeAction(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CodeActionParams) ([]lsp.CommandOrCodeAction, *jsonrpc.ResponseError) { - return server.ls.TextDocumentCodeActionReqFromIDE(ctx, logger, params) + return server.ls.textDocumentCodeActionReqFromIDE(ctx, logger, params) } +// CodeActionResolve is not implemented func (server *IDELSPServer) CodeActionResolve(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CodeAction) (*lsp.CodeAction, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentCodeLens is not implemented func (server *IDELSPServer) TextDocumentCodeLens(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CodeLensParams) ([]lsp.CodeLens, *jsonrpc.ResponseError) { panic("unimplemented") } +// CodeLensResolve is not implemented func (server *IDELSPServer) CodeLensResolve(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CodeLens) (*lsp.CodeLens, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentDocumentLink is not implemented func (server *IDELSPServer) TextDocumentDocumentLink(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentLinkParams) ([]lsp.DocumentLink, *jsonrpc.ResponseError) { panic("unimplemented") } +// DocumentLinkResolve is not implemented func (server *IDELSPServer) DocumentLinkResolve(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentLink) (*lsp.DocumentLink, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentDocumentColor is not implemented func (server *IDELSPServer) TextDocumentDocumentColor(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentColorParams) ([]lsp.ColorInformation, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentColorPresentation is not implemented func (server *IDELSPServer) TextDocumentColorPresentation(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.ColorPresentationParams) ([]lsp.ColorPresentation, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentFormatting sends a request to format a text document func (server *IDELSPServer) TextDocumentFormatting(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { - return server.ls.TextDocumentFormattingReqFromIDE(ctx, logger, params) + return server.ls.textDocumentFormattingReqFromIDE(ctx, logger, params) } +// TextDocumentRangeFormatting sends a request to format the range a text document func (server *IDELSPServer) TextDocumentRangeFormatting(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { - return server.ls.TextDocumentRangeFormattingReqFromIDE(ctx, logger, params) + return server.ls.textDocumentRangeFormattingReqFromIDE(ctx, logger, params) } +// TextDocumentOnTypeFormatting is not implemented func (server *IDELSPServer) TextDocumentOnTypeFormatting(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.DocumentOnTypeFormattingParams) ([]lsp.TextEdit, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentRename sends a request to rename a text document func (server *IDELSPServer) TextDocumentRename(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.RenameParams) (*lsp.WorkspaceEdit, *jsonrpc.ResponseError) { - return server.ls.TextDocumentRenameReqFromIDE(ctx, logger, params) + return server.ls.textDocumentRenameReqFromIDE(ctx, logger, params) } +// TextDocumentFoldingRange is not implemented func (server *IDELSPServer) TextDocumentFoldingRange(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.FoldingRangeParams) ([]lsp.FoldingRange, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentSelectionRange is not implemented func (server *IDELSPServer) TextDocumentSelectionRange(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.SelectionRangeParams) ([]lsp.SelectionRange, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentPrepareCallHierarchy is not implemented func (server *IDELSPServer) TextDocumentPrepareCallHierarchy(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CallHierarchyPrepareParams) ([]lsp.CallHierarchyItem, *jsonrpc.ResponseError) { panic("unimplemented") } +// CallHierarchyIncomingCalls is not implemented func (server *IDELSPServer) CallHierarchyIncomingCalls(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CallHierarchyIncomingCallsParams) ([]lsp.CallHierarchyIncomingCall, *jsonrpc.ResponseError) { panic("unimplemented") } +// CallHierarchyOutgoingCalls is not implemented func (server *IDELSPServer) CallHierarchyOutgoingCalls(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.CallHierarchyOutgoingCallsParams) ([]lsp.CallHierarchyOutgoingCall, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentSemanticTokensFull is not implemented func (server *IDELSPServer) TextDocumentSemanticTokensFull(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.SemanticTokensParams) (*lsp.SemanticTokens, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentSemanticTokensFullDelta is not implemented func (server *IDELSPServer) TextDocumentSemanticTokensFullDelta(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.SemanticTokensDeltaParams) (*lsp.SemanticTokens, *lsp.SemanticTokensDelta, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentSemanticTokensRange is not implemented func (server *IDELSPServer) TextDocumentSemanticTokensRange(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.SemanticTokensRangeParams) (*lsp.SemanticTokens, *jsonrpc.ResponseError) { panic("unimplemented") } +// WorkspaceSemanticTokensRefresh is not implemented func (server *IDELSPServer) WorkspaceSemanticTokensRefresh(ctx context.Context, logger jsonrpc.FunctionLogger) *jsonrpc.ResponseError { panic("unimplemented") } +// TextDocumentLinkedEditingRange is not implemented func (server *IDELSPServer) TextDocumentLinkedEditingRange(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.LinkedEditingRangeParams) (*lsp.LinkedEditingRanges, *jsonrpc.ResponseError) { panic("unimplemented") } +// TextDocumentMoniker is not implemented func (server *IDELSPServer) TextDocumentMoniker(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.MonikerParams) ([]lsp.Moniker, *jsonrpc.ResponseError) { panic("unimplemented") } // Notifications -> +// Progress is not implemented func (server *IDELSPServer) Progress(logger jsonrpc.FunctionLogger, params *lsp.ProgressParams) { panic("unimplemented") } +// Initialized sends an initialized notification func (server *IDELSPServer) Initialized(logger jsonrpc.FunctionLogger, params *lsp.InitializedParams) { - server.ls.InitializedNotifFromIDE(logger, params) + server.ls.initializedNotifFromIDE(logger, params) } +// Exit sends an exit notification func (server *IDELSPServer) Exit(logger jsonrpc.FunctionLogger) { - server.ls.ExitNotifFromIDE(logger) + server.ls.exitNotifFromIDE(logger) } +// SetTrace sends a set trace notification func (server *IDELSPServer) SetTrace(logger jsonrpc.FunctionLogger, params *lsp.SetTraceParams) { - server.ls.SetTraceNotifFromIDE(logger, params) + server.ls.setTraceNotifFromIDE(logger, params) } +// WindowWorkDoneProgressCancel is not implemented func (server *IDELSPServer) WindowWorkDoneProgressCancel(logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCancelParams) { panic("unimplemented") } +// WorkspaceDidChangeWorkspaceFolders is not implemented func (server *IDELSPServer) WorkspaceDidChangeWorkspaceFolders(logger jsonrpc.FunctionLogger, params *lsp.DidChangeWorkspaceFoldersParams) { panic("unimplemented") } +// WorkspaceDidChangeConfiguration purpose is explained below func (server *IDELSPServer) WorkspaceDidChangeConfiguration(logger jsonrpc.FunctionLogger, params *lsp.DidChangeConfigurationParams) { // At least one LSP client, Eglot, sends this by default when // first connecting, even if the otions are empty. @@ -240,47 +292,57 @@ func (server *IDELSPServer) WorkspaceDidChangeConfiguration(logger jsonrpc.Funct } +// WorkspaceDidChangeWatchedFiles is not implemented func (server *IDELSPServer) WorkspaceDidChangeWatchedFiles(logger jsonrpc.FunctionLogger, params *lsp.DidChangeWatchedFilesParams) { panic("unimplemented") } +// WorkspaceDidCreateFiles is not implemented func (server *IDELSPServer) WorkspaceDidCreateFiles(logger jsonrpc.FunctionLogger, params *lsp.CreateFilesParams) { panic("unimplemented") } +// WorkspaceDidRenameFiles is not implemented func (server *IDELSPServer) WorkspaceDidRenameFiles(logger jsonrpc.FunctionLogger, params *lsp.RenameFilesParams) { panic("unimplemented") } +// WorkspaceDidDeleteFiles is not implemented func (server *IDELSPServer) WorkspaceDidDeleteFiles(logger jsonrpc.FunctionLogger, params *lsp.DeleteFilesParams) { panic("unimplemented") } +// TextDocumentDidOpen sends a notification the a text document is open func (server *IDELSPServer) TextDocumentDidOpen(logger jsonrpc.FunctionLogger, params *lsp.DidOpenTextDocumentParams) { - server.ls.TextDocumentDidOpenNotifFromIDE(logger, params) + server.ls.textDocumentDidOpenNotifFromIDE(logger, params) } +// TextDocumentDidChange sends a notification the a text document has changed func (server *IDELSPServer) TextDocumentDidChange(logger jsonrpc.FunctionLogger, params *lsp.DidChangeTextDocumentParams) { - server.ls.TextDocumentDidChangeNotifFromIDE(logger, params) + server.ls.textDocumentDidChangeNotifFromIDE(logger, params) } +// TextDocumentWillSave is not implemented func (server *IDELSPServer) TextDocumentWillSave(logger jsonrpc.FunctionLogger, params *lsp.WillSaveTextDocumentParams) { panic("unimplemented") } +// TextDocumentDidSave sends a notification the a text document has been saved func (server *IDELSPServer) TextDocumentDidSave(logger jsonrpc.FunctionLogger, params *lsp.DidSaveTextDocumentParams) { - server.ls.TextDocumentDidSaveNotifFromIDE(logger, params) + server.ls.textDocumentDidSaveNotifFromIDE(logger, params) } +// TextDocumentDidClose sends a notification the a text document has been closed func (server *IDELSPServer) TextDocumentDidClose(logger jsonrpc.FunctionLogger, params *lsp.DidCloseTextDocumentParams) { - server.ls.TextDocumentDidCloseNotifFromIDE(logger, params) + server.ls.textDocumentDidCloseNotifFromIDE(logger, params) } // DidCompleteBuildParams is a custom notification from the Arduino IDE, sent type DidCompleteBuildParams struct { - BuildOutputUri *lsp.DocumentURI `json:"buildOutputUri"` + BuildOutputURI *lsp.DocumentURI `json:"buildOutputUri"` } +// ArduinoBuildCompleted handles "buildComplete" messages from the IDE func (server *IDELSPServer) ArduinoBuildCompleted(logger jsonrpc.FunctionLogger, raw json.RawMessage) { if !server.ls.config.SkipLibrariesDiscoveryOnRebuild { return @@ -290,6 +352,6 @@ func (server *IDELSPServer) ArduinoBuildCompleted(logger jsonrpc.FunctionLogger, if err := json.Unmarshal(raw, ¶ms); err != nil { logger.Logf("ERROR decoding DidCompleteBuildParams: %s", err) } else { - server.ls.FullBuildCompletedFromIDE(logger, ¶ms) + server.ls.fullBuildCompletedFromIDE(logger, ¶ms) } } diff --git a/ls/progress.go b/ls/progress.go index 8f00f0d..76de479 100644 --- a/ls/progress.go +++ b/ls/progress.go @@ -9,7 +9,7 @@ import ( "go.bug.st/lsp" ) -type ProgressProxyHandler struct { +type progressProxyHandler struct { conn *lsp.Server mux sync.Mutex actionRequiredCond *sync.Cond @@ -34,8 +34,9 @@ type progressProxy struct { endReq *lsp.WorkDoneProgressEnd } -func NewProgressProxy(conn *lsp.Server) *ProgressProxyHandler { - res := &ProgressProxyHandler{ +// newProgressProxy creates a new ProgressProxyHandler and returns its pointer +func newProgressProxy(conn *lsp.Server) *progressProxyHandler { + res := &progressProxyHandler{ conn: conn, proxies: map[string]*progressProxy{}, } @@ -47,7 +48,7 @@ func NewProgressProxy(conn *lsp.Server) *ProgressProxyHandler { return res } -func (p *ProgressProxyHandler) handlerLoop() { +func (p *progressProxyHandler) handlerLoop() { p.mux.Lock() defer p.mux.Unlock() @@ -69,7 +70,7 @@ func (p *ProgressProxyHandler) handlerLoop() { } } -func (p *ProgressProxyHandler) handleProxy(id string, proxy *progressProxy) { +func (p *progressProxyHandler) handleProxy(id string, proxy *progressProxy) { switch proxy.currentStatus { case progressProxyNew: p.mux.Unlock() @@ -131,7 +132,7 @@ func (p *ProgressProxyHandler) handleProxy(id string, proxy *progressProxy) { } } -func (p *ProgressProxyHandler) Create(id string) { +func (p *progressProxyHandler) Create(id string) { p.mux.Lock() defer p.mux.Unlock() @@ -147,7 +148,7 @@ func (p *ProgressProxyHandler) Create(id string) { p.actionRequiredCond.Broadcast() } -func (p *ProgressProxyHandler) Begin(id string, req *lsp.WorkDoneProgressBegin) { +func (p *progressProxyHandler) Begin(id string, req *lsp.WorkDoneProgressBegin) { p.mux.Lock() defer p.mux.Unlock() @@ -167,7 +168,7 @@ func (p *ProgressProxyHandler) Begin(id string, req *lsp.WorkDoneProgressBegin) p.actionRequiredCond.Broadcast() } -func (p *ProgressProxyHandler) Report(id string, req *lsp.WorkDoneProgressReport) { +func (p *progressProxyHandler) Report(id string, req *lsp.WorkDoneProgressReport) { p.mux.Lock() defer p.mux.Unlock() @@ -183,7 +184,7 @@ func (p *ProgressProxyHandler) Report(id string, req *lsp.WorkDoneProgressReport p.actionRequiredCond.Broadcast() } -func (p *ProgressProxyHandler) End(id string, req *lsp.WorkDoneProgressEnd) { +func (p *progressProxyHandler) End(id string, req *lsp.WorkDoneProgressEnd) { p.mux.Lock() defer p.mux.Unlock() @@ -197,7 +198,7 @@ func (p *ProgressProxyHandler) End(id string, req *lsp.WorkDoneProgressEnd) { p.actionRequiredCond.Broadcast() } -func (p *ProgressProxyHandler) Shutdown() { +func (p *progressProxyHandler) Shutdown() { p.mux.Lock() defer p.mux.Unlock() diff --git a/sourcemapper/ino.go b/sourcemapper/ino.go index 6911efd..1c5648a 100644 --- a/sourcemapper/ino.go +++ b/sourcemapper/ino.go @@ -30,6 +30,7 @@ var NotIno = InoLine{"/not-ino", 0} // NotInoURI is the DocumentURI that do not belongs to an .ino file var NotInoURI, _ = lsp.NewDocumentURIFromURL("file:///not-ino") +// SourceRevision is a source code tagged with a version number type SourceRevision struct { Version int Text string