├── .circleci └── config.yml ├── .codecov.yml ├── .gitattributes ├── .github └── workflows │ └── codeql.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── base.go ├── base_test.go ├── basic.go ├── basic_test.go ├── callhierarchy.go ├── callhierarchy_test.go ├── capabilities_client.go ├── capabilities_client_test.go ├── capabilities_server.go ├── client.go ├── context.go ├── deprecated.go ├── diagnostics.go ├── diagnostics_test.go ├── doc.go ├── docs ├── README.md └── implementation-references.md ├── errors.go ├── general.go ├── general_test.go ├── go.mod ├── go.sum ├── hack ├── boilerplate │ └── boilerplate.go.txt └── make │ └── go.mk ├── handler.go ├── language.go ├── language_test.go ├── log.go ├── progress.go ├── progress_test.go ├── protocol.go ├── registration.go ├── registration_test.go ├── selectionrange.go ├── semantic_token.go ├── server.go ├── text.go ├── text_test.go ├── tools ├── go.mod ├── go.sum └── tools.go ├── util.go ├── util_test.go ├── version.go ├── window.go ├── window_test.go ├── workspace.go └── workspace_test.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | codecov: codecov/codecov@3.2.2 5 | 6 | executors: 7 | golang: 8 | parameters: 9 | go-version: 10 | type: string 11 | docker: 12 | - image: "golang:<< parameters.go-version >>-bullseye" 13 | working_directory: /go/src/go.lsp.dev/protocol 14 | 15 | command_vars: 16 | - cache_key: &cache_key gomod-<< parameters.go-version >>-{{ checksum "go.mod" }}-{{ checksum "go.sum" }}-2ptat08qmr4k 17 | - cache_tools_key: &cache_tools_key tools-<< parameters.go-version >>-{{ checksum "tools/go.mod" }}-{{ checksum "tools/go.sum" }}-2ptat08qmr4k 18 | 19 | commands: 20 | restore_dependencies: 21 | parameters: 22 | go-version: 23 | type: string 24 | steps: 25 | - restore_cache: 26 | name: "Restore module dependencies cache" 27 | keys: 28 | - *cache_key 29 | - restore_cache: 30 | name: "Restore dependencies tools" 31 | keys: 32 | - *cache_tools_key 33 | - run: 34 | name: "Download project modules" 35 | command: | 36 | go mod download 37 | 38 | save_dependencies: 39 | parameters: 40 | go-version: 41 | type: string 42 | steps: 43 | - save_cache: 44 | name: "Save module cache" 45 | key: *cache_key 46 | paths: 47 | - /go/pkg/mod/cache 48 | - save_cache: 49 | name: "Save dependencies tools" 50 | key: *cache_tools_key 51 | paths: 52 | - /go/bin/ 53 | - run: 54 | name: "go mod vendor" 55 | command: | 56 | go mod vendor 57 | 58 | install_tools: 59 | steps: 60 | - run: 61 | name: "Build project tools" 62 | command: | 63 | if [ -z $(find /go/bin/ -mindepth 1 -type f | head -1) ]; then 64 | make -j${CPUS} tools GOBIN=/go/bin 65 | fi 66 | 67 | setup: 68 | steps: 69 | - checkout 70 | - run: 71 | name: Check versions 72 | command: | 73 | go version 74 | go env 75 | - attach_workspace: 76 | name: "Attach vendor directory and dependencies tools" 77 | at: "/go" 78 | - run: 79 | name: "go mod vendor" 80 | command: | 81 | go mod vendor 82 | - run: 83 | name: "Parse CPUs" 84 | command: | 85 | # https://circleci.com/changelog#container-cgroup-limits-now-visible-inside-the-docker-executor 86 | CPUS="$(echo $(($(cat /sys/fs/cgroup/cpu/cpu.shares) / 1024)))" 87 | echo "export GOFLAGS='-p=${CPUS} -cpu=${CPUS}'" >> $BASH_ENV 88 | echo "export CPUS=${CPUS}" >> $BASH_ENV 89 | 90 | jobs: 91 | tools: 92 | parameters: 93 | go-version: 94 | type: string 95 | executor: 96 | name: golang 97 | go-version: "<< parameters.go-version >>" 98 | resource_class: xlarge 99 | steps: 100 | - checkout 101 | - restore_dependencies: 102 | go-version: "<< parameters.go-version >>" 103 | - install_tools 104 | - save_dependencies: 105 | go-version: "<< parameters.go-version >>" 106 | - persist_to_workspace: 107 | root: /go 108 | paths: 109 | - bin 110 | - pkg/mod/cache 111 | 112 | test: 113 | parameters: 114 | go-version: 115 | type: string 116 | executor: 117 | name: golang 118 | go-version: "<< parameters.go-version >>" 119 | resource_class: xlarge 120 | steps: 121 | - run: 122 | name: Test and take a coverage 123 | environment: 124 | GOTESTSUM_FORMAT: standard-verbose 125 | GOTESTSUM_JUNITFILE: /tmp/test-results/tests.xml 126 | GOTESTSUM_JSONFILE: /tmp/test-results/tests.json 127 | command: | 128 | mkdir -p /tmp/test-results 129 | make coverage 130 | - codecov/upload: 131 | when: on_success 132 | 133 | lint: 134 | parameters: 135 | go-version: 136 | type: string 137 | executor: 138 | name: golang 139 | go-version: "<< parameters.go-version >>" 140 | resource_class: large 141 | steps: 142 | - run: 143 | name: Run fmt and lint for sources 144 | command: | 145 | make lint JOBS=${CPUS} 146 | git add -N . && git diff --exit-code 147 | 148 | workflows: 149 | version: 2 150 | go1.18: 151 | jobs: 152 | - tools: 153 | name: go1.18-tools 154 | go-version: "1.18" 155 | - test: 156 | name: go1.18-test 157 | go-version: "1.18" 158 | requires: 159 | - go1.18-tools 160 | pre-steps: 161 | - setup 162 | post-steps: 163 | - store_test_results: 164 | path: /tmp/test-results 165 | - store_artifacts: 166 | path: /tmp/test-results 167 | - lint: 168 | name: go1.18-lint 169 | go-version: "1.18" 170 | requires: 171 | - go1.18-tools 172 | pre-steps: 173 | - setup 174 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | allow_coverage_offsets: true 3 | 4 | parsers: 5 | go: 6 | partials_as_hits: true 7 | 8 | coverage: 9 | precision: 1 10 | round: down 11 | range: "70...100" 12 | 13 | status: 14 | default_rules: 15 | flag_coverage_not_uploaded_behavior: include 16 | 17 | project: 18 | default: 19 | target: auto 20 | threshold: 1% 21 | if_not_found: success 22 | if_ci_failed: error 23 | 24 | patch: 25 | default: 26 | only_pulls: true 27 | target: 50% 28 | threshold: 10% 29 | 30 | changes: 31 | default: 32 | target: auto 33 | threshold: 10% 34 | if_not_found: success 35 | if_ci_failed: error 36 | branches: 37 | - main 38 | 39 | comment: 40 | behavior: default 41 | require_changes: true 42 | show_carryforward_flags: true 43 | 44 | github_checks: 45 | annotations: true 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # go.lsp.dev/protocol project gitattributes file 2 | # https://github.com/github/linguist#using-gitattributes 3 | # https://github.com/github/linguist/blob/master/lib/linguist/languages.yml 4 | 5 | # To prevent CRLF breakages on Windows for fragile files, like testdata. 6 | * -text 7 | 8 | docs/ linguist-documentation 9 | *.pb.go linguist-generated 10 | *_gen.go linguist-generated 11 | *_string.go linguist-generated 12 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | schedule: 11 | - cron: '0 20 * * *' 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-20.04 17 | 18 | strategy: 19 | fail-fast: false 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 2 26 | 27 | - name: Install Go 28 | uses: actions/setup-go@v2 29 | with: 30 | go-version: 1.16.x 31 | 32 | - name: Initialize CodeQL 33 | uses: github/codeql-action/init@v1 34 | with: 35 | languages: go 36 | 37 | - name: Cache Go module and build cache 38 | uses: actions/cache@v2 39 | with: 40 | key: analyze-go-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }} 41 | path: | 42 | ~/go/pkg/mod 43 | ~/.cache/go-build 44 | ~/Library/Caches/go-build 45 | '%LocalAppData%\go-build' 46 | restore-keys: | 47 | analyze-go- 48 | 49 | - name: Fetch vendors 50 | run: | 51 | go mod download 52 | go mod vendor 53 | 54 | - name: Perform CodeQL Analysis 55 | uses: github/codeql-action/analyze@v1 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # go.lsp.dev/protocol project generated files to ignore 2 | # if you want to ignore files created by your editor/tools, 3 | # please consider a global .gitignore https://help.github.com/articles/ignoring-files 4 | # please do not open a pull request to add something created by your editor or tools 5 | 6 | # github/gitignore/Go.gitignore 7 | # Binaries for programs and plugins 8 | *.exe 9 | *.exe~ 10 | *.dll 11 | *.so 12 | *.dylib 13 | 14 | # Test binary, built with `go test -c` 15 | *.test 16 | 17 | # Output of the go coverage tool, specifically when used with LiteIDE 18 | *.out 19 | 20 | # Dependency directories (remove the comment below to include it) 21 | vendor/ 22 | 23 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 24 | *.o 25 | *.a 26 | 27 | # Folders 28 | _obj 29 | _test 30 | 31 | # Architecture specific extensions/prefixes 32 | *.[568vq] 33 | [568vq].out 34 | 35 | # cgo generated 36 | *.cgo1.go 37 | *.cgo2.c 38 | _cgo_defun.c 39 | _cgo_gotypes.go 40 | _cgo_export.* 41 | 42 | # test generated 43 | _testmain.go 44 | 45 | # profile 46 | *.pprof 47 | 48 | # coverage 49 | coverage.* 50 | 51 | # tools 52 | tools/bin/ 53 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # https://golangci-lint.run/usage/configuration/ 2 | # https://github.com/golangci/golangci-lint/blob/master/pkg/config/linters_settings.go 3 | --- 4 | run: 5 | timeout: 3m 6 | issues-exit-code: 1 7 | tests: true 8 | build-tags: [] 9 | allow-parallel-runners: true 10 | go: '1.22' 11 | 12 | output: 13 | formats: 14 | - format: colored-line-number 15 | path: stdout 16 | print-issued-lines: true 17 | print-linter-name: true 18 | uniq-by-line: false 19 | sort-results: true 20 | 21 | linters: 22 | fast: true 23 | disable-all: true 24 | enable: 25 | - asasalint # check for pass []any as any in variadic func(...any) 26 | - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers 27 | - bidichk # Checks for dangerous unicode character sequences 28 | - bodyclose # checks whether HTTP response body is closed successfully 29 | - containedctx # containedctx is a linter that detects struct contained context.Context field 30 | - contextcheck # check whether the function uses a non-inherited context 31 | - cyclop # checks function and package cyclomatic complexity 32 | - decorder # check declaration order and count of types, constants, variables and functions 33 | - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) 34 | - dupword # checks for duplicate words in the source code 35 | - durationcheck # check for two durations multiplied together 36 | - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. 37 | - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. 38 | - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. 39 | - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds 40 | - exportloopref # checks for pointers to enclosing loop variables 41 | - funlen # Tool for detection of long functions 42 | - ginkgolinter # enforces standards of using ginkgo and gomega 43 | - gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid 44 | - gocognit # Computes and checks the cognitive complexity of functions 45 | - gocritic # Provides diagnostics that check for bugs, performance and style issues. 46 | - gocyclo # Computes and checks the cyclomatic complexity of functions 47 | - godot # Check if comments end in a period 48 | - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification 49 | - gofumpt # Gofumpt checks whether code was gofumpt-ed. 50 | - goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. 51 | - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. 52 | - goprintffuncname # Checks that printf-like functions are named with `f` at the end 53 | - gosec # Inspects source code for security problems 54 | - gosimple # Linter for Go source code that specializes in simplifying code 55 | - gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase 56 | - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string 57 | - grouper # An analyzer to analyze expression groups. 58 | - importas # Enforces consistent import aliases 59 | - inamedparam # reports interfaces with unnamed method parameters [fast: true, auto-fix: false] 60 | - ineffassign # Detects when assignments to existing variables are not used 61 | - intrange # intrange is a linter to find places where for loops could make use of an integer range. [fast: true, auto-fix: false] 62 | - loggercheck # Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). 63 | - maintidx # maintidx measures the maintainability index of each function. 64 | - makezero # Finds slice declarations with non-zero initial length 65 | - mirror # reports wrong mirror patterns of bytes/strings usage 66 | - misspell # Finds commonly misspelled English words in comments 67 | - musttag # enforce field tags in (un)marshaled structs [fast: false, auto-fix: false] 68 | - nakedret # Finds naked returns in functions greater than a specified function length 69 | - nestif # Reports deeply nested if statements 70 | - nilerr # Finds the code that returns nil even if it checks that the error is not nil. 71 | - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. 72 | - noctx # noctx finds sending http request without context.Context 73 | - nolintlint # Reports ill-formed or insufficient nolint directives 74 | - nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. 75 | - prealloc # Finds slice declarations that could potentially be pre-allocated 76 | - predeclared # find code that shadows one of Go's predeclared identifiers 77 | - promlinter # Check Prometheus metrics naming via promlint 78 | - protogetter # Reports direct reads from proto message fields when getters should be used [fast: false, auto-fix: true] 79 | - reassign # Checks that package variables are not reassigned 80 | - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. 81 | - rowserrcheck # checks whether Err of rows is checked successfully 82 | - sloglint # ensure consistent code style when using log/slog [fast: false, auto-fix: false] 83 | - spancheck # Checks for mistakes with OpenTelemetry/Census spans. [fast: false, auto-fix: false] 84 | - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. 85 | - staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. 86 | - stylecheck # Stylecheck is a replacement for golint 87 | - tagalign # check that struct tags are well aligned 88 | - tagliatelle # Checks the struct tags. 89 | - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 90 | - testableexamples # linter checks if examples are testable (have an expected output) 91 | - thelper # thelper detects Go test helpers without t.Helper() call and checks the consistency of test helpers 92 | - unconvert # Remove unnecessary type conversions 93 | - unparam # Reports unused function parameters 94 | - unused # Checks Go code for unused constants, variables, functions and types 95 | - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library 96 | - varnamelen # checks that the length of a variable's name matches its scope 97 | - wastedassign # wastedassign finds wasted assignment statements. 98 | - whitespace # Tool for detection of leading and trailing whitespace 99 | - zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false] 100 | 101 | linters-settings: 102 | asasalint: 103 | exclude: [] 104 | use-builtin-exclusions: true 105 | ignore-test: false 106 | cyclop: 107 | max-complexity: 15 108 | # package-average: 109 | skip-tests: true 110 | errorlint: 111 | errorf: true 112 | asserts: true 113 | comparison: true 114 | funlen: 115 | lines: 120 116 | statements: 60 117 | gocognit: 118 | min-complexity: 30 119 | gocritic: 120 | enabled-tags: 121 | - diagnostic 122 | - experimental 123 | - opinionated 124 | - performance 125 | - style 126 | disabled-checks: 127 | - commentedOutCode 128 | - deprecatedComment 129 | - whyNoLint 130 | settings: 131 | hugeParam: 132 | sizeThreshold: 80 133 | rangeExprCopy: 134 | sizeThreshold: 512 135 | rangeValCopy: 136 | sizeThreshold: 128 137 | gocyclo: 138 | min-complexity: 30 139 | godot: 140 | scope: declarations 141 | capital: false 142 | gofmt: 143 | simplify: true 144 | gofumpt: 145 | extra-rules: true 146 | goimports: 147 | local-prefixes: go.lsp.dev/protocol/ 148 | govet: 149 | enable-all: true 150 | disable: 151 | - fieldalignment 152 | importas: 153 | alias: [] 154 | no-unaliased: true 155 | lll: 156 | line-length: 200 157 | tab-width: 1 158 | maintidx: 159 | under: 15 160 | misspell: 161 | locale: US 162 | ignore-words: 163 | - cancelled 164 | - cancelling 165 | nakedret: 166 | max-func-lines: 30 167 | nestif: 168 | min-complexity: 4 169 | prealloc: 170 | simple: true 171 | range-loops: true 172 | for-loops: true 173 | testpackage: 174 | skip-regexp: '.*(export)_test\.go' 175 | unparam: 176 | check-exported: true 177 | varnamelen: 178 | max-distance: 5 179 | min-name-length: 1 180 | check-receiver: true 181 | check-return: true 182 | ignore-type-assert-ok: false 183 | ignore-map-index-ok: false 184 | ignore-chan-recv-ok: false 185 | whitespace: 186 | multi-if: true 187 | multi-func: true 188 | 189 | issues: 190 | include: 191 | # include revive rules 192 | - "EXC0013" 193 | - "EXC0014" 194 | - "EXC0015" 195 | max-issues-per-linter: 0 196 | exclude-dirs-use-default: true 197 | exclude-dirs: [] 198 | exclude-files: [] 199 | max-same-issues: 0 200 | exclude-use-default: true 201 | exclude-rules: 202 | - path: _test\.go 203 | linters: 204 | - errcheck 205 | - funlen 206 | - gocognit 207 | - goconst 208 | - gocyclo 209 | - gosec 210 | - lll 211 | - wrapcheck 212 | - path: "(.*)?_example_test.go" 213 | linters: 214 | - gocritic 215 | # Exclude shadow checking on the variable named err 216 | - text: "shadow: declaration of \"err|ok|ctx\"" 217 | linters: 218 | - govet 219 | - text: "continue with no blank line before" 220 | linters: 221 | - nlreturn 222 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, The Go Language Server Authors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------- 2 | # global 3 | 4 | .DEFAULT_GOAL := test 5 | comma := , 6 | empty := 7 | space := $(empty) $(empty) 8 | 9 | # ----------------------------------------------------------------------------- 10 | # go 11 | 12 | GO_PATH ?= $(shell go env GOPATH) 13 | 14 | PKG := $(subst $(GO_PATH)/src/,,$(CURDIR)) 15 | CGO_ENABLED ?= 0 16 | GO_BUILDTAGS=osusergo,netgo,static 17 | GO_LDFLAGS=-s -w "-extldflags=-static" 18 | GO_FLAGS ?= -tags='$(subst $(space),$(comma),${GO_BUILDTAGS})' -ldflags='${GO_LDFLAGS}' -installsuffix=netgo 19 | 20 | TOOLS_DIR := ${CURDIR}/tools 21 | TOOLS_BIN := ${TOOLS_DIR}/bin 22 | TOOLS := $(shell cd ${TOOLS_DIR} && go list -e -v -x -f '{{ join .Imports " " }}' -tags=tools) 23 | 24 | GO_PKGS := ./... 25 | 26 | GO_TEST ?= ${TOOLS_BIN}/gotestsum -- 27 | GO_TEST_PKGS ?= $(shell go list -f='{{if or .TestGoFiles .XTestGoFiles}}{{.ImportPath}}{{end}}' ./...) 28 | GO_TEST_FLAGS ?= -race -count=1 29 | GO_TEST_FUNC ?= . 30 | GO_BENCH_FLAGS ?= -benchmem 31 | GO_BENCH_FUNC ?= . 32 | GO_LINT_FLAGS ?= 33 | 34 | # Set build environment 35 | JOBS := $(shell getconf _NPROCESSORS_CONF) 36 | 37 | # ----------------------------------------------------------------------------- 38 | # defines 39 | 40 | define target 41 | @printf "+ $(patsubst ,$@,$(1))\\n" >&2 42 | endef 43 | 44 | # ----------------------------------------------------------------------------- 45 | # target 46 | 47 | ##@ test, bench, coverage 48 | 49 | export GOTESTSUM_FORMAT=standard-verbose 50 | 51 | .PHONY: test 52 | test: CGO_ENABLED=1 53 | test: tools/bin/gotestsum ## Runs package test including race condition. 54 | $(call target) 55 | @CGO_ENABLED=${CGO_ENABLED} ${GO_TEST} ${GO_TEST_FLAGS} -run=${GO_TEST_FUNC} -tags='$(subst $(space),$(comma),${GO_BUILDTAGS})' ${GO_TEST_PKGS} 56 | 57 | .PHONY: coverage 58 | coverage: CGO_ENABLED=1 59 | coverage: tools/bin/gotestsum ## Takes packages test coverage. 60 | $(call target) 61 | CGO_ENABLED=${CGO_ENABLED} ${GO_TEST} ${GO_TEST_FLAGS} -covermode=atomic -coverpkg=./... -coverprofile=coverage.out $(strip ${GO_FLAGS}) ${GO_PKGS} 62 | 63 | 64 | ##@ fmt, lint 65 | 66 | .PHONY: fmt 67 | fmt: tools/goimportz tools/gofumpt ## Run goimportz and gofumpt. 68 | $(call target) 69 | find . -iname "*.go" -not -path "./vendor/**" | xargs -P ${JOBS} ${TOOLS_BIN}/goimportz -local=${PKG},$(subst /protocol,,$(PKG)) -w 70 | find . -iname "*.go" -not -path "./vendor/**" | xargs -P ${JOBS} ${TOOLS_BIN}/gofumpt -extra -w 71 | 72 | .PHONY: lint 73 | lint: lint/golangci-lint ## Run all linters. 74 | 75 | .PHONY: lint/golangci-lint 76 | lint/golangci-lint: tools/golangci-lint .golangci.yml ## Run golangci-lint. 77 | $(call target) 78 | ${TOOLS_BIN}/golangci-lint -j ${JOBS} run $(strip ${GO_LINT_FLAGS}) ./... 79 | 80 | 81 | ##@ tools 82 | 83 | .PHONY: tools 84 | tools: tools/bin/'' ## Install tools 85 | 86 | tools/%: ## install an individual dependent tool 87 | @${MAKE} tools/bin/$* 1>/dev/null 88 | 89 | tools/bin/%: ${TOOLS_DIR}/go.mod ${TOOLS_DIR}/go.sum 90 | @cd tools; \ 91 | for t in ${TOOLS}; do \ 92 | if [ -z '$*' ] || [ $$(basename $$t) = '$*' ]; then \ 93 | echo "Install $$t ..." >&2; \ 94 | GOBIN=${TOOLS_BIN} CGO_ENABLED=0 go install -mod=mod ${GO_FLAGS} "$${t}"; \ 95 | fi \ 96 | done 97 | 98 | 99 | ##@ clean 100 | 101 | .PHONY: clean 102 | clean: ## Cleanups binaries and extra files in the package. 103 | $(call target) 104 | @rm -rf *.out *.test *.prof trace.txt ${TOOLS_BIN} 105 | 106 | 107 | ##@ miscellaneous 108 | 109 | .PHONY: todo 110 | TODO: ## Print the all of (TODO|BUG|XXX|FIXME|NOTE) in packages. 111 | @grep -E '(TODO|BUG|XXX|FIXME)(\(.+\):|:)' $(shell find . -type f -name '*.go' -and -not -iwholename '*vendor*') 112 | 113 | .PHONY: nolint 114 | nolint: ## Print the all of //nolint:... pragma in packages. 115 | @grep -E -C 3 '//nolint.+' $(shell find . -type f -name '*.go' -and -not -iwholename '*vendor*' -and -not -iwholename '*internal*') 116 | 117 | .PHONY: env/% 118 | env/%: ## Print the value of MAKEFILE_VARIABLE. Use `make env/GO_FLAGS` or etc. 119 | @echo $($*) 120 | 121 | 122 | ##@ help 123 | 124 | .PHONY: help 125 | help: ## Show this help. 126 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[33m\033[0m\n"} /^[a-zA-Z_0-9\/%_-]+:.*?##/ { printf " \033[1;32m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protocol 2 | 3 | [![CircleCI][circleci-badge]][circleci] [![pkg.go.dev][pkg.go.dev-badge]][pkg.go.dev] [![Go module][module-badge]][module] [![codecov.io][codecov-badge]][codecov] [![GA][ga-badge]][ga] 4 | 5 | Package protocol implements Language Server Protocol specification in Go. 6 | 7 | 8 | 9 | [circleci]: https://app.circleci.com/pipelines/github/go-language-server/protocol 10 | [pkg.go.dev]: https://pkg.go.dev/go.lsp.dev/protocol 11 | [module]: https://github.com/go-language-server/protocol/releases/latest 12 | [codecov]: https://codecov.io/gh/go-language-server/protocol 13 | [ga]: https://github.com/go-language-server/protocol 14 | 15 | [circleci-badge]: https://img.shields.io/circleci/build/github/go-language-server/protocol/main.svg?style=for-the-badge&label=CIRCLECI&logo=circleci 16 | [pkg.go.dev-badge]: https://bit.ly/pkg-go-dev-badge 17 | [module-badge]: https://img.shields.io/github/release/go-language-server/protocol.svg?color=007D9C&label=MODULE&style=for-the-badge&logoWidth=25&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ijg1IDU1IDEyMCAxMjAiPjxwYXRoIGZpbGw9IiMwMEFERDgiIGQ9Ik00MC4yIDEwMS4xYy0uNCAwLS41LS4yLS4zLS41bDIuMS0yLjdjLjItLjMuNy0uNSAxLjEtLjVoMzUuN2MuNCAwIC41LjMuMy42bC0xLjcgMi42Yy0uMi4zLS43LjYtMSAuNmwtMzYuMi0uMXptLTE1LjEgOS4yYy0uNCAwLS41LS4yLS4zLS41bDIuMS0yLjdjLjItLjMuNy0uNSAxLjEtLjVoNDUuNmMuNCAwIC42LjMuNS42bC0uOCAyLjRjLS4xLjQtLjUuNi0uOS42bC00Ny4zLjF6bTI0LjIgOS4yYy0uNCAwLS41LS4zLS4zLS42bDEuNC0yLjVjLjItLjMuNi0uNiAxLS42aDIwYy40IDAgLjYuMy42LjdsLS4yIDIuNGMwIC40LS40LjctLjcuN2wtMjEuOC0uMXptMTAzLjgtMjAuMmMtNi4zIDEuNi0xMC42IDIuOC0xNi44IDQuNC0xLjUuNC0xLjYuNS0yLjktMS0xLjUtMS43LTIuNi0yLjgtNC43LTMuOC02LjMtMy4xLTEyLjQtMi4yLTE4LjEgMS41LTYuOCA0LjQtMTAuMyAxMC45LTEwLjIgMTkgLjEgOCA1LjYgMTQuNiAxMy41IDE1LjcgNi44LjkgMTIuNS0xLjUgMTctNi42LjktMS4xIDEuNy0yLjMgMi43LTMuN2gtMTkuM2MtMi4xIDAtMi42LTEuMy0xLjktMyAxLjMtMy4xIDMuNy04LjMgNS4xLTEwLjkuMy0uNiAxLTEuNiAyLjUtMS42aDM2LjRjLS4yIDIuNy0uMiA1LjQtLjYgOC4xLTEuMSA3LjItMy44IDEzLjgtOC4yIDE5LjYtNy4yIDkuNS0xNi42IDE1LjQtMjguNSAxNy05LjggMS4zLTE4LjktLjYtMjYuOS02LjYtNy40LTUuNi0xMS42LTEzLTEyLjctMjIuMi0xLjMtMTAuOSAxLjktMjAuNyA4LjUtMjkuMyA3LjEtOS4zIDE2LjUtMTUuMiAyOC0xNy4zIDkuNC0xLjcgMTguNC0uNiAyNi41IDQuOSA1LjMgMy41IDkuMSA4LjMgMTEuNiAxNC4xLjYuOS4yIDEuNC0xIDEuN3oiLz48cGF0aCBmaWxsPSIjMDBBREQ4IiBkPSJNMTg2LjIgMTU0LjZjLTkuMS0uMi0xNy40LTIuOC0yNC40LTguOC01LjktNS4xLTkuNi0xMS42LTEwLjgtMTkuMy0xLjgtMTEuMyAxLjMtMjEuMyA4LjEtMzAuMiA3LjMtOS42IDE2LjEtMTQuNiAyOC0xNi43IDEwLjItMS44IDE5LjgtLjggMjguNSA1LjEgNy45IDUuNCAxMi44IDEyLjcgMTQuMSAyMi4zIDEuNyAxMy41LTIuMiAyNC41LTExLjUgMzMuOS02LjYgNi43LTE0LjcgMTAuOS0yNCAxMi44LTIuNy41LTUuNC42LTggLjl6bTIzLjgtNDAuNGMtLjEtMS4zLS4xLTIuMy0uMy0zLjMtMS44LTkuOS0xMC45LTE1LjUtMjAuNC0xMy4zLTkuMyAyLjEtMTUuMyA4LTE3LjUgMTcuNC0xLjggNy44IDIgMTUuNyA5LjIgMTguOSA1LjUgMi40IDExIDIuMSAxNi4zLS42IDcuOS00LjEgMTIuMi0xMC41IDEyLjctMTkuMXoiLz48L3N2Zz4= 18 | [codecov-badge]: https://img.shields.io/codecov/c/github/go-language-server/protocol/main?logo=codecov&style=for-the-badge 19 | [ga-badge]: https://gh-ga-beacon.appspot.com/UA-89201129-1/go-language-server/protocol?useReferer&pixel 20 | -------------------------------------------------------------------------------- /base.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/segmentio/encoding/json" 10 | ) 11 | 12 | // CancelParams params of cancelRequest. 13 | type CancelParams struct { 14 | // ID is the request id to cancel. 15 | ID interface{} `json:"id"` // int32 | string 16 | } 17 | 18 | // ProgressParams params of Progress netification. 19 | // 20 | // @since 3.15.0. 21 | type ProgressParams struct { 22 | // Token is the progress token provided by the client or server. 23 | Token ProgressToken `json:"token"` 24 | 25 | // Value is the progress data. 26 | Value interface{} `json:"value"` 27 | } 28 | 29 | // ProgressToken is the progress token provided by the client or server. 30 | // 31 | // @since 3.15.0. 32 | type ProgressToken struct { 33 | name string 34 | number int32 35 | } 36 | 37 | // compile time check whether the ProgressToken implements a fmt.Formatter, fmt.Stringer, json.Marshaler and json.Unmarshaler interfaces. 38 | var ( 39 | _ fmt.Formatter = (*ProgressToken)(nil) 40 | _ fmt.Stringer = (*ProgressToken)(nil) 41 | _ json.Marshaler = (*ProgressToken)(nil) 42 | _ json.Unmarshaler = (*ProgressToken)(nil) 43 | ) 44 | 45 | // NewProgressToken returns a new ProgressToken. 46 | func NewProgressToken(s string) *ProgressToken { 47 | return &ProgressToken{name: s} 48 | } 49 | 50 | // NewNumberProgressToken returns a new number ProgressToken. 51 | func NewNumberProgressToken(n int32) *ProgressToken { 52 | return &ProgressToken{number: n} 53 | } 54 | 55 | // Format writes the ProgressToken to the formatter. 56 | // 57 | // If the rune is q the representation is non ambiguous, 58 | // string forms are quoted. 59 | func (v ProgressToken) Format(f fmt.State, r rune) { 60 | const numF = `%d` 61 | strF := `%s` 62 | if r == 'q' { 63 | strF = `%q` 64 | } 65 | 66 | switch { 67 | case v.name != "": 68 | fmt.Fprintf(f, strF, v.name) 69 | default: 70 | fmt.Fprintf(f, numF, v.number) 71 | } 72 | } 73 | 74 | // String returns a string representation of the ProgressToken. 75 | func (v ProgressToken) String() string { 76 | return fmt.Sprint(v) //nolint:gocritic 77 | } 78 | 79 | // MarshalJSON implements json.Marshaler. 80 | func (v *ProgressToken) MarshalJSON() ([]byte, error) { 81 | if v.name != "" { 82 | return json.Marshal(v.name) 83 | } 84 | 85 | return json.Marshal(v.number) 86 | } 87 | 88 | // UnmarshalJSON implements json.Unmarshaler. 89 | func (v *ProgressToken) UnmarshalJSON(data []byte) error { 90 | *v = ProgressToken{} 91 | if err := json.Unmarshal(data, &v.number); err == nil { 92 | return nil 93 | } 94 | 95 | return json.Unmarshal(data, &v.name) 96 | } 97 | -------------------------------------------------------------------------------- /base_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "reflect" 8 | "testing" 9 | 10 | "github.com/google/go-cmp/cmp" 11 | "github.com/google/go-cmp/cmp/cmpopts" 12 | "github.com/segmentio/encoding/json" 13 | ) 14 | 15 | func TestCancelParams(t *testing.T) { 16 | t.Parallel() 17 | 18 | const want = `{"id":"testID"}` 19 | wantType := CancelParams{ 20 | ID: "testID", 21 | } 22 | 23 | t.Run("Marshal", func(t *testing.T) { 24 | t.Parallel() 25 | 26 | tests := []struct { 27 | name string 28 | field CancelParams 29 | want string 30 | wantMarshalErr bool 31 | wantErr bool 32 | }{ 33 | { 34 | name: "Valid", 35 | field: wantType, 36 | want: want, 37 | wantMarshalErr: false, 38 | wantErr: false, 39 | }, 40 | } 41 | 42 | for _, tt := range tests { 43 | tt := tt 44 | t.Run(tt.name, func(t *testing.T) { 45 | t.Parallel() 46 | 47 | got, err := json.Marshal(&tt.field) 48 | if (err != nil) != tt.wantMarshalErr { 49 | t.Fatal(err) 50 | } 51 | 52 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 53 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 54 | } 55 | }) 56 | } 57 | }) 58 | 59 | t.Run("Unmarshal", func(t *testing.T) { 60 | t.Parallel() 61 | 62 | tests := []struct { 63 | name string 64 | field string 65 | want CancelParams 66 | wantUnmarshalErr bool 67 | wantErr bool 68 | }{ 69 | { 70 | name: "Valid", 71 | field: want, 72 | want: wantType, 73 | wantUnmarshalErr: false, 74 | wantErr: false, 75 | }, 76 | } 77 | 78 | for _, tt := range tests { 79 | tt := tt 80 | t.Run(tt.name, func(t *testing.T) { 81 | t.Parallel() 82 | 83 | var got CancelParams 84 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 85 | t.Fatal(err) 86 | } 87 | 88 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 89 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 90 | } 91 | }) 92 | } 93 | }) 94 | } 95 | 96 | func TestProgressParams(t *testing.T) { 97 | t.Parallel() 98 | 99 | const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" 100 | const want = `{"token":"` + wantWorkDoneToken + `","value":"testValue"}` 101 | 102 | token := NewProgressToken(wantWorkDoneToken) 103 | wantType := ProgressParams{ 104 | Token: *token, 105 | Value: "testValue", 106 | } 107 | 108 | t.Run("Marshal", func(t *testing.T) { 109 | t.Parallel() 110 | 111 | tests := []struct { 112 | name string 113 | field ProgressParams 114 | want string 115 | wantMarshalErr bool 116 | wantErr bool 117 | }{ 118 | { 119 | name: "Valid", 120 | field: wantType, 121 | want: want, 122 | wantMarshalErr: false, 123 | wantErr: false, 124 | }, 125 | } 126 | 127 | for _, tt := range tests { 128 | tt := tt 129 | t.Run(tt.name, func(t *testing.T) { 130 | t.Parallel() 131 | 132 | got, err := json.Marshal(&tt.field) 133 | if (err != nil) != tt.wantMarshalErr { 134 | t.Fatal(err) 135 | } 136 | 137 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 138 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 139 | } 140 | }) 141 | } 142 | }) 143 | 144 | t.Run("Unmarshal", func(t *testing.T) { 145 | t.Parallel() 146 | 147 | tests := []struct { 148 | name string 149 | field string 150 | want ProgressParams 151 | wantUnmarshalErr bool 152 | wantErr bool 153 | }{ 154 | { 155 | name: "Valid", 156 | field: want, 157 | want: wantType, 158 | wantUnmarshalErr: false, 159 | wantErr: false, 160 | }, 161 | } 162 | 163 | for _, tt := range tests { 164 | tt := tt 165 | t.Run(tt.name, func(t *testing.T) { 166 | t.Parallel() 167 | 168 | var got ProgressParams 169 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 170 | t.Fatal(err) 171 | } 172 | 173 | if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(ProgressParams{}, "Token")); (diff != "") != tt.wantErr { 174 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 175 | } 176 | 177 | if token := got.Token; !reflect.ValueOf(token).IsZero() { 178 | if diff := cmp.Diff(token.String(), wantWorkDoneToken); (diff != "") != tt.wantErr { 179 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 180 | } 181 | } 182 | }) 183 | } 184 | }) 185 | } 186 | -------------------------------------------------------------------------------- /callhierarchy.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // CallHierarchy capabilities specific to the "textDocument/callHierarchy". 7 | // 8 | // @since 3.16.0. 9 | type CallHierarchy struct { 10 | // DynamicRegistration whether implementation supports dynamic registration. 11 | // 12 | // If this is set to "true" the client supports the new 13 | // TextDocumentRegistrationOptions && StaticRegistrationOptions return 14 | // value for the corresponding server capability as well. 15 | DynamicRegistration bool `json:"dynamicRegistration,omitempty"` 16 | } 17 | 18 | // CallHierarchyPrepareParams params of CallHierarchyPrepare. 19 | // 20 | // @since 3.16.0. 21 | type CallHierarchyPrepareParams struct { 22 | TextDocumentPositionParams 23 | WorkDoneProgressParams 24 | } 25 | 26 | // CallHierarchyItem is the result of a "textDocument/prepareCallHierarchy" request. 27 | // 28 | // @since 3.16.0. 29 | type CallHierarchyItem struct { 30 | // name is the name of this item. 31 | Name string `json:"name"` 32 | 33 | // Kind is the kind of this item. 34 | Kind SymbolKind `json:"kind"` 35 | 36 | // Tags for this item. 37 | Tags []SymbolTag `json:"tags,omitempty"` 38 | 39 | // Detail more detail for this item, e.g. the signature of a function. 40 | Detail string `json:"detail,omitempty"` 41 | 42 | // URI is the resource identifier of this item. 43 | URI DocumentURI `json:"uri"` 44 | 45 | // Range is the range enclosing this symbol not including leading/trailing whitespace 46 | // but everything else, e.g. comments and code. 47 | Range Range `json:"range"` 48 | 49 | // SelectionRange is the range that should be selected and revealed when this symbol is being 50 | // picked, e.g. the name of a function. Must be contained by the 51 | // Range. 52 | SelectionRange Range `json:"selectionRange"` 53 | 54 | // Data is a data entry field that is preserved between a call hierarchy prepare and 55 | // incoming calls or outgoing calls requests. 56 | Data interface{} `json:"data,omitempty"` 57 | } 58 | 59 | // CallHierarchyIncomingCallsParams params of CallHierarchyIncomingCalls. 60 | // 61 | // @since 3.16.0. 62 | type CallHierarchyIncomingCallsParams struct { 63 | WorkDoneProgressParams 64 | PartialResultParams 65 | 66 | // Item is the IncomingCalls item. 67 | Item CallHierarchyItem `json:"item"` 68 | } 69 | 70 | // CallHierarchyIncomingCall is the result of a "callHierarchy/incomingCalls" request. 71 | // 72 | // @since 3.16.0. 73 | type CallHierarchyIncomingCall struct { 74 | // From is the item that makes the call. 75 | From CallHierarchyItem `json:"from"` 76 | 77 | // FromRanges is the ranges at which the calls appear. This is relative to the caller 78 | // denoted by From. 79 | FromRanges []Range `json:"fromRanges"` 80 | } 81 | 82 | // CallHierarchyOutgoingCallsParams params of CallHierarchyOutgoingCalls. 83 | // 84 | // @since 3.16.0. 85 | type CallHierarchyOutgoingCallsParams struct { 86 | WorkDoneProgressParams 87 | PartialResultParams 88 | 89 | // Item is the OutgoingCalls item. 90 | Item CallHierarchyItem `json:"item"` 91 | } 92 | 93 | // CallHierarchyOutgoingCall is the result of a "callHierarchy/outgoingCalls" request. 94 | // 95 | // @since 3.16.0. 96 | type CallHierarchyOutgoingCall struct { 97 | // To is the item that is called. 98 | To CallHierarchyItem `json:"to"` 99 | 100 | // FromRanges is the range at which this item is called. This is the range relative to 101 | // the caller, e.g the item passed to "callHierarchy/outgoingCalls" request. 102 | FromRanges []Range `json:"fromRanges"` 103 | } 104 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "fmt" 10 | 11 | "github.com/segmentio/encoding/json" 12 | "go.uber.org/zap" 13 | 14 | "go.lsp.dev/jsonrpc2" 15 | "go.lsp.dev/pkg/xcontext" 16 | ) 17 | 18 | // ClientDispatcher returns a Client that dispatches LSP requests across the 19 | // given jsonrpc2 connection. 20 | func ClientDispatcher(conn jsonrpc2.Conn, logger *zap.Logger) Client { 21 | return &client{ 22 | Conn: conn, 23 | logger: logger, 24 | } 25 | } 26 | 27 | // ClientHandler handler of LSP client. 28 | func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler { 29 | h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { 30 | if ctx.Err() != nil { 31 | xctx := xcontext.Detach(ctx) 32 | 33 | return reply(xctx, nil, ErrRequestCancelled) 34 | } 35 | 36 | handled, err := clientDispatch(ctx, client, reply, req) 37 | if handled || err != nil { 38 | return err 39 | } 40 | 41 | return handler(ctx, reply, req) 42 | } 43 | 44 | return h 45 | } 46 | 47 | // clientDispatch implements jsonrpc2.Handler. 48 | // 49 | //nolint:funlen,cyclop 50 | func clientDispatch(ctx context.Context, client Client, reply jsonrpc2.Replier, req jsonrpc2.Request) (handled bool, err error) { 51 | if ctx.Err() != nil { 52 | return true, reply(ctx, nil, ErrRequestCancelled) 53 | } 54 | 55 | dec := json.NewDecoder(bytes.NewReader(req.Params())) 56 | logger := LoggerFromContext(ctx) 57 | 58 | switch req.Method() { 59 | case MethodProgress: // notification 60 | defer logger.Debug(MethodProgress, zap.Error(err)) 61 | 62 | var params ProgressParams 63 | if err := dec.Decode(¶ms); err != nil { 64 | return true, replyParseError(ctx, reply, err) 65 | } 66 | 67 | err := client.Progress(ctx, ¶ms) 68 | 69 | return true, reply(ctx, nil, err) 70 | 71 | case MethodWorkDoneProgressCreate: // request 72 | defer logger.Debug(MethodWorkDoneProgressCreate, zap.Error(err)) 73 | 74 | var params WorkDoneProgressCreateParams 75 | if err := dec.Decode(¶ms); err != nil { 76 | return true, replyParseError(ctx, reply, err) 77 | } 78 | 79 | err := client.WorkDoneProgressCreate(ctx, ¶ms) 80 | 81 | return true, reply(ctx, nil, err) 82 | 83 | case MethodWindowLogMessage: // notification 84 | defer logger.Debug(MethodWindowLogMessage, zap.Error(err)) 85 | 86 | var params LogMessageParams 87 | if err := dec.Decode(¶ms); err != nil { 88 | return true, replyParseError(ctx, reply, err) 89 | } 90 | 91 | err := client.LogMessage(ctx, ¶ms) 92 | 93 | return true, reply(ctx, nil, err) 94 | 95 | case MethodTextDocumentPublishDiagnostics: // notification 96 | defer logger.Debug(MethodTextDocumentPublishDiagnostics, zap.Error(err)) 97 | 98 | var params PublishDiagnosticsParams 99 | if err := dec.Decode(¶ms); err != nil { 100 | return true, replyParseError(ctx, reply, err) 101 | } 102 | 103 | err := client.PublishDiagnostics(ctx, ¶ms) 104 | 105 | return true, reply(ctx, nil, err) 106 | 107 | case MethodWindowShowMessage: // notification 108 | defer logger.Debug(MethodWindowShowMessage, zap.Error(err)) 109 | 110 | var params ShowMessageParams 111 | if err := dec.Decode(¶ms); err != nil { 112 | return true, replyParseError(ctx, reply, err) 113 | } 114 | 115 | err := client.ShowMessage(ctx, ¶ms) 116 | 117 | return true, reply(ctx, nil, err) 118 | 119 | case MethodWindowShowMessageRequest: // request 120 | defer logger.Debug(MethodWindowShowMessageRequest, zap.Error(err)) 121 | 122 | var params ShowMessageRequestParams 123 | if err := dec.Decode(¶ms); err != nil { 124 | return true, replyParseError(ctx, reply, err) 125 | } 126 | 127 | resp, err := client.ShowMessageRequest(ctx, ¶ms) 128 | 129 | return true, reply(ctx, resp, err) 130 | 131 | case MethodTelemetryEvent: // notification 132 | defer logger.Debug(MethodTelemetryEvent, zap.Error(err)) 133 | 134 | var params interface{} 135 | if err := dec.Decode(¶ms); err != nil { 136 | return true, replyParseError(ctx, reply, err) 137 | } 138 | 139 | err := client.Telemetry(ctx, ¶ms) 140 | 141 | return true, reply(ctx, nil, err) 142 | 143 | case MethodClientRegisterCapability: // request 144 | defer logger.Debug(MethodClientRegisterCapability, zap.Error(err)) 145 | 146 | var params RegistrationParams 147 | if err := dec.Decode(¶ms); err != nil { 148 | return true, replyParseError(ctx, reply, err) 149 | } 150 | 151 | err := client.RegisterCapability(ctx, ¶ms) 152 | 153 | return true, reply(ctx, nil, err) 154 | 155 | case MethodClientUnregisterCapability: // request 156 | defer logger.Debug(MethodClientUnregisterCapability, zap.Error(err)) 157 | 158 | var params UnregistrationParams 159 | if err := dec.Decode(¶ms); err != nil { 160 | return true, replyParseError(ctx, reply, err) 161 | } 162 | 163 | err := client.UnregisterCapability(ctx, ¶ms) 164 | 165 | return true, reply(ctx, nil, err) 166 | 167 | case MethodWorkspaceApplyEdit: // request 168 | defer logger.Debug(MethodWorkspaceApplyEdit, zap.Error(err)) 169 | 170 | var params ApplyWorkspaceEditParams 171 | if err := dec.Decode(¶ms); err != nil { 172 | return true, replyParseError(ctx, reply, err) 173 | } 174 | 175 | resp, err := client.ApplyEdit(ctx, ¶ms) 176 | 177 | return true, reply(ctx, resp, err) 178 | 179 | case MethodWorkspaceConfiguration: // request 180 | defer logger.Debug(MethodWorkspaceConfiguration, zap.Error(err)) 181 | 182 | var params ConfigurationParams 183 | if err := dec.Decode(¶ms); err != nil { 184 | return true, replyParseError(ctx, reply, err) 185 | } 186 | 187 | resp, err := client.Configuration(ctx, ¶ms) 188 | 189 | return true, reply(ctx, resp, err) 190 | 191 | case MethodWorkspaceWorkspaceFolders: // request 192 | defer logger.Debug(MethodWorkspaceWorkspaceFolders, zap.Error(err)) 193 | 194 | if len(req.Params()) > 0 { 195 | return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) 196 | } 197 | 198 | resp, err := client.WorkspaceFolders(ctx) 199 | 200 | return true, reply(ctx, resp, err) 201 | 202 | default: 203 | return false, nil 204 | } 205 | } 206 | 207 | // Client represents a Language Server Protocol client. 208 | type Client interface { 209 | Progress(ctx context.Context, params *ProgressParams) (err error) 210 | WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error) 211 | LogMessage(ctx context.Context, params *LogMessageParams) (err error) 212 | PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error) 213 | ShowMessage(ctx context.Context, params *ShowMessageParams) (err error) 214 | ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (result *MessageActionItem, err error) 215 | Telemetry(ctx context.Context, params interface{}) (err error) 216 | RegisterCapability(ctx context.Context, params *RegistrationParams) (err error) 217 | UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error) 218 | ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error) 219 | Configuration(ctx context.Context, params *ConfigurationParams) (result []interface{}, err error) 220 | WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error) 221 | } 222 | 223 | // list of client methods. 224 | const ( 225 | // MethodProgress method name of "$/progress". 226 | MethodProgress = "$/progress" 227 | 228 | // MethodWorkDoneProgressCreate method name of "window/workDoneProgress/create". 229 | MethodWorkDoneProgressCreate = "window/workDoneProgress/create" 230 | 231 | // MethodWindowShowMessage method name of "window/showMessage". 232 | MethodWindowShowMessage = "window/showMessage" 233 | 234 | // MethodWindowShowMessageRequest method name of "window/showMessageRequest. 235 | MethodWindowShowMessageRequest = "window/showMessageRequest" 236 | 237 | // MethodWindowLogMessage method name of "window/logMessage. 238 | MethodWindowLogMessage = "window/logMessage" 239 | 240 | // MethodTelemetryEvent method name of "telemetry/event. 241 | MethodTelemetryEvent = "telemetry/event" 242 | 243 | // MethodClientRegisterCapability method name of "client/registerCapability. 244 | MethodClientRegisterCapability = "client/registerCapability" 245 | 246 | // MethodClientUnregisterCapability method name of "client/unregisterCapability. 247 | MethodClientUnregisterCapability = "client/unregisterCapability" 248 | 249 | // MethodTextDocumentPublishDiagnostics method name of "textDocument/publishDiagnostics. 250 | MethodTextDocumentPublishDiagnostics = "textDocument/publishDiagnostics" 251 | 252 | // MethodWorkspaceApplyEdit method name of "workspace/applyEdit. 253 | MethodWorkspaceApplyEdit = "workspace/applyEdit" 254 | 255 | // MethodWorkspaceConfiguration method name of "workspace/configuration. 256 | MethodWorkspaceConfiguration = "workspace/configuration" 257 | 258 | // MethodWorkspaceWorkspaceFolders method name of "workspace/workspaceFolders". 259 | MethodWorkspaceWorkspaceFolders = "workspace/workspaceFolders" 260 | ) 261 | 262 | // client implements a Language Server Protocol client. 263 | type client struct { 264 | jsonrpc2.Conn 265 | 266 | logger *zap.Logger 267 | } 268 | 269 | // compiler time check whether the Client implements ClientInterface interface. 270 | var _ Client = (*client)(nil) 271 | 272 | // Progress is the base protocol offers also support to report progress in a generic fashion. 273 | // 274 | // This mechanism can be used to report any kind of progress including work done progress (usually used to report progress in the user interface using a progress bar) and 275 | // partial result progress to support streaming of results. 276 | // 277 | // @since 3.16.0. 278 | func (c *client) Progress(ctx context.Context, params *ProgressParams) (err error) { 279 | c.logger.Debug("call " + MethodProgress) 280 | defer c.logger.Debug("end "+MethodProgress, zap.Error(err)) 281 | 282 | return c.Conn.Notify(ctx, MethodProgress, params) 283 | } 284 | 285 | // WorkDoneProgressCreate sends the request is sent from the server to the client to ask the client to create a work done progress. 286 | // 287 | // @since 3.16.0. 288 | func (c *client) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error) { 289 | c.logger.Debug("call " + MethodWorkDoneProgressCreate) 290 | defer c.logger.Debug("end "+MethodWorkDoneProgressCreate, zap.Error(err)) 291 | 292 | return Call(ctx, c.Conn, MethodWorkDoneProgressCreate, params, nil) 293 | } 294 | 295 | // LogMessage sends the notification from the server to the client to ask the client to log a particular message. 296 | func (c *client) LogMessage(ctx context.Context, params *LogMessageParams) (err error) { 297 | c.logger.Debug("call " + MethodWindowLogMessage) 298 | defer c.logger.Debug("end "+MethodWindowLogMessage, zap.Error(err)) 299 | 300 | return c.Conn.Notify(ctx, MethodWindowLogMessage, params) 301 | } 302 | 303 | // PublishDiagnostics sends the notification from the server to the client to signal results of validation runs. 304 | // 305 | // Diagnostics are “owned” by the server so it is the server’s responsibility to clear them if necessary. The following rule is used for VS Code servers that generate diagnostics: 306 | // 307 | // - if a language is single file only (for example HTML) then diagnostics are cleared by the server when the file is closed. 308 | // - if a language has a project system (for example C#) diagnostics are not cleared when a file closes. When a project is opened all diagnostics for all files are recomputed (or read from a cache). 309 | // 310 | // When a file changes it is the server’s responsibility to re-compute diagnostics and push them to the client. 311 | // If the computed set is empty it has to push the empty array to clear former diagnostics. 312 | // Newly pushed diagnostics always replace previously pushed diagnostics. There is no merging that happens on the client side. 313 | func (c *client) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error) { 314 | c.logger.Debug("call " + MethodTextDocumentPublishDiagnostics) 315 | defer c.logger.Debug("end "+MethodTextDocumentPublishDiagnostics, zap.Error(err)) 316 | 317 | return c.Conn.Notify(ctx, MethodTextDocumentPublishDiagnostics, params) 318 | } 319 | 320 | // ShowMessage sends the notification from a server to a client to ask the 321 | // client to display a particular message in the user interface. 322 | func (c *client) ShowMessage(ctx context.Context, params *ShowMessageParams) (err error) { 323 | return c.Conn.Notify(ctx, MethodWindowShowMessage, params) 324 | } 325 | 326 | // ShowMessageRequest sends the request from a server to a client to ask the client to display a particular message in the user interface. 327 | // 328 | // In addition to the show message notification the request allows to pass actions and to wait for an answer from the client. 329 | func (c *client) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (_ *MessageActionItem, err error) { 330 | c.logger.Debug("call " + MethodWindowShowMessageRequest) 331 | defer c.logger.Debug("end "+MethodWindowShowMessageRequest, zap.Error(err)) 332 | 333 | var result *MessageActionItem 334 | if err := Call(ctx, c.Conn, MethodWindowShowMessageRequest, params, &result); err != nil { 335 | return nil, err 336 | } 337 | 338 | return result, nil 339 | } 340 | 341 | // Telemetry sends the notification from the server to the client to ask the client to log a telemetry event. 342 | func (c *client) Telemetry(ctx context.Context, params interface{}) (err error) { 343 | c.logger.Debug("call " + MethodTelemetryEvent) 344 | defer c.logger.Debug("end "+MethodTelemetryEvent, zap.Error(err)) 345 | 346 | return c.Conn.Notify(ctx, MethodTelemetryEvent, params) 347 | } 348 | 349 | // RegisterCapability sends the request from the server to the client to register for a new capability on the client side. 350 | // 351 | // Not all clients need to support dynamic capability registration. 352 | // 353 | // A client opts in via the dynamicRegistration property on the specific client capabilities. 354 | // A client can even provide dynamic registration for capability A but not for capability B (see TextDocumentClientCapabilities as an example). 355 | func (c *client) RegisterCapability(ctx context.Context, params *RegistrationParams) (err error) { 356 | c.logger.Debug("call " + MethodClientRegisterCapability) 357 | defer c.logger.Debug("end "+MethodClientRegisterCapability, zap.Error(err)) 358 | 359 | return Call(ctx, c.Conn, MethodClientRegisterCapability, params, nil) 360 | } 361 | 362 | // UnregisterCapability sends the request from the server to the client to unregister a previously registered capability. 363 | func (c *client) UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error) { 364 | c.logger.Debug("call " + MethodClientUnregisterCapability) 365 | defer c.logger.Debug("end "+MethodClientUnregisterCapability, zap.Error(err)) 366 | 367 | return Call(ctx, c.Conn, MethodClientUnregisterCapability, params, nil) 368 | } 369 | 370 | // ApplyEdit sends the request from the server to the client to modify resource on the client side. 371 | func (c *client) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error) { 372 | c.logger.Debug("call " + MethodWorkspaceApplyEdit) 373 | defer c.logger.Debug("end "+MethodWorkspaceApplyEdit, zap.Error(err)) 374 | 375 | if err := Call(ctx, c.Conn, MethodWorkspaceApplyEdit, params, &result); err != nil { 376 | return nil, err 377 | } 378 | 379 | return result, nil 380 | } 381 | 382 | // Configuration sends the request from the server to the client to fetch configuration settings from the client. 383 | // 384 | // The request can fetch several configuration settings in one roundtrip. 385 | // The order of the returned configuration settings correspond to the order of the 386 | // passed ConfigurationItems (e.g. the first item in the response is the result for the first configuration item in the params). 387 | func (c *client) Configuration(ctx context.Context, params *ConfigurationParams) (_ []interface{}, err error) { 388 | c.logger.Debug("call " + MethodWorkspaceConfiguration) 389 | defer c.logger.Debug("end "+MethodWorkspaceConfiguration, zap.Error(err)) 390 | 391 | var result []interface{} 392 | if err := Call(ctx, c.Conn, MethodWorkspaceConfiguration, params, &result); err != nil { 393 | return nil, err 394 | } 395 | 396 | return result, nil 397 | } 398 | 399 | // WorkspaceFolders sends the request from the server to the client to fetch the current open list of workspace folders. 400 | // 401 | // Returns null in the response if only a single file is open in the tool. Returns an empty array if a workspace is open but no folders are configured. 402 | // 403 | // @since 3.6.0. 404 | func (c *client) WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error) { 405 | c.logger.Debug("call " + MethodWorkspaceWorkspaceFolders) 406 | defer c.logger.Debug("end "+MethodWorkspaceWorkspaceFolders, zap.Error(err)) 407 | 408 | if err := Call(ctx, c.Conn, MethodWorkspaceWorkspaceFolders, nil, &result); err != nil { 409 | return nil, err 410 | } 411 | 412 | return result, nil 413 | } 414 | -------------------------------------------------------------------------------- /context.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "context" 8 | 9 | "go.uber.org/zap" 10 | ) 11 | 12 | type ( 13 | ctxLogger struct{} 14 | ctxClient struct{} 15 | ) 16 | 17 | // WithLogger returns the context with zap.Logger value. 18 | func WithLogger(ctx context.Context, logger *zap.Logger) context.Context { 19 | return context.WithValue(ctx, ctxLogger{}, logger) 20 | } 21 | 22 | // LoggerFromContext extracts zap.Logger from context. 23 | func LoggerFromContext(ctx context.Context) *zap.Logger { 24 | logger, ok := ctx.Value(ctxLogger{}).(*zap.Logger) 25 | if !ok { 26 | return zap.NewNop() 27 | } 28 | 29 | return logger 30 | } 31 | 32 | // WithClient returns the context with Client value. 33 | func WithClient(ctx context.Context, client Client) context.Context { 34 | return context.WithValue(ctx, ctxClient{}, client) 35 | } 36 | -------------------------------------------------------------------------------- /deprecated.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // ClientCapabilitiesShowDocument alias of ShowDocumentClientCapabilities. 7 | // 8 | // Deprecated: Use ShowDocumentClientCapabilities instead. 9 | type ClientCapabilitiesShowDocument = ShowDocumentClientCapabilities 10 | 11 | // ClientCapabilitiesShowMessageRequest alias of ShowMessageRequestClientCapabilities. 12 | // 13 | // Deprecated: Use ShowMessageRequestClientCapabilities instead. 14 | type ClientCapabilitiesShowMessageRequest = ShowMessageRequestClientCapabilities 15 | 16 | // ClientCapabilitiesShowMessageRequestMessageActionItem alias of ShowMessageRequestClientCapabilitiesMessageActionItem. 17 | // 18 | // Deprecated: Use ShowMessageRequestClientCapabilitiesMessageActionItem instead. 19 | type ClientCapabilitiesShowMessageRequestMessageActionItem = ShowMessageRequestClientCapabilitiesMessageActionItem 20 | 21 | // ReferencesParams alias of ReferenceParams. 22 | // 23 | // Deprecated: Use ReferenceParams instead. 24 | type ReferencesParams = ReferenceParams 25 | 26 | // TextDocumentClientCapabilitiesCallHierarchy alias of CallHierarchyClientCapabilities. 27 | // 28 | // Deprecated: Use CallHierarchyClientCapabilities instead. 29 | type TextDocumentClientCapabilitiesCallHierarchy = CallHierarchyClientCapabilities 30 | 31 | // TextDocumentClientCapabilitiesCodeAction alias of CodeActionClientCapabilities. 32 | // 33 | // Deprecated: Use CodeActionClientCapabilities instead. 34 | type TextDocumentClientCapabilitiesCodeAction = CodeActionClientCapabilities 35 | 36 | // TextDocumentClientCapabilitiesCodeActionKind alias of CodeActionClientCapabilitiesKind. 37 | // 38 | // Deprecated: Use CodeActionClientCapabilitiesKind instead. 39 | type TextDocumentClientCapabilitiesCodeActionKind = CodeActionClientCapabilitiesKind 40 | 41 | // TextDocumentClientCapabilitiesCodeActionLiteralSupport alias of CodeActionClientCapabilitiesLiteralSupport. 42 | // 43 | // Deprecated: Use CodeActionClientCapabilitiesLiteralSupport instead. 44 | type TextDocumentClientCapabilitiesCodeActionLiteralSupport = CodeActionClientCapabilitiesLiteralSupport 45 | 46 | // TextDocumentClientCapabilitiesCodeActionResolveSupport alias of CodeActionClientCapabilitiesResolveSupport. 47 | // 48 | // Deprecated: Use CodeActionClientCapabilitiesResolveSupport instead. 49 | type TextDocumentClientCapabilitiesCodeActionResolveSupport = CodeActionClientCapabilitiesResolveSupport 50 | 51 | // TextDocumentClientCapabilitiesCodeLens alias of CodeLensClientCapabilities. 52 | // 53 | // Deprecated: Use CodeLensClientCapabilities instead. 54 | type TextDocumentClientCapabilitiesCodeLens = CodeLensClientCapabilities 55 | 56 | // TextDocumentClientCapabilitiesColorProvider alias of DocumentColorClientCapabilities. 57 | // 58 | // Deprecated: Use DocumentColorClientCapabilities instead. 59 | type TextDocumentClientCapabilitiesColorProvider = DocumentColorClientCapabilities 60 | 61 | // TextDocumentClientCapabilitiesCompletion alias of CompletionTextDocumentClientCapabilities. 62 | // 63 | // Deprecated: Use CompletionTextDocumentClientCapabilities instead. 64 | type TextDocumentClientCapabilitiesCompletion = CompletionTextDocumentClientCapabilities 65 | 66 | // TextDocumentClientCapabilitiesCompletionItem alias of CompletionTextDocumentClientCapabilitiesItem. 67 | // 68 | // Deprecated: Use CompletionTextDocumentClientCapabilitiesItem instead. 69 | type TextDocumentClientCapabilitiesCompletionItem = CompletionTextDocumentClientCapabilitiesItem 70 | 71 | // TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport alias of CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport. 72 | // 73 | // Deprecated: Use CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport instead. 74 | type TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport = CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport 75 | 76 | // TextDocumentClientCapabilitiesCompletionItemKind alias of CompletionTextDocumentClientCapabilitiesItemKind. 77 | // 78 | // Deprecated: Use CompletionTextDocumentClientCapabilitiesItemKind instead. 79 | type TextDocumentClientCapabilitiesCompletionItemKind = CompletionTextDocumentClientCapabilitiesItemKind 80 | 81 | // TextDocumentClientCapabilitiesCompletionItemResolveSupport alias of CompletionTextDocumentClientCapabilitiesItemResolveSupport. 82 | // 83 | // Deprecated: Use CompletionTextDocumentClientCapabilitiesItemResolveSupport instead. 84 | type TextDocumentClientCapabilitiesCompletionItemResolveSupport = CompletionTextDocumentClientCapabilitiesItemResolveSupport 85 | 86 | // TextDocumentClientCapabilitiesCompletionItemTagSupport alias of CompletionTextDocumentClientCapabilitiesItemTagSupport. 87 | // 88 | // Deprecated: Use CompletionTextDocumentClientCapabilitiesItemTagSupport instead. 89 | type TextDocumentClientCapabilitiesCompletionItemTagSupport = CompletionTextDocumentClientCapabilitiesItemTagSupport 90 | 91 | // TextDocumentClientCapabilitiesDeclaration alias of DeclarationTextDocumentClientCapabilities. 92 | // 93 | // Deprecated: Use DeclarationTextDocumentClientCapabilities instead. 94 | type TextDocumentClientCapabilitiesDeclaration = DeclarationTextDocumentClientCapabilities 95 | 96 | // TextDocumentClientCapabilitiesDefinition alias of DefinitionTextDocumentClientCapabilities. 97 | // 98 | // Deprecated: Use DefinitionTextDocumentClientCapabilities instead. 99 | type TextDocumentClientCapabilitiesDefinition = DefinitionTextDocumentClientCapabilities 100 | 101 | // TextDocumentClientCapabilitiesDocumentHighlight alias of DocumentHighlightClientCapabilities. 102 | // 103 | // Deprecated: Use DocumentHighlightClientCapabilities instead. 104 | type TextDocumentClientCapabilitiesDocumentHighlight = DocumentHighlightClientCapabilities 105 | 106 | // TextDocumentClientCapabilitiesDocumentLink alias of DocumentLinkClientCapabilities. 107 | // 108 | // Deprecated: Use DocumentLinkClientCapabilities instead. 109 | type TextDocumentClientCapabilitiesDocumentLink = DocumentLinkClientCapabilities 110 | 111 | // TextDocumentClientCapabilitiesDocumentSymbol alias of DocumentSymbolClientCapabilities. 112 | // 113 | // Deprecated: Use DocumentSymbolClientCapabilities instead. 114 | type TextDocumentClientCapabilitiesDocumentSymbol = DocumentSymbolClientCapabilities 115 | 116 | // TextDocumentClientCapabilitiesDocumentSymbolTagSupport alias of DocumentSymbolClientCapabilitiesTagSupport. 117 | // 118 | // Deprecated: Use DocumentSymbolClientCapabilitiesTagSupport instead. 119 | type TextDocumentClientCapabilitiesDocumentSymbolTagSupport = DocumentSymbolClientCapabilitiesTagSupport 120 | 121 | // TextDocumentClientCapabilitiesFoldingRange alias of FoldingRangeClientCapabilities. 122 | // 123 | // Deprecated: Use FoldingRangeClientCapabilities instead. 124 | type TextDocumentClientCapabilitiesFoldingRange = FoldingRangeClientCapabilities 125 | 126 | // TextDocumentClientCapabilitiesFormatting alias of DocumentFormattingClientCapabilities. 127 | // 128 | // Deprecated: Use DocumentFormattingClientCapabilities instead. 129 | type TextDocumentClientCapabilitiesFormatting = DocumentFormattingClientCapabilities 130 | 131 | // TextDocumentClientCapabilitiesHover alias of HoverTextDocumentClientCapabilities. 132 | // 133 | // Deprecated: Use HoverTextDocumentClientCapabilities instead. 134 | type TextDocumentClientCapabilitiesHover = HoverTextDocumentClientCapabilities 135 | 136 | // TextDocumentClientCapabilitiesImplementation alias of ImplementationTextDocumentClientCapabilities. 137 | // 138 | // Deprecated: Use ImplementationTextDocumentClientCapabilities instead. 139 | type TextDocumentClientCapabilitiesImplementation = ImplementationTextDocumentClientCapabilities 140 | 141 | // TextDocumentClientCapabilitiesLinkedEditingRange alias of LinkedEditingRangeClientCapabilities. 142 | // 143 | // Deprecated: Use LinkedEditingRangeClientCapabilities instead. 144 | type TextDocumentClientCapabilitiesLinkedEditingRange = LinkedEditingRangeClientCapabilities 145 | 146 | // TextDocumentClientCapabilitiesMoniker of MonikerClientCapabilities. 147 | // 148 | // Deprecated: Use MonikerClientCapabilities instead. 149 | type TextDocumentClientCapabilitiesMoniker = MonikerClientCapabilities 150 | 151 | // TextDocumentClientCapabilitiesOnTypeFormatting of DocumentOnTypeFormattingClientCapabilities. 152 | // 153 | // Deprecated: Use DocumentOnTypeFormattingClientCapabilities instead. 154 | type TextDocumentClientCapabilitiesOnTypeFormatting = DocumentOnTypeFormattingClientCapabilities 155 | 156 | // TextDocumentClientCapabilitiesPublishDiagnostics of PublishDiagnosticsClientCapabilities. 157 | // 158 | // Deprecated: Use PublishDiagnosticsClientCapabilities instead. 159 | type TextDocumentClientCapabilitiesPublishDiagnostics = PublishDiagnosticsClientCapabilities 160 | 161 | // TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport of PublishDiagnosticsClientCapabilitiesTagSupport. 162 | // 163 | // Deprecated: Use PublishDiagnosticsClientCapabilitiesTagSupport instead. 164 | type TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport = PublishDiagnosticsClientCapabilitiesTagSupport 165 | 166 | // TextDocumentClientCapabilitiesRangeFormatting of DocumentRangeFormattingClientCapabilities. 167 | // 168 | // Deprecated: Use DocumentRangeFormattingClientCapabilities instead. 169 | type TextDocumentClientCapabilitiesRangeFormatting = DocumentRangeFormattingClientCapabilities 170 | 171 | // TextDocumentClientCapabilitiesReferences of ReferencesTextDocumentClientCapabilities. 172 | // 173 | // Deprecated: Use ReferencesTextDocumentClientCapabilities instead. 174 | type TextDocumentClientCapabilitiesReferences = ReferencesTextDocumentClientCapabilities 175 | 176 | // TextDocumentClientCapabilitiesRename of RenameClientCapabilities. 177 | // 178 | // Deprecated: Use RenameClientCapabilities instead. 179 | type TextDocumentClientCapabilitiesRename = RenameClientCapabilities 180 | 181 | // TextDocumentClientCapabilitiesSelectionRange of SelectionRangeClientCapabilities. 182 | // 183 | // Deprecated: Use SelectionRangeClientCapabilities instead. 184 | type TextDocumentClientCapabilitiesSelectionRange = SelectionRangeClientCapabilities 185 | 186 | // TextDocumentClientCapabilitiesSemanticTokens of SemanticTokensClientCapabilities. 187 | // 188 | // Deprecated: Use SemanticTokensClientCapabilities instead. 189 | type TextDocumentClientCapabilitiesSemanticTokens = SemanticTokensClientCapabilities 190 | 191 | // TextDocumentClientCapabilitiesSignatureHelp of SignatureHelpTextDocumentClientCapabilities. 192 | // 193 | // Deprecated: Use SignatureHelpTextDocumentClientCapabilities instead. 194 | type TextDocumentClientCapabilitiesSignatureHelp = SignatureHelpTextDocumentClientCapabilities 195 | 196 | // TextDocumentClientCapabilitiesSynchronization of TextDocumentSyncClientCapabilities. 197 | // 198 | // Deprecated: Use TextDocumentSyncClientCapabilities instead. 199 | type TextDocumentClientCapabilitiesSynchronization = TextDocumentSyncClientCapabilities 200 | 201 | // TextDocumentClientCapabilitiesTypeDefinition of TypeDefinitionTextDocumentClientCapabilities. 202 | // 203 | // Deprecated: Use TypeDefinitionTextDocumentClientCapabilities instead. 204 | type TextDocumentClientCapabilitiesTypeDefinition = TypeDefinitionTextDocumentClientCapabilities 205 | 206 | // Abort alias of FailureHandlingKindAbort. 207 | // 208 | // Deprecated: Use FailureHandlingKindAbort instead. 209 | const Abort = FailureHandlingKindAbort 210 | 211 | // TextOnlyTransactional alias of FailureHandlingKindTextOnlyTransactional. 212 | // 213 | // Deprecated: Use FailureHandlingKindTextOnlyTransactional instead. 214 | const TextOnlyTransactional = FailureHandlingKindTextOnlyTransactional 215 | 216 | // Transactional alias of FailureHandlingKindTransactional. 217 | // 218 | // Deprecated: Use FailureHandlingKindTransactional instead. 219 | const Transactional = FailureHandlingKindTransactional 220 | 221 | // Undo alias of FailureHandlingKindUndo. 222 | // 223 | // Deprecated: Use FailureHandlingKindUndo instead. 224 | const Undo = FailureHandlingKindUndo 225 | 226 | // WorkspaceClientCapabilitiesSymbol alias of WorkspaceSymbolClientCapabilities. 227 | // 228 | // Deprecated: Use WorkspaceSymbolClientCapabilities instead. 229 | type WorkspaceClientCapabilitiesSymbol = WorkspaceSymbolClientCapabilities 230 | 231 | // WorkspaceClientCapabilitiesSymbolKind alias of SymbolKindCapabilities. 232 | // 233 | // Deprecated: Use SymbolKindCapabilities instead. 234 | type WorkspaceClientCapabilitiesSymbolKind = SymbolKindCapabilities 235 | 236 | // WorkspaceClientCapabilitiesCodeLens alias of CodeLensWorkspaceClientCapabilities. 237 | // 238 | // Deprecated: Use CodeLensWorkspaceClientCapabilities instead. 239 | type WorkspaceClientCapabilitiesCodeLens = CodeLensWorkspaceClientCapabilities 240 | 241 | // WorkspaceClientCapabilitiesDidChangeConfiguration alias of DidChangeConfigurationWorkspaceClientCapabilities. 242 | // 243 | // Deprecated: Use DidChangeConfigurationWorkspaceClientCapabilities instead. 244 | type WorkspaceClientCapabilitiesDidChangeConfiguration = DidChangeConfigurationWorkspaceClientCapabilities 245 | 246 | // WorkspaceClientCapabilitiesDidChangeWatchedFiles alias of DidChangeWatchedFilesWorkspaceClientCapabilities. 247 | // 248 | // Deprecated: Use DidChangeWatchedFilesWorkspaceClientCapabilities instead. 249 | type WorkspaceClientCapabilitiesDidChangeWatchedFiles = DidChangeWatchedFilesWorkspaceClientCapabilities 250 | 251 | // WorkspaceClientCapabilitiesExecuteCommand alias of ExecuteCommandClientCapabilities. 252 | // 253 | // Deprecated: Use ExecuteCommandClientCapabilities instead. 254 | type WorkspaceClientCapabilitiesExecuteCommand = ExecuteCommandClientCapabilities 255 | 256 | // WorkspaceClientCapabilitiesSemanticTokens alias of SemanticTokensWorkspaceClientCapabilities. 257 | // 258 | // Deprecated: Use SemanticTokensWorkspaceClientCapabilities instead. 259 | type WorkspaceClientCapabilitiesSemanticTokens = SemanticTokensWorkspaceClientCapabilities 260 | 261 | // WorkspaceClientCapabilitiesSemanticTokensRequests alias of SemanticTokensWorkspaceClientCapabilitiesRequests. 262 | // 263 | // Deprecated: Use SemanticTokensWorkspaceClientCapabilitiesRequests instead. 264 | type WorkspaceClientCapabilitiesSemanticTokensRequests = SemanticTokensWorkspaceClientCapabilitiesRequests 265 | -------------------------------------------------------------------------------- /diagnostics.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "strconv" 8 | ) 9 | 10 | // Diagnostic represents a diagnostic, such as a compiler error or warning. 11 | // 12 | // Diagnostic objects are only valid in the scope of a resource. 13 | type Diagnostic struct { 14 | // Range is the range at which the message applies. 15 | Range Range `json:"range"` 16 | 17 | // Severity is the diagnostic's severity. Can be omitted. If omitted it is up to the 18 | // client to interpret diagnostics as error, warning, info or hint. 19 | Severity DiagnosticSeverity `json:"severity,omitempty"` 20 | 21 | // Code is the diagnostic's code, which might appear in the user interface. 22 | Code interface{} `json:"code,omitempty"` // int32 | string; 23 | 24 | // CodeDescription an optional property to describe the error code. 25 | // 26 | // @since 3.16.0. 27 | CodeDescription *CodeDescription `json:"codeDescription,omitempty"` 28 | 29 | // Source a human-readable string describing the source of this 30 | // diagnostic, e.g. 'typescript' or 'super lint'. 31 | Source string `json:"source,omitempty"` 32 | 33 | // Message is the diagnostic's message. 34 | Message string `json:"message"` 35 | 36 | // Tags is the additional metadata about the diagnostic. 37 | // 38 | // @since 3.15.0. 39 | Tags []DiagnosticTag `json:"tags,omitempty"` 40 | 41 | // RelatedInformation an array of related diagnostic information, e.g. when symbol-names within 42 | // a scope collide all definitions can be marked via this property. 43 | RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` 44 | 45 | // Data is a data entry field that is preserved between a 46 | // "textDocument/publishDiagnostics" notification and 47 | // "textDocument/codeAction" request. 48 | // 49 | // @since 3.16.0. 50 | Data interface{} `json:"data,omitempty"` 51 | } 52 | 53 | // DiagnosticSeverity indicates the severity of a Diagnostic message. 54 | type DiagnosticSeverity float64 55 | 56 | const ( 57 | // DiagnosticSeverityError reports an error. 58 | DiagnosticSeverityError DiagnosticSeverity = 1 59 | 60 | // DiagnosticSeverityWarning reports a warning. 61 | DiagnosticSeverityWarning DiagnosticSeverity = 2 62 | 63 | // DiagnosticSeverityInformation reports an information. 64 | DiagnosticSeverityInformation DiagnosticSeverity = 3 65 | 66 | // DiagnosticSeverityHint reports a hint. 67 | DiagnosticSeverityHint DiagnosticSeverity = 4 68 | ) 69 | 70 | // String implements fmt.Stringer. 71 | func (d DiagnosticSeverity) String() string { 72 | switch d { 73 | case DiagnosticSeverityError: 74 | return "Error" 75 | case DiagnosticSeverityWarning: 76 | return "Warning" 77 | case DiagnosticSeverityInformation: 78 | return "Information" 79 | case DiagnosticSeverityHint: 80 | return "Hint" 81 | default: 82 | return strconv.FormatFloat(float64(d), 'f', -10, 64) 83 | } 84 | } 85 | 86 | // CodeDescription is the structure to capture a description for an error code. 87 | // 88 | // @since 3.16.0. 89 | type CodeDescription struct { 90 | // Href an URI to open with more information about the diagnostic error. 91 | Href URI `json:"href"` 92 | } 93 | 94 | // DiagnosticTag is the diagnostic tags. 95 | // 96 | // @since 3.15.0. 97 | type DiagnosticTag float64 98 | 99 | // list of DiagnosticTag. 100 | const ( 101 | // DiagnosticTagUnnecessary unused or unnecessary code. 102 | // 103 | // Clients are allowed to render diagnostics with this tag faded out instead of having 104 | // an error squiggle. 105 | DiagnosticTagUnnecessary DiagnosticTag = 1 106 | 107 | // DiagnosticTagDeprecated deprecated or obsolete code. 108 | // 109 | // Clients are allowed to rendered diagnostics with this tag strike through. 110 | DiagnosticTagDeprecated DiagnosticTag = 2 111 | ) 112 | 113 | // String implements fmt.Stringer. 114 | func (d DiagnosticTag) String() string { 115 | switch d { 116 | case DiagnosticTagUnnecessary: 117 | return "Unnecessary" 118 | case DiagnosticTagDeprecated: 119 | return "Deprecated" 120 | default: 121 | return strconv.FormatFloat(float64(d), 'f', -10, 64) 122 | } 123 | } 124 | 125 | // DiagnosticRelatedInformation represents a related message and source code location for a diagnostic. 126 | // 127 | // This should be used to point to code locations that cause or related to a diagnostics, e.g when duplicating 128 | // a symbol in a scope. 129 | type DiagnosticRelatedInformation struct { 130 | // Location is the location of this related diagnostic information. 131 | Location Location `json:"location"` 132 | 133 | // Message is the message of this related diagnostic information. 134 | Message string `json:"message"` 135 | } 136 | 137 | // PublishDiagnosticsParams represents a params of PublishDiagnostics notification. 138 | type PublishDiagnosticsParams struct { 139 | // URI is the URI for which diagnostic information is reported. 140 | URI DocumentURI `json:"uri"` 141 | 142 | // Version optional the version number of the document the diagnostics are published for. 143 | // 144 | // @since 3.15 145 | Version uint32 `json:"version,omitempty"` 146 | 147 | // Diagnostics an array of diagnostic information items. 148 | Diagnostics []Diagnostic `json:"diagnostics"` 149 | } 150 | -------------------------------------------------------------------------------- /diagnostics_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/google/go-cmp/cmp" 10 | "github.com/segmentio/encoding/json" 11 | 12 | "go.lsp.dev/uri" 13 | ) 14 | 15 | func TestDiagnostic(t *testing.T) { 16 | t.Parallel() 17 | 18 | const ( 19 | want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","tags":[1,2],"relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` 20 | wantNilSeverity = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` 21 | wantNilCode = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` 22 | wantNilRelatedInformation = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","data":"testData"}` 23 | wantNilAll = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"message":"foo bar"}` 24 | wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}],"data":"invalidData"}` 25 | ) 26 | wantType := Diagnostic{ 27 | Range: Range{ 28 | Start: Position{ 29 | Line: 25, 30 | Character: 1, 31 | }, 32 | End: Position{ 33 | Line: 27, 34 | Character: 3, 35 | }, 36 | }, 37 | Severity: DiagnosticSeverityError, 38 | Code: "foo/bar", 39 | CodeDescription: &CodeDescription{ 40 | Href: uri.File("/path/to/test.go"), 41 | }, 42 | Source: "test foo bar", 43 | Message: "foo bar", 44 | Tags: []DiagnosticTag{ 45 | DiagnosticTagUnnecessary, 46 | DiagnosticTagDeprecated, 47 | }, 48 | RelatedInformation: []DiagnosticRelatedInformation{ 49 | { 50 | Location: Location{ 51 | URI: uri.File("/path/to/basic.go"), 52 | Range: Range{ 53 | Start: Position{ 54 | Line: 25, 55 | Character: 1, 56 | }, 57 | End: Position{ 58 | Line: 27, 59 | Character: 3, 60 | }, 61 | }, 62 | }, 63 | Message: "basic_gen.go", 64 | }, 65 | }, 66 | Data: "testData", 67 | } 68 | wantTypeNilSeverity := Diagnostic{ 69 | Range: Range{ 70 | Start: Position{ 71 | Line: 25, 72 | Character: 1, 73 | }, 74 | End: Position{ 75 | Line: 27, 76 | Character: 3, 77 | }, 78 | }, 79 | Code: "foo/bar", 80 | CodeDescription: &CodeDescription{ 81 | Href: uri.File("/path/to/test.go"), 82 | }, 83 | Source: "test foo bar", 84 | Message: "foo bar", 85 | RelatedInformation: []DiagnosticRelatedInformation{ 86 | { 87 | Location: Location{ 88 | URI: uri.File("/path/to/basic.go"), 89 | Range: Range{ 90 | Start: Position{ 91 | Line: 25, 92 | Character: 1, 93 | }, 94 | End: Position{ 95 | Line: 27, 96 | Character: 3, 97 | }, 98 | }, 99 | }, 100 | Message: "basic_gen.go", 101 | }, 102 | }, 103 | Data: "testData", 104 | } 105 | wantTypeNilCode := Diagnostic{ 106 | Range: Range{ 107 | Start: Position{ 108 | Line: 25, 109 | Character: 1, 110 | }, 111 | End: Position{ 112 | Line: 27, 113 | Character: 3, 114 | }, 115 | }, 116 | Severity: DiagnosticSeverityError, 117 | CodeDescription: &CodeDescription{ 118 | Href: uri.File("/path/to/test.go"), 119 | }, 120 | Source: "test foo bar", 121 | Message: "foo bar", 122 | RelatedInformation: []DiagnosticRelatedInformation{ 123 | { 124 | Location: Location{ 125 | URI: uri.File("/path/to/basic.go"), 126 | Range: Range{ 127 | Start: Position{ 128 | Line: 25, 129 | Character: 1, 130 | }, 131 | End: Position{ 132 | Line: 27, 133 | Character: 3, 134 | }, 135 | }, 136 | }, 137 | Message: "basic_gen.go", 138 | }, 139 | }, 140 | Data: "testData", 141 | } 142 | wantTypeNilRelatedInformation := Diagnostic{ 143 | Range: Range{ 144 | Start: Position{ 145 | Line: 25, 146 | Character: 1, 147 | }, 148 | End: Position{ 149 | Line: 27, 150 | Character: 3, 151 | }, 152 | }, 153 | Severity: DiagnosticSeverityError, 154 | Code: "foo/bar", 155 | CodeDescription: &CodeDescription{ 156 | Href: uri.File("/path/to/test.go"), 157 | }, 158 | Source: "test foo bar", 159 | Message: "foo bar", 160 | Data: "testData", 161 | } 162 | wantTypeNilAll := Diagnostic{ 163 | Range: Range{ 164 | Start: Position{ 165 | Line: 25, 166 | Character: 1, 167 | }, 168 | End: Position{ 169 | Line: 27, 170 | Character: 3, 171 | }, 172 | }, 173 | Message: "foo bar", 174 | } 175 | 176 | t.Run("Marshal", func(t *testing.T) { 177 | t.Parallel() 178 | 179 | tests := []struct { 180 | name string 181 | field Diagnostic 182 | want string 183 | wantMarshalErr bool 184 | wantErr bool 185 | }{ 186 | { 187 | name: "Valid", 188 | field: wantType, 189 | want: want, 190 | wantMarshalErr: false, 191 | wantErr: false, 192 | }, 193 | { 194 | name: "ValidNilSeverity", 195 | field: wantTypeNilSeverity, 196 | want: wantNilSeverity, 197 | wantMarshalErr: false, 198 | wantErr: false, 199 | }, 200 | { 201 | name: "ValidNilCode", 202 | field: wantTypeNilCode, 203 | want: wantNilCode, 204 | wantMarshalErr: false, 205 | wantErr: false, 206 | }, 207 | { 208 | name: "ValidNilRelatedInformation", 209 | field: wantTypeNilRelatedInformation, 210 | want: wantNilRelatedInformation, 211 | wantMarshalErr: false, 212 | wantErr: false, 213 | }, 214 | { 215 | name: "ValidNilAll", 216 | field: wantTypeNilAll, 217 | want: wantNilAll, 218 | wantMarshalErr: false, 219 | wantErr: false, 220 | }, 221 | { 222 | name: "Invalid", 223 | field: wantType, 224 | want: wantInvalid, 225 | wantMarshalErr: false, 226 | wantErr: true, 227 | }, 228 | } 229 | for _, tt := range tests { 230 | tt := tt 231 | t.Run(tt.name, func(t *testing.T) { 232 | t.Parallel() 233 | 234 | got, err := json.Marshal(&tt.field) 235 | if (err != nil) != tt.wantMarshalErr { 236 | t.Fatal(err) 237 | } 238 | 239 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 240 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 241 | } 242 | }) 243 | } 244 | }) 245 | 246 | t.Run("Unmarshal", func(t *testing.T) { 247 | t.Parallel() 248 | 249 | tests := []struct { 250 | name string 251 | field string 252 | want Diagnostic 253 | wantUnmarshalErr bool 254 | wantErr bool 255 | }{ 256 | { 257 | name: "Valid", 258 | field: want, 259 | want: wantType, 260 | wantUnmarshalErr: false, 261 | wantErr: false, 262 | }, 263 | { 264 | name: "ValidNilSeverity", 265 | field: wantNilSeverity, 266 | want: wantTypeNilSeverity, 267 | wantUnmarshalErr: false, 268 | wantErr: false, 269 | }, 270 | { 271 | name: "ValidNilCode", 272 | field: wantNilCode, 273 | want: wantTypeNilCode, 274 | wantUnmarshalErr: false, 275 | wantErr: false, 276 | }, 277 | { 278 | name: "ValidNilRelatedInformation", 279 | field: wantNilRelatedInformation, 280 | want: wantTypeNilRelatedInformation, 281 | wantUnmarshalErr: false, 282 | wantErr: false, 283 | }, 284 | { 285 | name: "ValidNilAll", 286 | field: wantNilAll, 287 | want: wantTypeNilAll, 288 | wantUnmarshalErr: false, 289 | wantErr: false, 290 | }, 291 | { 292 | name: "Invalid", 293 | field: wantInvalid, 294 | want: wantType, 295 | wantUnmarshalErr: false, 296 | wantErr: true, 297 | }, 298 | } 299 | for _, tt := range tests { 300 | tt := tt 301 | t.Run(tt.name, func(t *testing.T) { 302 | t.Parallel() 303 | 304 | var got Diagnostic 305 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 306 | t.Fatal(err) 307 | } 308 | 309 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 310 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 311 | } 312 | }) 313 | } 314 | }) 315 | } 316 | 317 | func TestDiagnosticSeverity_String(t *testing.T) { 318 | t.Parallel() 319 | 320 | tests := []struct { 321 | name string 322 | d DiagnosticSeverity 323 | want string 324 | }{ 325 | { 326 | name: "Error", 327 | d: DiagnosticSeverityError, 328 | want: "Error", 329 | }, 330 | { 331 | name: "Warning", 332 | d: DiagnosticSeverityWarning, 333 | want: "Warning", 334 | }, 335 | { 336 | name: "Information", 337 | d: DiagnosticSeverityInformation, 338 | want: "Information", 339 | }, 340 | { 341 | name: "Hint", 342 | d: DiagnosticSeverityHint, 343 | want: "Hint", 344 | }, 345 | { 346 | name: "Unknown", 347 | d: DiagnosticSeverity(0), 348 | want: "0", 349 | }, 350 | } 351 | for _, tt := range tests { 352 | tt := tt 353 | t.Run(tt.name, func(t *testing.T) { 354 | t.Parallel() 355 | 356 | if got := tt.d.String(); got != tt.want { 357 | t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got) 358 | } 359 | }) 360 | } 361 | } 362 | 363 | func TestDiagnosticTag_String(t *testing.T) { 364 | t.Parallel() 365 | 366 | tests := []struct { 367 | name string 368 | d DiagnosticTag 369 | want string 370 | }{ 371 | { 372 | name: "Unnecessary", 373 | d: DiagnosticTagUnnecessary, 374 | want: "Unnecessary", 375 | }, 376 | { 377 | name: "Deprecated", 378 | d: DiagnosticTagDeprecated, 379 | want: "Deprecated", 380 | }, 381 | { 382 | name: "Unknown", 383 | d: DiagnosticTag(0), 384 | want: "0", 385 | }, 386 | } 387 | for _, tt := range tests { 388 | tt := tt 389 | t.Run(tt.name, func(t *testing.T) { 390 | t.Parallel() 391 | 392 | if got := tt.d.String(); got != tt.want { 393 | t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got) 394 | } 395 | }) 396 | } 397 | } 398 | 399 | func TestDiagnosticRelatedInformation(t *testing.T) { 400 | t.Parallel() 401 | 402 | const ( 403 | want = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}` 404 | wantInvalid = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}` 405 | ) 406 | wantType := DiagnosticRelatedInformation{ 407 | Location: Location{ 408 | URI: uri.File("/path/to/basic.go"), 409 | Range: Range{ 410 | Start: Position{ 411 | Line: 25, 412 | Character: 1, 413 | }, 414 | End: Position{ 415 | Line: 27, 416 | Character: 3, 417 | }, 418 | }, 419 | }, 420 | Message: "basic_gen.go", 421 | } 422 | 423 | t.Run("Marshal", func(t *testing.T) { 424 | t.Parallel() 425 | 426 | tests := []struct { 427 | name string 428 | field DiagnosticRelatedInformation 429 | want string 430 | wantMarshalErr bool 431 | wantErr bool 432 | }{ 433 | { 434 | name: "Valid", 435 | field: wantType, 436 | want: want, 437 | wantMarshalErr: false, 438 | wantErr: false, 439 | }, 440 | { 441 | name: "Invalid", 442 | field: wantType, 443 | want: wantInvalid, 444 | wantMarshalErr: false, 445 | wantErr: true, 446 | }, 447 | } 448 | for _, tt := range tests { 449 | tt := tt 450 | t.Run(tt.name, func(t *testing.T) { 451 | t.Parallel() 452 | 453 | got, err := json.Marshal(&tt.field) 454 | if (err != nil) != tt.wantMarshalErr { 455 | t.Fatal(err) 456 | } 457 | 458 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 459 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 460 | } 461 | }) 462 | } 463 | }) 464 | 465 | t.Run("Unmarshal", func(t *testing.T) { 466 | t.Parallel() 467 | 468 | tests := []struct { 469 | name string 470 | field string 471 | want DiagnosticRelatedInformation 472 | wantUnmarshalErr bool 473 | wantErr bool 474 | }{ 475 | { 476 | name: "Valid", 477 | field: want, 478 | want: wantType, 479 | wantUnmarshalErr: false, 480 | wantErr: false, 481 | }, 482 | { 483 | name: "Invalid", 484 | field: wantInvalid, 485 | want: wantType, 486 | wantUnmarshalErr: false, 487 | wantErr: true, 488 | }, 489 | } 490 | for _, tt := range tests { 491 | tt := tt 492 | t.Run(tt.name, func(t *testing.T) { 493 | t.Parallel() 494 | 495 | var got DiagnosticRelatedInformation 496 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 497 | t.Fatal(err) 498 | } 499 | 500 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 501 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 502 | } 503 | }) 504 | } 505 | }) 506 | } 507 | 508 | func TestPublishDiagnosticsParams(t *testing.T) { 509 | t.Parallel() 510 | 511 | const ( 512 | want = `{"uri":"file:///path/to/diagnostics.go","version":1,"diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"diagnostics.go"}]}]}` 513 | wantInvalid = `{"uri":"file:///path/to/diagnostics_gen.go","version":2,"diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics_gen.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"diagnostics_gen.go"}]}]}` 514 | ) 515 | wantType := PublishDiagnosticsParams{ 516 | URI: DocumentURI("file:///path/to/diagnostics.go"), 517 | Version: 1, 518 | Diagnostics: []Diagnostic{ 519 | { 520 | Range: Range{ 521 | Start: Position{ 522 | Line: 25, 523 | Character: 1, 524 | }, 525 | End: Position{ 526 | Line: 27, 527 | Character: 3, 528 | }, 529 | }, 530 | Severity: DiagnosticSeverityError, 531 | Code: "foo/bar", 532 | Source: "test foo bar", 533 | Message: "foo bar", 534 | RelatedInformation: []DiagnosticRelatedInformation{ 535 | { 536 | Location: Location{ 537 | URI: uri.File("/path/to/diagnostics.go"), 538 | Range: Range{ 539 | Start: Position{ 540 | Line: 25, 541 | Character: 1, 542 | }, 543 | End: Position{ 544 | Line: 27, 545 | Character: 3, 546 | }, 547 | }, 548 | }, 549 | Message: "diagnostics.go", 550 | }, 551 | }, 552 | }, 553 | }, 554 | } 555 | 556 | t.Run("Marshal", func(t *testing.T) { 557 | t.Parallel() 558 | 559 | tests := []struct { 560 | name string 561 | field PublishDiagnosticsParams 562 | want string 563 | wantMarshalErr bool 564 | wantErr bool 565 | }{ 566 | { 567 | name: "Valid", 568 | field: wantType, 569 | want: want, 570 | wantMarshalErr: false, 571 | wantErr: false, 572 | }, 573 | { 574 | name: "Invalid", 575 | field: wantType, 576 | want: wantInvalid, 577 | wantMarshalErr: false, 578 | wantErr: true, 579 | }, 580 | } 581 | 582 | for _, tt := range tests { 583 | tt := tt 584 | t.Run(tt.name, func(t *testing.T) { 585 | t.Parallel() 586 | 587 | got, err := json.Marshal(&tt.field) 588 | if (err != nil) != tt.wantMarshalErr { 589 | t.Fatal(err) 590 | } 591 | 592 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 593 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 594 | } 595 | }) 596 | } 597 | }) 598 | 599 | t.Run("Unmarshal", func(t *testing.T) { 600 | t.Parallel() 601 | 602 | tests := []struct { 603 | name string 604 | field string 605 | want PublishDiagnosticsParams 606 | wantUnmarshalErr bool 607 | wantErr bool 608 | }{ 609 | { 610 | name: "Valid", 611 | field: want, 612 | want: wantType, 613 | wantUnmarshalErr: false, 614 | wantErr: false, 615 | }, 616 | { 617 | name: "Invalid", 618 | field: wantInvalid, 619 | want: wantType, 620 | wantUnmarshalErr: false, 621 | wantErr: true, 622 | }, 623 | } 624 | 625 | for _, tt := range tests { 626 | tt := tt 627 | t.Run(tt.name, func(t *testing.T) { 628 | t.Parallel() 629 | 630 | var got PublishDiagnosticsParams 631 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 632 | t.Fatal(err) 633 | } 634 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 635 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 636 | } 637 | }) 638 | } 639 | }) 640 | } 641 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | // Package protocol implements Language Server Protocol specification in Go. 5 | // 6 | // This package contains the structs that map directly to the wire format 7 | // of the Language Server Protocol. 8 | // 9 | // It is a literal transcription, with unmodified comments, and only the changes 10 | // required to make it Go code. 11 | // 12 | // - Names are uppercased to export them. 13 | // 14 | // - All fields have JSON tags added to correct the names. 15 | // 16 | // - Fields marked with a ? are also marked as "omitempty". 17 | // 18 | // - Fields that are "|| null" are made pointers. 19 | // 20 | // - Fields that are string or number are left as string. 21 | // 22 | // - Fields that are type "number" are made float64. 23 | package protocol // import "go.lsp.dev/protocol" 24 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # docs 2 | 3 | ## [Implementation references](implementation-references.md) 4 | -------------------------------------------------------------------------------- /docs/implementation-references.md: -------------------------------------------------------------------------------- 1 | # Implementation references 2 | - [Implementation references](#implementation-references) 3 | - [Go](#go) 4 | - [Node.js](#nodejs) 5 | - [Rust](#rust) 6 | 7 | ## Go 8 | 9 | - [tools/internal/lsp: golang/tools](https://github.com/golang/tools/tree/master/internal/lsp) 10 | - [sourcegraph/go-langserver: Go language server to add Go support to editors and other tools that use the Language Server Protocol (LSP)](https://github.com/sourcegraph/go-langserver) 11 | - [sourcegraph/go-lsp: Go types for the messages used in the Language Server Protocol.](https://github.com/sourcegraph/go-lsp) 12 | 13 | ## Node.js 14 | 15 | - [Microsoft/vscode-languageserver-node: Language server protocol implementation for VSCode.](https://github.com/Microsoft/vscode-languageserver-node) 16 | 17 | ## Rust 18 | 19 | - [autozimu/LanguageClient-neovim: Language Server Protocol (LSP) support for vim and neovim.](https://github.com/autozimu/LanguageClient-neovim/tree/next) 20 | - [rust-lang-nursery/rls: Repository for the Rust Language Server (aka RLS)](https://github.com/rust-lang-nursery/rls) 21 | 22 | - [gluon-lang/lsp-types: Types for communicating with a language server](https://github.com/gluon-lang/lsp-types) 23 | - [RustDT/RustLSP: A Language Server Protocol implementation in Rust](https://github.com/RustDT/RustLSP) 24 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import "go.lsp.dev/jsonrpc2" 7 | 8 | const ( 9 | // LSPReservedErrorRangeStart is the start range of LSP reserved error codes. 10 | // 11 | // It doesn't denote a real error code. 12 | // 13 | // @since 3.16.0. 14 | LSPReservedErrorRangeStart jsonrpc2.Code = -32899 15 | 16 | // CodeContentModified is the state change that invalidates the result of a request in execution. 17 | // 18 | // Defined by the protocol. 19 | CodeContentModified jsonrpc2.Code = -32801 20 | 21 | // CodeRequestCancelled is the cancellation error. 22 | // 23 | // Defined by the protocol. 24 | CodeRequestCancelled jsonrpc2.Code = -32800 25 | 26 | // LSPReservedErrorRangeEnd is the end range of LSP reserved error codes. 27 | // 28 | // It doesn't denote a real error code. 29 | // 30 | // @since 3.16.0. 31 | LSPReservedErrorRangeEnd jsonrpc2.Code = -32800 32 | ) 33 | 34 | var ( 35 | // ErrContentModified should be used when a request is canceled early. 36 | ErrContentModified = jsonrpc2.NewError(CodeContentModified, "cancelled JSON-RPC") 37 | 38 | // ErrRequestCancelled should be used when a request is canceled early. 39 | ErrRequestCancelled = jsonrpc2.NewError(CodeRequestCancelled, "cancelled JSON-RPC") 40 | ) 41 | -------------------------------------------------------------------------------- /general.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // TraceValue represents a InitializeParams Trace mode. 7 | type TraceValue string 8 | 9 | // list of TraceValue. 10 | const ( 11 | // TraceOff disable tracing. 12 | TraceOff TraceValue = "off" 13 | 14 | // TraceMessage normal tracing mode. 15 | TraceMessage TraceValue = "message" 16 | 17 | // TraceVerbose verbose tracing mode. 18 | TraceVerbose TraceValue = "verbose" 19 | ) 20 | 21 | // ClientInfo information about the client. 22 | // 23 | // @since 3.15.0. 24 | type ClientInfo struct { 25 | // Name is the name of the client as defined by the client. 26 | Name string `json:"name"` 27 | 28 | // Version is the client's version as defined by the client. 29 | Version string `json:"version,omitempty"` 30 | } 31 | 32 | // InitializeParams params of Initialize request. 33 | type InitializeParams struct { 34 | WorkDoneProgressParams 35 | 36 | // ProcessID is the process Id of the parent process that started 37 | // the server. Is null if the process has not been started by another process. 38 | // If the parent process is not alive then the server should exit (see exit notification) its process. 39 | ProcessID int32 `json:"processId"` 40 | 41 | // ClientInfo is the information about the client. 42 | // 43 | // @since 3.15.0 44 | ClientInfo *ClientInfo `json:"clientInfo,omitempty"` 45 | 46 | // Locale is the locale the client is currently showing the user interface 47 | // in. This must not necessarily be the locale of the operating 48 | // system. 49 | // 50 | // Uses IETF language tags as the value's syntax 51 | // (See https://en.wikipedia.org/wiki/IETF_language_tag) 52 | // 53 | // @since 3.16.0. 54 | Locale string `json:"locale,omitempty"` 55 | 56 | // RootPath is the rootPath of the workspace. Is null 57 | // if no folder is open. 58 | // 59 | // Deprecated: Use RootURI instead. 60 | RootPath string `json:"rootPath,omitempty"` 61 | 62 | // RootURI is the rootUri of the workspace. Is null if no 63 | // folder is open. If both `rootPath` and "rootUri" are set 64 | // "rootUri" wins. 65 | // 66 | // Deprecated: Use WorkspaceFolders instead. 67 | RootURI DocumentURI `json:"rootUri,omitempty"` 68 | 69 | // InitializationOptions user provided initialization options. 70 | InitializationOptions interface{} `json:"initializationOptions,omitempty"` 71 | 72 | // Capabilities is the capabilities provided by the client (editor or tool) 73 | Capabilities ClientCapabilities `json:"capabilities"` 74 | 75 | // Trace is the initial trace setting. If omitted trace is disabled ('off'). 76 | Trace TraceValue `json:"trace,omitempty"` 77 | 78 | // WorkspaceFolders is the workspace folders configured in the client when the server starts. 79 | // This property is only available if the client supports workspace folders. 80 | // It can be `null` if the client supports workspace folders but none are 81 | // configured. 82 | // 83 | // @since 3.6.0. 84 | WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"` 85 | } 86 | 87 | // InitializeResult result of ClientCapabilities. 88 | type InitializeResult struct { 89 | // Capabilities is the capabilities the language server provides. 90 | Capabilities ServerCapabilities `json:"capabilities"` 91 | 92 | // ServerInfo Information about the server. 93 | // 94 | // @since 3.15.0. 95 | ServerInfo *ServerInfo `json:"serverInfo,omitempty"` 96 | } 97 | 98 | // LogTraceParams params of LogTrace notification. 99 | // 100 | // @since 3.16.0. 101 | type LogTraceParams struct { 102 | // Message is the message to be logged. 103 | Message string `json:"message"` 104 | 105 | // Verbose is the additional information that can be computed if the "trace" configuration 106 | // is set to "verbose". 107 | Verbose TraceValue `json:"verbose,omitempty"` 108 | } 109 | 110 | // SetTraceParams params of SetTrace notification. 111 | // 112 | // @since 3.16.0. 113 | type SetTraceParams struct { 114 | // Value is the new value that should be assigned to the trace setting. 115 | Value TraceValue `json:"value"` 116 | } 117 | 118 | // FileOperationPatternKind is a pattern kind describing if a glob pattern matches a file a folder or 119 | // both. 120 | // 121 | // @since 3.16.0. 122 | type FileOperationPatternKind string 123 | 124 | // list of FileOperationPatternKind. 125 | const ( 126 | // FileOperationPatternKindFile is the pattern matches a file only. 127 | FileOperationPatternKindFile FileOperationPatternKind = "file" 128 | 129 | // FileOperationPatternKindFolder is the pattern matches a folder only. 130 | FileOperationPatternKindFolder FileOperationPatternKind = "folder" 131 | ) 132 | 133 | // FileOperationPatternOptions matching options for the file operation pattern. 134 | // 135 | // @since 3.16.0. 136 | type FileOperationPatternOptions struct { 137 | // IgnoreCase is The pattern should be matched ignoring casing. 138 | IgnoreCase bool `json:"ignoreCase,omitempty"` 139 | } 140 | 141 | // FileOperationPattern a pattern to describe in which file operation requests or notifications 142 | // the server is interested in. 143 | // 144 | // @since 3.16.0. 145 | type FileOperationPattern struct { 146 | // The glob pattern to match. Glob patterns can have the following syntax: 147 | // - `*` to match one or more characters in a path segment 148 | // - `?` to match on one character in a path segment 149 | // - `**` to match any number of path segments, including none 150 | // - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript 151 | // and JavaScript files) 152 | // - `[]` to declare a range of characters to match in a path segment 153 | // (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 154 | // - `[!...]` to negate a range of characters to match in a path segment 155 | // (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but 156 | // not `example.0`) 157 | Glob string `json:"glob"` 158 | 159 | // Matches whether to match files or folders with this pattern. 160 | // 161 | // Matches both if undefined. 162 | Matches FileOperationPatternKind `json:"matches,omitempty"` 163 | 164 | // Options additional options used during matching. 165 | Options FileOperationPatternOptions `json:"options,omitempty"` 166 | } 167 | 168 | // FileOperationFilter is a filter to describe in which file operation requests or notifications 169 | // the server is interested in. 170 | // 171 | // @since 3.16.0. 172 | type FileOperationFilter struct { 173 | // Scheme is a URI like "file" or "untitled". 174 | Scheme string `json:"scheme,omitempty"` 175 | 176 | // Pattern is the actual file operation pattern. 177 | Pattern FileOperationPattern `json:"pattern"` 178 | } 179 | 180 | // CreateFilesParams is the parameters sent in notifications/requests for user-initiated creation 181 | // of files. 182 | // 183 | // @since 3.16.0. 184 | type CreateFilesParams struct { 185 | // Files an array of all files/folders created in this operation. 186 | Files []FileCreate `json:"files"` 187 | } 188 | 189 | // FileCreate nepresents information on a file/folder create. 190 | // 191 | // @since 3.16.0. 192 | type FileCreate struct { 193 | // URI is a file:// URI for the location of the file/folder being created. 194 | URI string `json:"uri"` 195 | } 196 | 197 | // RenameFilesParams is the parameters sent in notifications/requests for user-initiated renames 198 | // of files. 199 | // 200 | // @since 3.16.0. 201 | type RenameFilesParams struct { 202 | // Files an array of all files/folders renamed in this operation. When a folder 203 | // is renamed, only the folder will be included, and not its children. 204 | Files []FileRename `json:"files"` 205 | } 206 | 207 | // FileRename represents information on a file/folder rename. 208 | // 209 | // @since 3.16.0. 210 | type FileRename struct { 211 | // OldURI is a file:// URI for the original location of the file/folder being renamed. 212 | OldURI string `json:"oldUri"` 213 | 214 | // NewURI is a file:// URI for the new location of the file/folder being renamed. 215 | NewURI string `json:"newUri"` 216 | } 217 | 218 | // DeleteFilesParams is the parameters sent in notifications/requests for user-initiated deletes 219 | // of files. 220 | // 221 | // @since 3.16.0. 222 | type DeleteFilesParams struct { 223 | // Files an array of all files/folders deleted in this operation. 224 | Files []FileDelete `json:"files"` 225 | } 226 | 227 | // FileDelete represents information on a file/folder delete. 228 | // 229 | // @since 3.16.0. 230 | type FileDelete struct { 231 | // URI is a file:// URI for the location of the file/folder being deleted. 232 | URI string `json:"uri"` 233 | } 234 | 235 | // DocumentHighlightParams params of DocumentHighlight request. 236 | // 237 | // @since 3.15.0. 238 | type DocumentHighlightParams struct { 239 | TextDocumentPositionParams 240 | WorkDoneProgressParams 241 | PartialResultParams 242 | } 243 | 244 | // DeclarationParams params of Declaration request. 245 | // 246 | // @since 3.15.0. 247 | type DeclarationParams struct { 248 | TextDocumentPositionParams 249 | WorkDoneProgressParams 250 | PartialResultParams 251 | } 252 | 253 | // DefinitionParams params of Definition request. 254 | // 255 | // @since 3.15.0. 256 | type DefinitionParams struct { 257 | TextDocumentPositionParams 258 | WorkDoneProgressParams 259 | PartialResultParams 260 | } 261 | 262 | // TypeDefinitionParams params of TypeDefinition request. 263 | // 264 | // @since 3.15.0. 265 | type TypeDefinitionParams struct { 266 | TextDocumentPositionParams 267 | WorkDoneProgressParams 268 | PartialResultParams 269 | } 270 | 271 | // ImplementationParams params of Implementation request. 272 | // 273 | // @since 3.15.0. 274 | type ImplementationParams struct { 275 | TextDocumentPositionParams 276 | WorkDoneProgressParams 277 | PartialResultParams 278 | } 279 | 280 | // ShowDocumentParams params to show a document. 281 | // 282 | // @since 3.16.0. 283 | type ShowDocumentParams struct { 284 | // URI is the document uri to show. 285 | URI URI `json:"uri"` 286 | 287 | // External indicates to show the resource in an external program. 288 | // To show for example `https://code.visualstudio.com/` 289 | // in the default WEB browser set `external` to `true`. 290 | External bool `json:"external,omitempty"` 291 | 292 | // TakeFocus an optional property to indicate whether the editor 293 | // showing the document should take focus or not. 294 | // Clients might ignore this property if an external 295 | // program is started. 296 | TakeFocus bool `json:"takeFocus,omitempty"` 297 | 298 | // Selection an optional selection range if the document is a text 299 | // document. Clients might ignore the property if an 300 | // external program is started or the file is not a text 301 | // file. 302 | Selection *Range `json:"selection,omitempty"` 303 | } 304 | 305 | // ShowDocumentResult is the result of an show document request. 306 | // 307 | // @since 3.16.0. 308 | type ShowDocumentResult struct { 309 | // Success a boolean indicating if the show was successful. 310 | Success bool `json:"success"` 311 | } 312 | 313 | // ServerInfo Information about the server. 314 | // 315 | // @since 3.15.0. 316 | type ServerInfo struct { 317 | // Name is the name of the server as defined by the server. 318 | Name string `json:"name"` 319 | 320 | // Version is the server's version as defined by the server. 321 | Version string `json:"version,omitempty"` 322 | } 323 | 324 | // InitializeError known error codes for an "InitializeError". 325 | type InitializeError struct { 326 | // Retry indicates whether the client execute the following retry logic: 327 | // (1) show the message provided by the ResponseError to the user 328 | // (2) user selects retry or cancel 329 | // (3) if user selected retry the initialize method is sent again. 330 | Retry bool `json:"retry,omitempty"` 331 | } 332 | 333 | // ReferencesOptions ReferencesProvider options. 334 | // 335 | // @since 3.15.0. 336 | type ReferencesOptions struct { 337 | WorkDoneProgressOptions 338 | } 339 | 340 | // WorkDoneProgressOptions WorkDoneProgress options. 341 | // 342 | // @since 3.15.0. 343 | type WorkDoneProgressOptions struct { 344 | WorkDoneProgress bool `json:"workDoneProgress,omitempty"` 345 | } 346 | 347 | // LinkedEditingRangeParams params for the LinkedEditingRange request. 348 | // 349 | // @since 3.16.0. 350 | type LinkedEditingRangeParams struct { 351 | TextDocumentPositionParams 352 | WorkDoneProgressParams 353 | } 354 | 355 | // LinkedEditingRanges result of LinkedEditingRange request. 356 | // 357 | // @since 3.16.0. 358 | type LinkedEditingRanges struct { 359 | // Ranges a list of ranges that can be renamed together. 360 | // 361 | // The ranges must have identical length and contain identical text content. 362 | // 363 | // The ranges cannot overlap. 364 | Ranges []Range `json:"ranges"` 365 | 366 | // WordPattern an optional word pattern (regular expression) that describes valid contents for 367 | // the given ranges. 368 | // 369 | // If no pattern is provided, the client configuration's word pattern will be used. 370 | WordPattern string `json:"wordPattern,omitempty"` 371 | } 372 | 373 | // MonikerParams params for the Moniker request. 374 | // 375 | // @since 3.16.0. 376 | type MonikerParams struct { 377 | TextDocumentPositionParams 378 | WorkDoneProgressParams 379 | PartialResultParams 380 | } 381 | 382 | // UniquenessLevel is the Moniker uniqueness level to define scope of the moniker. 383 | // 384 | // @since 3.16.0. 385 | type UniquenessLevel string 386 | 387 | // list of UniquenessLevel. 388 | const ( 389 | // UniquenessLevelDocument is the moniker is only unique inside a document. 390 | UniquenessLevelDocument UniquenessLevel = "document" 391 | 392 | // UniquenessLevelProject is the moniker is unique inside a project for which a dump got created. 393 | UniquenessLevelProject UniquenessLevel = "project" 394 | 395 | // UniquenessLevelGroup is the moniker is unique inside the group to which a project belongs. 396 | UniquenessLevelGroup UniquenessLevel = "group" 397 | 398 | // UniquenessLevelScheme is the moniker is unique inside the moniker scheme. 399 | UniquenessLevelScheme UniquenessLevel = "scheme" 400 | 401 | // UniquenessLevelGlobal is the moniker is globally unique. 402 | UniquenessLevelGlobal UniquenessLevel = "global" 403 | ) 404 | 405 | // MonikerKind is the moniker kind. 406 | // 407 | // @since 3.16.0. 408 | type MonikerKind string 409 | 410 | // list of MonikerKind. 411 | const ( 412 | // MonikerKindImport is the moniker represent a symbol that is imported into a project. 413 | MonikerKindImport MonikerKind = "import" 414 | 415 | // MonikerKindExport is the moniker represents a symbol that is exported from a project. 416 | MonikerKindExport MonikerKind = "export" 417 | 418 | // MonikerKindLocal is the moniker represents a symbol that is local to a project (e.g. a local 419 | // variable of a function, a class not visible outside the project, ...). 420 | MonikerKindLocal MonikerKind = "local" 421 | ) 422 | 423 | // Moniker definition to match LSIF 0.5 moniker definition. 424 | // 425 | // @since 3.16.0. 426 | type Moniker struct { 427 | // Scheme is the scheme of the moniker. For example tsc or .Net. 428 | Scheme string `json:"scheme"` 429 | 430 | // Identifier is the identifier of the moniker. 431 | // 432 | // The value is opaque in LSIF however schema owners are allowed to define the structure if they want. 433 | Identifier string `json:"identifier"` 434 | 435 | // Unique is the scope in which the moniker is unique. 436 | Unique UniquenessLevel `json:"unique"` 437 | 438 | // Kind is the moniker kind if known. 439 | Kind MonikerKind `json:"kind,omitempty"` 440 | } 441 | 442 | // StaticRegistrationOptions staticRegistration options to be returned in the initialize request. 443 | type StaticRegistrationOptions struct { 444 | // ID is the id used to register the request. The id can be used to deregister 445 | // the request again. See also Registration#id. 446 | ID string `json:"id,omitempty"` 447 | } 448 | 449 | // DocumentLinkRegistrationOptions DocumentLinkRegistration options. 450 | type DocumentLinkRegistrationOptions struct { 451 | TextDocumentRegistrationOptions 452 | 453 | // ResolveProvider document links have a resolve provider as well. 454 | ResolveProvider bool `json:"resolveProvider,omitempty"` 455 | } 456 | 457 | // InitializedParams params of Initialized notification. 458 | type InitializedParams struct{} 459 | 460 | // WorkspaceFolders represents a slice of WorkspaceFolder. 461 | type WorkspaceFolders []WorkspaceFolder 462 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module go.lsp.dev/protocol 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/google/go-cmp v0.6.0 7 | github.com/segmentio/encoding v0.4.0 8 | go.lsp.dev/jsonrpc2 v0.10.0 9 | go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 10 | go.lsp.dev/uri v0.3.0 11 | go.uber.org/zap v1.27.0 12 | ) 13 | 14 | require ( 15 | github.com/segmentio/asm v1.1.3 // indirect 16 | go.uber.org/multierr v1.10.0 // indirect 17 | golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 5 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 8 | github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= 9 | github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= 10 | github.com/segmentio/encoding v0.4.0 h1:MEBYvRqiUB2nfR2criEXWqwdY6HJOUrCn5hboVOVmy8= 11 | github.com/segmentio/encoding v0.4.0/go.mod h1:/d03Cd8PoaDeceuhUUUQWjU0KhWjrmYrWPgtJHYZSnI= 12 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 13 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 14 | go.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI= 15 | go.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac= 16 | go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 h1:hCzQgh6UcwbKgNSRurYWSqh8MufqRRPODRBblutn4TE= 17 | go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2/go.mod h1:gtSHRuYfbCT0qnbLnovpie/WEmqyJ7T4n6VXiFMBtcw= 18 | go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= 19 | go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= 20 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 21 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 22 | go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= 23 | go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 24 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 25 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 26 | golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= 27 | golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 28 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 29 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 30 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 31 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | -------------------------------------------------------------------------------- /hack/make/go.mk: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------------------------------- 2 | # global 3 | 4 | SHELL = /usr/bin/env bash 5 | 6 | ifneq ($(shell command -v go),) 7 | GO_PATH ?= $(shell go env GOPATH) 8 | GO_OS ?= $(shell go env GOOS) 9 | GO_ARCH ?= $(shell go env GOARCH) 10 | 11 | ifneq ($(wildcard vendor),) # exist vendor directory 12 | PKG := $(subst $(GO_PATH)/src/,,$(CURDIR)) 13 | GO_PKGS := $(shell go list ./... | grep -v -e '.pb.go') 14 | GO_APP_PKGS := $(shell go list -f '{{if and (or .GoFiles .CgoFiles) (ne .Name "main")}}{{.ImportPath}}{{end}}' ${PKG}/...) 15 | GO_TEST_PKGS := $(shell go list -f='{{if or .TestGoFiles .XTestGoFiles}}{{.ImportPath}}{{end}}' ./...) 16 | GO_VENDOR_PKGS= 17 | ifneq ($(wildcard ./vendor),) 18 | GO_VENDOR_PKGS = $(shell go list -f '{{if and (or .GoFiles .CgoFiles) (ne .Name "main")}}./vendor/{{.ImportPath}}{{end}}' ./vendor/...) 19 | endif 20 | endif 21 | 22 | GO_TEST ?= go test 23 | ifneq ($(shell command -v gotest),) 24 | GO_TEST=gotest 25 | endif 26 | GO_TEST_FUNC ?= . 27 | GO_TEST_FLAGS ?= 28 | GO_BENCH_FUNC ?= . 29 | GO_BENCH_FLAGS ?= -benchmem 30 | GO_LINT_FLAGS ?= 31 | 32 | CGO_ENABLED ?= 0 33 | GO_GCFLAGS= 34 | GO_LDFLAGS=-s -w 35 | GO_LDFLAGS_STATIC=-s -w '-extldflags=-static' 36 | 37 | GO_BUILDTAGS=osusergo 38 | ifneq ($(GO_OS),darwin) 39 | GO_BUILDTAGS+=netgo 40 | endif 41 | GO_BUILDTAGS_STATIC=static static_build 42 | GO_INSTALLSUFFIX_STATIC=netgo 43 | GO_FLAGS ?= -tags='$(GO_BUILDTAGS)' -gcflags="${GO_GCFLAGS}" -ldflags="${GO_LDFLAGS}" 44 | 45 | GO_MOD_FLAGS = 46 | ifneq ($(wildcard go.mod),) # exist go.mod 47 | ifneq ($(GO111MODULE),off) 48 | GO_MOD_FLAGS=-mod=vendor 49 | endif 50 | endif 51 | endif 52 | 53 | # ---------------------------------------------------------------------------- 54 | # defines 55 | 56 | GOPHER = "" 57 | define target 58 | @printf "$(GOPHER) \\x1b[1;32m$(patsubst ,$@,$(1))\\x1b[0m\\n" 59 | endef 60 | 61 | # ---------------------------------------------------------------------------- 62 | # targets 63 | 64 | ## build and install 65 | 66 | .PHONY: pkg/install 67 | pkg/install: GO_FLAGS+=${GO_MOD_FLAGS} 68 | pkg/install: GO_LDFLAGS= 69 | pkg/install: GO_BUILDTAGS= 70 | pkg/install: 71 | $(call target) 72 | GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GO_OS) GOARCH=$(GO_ARCH) go install -v ${GO_APP_PKGS} 73 | 74 | ## test, bench and coverage 75 | 76 | .PHONY: test 77 | test: CGO_ENABLED=1 78 | test: GO_FLAGS+=${GO_MOD_FLAGS} 79 | test: GO_LDFLAGS=${GO_LDFLAGS_STATIC} 80 | test: GO_BUILDTAGS+=${GO_BUILDTAGS_STATIC} 81 | test: GO_FLAGS+=-installsuffix ${GO_INSTALLSUFFIX_STATIC} 82 | test: ## Runs package test including race condition. 83 | $(call target,${TARGET}) 84 | @GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) $(GO_TEST) -v -race -count 1 $(strip $(GO_FLAGS)) -run=$(GO_TEST_FUNC) $(GO_TEST_PKGS) 85 | 86 | .PHONY: bench 87 | bench: GO_FLAGS+=${GO_MOD_FLAGS} 88 | bench: GO_LDFLAGS=${GO_LDFLAGS_STATIC} 89 | bench: GO_BUILDTAGS+=${GO_BUILDTAGS_STATIC} 90 | bench: GO_FLAGS+=-installsuffix ${GO_INSTALLSUFFIX_STATIC} 91 | bench: ## Take a package benchmark. 92 | $(call target) 93 | @GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) $(GO_TEST) -v $(strip $(GO_FLAGS)) -run='^$$' -bench=$(GO_BENCH_FUNC) -benchmem $(GO_TEST_PKGS) 94 | 95 | .PHONY: bench/race 96 | bench/race: ## Takes packages benchmarks with the race condition. 97 | $(call target) 98 | @GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) $(GO_TEST) -v -race $(strip $(GO_FLAGS)) -run='^$$' -bench=$(GO_BENCH_FUNC) -benchmem $(GO_TEST_PKGS) 99 | 100 | .PHONY: bench/trace 101 | bench/trace: ## Take a package benchmark with take a trace profiling. 102 | $(GO_TEST) -v -c -o bench-trace.test $(PKG) 103 | GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) GODEBUG=allocfreetrace=1 ./bench-trace.test -test.run=none -test.bench=$(GO_BENCH_FUNC) -test.benchmem -test.benchtime=10ms 2> trace.log 104 | 105 | .PHONY: coverage 106 | coverage: CGO_ENABLED=1 107 | coverage: GO_FLAGS+=${GO_MOD_FLAGS} 108 | coverage: GO_LDFLAGS=${GO_LDFLAGS_STATIC} 109 | coverage: GO_BUILDTAGS+=${GO_BUILDTAGS_STATIC} 110 | coverage: GO_FLAGS+=-installsuffix ${GO_INSTALLSUFFIX_STATIC} 111 | coverage: ## Takes packages test coverage. 112 | $(call target) 113 | GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) $(GO_TEST) -v -race $(strip $(GO_FLAGS)) -covermode=atomic -coverpkg=$(PKG)/... -coverprofile=coverage.out $(GO_PKGS) 114 | 115 | $(GO_PATH)/bin/go-junit-report: 116 | @GO111MODULE=off go get -u github.com/jstemmer/go-junit-report 117 | 118 | .PHONY: cmd/go-junit-report 119 | cmd/go-junit-report: $(GO_PATH)/bin/go-junit-report # go get 'go-junit-report' binary 120 | 121 | .PHONY: coverage/ci 122 | coverage/ci: CGO_ENABLED=1 123 | coverage/ci: GO_FLAGS+=${GO_MOD_FLAGS} 124 | coverage/ci: GO_LDFLAGS=${GO_LDFLAGS_STATIC} 125 | coverage/ci: GO_BUILDTAGS+=${GO_BUILDTAGS_STATIC} 126 | coverage/ci: GO_FLAGS+=-installsuffix ${GO_INSTALLSUFFIX_STATIC} 127 | coverage/ci: cmd/go-junit-report 128 | coverage/ci: ## Takes packages test coverage, and output coverage results to CI artifacts. 129 | $(call target) 130 | @mkdir -p /tmp/ci/artifacts /tmp/ci/test-results 131 | GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) $(GO_TEST) -a -v -race $(strip $(GO_FLAGS)) -covermode=atomic -coverpkg=$(PKG)/... -coverprofile=/tmp/ci/artifacts/coverage.out $(GO_PKGS) 2>&1 | tee /dev/stderr | go-junit-report -set-exit-code > /tmp/ci/test-results/junit.xml 132 | @if [[ -f '/tmp/ci/artifacts/coverage.out' ]]; then go tool cover -html=/tmp/ci/artifacts/coverage.out -o /tmp/ci/artifacts/coverage.html; fi 133 | 134 | 135 | ## lint 136 | 137 | .PHONY: lint 138 | lint: lint/golangci-lint ## Run all linters. 139 | 140 | $(GO_PATH)/bin/golangci-lint: 141 | @GO111MODULE=off go get -u github.com/golangci/golangci-lint/cmd/golangci-lint 142 | 143 | .PHONY: cmd/golangci-lint 144 | cmd/golangci-lint: $(GO_PATH)/bin/golangci-lint # go get 'golangci-lint' binary 145 | 146 | .PHONY: lint/golangci-lint 147 | lint/golangci-lint: cmd/golangci-lint .golangci.yml ## Run golangci-lint. 148 | $(call target) 149 | @GO111MODULE=on golangci-lint run $(strip ${GO_LINT_FLAGS}) ./... 150 | 151 | 152 | ## mod 153 | 154 | .PHONY: mod/init 155 | mod/init: ## Initializes and writes a new `go.mod` to the current directory. 156 | $(call target) 157 | @GO111MODULE=on go mod init > /dev/null 2>&1 || true 158 | 159 | .PHONY: mod/get 160 | mod/get: ## Updates all module packages and go.mod. 161 | $(call target) 162 | @GO111MODULE=on go get -u -m -v -x 163 | 164 | .PHONY: mod/tidy 165 | mod/tidy: ## Makes sure go.mod matches the source code in the module. 166 | $(call target) 167 | @GO111MODULE=on go mod tidy -v 168 | 169 | .PHONY: mod/vendor 170 | mod/vendor: mod/tidy ## Resets the module's vendor directory and fetch all modules packages. 171 | $(call target) 172 | @GO111MODULE=on go mod vendor -v 173 | 174 | .PHONY: mod/graph 175 | mod/graph: ## Prints the module requirement graph with replacements applied. 176 | $(call target) 177 | @GO111MODULE=on go mod graph 178 | 179 | .PHONY: mod/install 180 | mod/install: mod/tidy mod/vendor 181 | mod/install: ## Install the module vendor package as an object file. 182 | $(call target) 183 | @GO111MODULE=off go install -v $(strip $(GO_FLAGS)) $(GO_VENDOR_PKGS) || GO111MODULE=on go install -mod=vendor -v $(strip $(GO_FLAGS)) $(GO_VENDOR_PKGS) 184 | 185 | .PHONY: mod/update 186 | mod/update: mod/get mod/tidy mod/vendor mod/install ## Updates all of vendor packages. 187 | @GO111MODULE=on go mod edit -go 1.13 188 | 189 | .PHONY: mod 190 | mod: mod/init mod/tidy mod/vendor mod/install 191 | mod: ## Updates the vendoring directory using go mod. 192 | @GO111MODULE=on go mod edit -go 1.13 193 | 194 | 195 | ## clean 196 | 197 | .PHONY: clean 198 | clean: ## Cleanups binaries and extra files in the package. 199 | $(call target) 200 | @$(RM) $(APP) *.out *.test *.prof trace.log 201 | 202 | 203 | ## boilerplate 204 | 205 | .PHONY: boilerplate/go/% 206 | boilerplate/go/%: BOILERPLATE_PKG_DIR=$(shell printf $@ | cut -d'/' -f3- | rev | cut -d'/' -f2- | rev | awk -F. '{print $$1}') 207 | boilerplate/go/%: BOILERPLATE_PKG_NAME=$(if $(findstring .go,$(suffix $(BOILERPLATE_PKG_DIR))),$(basename ${@F}),$(shell printf $@ | rev | cut -d/ -f2 | rev)) 208 | boilerplate/go/%: hack/boilerplate/boilerplate.go.txt 209 | boilerplate/go/%: ## Creates a go file based on boilerplate.go.txt in % location. 210 | @if [ -n ${BOILERPLATE_PKG_DIR} ] && [ ! -d ${BOILERPLATE_PKG_DIR} ]; then mkdir -p ${BOILERPLATE_PKG_DIR}; fi 211 | @if [[ ${@F} == *'.go'* ]] || [[ ${BOILERPLATE_PKG_DIR} == *'cmd'* ]] || [ -z ${BOILERPLATE_PKG_DIR} ]; then \ 212 | cat hack/boilerplate/boilerplate.go.txt <(printf "\npackage $(basename ${@F})\\n") > $*; \ 213 | else \ 214 | cat hack/boilerplate/boilerplate.go.txt <(printf "\npackage ${BOILERPLATE_PKG_NAME}\\n") > $*; \ 215 | fi 216 | @sed -i "s|YEAR|$(shell date '+%Y')|g" $* 217 | 218 | 219 | ## miscellaneous 220 | 221 | .PHONY: AUTHORS 222 | AUTHORS: ## Creates AUTHORS file. 223 | @$(file >$@,# This file lists all individuals having contributed content to the repository.) 224 | @$(file >>$@,# For how it is generated, see `make AUTHORS`.) 225 | @printf "$(shell git log --format="\n%aN <%aE>" | LC_ALL=C.UTF-8 sort -uf)" >> $@ 226 | 227 | .PHONY: todo 228 | TODO: ## Print the all of (TODO|BUG|XXX|FIXME|NOTE) in packages. 229 | @rg -e '(TODO|BUG|XXX|FIXME|NOTE)(\(.+\):|:)' --follow --hidden --glob='!.git' --glob='!vendor' --glob='!internal' --glob='!Makefile' --glob='!snippets' --glob='!indent' 230 | 231 | .PHONY: nolint 232 | nolint: ## Print the all of //nolint:... pragma in packages. 233 | @rg -t go -C 3 -e '//nolint.+' --follow --hidden --glob='!vendor' --glob='!internal' 234 | 235 | .PHONY: help 236 | help: ## Show make target help. 237 | @perl -nle 'BEGIN {printf "Usage:\n make \033[33m\033[0m\n\nTargets:\n"} printf " \033[36m%-30s\033[0m %s\n", $$1, $$2 if /^([a-zA-Z\/_-].+)+:.*?\s+## (.*)/' ${MAKEFILE_LIST} 238 | -------------------------------------------------------------------------------- /handler.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | 10 | "github.com/segmentio/encoding/json" 11 | 12 | "go.lsp.dev/jsonrpc2" 13 | "go.lsp.dev/pkg/xcontext" 14 | ) 15 | 16 | // CancelHandler handler of cancelling. 17 | func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler { 18 | handler, canceller := jsonrpc2.CancelHandler(handler) 19 | 20 | h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { 21 | if req.Method() != MethodCancelRequest { 22 | // TODO(iancottrell): See if we can generate a reply for the request to be cancelled 23 | // at the point of cancellation rather than waiting for gopls to naturally reply. 24 | // To do that, we need to keep track of whether a reply has been sent already and 25 | // be careful about racing between the two paths. 26 | // TODO(iancottrell): Add a test that watches the stream and verifies the response 27 | // for the cancelled request flows. 28 | reply := func(ctx context.Context, resp interface{}, err error) error { 29 | // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest 30 | if ctx.Err() != nil && err == nil { 31 | err = ErrRequestCancelled 32 | } 33 | ctx = xcontext.Detach(ctx) 34 | 35 | return reply(ctx, resp, err) 36 | } 37 | 38 | return handler(ctx, reply, req) 39 | } 40 | 41 | var params CancelParams 42 | if err := json.Unmarshal(req.Params(), ¶ms); err != nil { 43 | return replyParseError(ctx, reply, err) 44 | } 45 | 46 | switch id := params.ID.(type) { 47 | case int32: 48 | canceller(jsonrpc2.NewNumberID(id)) 49 | case string: 50 | canceller(jsonrpc2.NewStringID(id)) 51 | default: 52 | return replyParseError(ctx, reply, fmt.Errorf("request ID %v malformed", id)) 53 | } 54 | 55 | return reply(ctx, nil, nil) 56 | } 57 | 58 | return h 59 | } 60 | 61 | // Handlers default jsonrpc2.Handler. 62 | func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler { 63 | return CancelHandler( 64 | jsonrpc2.AsyncHandler( 65 | jsonrpc2.ReplyHandler(handler), 66 | ), 67 | ) 68 | } 69 | 70 | // Call calls method to params and result. 71 | func Call(ctx context.Context, conn jsonrpc2.Conn, method string, params, result interface{}) error { 72 | id, err := conn.Call(ctx, method, params, result) 73 | if ctx.Err() != nil { 74 | notifyCancel(ctx, conn, id) 75 | } 76 | 77 | return err 78 | } 79 | 80 | func notifyCancel(ctx context.Context, conn jsonrpc2.Conn, id jsonrpc2.ID) { 81 | ctx = xcontext.Detach(ctx) 82 | // Note that only *jsonrpc2.ID implements json.Marshaler. 83 | conn.Notify(ctx, MethodCancelRequest, &CancelParams{ID: &id}) 84 | } 85 | 86 | func replyParseError(ctx context.Context, reply jsonrpc2.Replier, err error) error { 87 | return reply(ctx, nil, fmt.Errorf("%w: %w", jsonrpc2.ErrParse, err)) 88 | } 89 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "fmt" 10 | "io" 11 | "sync" 12 | "time" 13 | 14 | "go.lsp.dev/jsonrpc2" 15 | ) 16 | 17 | // loggingStream represents a logging of jsonrpc2.Stream. 18 | type loggingStream struct { 19 | stream jsonrpc2.Stream 20 | log io.Writer 21 | logMu sync.Mutex 22 | } 23 | 24 | // LoggingStream returns a stream that does LSP protocol logging. 25 | func LoggingStream(stream jsonrpc2.Stream, w io.Writer) jsonrpc2.Stream { 26 | return &loggingStream{ 27 | stream: stream, 28 | log: w, 29 | } 30 | } 31 | 32 | // Read implements jsonrpc2.Stream.Read. 33 | func (s *loggingStream) Read(ctx context.Context) (jsonrpc2.Message, int64, error) { 34 | msg, count, err := s.stream.Read(ctx) 35 | if err == nil { 36 | s.logCommon(msg, true) 37 | } 38 | 39 | return msg, count, err 40 | } 41 | 42 | // Write implements jsonrpc2.Stream.Write. 43 | func (s *loggingStream) Write(ctx context.Context, msg jsonrpc2.Message) (int64, error) { 44 | s.logCommon(msg, false) 45 | count, err := s.stream.Write(ctx, msg) 46 | 47 | return count, err 48 | } 49 | 50 | // Close implements jsonrpc2.Stream.Close. 51 | func (s *loggingStream) Close() error { 52 | return s.stream.Close() 53 | } 54 | 55 | type req struct { 56 | method string 57 | start time.Time 58 | } 59 | 60 | type mapped struct { 61 | mu sync.Mutex 62 | clientCalls map[string]req 63 | serverCalls map[string]req 64 | } 65 | 66 | var maps = &mapped{ 67 | mu: sync.Mutex{}, 68 | clientCalls: make(map[string]req), 69 | serverCalls: make(map[string]req), 70 | } 71 | 72 | // these 4 methods are each used exactly once, but it seemed 73 | // better to have the encapsulation rather than ad hoc mutex 74 | // code in 4 places. 75 | func (m *mapped) client(id string) req { 76 | m.mu.Lock() 77 | v := m.clientCalls[id] 78 | delete(m.clientCalls, id) 79 | m.mu.Unlock() 80 | 81 | return v 82 | } 83 | 84 | func (m *mapped) server(id string) req { 85 | m.mu.Lock() 86 | v := m.serverCalls[id] 87 | delete(m.serverCalls, id) 88 | m.mu.Unlock() 89 | 90 | return v 91 | } 92 | 93 | func (m *mapped) setClient(id string, r req) { 94 | m.mu.Lock() 95 | m.clientCalls[id] = r 96 | m.mu.Unlock() 97 | } 98 | 99 | func (m *mapped) setServer(id string, r req) { 100 | m.mu.Lock() 101 | m.serverCalls[id] = r 102 | m.mu.Unlock() 103 | } 104 | 105 | const eor = "\r\n\r\n\r\n" 106 | 107 | func (s *loggingStream) logCommon(msg jsonrpc2.Message, isRead bool) { 108 | if msg == nil || s.log == nil { 109 | return 110 | } 111 | 112 | s.logMu.Lock() 113 | 114 | direction, pastTense := "Received", "Received" 115 | get, set := maps.client, maps.setServer 116 | if isRead { 117 | direction, pastTense = "Sending", "Sent" 118 | get, set = maps.server, maps.setClient 119 | } 120 | 121 | tm := time.Now() 122 | tmfmt := tm.Format("15:04:05.000 PM") 123 | 124 | var buf bytes.Buffer 125 | fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning 126 | 127 | switch msg := msg.(type) { 128 | case *jsonrpc2.Call: 129 | id := fmt.Sprint(msg.ID()) 130 | fmt.Fprintf(&buf, "%s request '%s - (%s)'.\n", direction, msg.Method(), id) 131 | fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor) 132 | set(id, req{method: msg.Method(), start: tm}) 133 | 134 | case *jsonrpc2.Notification: 135 | fmt.Fprintf(&buf, "%s notification '%s'.\n", direction, msg.Method()) 136 | fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor) 137 | 138 | case *jsonrpc2.Response: 139 | id := fmt.Sprint(msg.ID()) 140 | if err := msg.Err(); err != nil { 141 | fmt.Fprintf(s.log, "[Error - %s] %s #%s %s%s", pastTense, tmfmt, id, err, eor) 142 | 143 | return 144 | } 145 | 146 | cc := get(id) 147 | elapsed := tm.Sub(cc.start) 148 | fmt.Fprintf(&buf, "%s response '%s - (%s)' in %dms.\n", 149 | direction, cc.method, id, elapsed/time.Millisecond) 150 | fmt.Fprintf(&buf, "Result: %s%s", msg.Result(), eor) 151 | } 152 | 153 | s.log.Write(buf.Bytes()) 154 | 155 | s.logMu.Unlock() 156 | } 157 | -------------------------------------------------------------------------------- /progress.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // WorkDoneProgressKind kind of WorkDoneProgress. 7 | // 8 | // @since 3.15.0. 9 | type WorkDoneProgressKind string 10 | 11 | // list of WorkDoneProgressKind. 12 | const ( 13 | // WorkDoneProgressKindBegin kind of WorkDoneProgressBegin. 14 | WorkDoneProgressKindBegin WorkDoneProgressKind = "begin" 15 | 16 | // WorkDoneProgressKindReport kind of WorkDoneProgressReport. 17 | WorkDoneProgressKindReport WorkDoneProgressKind = "report" 18 | 19 | // WorkDoneProgressKindEnd kind of WorkDoneProgressEnd. 20 | WorkDoneProgressKindEnd WorkDoneProgressKind = "end" 21 | ) 22 | 23 | // WorkDoneProgressBegin is the to start progress reporting a "$/progress" notification. 24 | // 25 | // @since 3.15.0. 26 | type WorkDoneProgressBegin struct { 27 | // Kind is the kind of WorkDoneProgressBegin. 28 | // 29 | // It must be WorkDoneProgressKindBegin. 30 | Kind WorkDoneProgressKind `json:"kind"` 31 | 32 | // Title mandatory title of the progress operation. Used to briefly inform about 33 | // the kind of operation being performed. 34 | // 35 | // Examples: "Indexing" or "Linking dependencies". 36 | Title string `json:"title"` 37 | 38 | // Cancellable controls if a cancel button should show to allow the user to cancel the 39 | // long running operation. Clients that don't support cancellation are allowed 40 | // to ignore the setting. 41 | Cancellable bool `json:"cancellable,omitempty"` 42 | 43 | // Message is optional, more detailed associated progress message. Contains 44 | // complementary information to the `title`. 45 | // 46 | // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". 47 | // If unset, the previous progress message (if any) is still valid. 48 | Message string `json:"message,omitempty"` 49 | 50 | // Percentage is optional progress percentage to display (value 100 is considered 100%). 51 | // If not provided infinite progress is assumed and clients are allowed 52 | // to ignore the `percentage` value in subsequent in report notifications. 53 | // 54 | // The value should be steadily rising. Clients are free to ignore values 55 | // that are not following this rule. 56 | Percentage uint32 `json:"percentage,omitempty"` 57 | } 58 | 59 | // WorkDoneProgressReport is the reporting progress is done. 60 | // 61 | // @since 3.15.0. 62 | type WorkDoneProgressReport struct { 63 | // Kind is the kind of WorkDoneProgressReport. 64 | // 65 | // It must be WorkDoneProgressKindReport. 66 | Kind WorkDoneProgressKind `json:"kind"` 67 | 68 | // Cancellable controls enablement state of a cancel button. 69 | // 70 | // Clients that don't support cancellation or don't support controlling the button's 71 | // enablement state are allowed to ignore the property. 72 | Cancellable bool `json:"cancellable,omitempty"` 73 | 74 | // Message is optional, more detailed associated progress message. Contains 75 | // complementary information to the `title`. 76 | // 77 | // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". 78 | // If unset, the previous progress message (if any) is still valid. 79 | Message string `json:"message,omitempty"` 80 | 81 | // Percentage is optional progress percentage to display (value 100 is considered 100%). 82 | // If not provided infinite progress is assumed and clients are allowed 83 | // to ignore the `percentage` value in subsequent in report notifications. 84 | // 85 | // The value should be steadily rising. Clients are free to ignore values 86 | // that are not following this rule. 87 | Percentage uint32 `json:"percentage,omitempty"` 88 | } 89 | 90 | // WorkDoneProgressEnd is the signaling the end of a progress reporting is done. 91 | // 92 | // @since 3.15.0. 93 | type WorkDoneProgressEnd struct { 94 | // Kind is the kind of WorkDoneProgressEnd. 95 | // 96 | // It must be WorkDoneProgressKindEnd. 97 | Kind WorkDoneProgressKind `json:"kind"` 98 | 99 | // Message is optional, a final message indicating to for example indicate the outcome 100 | // of the operation. 101 | Message string `json:"message,omitempty"` 102 | } 103 | 104 | // WorkDoneProgressParams is a parameter property of report work done progress. 105 | // 106 | // @since 3.15.0. 107 | type WorkDoneProgressParams struct { 108 | // WorkDoneToken an optional token that a server can use to report work done progress. 109 | WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"` 110 | } 111 | 112 | // PartialResultParams is the parameter literal used to pass a partial result token. 113 | // 114 | // @since 3.15.0. 115 | type PartialResultParams struct { 116 | // PartialResultToken an optional token that a server can use to report partial results 117 | // (for example, streaming) to the client. 118 | PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` 119 | } 120 | -------------------------------------------------------------------------------- /progress_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/google/go-cmp/cmp" 10 | "github.com/segmentio/encoding/json" 11 | ) 12 | 13 | func TestWorkDoneProgressBegin(t *testing.T) { 14 | t.Parallel() 15 | 16 | const ( 17 | want = `{"kind":"begin","title":"testTitle","cancellable":true,"message":"testMessage","percentage":30}` 18 | wantNil = `{"kind":"begin","title":"testTitle"}` 19 | wantInvalid = `{"kind":"invalid","title":"invalidTitle","cancellable":false,"message":"invalidMessage","percentage":0}` 20 | ) 21 | wantType := WorkDoneProgressBegin{ 22 | Kind: WorkDoneProgressKindBegin, 23 | Title: "testTitle", 24 | Cancellable: true, 25 | Message: "testMessage", 26 | Percentage: uint32(30), 27 | } 28 | wantTypeNil := WorkDoneProgressBegin{ 29 | Kind: WorkDoneProgressKindBegin, 30 | Title: "testTitle", 31 | } 32 | 33 | t.Run("Marshal", func(t *testing.T) { 34 | tests := []struct { 35 | name string 36 | field WorkDoneProgressBegin 37 | want string 38 | wantMarshalErr bool 39 | wantErr bool 40 | }{ 41 | { 42 | name: "Valid", 43 | field: wantType, 44 | want: want, 45 | wantMarshalErr: false, 46 | wantErr: false, 47 | }, 48 | { 49 | name: "Nil", 50 | field: wantTypeNil, 51 | want: wantNil, 52 | wantMarshalErr: false, 53 | wantErr: false, 54 | }, 55 | { 56 | name: "Invalid", 57 | field: wantType, 58 | want: wantInvalid, 59 | wantMarshalErr: false, 60 | wantErr: true, 61 | }, 62 | } 63 | for _, tt := range tests { 64 | tt := tt 65 | t.Run(tt.name, func(t *testing.T) { 66 | t.Parallel() 67 | 68 | got, err := json.Marshal(&tt.field) 69 | if (err != nil) != tt.wantMarshalErr { 70 | t.Fatal(err) 71 | } 72 | 73 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 74 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 75 | } 76 | }) 77 | } 78 | }) 79 | 80 | t.Run("Unmarshal", func(t *testing.T) { 81 | tests := []struct { 82 | name string 83 | field string 84 | want WorkDoneProgressBegin 85 | wantUnmarshalErr bool 86 | wantErr bool 87 | }{ 88 | { 89 | name: "Valid", 90 | field: want, 91 | want: wantType, 92 | wantUnmarshalErr: false, 93 | wantErr: false, 94 | }, 95 | { 96 | name: "Nil", 97 | field: wantNil, 98 | want: wantTypeNil, 99 | wantUnmarshalErr: false, 100 | wantErr: false, 101 | }, 102 | { 103 | name: "Invalid", 104 | field: wantInvalid, 105 | want: wantType, 106 | wantUnmarshalErr: false, 107 | wantErr: true, 108 | }, 109 | } 110 | for _, tt := range tests { 111 | tt := tt 112 | t.Run(tt.name, func(t *testing.T) { 113 | t.Parallel() 114 | 115 | var got WorkDoneProgressBegin 116 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 117 | t.Fatal(err) 118 | } 119 | 120 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 121 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 122 | } 123 | }) 124 | } 125 | }) 126 | } 127 | 128 | func TestWorkDoneProgressReport(t *testing.T) { 129 | t.Parallel() 130 | 131 | const ( 132 | want = `{"kind":"report","cancellable":true,"message":"testMessage","percentage":30}` 133 | wantNil = `{"kind":"report"}` 134 | wantInvalid = `{"kind":"invalid","cancellable":false,"message":"invalidMessage","percentage":0}` 135 | ) 136 | wantType := WorkDoneProgressReport{ 137 | Kind: WorkDoneProgressKindReport, 138 | Cancellable: true, 139 | Message: "testMessage", 140 | Percentage: uint32(30), 141 | } 142 | wantTypeNil := WorkDoneProgressReport{ 143 | Kind: WorkDoneProgressKindReport, 144 | } 145 | 146 | t.Run("Marshal", func(t *testing.T) { 147 | tests := []struct { 148 | name string 149 | field WorkDoneProgressReport 150 | want string 151 | wantMarshalErr bool 152 | wantErr bool 153 | }{ 154 | { 155 | name: "Valid", 156 | field: wantType, 157 | want: want, 158 | wantMarshalErr: false, 159 | wantErr: false, 160 | }, 161 | { 162 | name: "Nil", 163 | field: wantTypeNil, 164 | want: wantNil, 165 | wantMarshalErr: false, 166 | wantErr: false, 167 | }, 168 | { 169 | name: "Invalid", 170 | field: wantType, 171 | want: wantInvalid, 172 | wantMarshalErr: false, 173 | wantErr: true, 174 | }, 175 | } 176 | for _, tt := range tests { 177 | tt := tt 178 | t.Run(tt.name, func(t *testing.T) { 179 | t.Parallel() 180 | 181 | got, err := json.Marshal(&tt.field) 182 | if (err != nil) != tt.wantMarshalErr { 183 | t.Fatal(err) 184 | } 185 | 186 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 187 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 188 | } 189 | }) 190 | } 191 | }) 192 | 193 | t.Run("Unmarshal", func(t *testing.T) { 194 | tests := []struct { 195 | name string 196 | field string 197 | want WorkDoneProgressReport 198 | wantUnmarshalErr bool 199 | wantErr bool 200 | }{ 201 | { 202 | name: "Valid", 203 | field: want, 204 | want: wantType, 205 | wantUnmarshalErr: false, 206 | wantErr: false, 207 | }, 208 | { 209 | name: "Nil", 210 | field: wantNil, 211 | want: wantTypeNil, 212 | wantUnmarshalErr: false, 213 | wantErr: false, 214 | }, 215 | { 216 | name: "Invalid", 217 | field: wantInvalid, 218 | want: wantType, 219 | wantUnmarshalErr: false, 220 | wantErr: true, 221 | }, 222 | } 223 | for _, tt := range tests { 224 | tt := tt 225 | t.Run(tt.name, func(t *testing.T) { 226 | t.Parallel() 227 | 228 | var got WorkDoneProgressReport 229 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 230 | t.Fatal(err) 231 | } 232 | 233 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 234 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 235 | } 236 | }) 237 | } 238 | }) 239 | } 240 | 241 | func TestWorkDoneProgressEnd(t *testing.T) { 242 | t.Parallel() 243 | 244 | const ( 245 | want = `{"kind":"end","message":"testMessage"}` 246 | wantNil = `{"kind":"end"}` 247 | wantInvalid = `{"kind":"invalid","message":"invalidMessage"}` 248 | ) 249 | wantType := WorkDoneProgressEnd{ 250 | Kind: WorkDoneProgressKindEnd, 251 | Message: "testMessage", 252 | } 253 | wantTypeNil := WorkDoneProgressEnd{ 254 | Kind: WorkDoneProgressKindEnd, 255 | } 256 | 257 | t.Run("Marshal", func(t *testing.T) { 258 | tests := []struct { 259 | name string 260 | field WorkDoneProgressEnd 261 | want string 262 | wantMarshalErr bool 263 | wantErr bool 264 | }{ 265 | { 266 | name: "Valid", 267 | field: wantType, 268 | want: want, 269 | wantMarshalErr: false, 270 | wantErr: false, 271 | }, 272 | { 273 | name: "Nil", 274 | field: wantTypeNil, 275 | want: wantNil, 276 | wantMarshalErr: false, 277 | wantErr: false, 278 | }, 279 | { 280 | name: "Invalid", 281 | field: wantType, 282 | want: wantInvalid, 283 | wantMarshalErr: false, 284 | wantErr: true, 285 | }, 286 | } 287 | for _, tt := range tests { 288 | tt := tt 289 | t.Run(tt.name, func(t *testing.T) { 290 | t.Parallel() 291 | 292 | got, err := json.Marshal(&tt.field) 293 | if (err != nil) != tt.wantMarshalErr { 294 | t.Fatal(err) 295 | } 296 | 297 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 298 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 299 | } 300 | }) 301 | } 302 | }) 303 | 304 | t.Run("Unmarshal", func(t *testing.T) { 305 | tests := []struct { 306 | name string 307 | field string 308 | want WorkDoneProgressEnd 309 | wantUnmarshalErr bool 310 | wantErr bool 311 | }{ 312 | { 313 | name: "Valid", 314 | field: want, 315 | want: wantType, 316 | wantUnmarshalErr: false, 317 | wantErr: false, 318 | }, 319 | { 320 | name: "Nil", 321 | field: wantNil, 322 | want: wantTypeNil, 323 | wantUnmarshalErr: false, 324 | wantErr: false, 325 | }, 326 | { 327 | name: "Invalid", 328 | field: wantInvalid, 329 | want: wantType, 330 | wantUnmarshalErr: false, 331 | wantErr: true, 332 | }, 333 | } 334 | for _, tt := range tests { 335 | tt := tt 336 | t.Run(tt.name, func(t *testing.T) { 337 | t.Parallel() 338 | 339 | var got WorkDoneProgressEnd 340 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 341 | t.Fatal(err) 342 | } 343 | 344 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 345 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 346 | } 347 | }) 348 | } 349 | }) 350 | } 351 | 352 | func TestWorkDoneProgressParams(t *testing.T) { 353 | t.Parallel() 354 | 355 | const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" 356 | const want = `{"workDoneToken":"` + wantWorkDoneToken + `"}` 357 | 358 | wantType := WorkDoneProgressParams{ 359 | WorkDoneToken: NewProgressToken(wantWorkDoneToken), 360 | } 361 | 362 | t.Run("Marshal", func(t *testing.T) { 363 | tests := []struct { 364 | name string 365 | field WorkDoneProgressParams 366 | want string 367 | wantMarshalErr bool 368 | wantErr bool 369 | }{ 370 | { 371 | name: "Valid", 372 | field: wantType, 373 | want: want, 374 | wantMarshalErr: false, 375 | wantErr: false, 376 | }, 377 | } 378 | for _, tt := range tests { 379 | tt := tt 380 | t.Run(tt.name, func(t *testing.T) { 381 | t.Parallel() 382 | 383 | got, err := json.Marshal(&tt.field) 384 | if (err != nil) != tt.wantMarshalErr { 385 | t.Fatal(err) 386 | } 387 | 388 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 389 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 390 | } 391 | }) 392 | } 393 | }) 394 | 395 | t.Run("Unmarshal", func(t *testing.T) { 396 | tests := []struct { 397 | name string 398 | field string 399 | want WorkDoneProgressParams 400 | wantUnmarshalErr bool 401 | wantErr bool 402 | }{ 403 | { 404 | name: "Valid", 405 | field: want, 406 | want: wantType, 407 | wantUnmarshalErr: false, 408 | wantErr: false, 409 | }, 410 | } 411 | for _, tt := range tests { 412 | tt := tt 413 | t.Run(tt.name, func(t *testing.T) { 414 | t.Parallel() 415 | 416 | var got WorkDoneProgressParams 417 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 418 | t.Fatal(err) 419 | } 420 | 421 | if workDoneToken := got.WorkDoneToken; workDoneToken != nil { 422 | if diff := cmp.Diff(workDoneToken.String(), wantWorkDoneToken); (diff != "") != tt.wantErr { 423 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 424 | } 425 | } 426 | }) 427 | } 428 | }) 429 | } 430 | 431 | func TestPartialResultParams(t *testing.T) { 432 | t.Parallel() 433 | 434 | const wantPartialResultParams = "156edea9-9d8d-422f-b7ee-81a84594afbb" 435 | const want = `{"partialResultToken":"` + wantPartialResultParams + `"}` 436 | 437 | wantType := PartialResultParams{ 438 | PartialResultToken: NewProgressToken(wantPartialResultParams), 439 | } 440 | 441 | t.Run("Marshal", func(t *testing.T) { 442 | tests := []struct { 443 | name string 444 | field PartialResultParams 445 | want string 446 | wantMarshalErr bool 447 | wantErr bool 448 | }{ 449 | { 450 | name: "Valid", 451 | field: wantType, 452 | want: want, 453 | wantMarshalErr: false, 454 | wantErr: false, 455 | }, 456 | } 457 | for _, tt := range tests { 458 | tt := tt 459 | t.Run(tt.name, func(t *testing.T) { 460 | t.Parallel() 461 | 462 | got, err := json.Marshal(&tt.field) 463 | if (err != nil) != tt.wantMarshalErr { 464 | t.Fatal(err) 465 | } 466 | 467 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 468 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 469 | } 470 | }) 471 | } 472 | }) 473 | 474 | t.Run("Unmarshal", func(t *testing.T) { 475 | tests := []struct { 476 | name string 477 | field string 478 | want PartialResultParams 479 | wantUnmarshalErr bool 480 | wantErr bool 481 | }{ 482 | { 483 | name: "Valid", 484 | field: want, 485 | want: wantType, 486 | wantUnmarshalErr: false, 487 | wantErr: false, 488 | }, 489 | } 490 | for _, tt := range tests { 491 | tt := tt 492 | t.Run(tt.name, func(t *testing.T) { 493 | t.Parallel() 494 | 495 | var got PartialResultParams 496 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 497 | t.Fatal(err) 498 | } 499 | 500 | if partialResultToken := got.PartialResultToken; partialResultToken != nil { 501 | if diff := cmp.Diff(partialResultToken.String(), wantPartialResultParams); (diff != "") != tt.wantErr { 502 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 503 | } 504 | } 505 | }) 506 | } 507 | }) 508 | } 509 | -------------------------------------------------------------------------------- /protocol.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "context" 8 | 9 | "go.uber.org/zap" 10 | 11 | "go.lsp.dev/jsonrpc2" 12 | ) 13 | 14 | // NewServer returns the context in which client is embedded, jsonrpc2.Conn, and the Client. 15 | func NewServer(ctx context.Context, server Server, stream jsonrpc2.Stream, logger *zap.Logger) (context.Context, jsonrpc2.Conn, Client) { 16 | conn := jsonrpc2.NewConn(stream) 17 | cliint := ClientDispatcher(conn, logger.Named("client")) 18 | ctx = WithClient(ctx, cliint) 19 | 20 | conn.Go(ctx, 21 | Handlers( 22 | ServerHandler(server, jsonrpc2.MethodNotFoundHandler), 23 | ), 24 | ) 25 | 26 | return ctx, conn, cliint 27 | } 28 | 29 | // NewClient returns the context in which Client is embedded, jsonrpc2.Conn, and the Server. 30 | func NewClient(ctx context.Context, client Client, stream jsonrpc2.Stream, logger *zap.Logger) (context.Context, jsonrpc2.Conn, Server) { 31 | ctx = WithClient(ctx, client) 32 | 33 | conn := jsonrpc2.NewConn(stream) 34 | conn.Go(ctx, 35 | Handlers( 36 | ClientHandler(client, jsonrpc2.MethodNotFoundHandler), 37 | ), 38 | ) 39 | server := ServerDispatcher(conn, logger.Named("server")) 40 | 41 | return ctx, conn, server 42 | } 43 | -------------------------------------------------------------------------------- /registration.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // Registration general parameters to register for a capability. 7 | type Registration struct { 8 | // ID is the id used to register the request. The id can be used to deregister 9 | // the request again. 10 | ID string `json:"id"` 11 | 12 | // Method is the method / capability to register for. 13 | Method string `json:"method"` 14 | 15 | // RegisterOptions options necessary for the registration. 16 | RegisterOptions interface{} `json:"registerOptions,omitempty"` 17 | } 18 | 19 | // RegistrationParams params of Register Capability. 20 | type RegistrationParams struct { 21 | Registrations []Registration `json:"registrations"` 22 | } 23 | 24 | // TextDocumentRegistrationOptions TextDocumentRegistration options. 25 | type TextDocumentRegistrationOptions struct { 26 | // DocumentSelector a document selector to identify the scope of the registration. If set to null 27 | // the document selector provided on the client side will be used. 28 | DocumentSelector DocumentSelector `json:"documentSelector"` 29 | } 30 | 31 | // Unregistration general parameters to unregister a capability. 32 | type Unregistration struct { 33 | // ID is the id used to unregister the request or notification. Usually an id 34 | // provided during the register request. 35 | ID string `json:"id"` 36 | 37 | // Method is the method / capability to unregister for. 38 | Method string `json:"method"` 39 | } 40 | 41 | // UnregistrationParams params of Unregistration. 42 | type UnregistrationParams struct { 43 | Unregisterations []Unregistration `json:"unregisterations"` 44 | } 45 | -------------------------------------------------------------------------------- /registration_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/google/go-cmp/cmp" 10 | "github.com/segmentio/encoding/json" 11 | ) 12 | 13 | func TestRegistration(t *testing.T) { 14 | t.Parallel() 15 | 16 | const ( 17 | want = `{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}` 18 | wantInterfaces = `{"id":"1","method":"testMethod","registerOptions":["foo","bar"]}` 19 | wantNil = `{"id":"1","method":"testMethod"}` 20 | wantInvalid = `{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}` 21 | ) 22 | wantTypeStringInterface := Registration{ 23 | ID: "1", 24 | Method: "testMethod", 25 | RegisterOptions: map[string]interface{}{ 26 | "foo": "bar", 27 | }, 28 | } 29 | wantTypeStringString := Registration{ 30 | ID: "1", 31 | Method: "testMethod", 32 | RegisterOptions: map[string]string{ 33 | "foo": "bar", 34 | }, 35 | } 36 | wantTypeInterfaces := Registration{ 37 | ID: "1", 38 | Method: "testMethod", 39 | RegisterOptions: []interface{}{ 40 | "foo", 41 | "bar", 42 | }, 43 | } 44 | wantTypeNil := Registration{ 45 | ID: "1", 46 | Method: "testMethod", 47 | } 48 | 49 | t.Run("Marshal", func(t *testing.T) { 50 | tests := []struct { 51 | name string 52 | field Registration 53 | want string 54 | wantMarshalErr bool 55 | wantErr bool 56 | }{ 57 | { 58 | name: "ValidStringInterface", 59 | field: wantTypeStringInterface, 60 | want: want, 61 | wantMarshalErr: false, 62 | wantErr: false, 63 | }, 64 | { 65 | name: "ValidStringString", 66 | field: wantTypeStringString, 67 | want: want, 68 | wantMarshalErr: false, 69 | wantErr: false, 70 | }, 71 | { 72 | name: "ValidInterfaces", 73 | field: wantTypeInterfaces, 74 | want: wantInterfaces, 75 | wantMarshalErr: false, 76 | wantErr: false, 77 | }, 78 | { 79 | name: "ValidNilAll", 80 | field: wantTypeNil, 81 | want: wantNil, 82 | wantMarshalErr: false, 83 | wantErr: false, 84 | }, 85 | { 86 | name: "Invalid", 87 | field: wantTypeStringInterface, 88 | want: wantInvalid, 89 | wantMarshalErr: false, 90 | wantErr: true, 91 | }, 92 | } 93 | for _, tt := range tests { 94 | tt := tt 95 | t.Run(tt.name, func(t *testing.T) { 96 | t.Parallel() 97 | 98 | got, err := json.Marshal(&tt.field) 99 | if (err != nil) != tt.wantMarshalErr { 100 | t.Fatal(err) 101 | } 102 | 103 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 104 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 105 | } 106 | }) 107 | } 108 | }) 109 | 110 | t.Run("Unmarshal", func(t *testing.T) { 111 | tests := []struct { 112 | name string 113 | field string 114 | want Registration 115 | wantUnmarshalErr bool 116 | wantErr bool 117 | }{ 118 | { 119 | name: "ValidStringInterface", 120 | field: want, 121 | want: wantTypeStringInterface, 122 | wantUnmarshalErr: false, 123 | wantErr: false, 124 | }, 125 | { 126 | name: "ValidInterfaces", 127 | field: wantInterfaces, 128 | want: wantTypeInterfaces, 129 | wantUnmarshalErr: false, 130 | wantErr: false, 131 | }, 132 | { 133 | name: "ValidNilAll", 134 | field: wantNil, 135 | want: wantTypeNil, 136 | wantUnmarshalErr: false, 137 | wantErr: false, 138 | }, 139 | { 140 | name: "Invalid", 141 | field: wantInvalid, 142 | want: wantTypeStringInterface, 143 | wantUnmarshalErr: false, 144 | wantErr: true, 145 | }, 146 | } 147 | for _, tt := range tests { 148 | tt := tt 149 | t.Run(tt.name, func(t *testing.T) { 150 | t.Parallel() 151 | 152 | var got Registration 153 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 154 | t.Fatal(err) 155 | } 156 | 157 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 158 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 159 | } 160 | }) 161 | } 162 | }) 163 | } 164 | 165 | func TestRegistrationParams(t *testing.T) { 166 | t.Parallel() 167 | 168 | const ( 169 | want = `{"registrations":[{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}]}` 170 | wantNil = `{"registrations":[{"id":"1","method":"testMethod"}]}` 171 | wantInvalid = `{"registrations":[{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}]}` 172 | ) 173 | wantType := RegistrationParams{ 174 | Registrations: []Registration{ 175 | { 176 | ID: "1", 177 | Method: "testMethod", 178 | RegisterOptions: map[string]interface{}{ 179 | "foo": "bar", 180 | }, 181 | }, 182 | }, 183 | } 184 | wantTypeNil := RegistrationParams{ 185 | Registrations: []Registration{ 186 | { 187 | ID: "1", 188 | Method: "testMethod", 189 | }, 190 | }, 191 | } 192 | 193 | t.Run("Marshal", func(t *testing.T) { 194 | tests := []struct { 195 | name string 196 | field RegistrationParams 197 | want string 198 | wantMarshalErr bool 199 | wantErr bool 200 | }{ 201 | { 202 | name: "Valid", 203 | field: wantType, 204 | want: want, 205 | wantMarshalErr: false, 206 | wantErr: false, 207 | }, 208 | { 209 | name: "ValidNilAll", 210 | field: wantTypeNil, 211 | want: wantNil, 212 | wantMarshalErr: false, 213 | wantErr: false, 214 | }, 215 | { 216 | name: "Invalid", 217 | field: wantType, 218 | want: wantInvalid, 219 | wantMarshalErr: false, 220 | wantErr: true, 221 | }, 222 | } 223 | for _, tt := range tests { 224 | tt := tt 225 | t.Run(tt.name, func(t *testing.T) { 226 | t.Parallel() 227 | 228 | got, err := json.Marshal(&tt.field) 229 | if (err != nil) != tt.wantMarshalErr { 230 | t.Fatal(err) 231 | } 232 | 233 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 234 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 235 | } 236 | }) 237 | } 238 | }) 239 | 240 | t.Run("Unmarshal", func(t *testing.T) { 241 | tests := []struct { 242 | name string 243 | field string 244 | want RegistrationParams 245 | wantUnmarshalErr bool 246 | wantErr bool 247 | }{ 248 | { 249 | name: "Valid", 250 | field: want, 251 | want: wantType, 252 | wantUnmarshalErr: false, 253 | wantErr: false, 254 | }, 255 | { 256 | name: "ValidNilAll", 257 | field: wantNil, 258 | want: wantTypeNil, 259 | wantUnmarshalErr: false, 260 | wantErr: false, 261 | }, 262 | { 263 | name: "Invalid", 264 | field: wantInvalid, 265 | want: wantType, 266 | wantUnmarshalErr: false, 267 | wantErr: true, 268 | }, 269 | } 270 | for _, tt := range tests { 271 | tt := tt 272 | t.Run(tt.name, func(t *testing.T) { 273 | t.Parallel() 274 | 275 | var got RegistrationParams 276 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 277 | t.Fatal(err) 278 | } 279 | 280 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 281 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 282 | } 283 | }) 284 | } 285 | }) 286 | } 287 | 288 | func TestTextDocumentRegistrationOptions(t *testing.T) { 289 | t.Parallel() 290 | 291 | const ( 292 | want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]}` 293 | wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}]}` 294 | ) 295 | wantType := TextDocumentRegistrationOptions{ 296 | DocumentSelector: DocumentSelector{ 297 | { 298 | Language: "go", 299 | Scheme: "file", 300 | Pattern: "*.go", 301 | }, 302 | { 303 | Language: "cpp", 304 | Scheme: "untitled", 305 | Pattern: "*.{cpp,hpp}", 306 | }, 307 | }, 308 | } 309 | 310 | t.Run("Marshal", func(t *testing.T) { 311 | tests := []struct { 312 | name string 313 | field TextDocumentRegistrationOptions 314 | want string 315 | wantMarshalErr bool 316 | wantErr bool 317 | }{ 318 | { 319 | name: "Valid", 320 | field: wantType, 321 | want: want, 322 | wantMarshalErr: false, 323 | wantErr: false, 324 | }, 325 | { 326 | name: "Invalid", 327 | field: wantType, 328 | want: wantInvalid, 329 | wantMarshalErr: false, 330 | wantErr: true, 331 | }, 332 | } 333 | for _, tt := range tests { 334 | tt := tt 335 | t.Run(tt.name, func(t *testing.T) { 336 | t.Parallel() 337 | 338 | got, err := json.Marshal(&tt.field) 339 | if (err != nil) != tt.wantMarshalErr { 340 | t.Fatal(err) 341 | } 342 | 343 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 344 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 345 | } 346 | }) 347 | } 348 | }) 349 | 350 | t.Run("Unmarshal", func(t *testing.T) { 351 | tests := []struct { 352 | name string 353 | field string 354 | want TextDocumentRegistrationOptions 355 | wantUnmarshalErr bool 356 | wantErr bool 357 | }{ 358 | { 359 | name: "Valid", 360 | field: want, 361 | want: wantType, 362 | wantUnmarshalErr: false, 363 | wantErr: false, 364 | }, 365 | { 366 | name: "Invalid", 367 | field: wantInvalid, 368 | want: wantType, 369 | wantUnmarshalErr: false, 370 | wantErr: true, 371 | }, 372 | } 373 | for _, tt := range tests { 374 | tt := tt 375 | t.Run(tt.name, func(t *testing.T) { 376 | t.Parallel() 377 | 378 | var got TextDocumentRegistrationOptions 379 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 380 | t.Fatal(err) 381 | } 382 | 383 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 384 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 385 | } 386 | }) 387 | } 388 | }) 389 | } 390 | 391 | func TestUnregistration(t *testing.T) { 392 | t.Parallel() 393 | 394 | const ( 395 | want = `{"id":"1","method":"testMethod"}` 396 | wantInvalid = `{"id":"2","method":"invalidMethod"}` 397 | ) 398 | wantType := Unregistration{ 399 | ID: "1", 400 | Method: "testMethod", 401 | } 402 | 403 | t.Run("Marshal", func(t *testing.T) { 404 | tests := []struct { 405 | name string 406 | field Unregistration 407 | want string 408 | wantMarshalErr bool 409 | wantErr bool 410 | }{ 411 | { 412 | name: "Valid", 413 | field: wantType, 414 | want: want, 415 | wantMarshalErr: false, 416 | wantErr: false, 417 | }, 418 | { 419 | name: "Invalid", 420 | field: wantType, 421 | want: wantInvalid, 422 | wantMarshalErr: false, 423 | wantErr: true, 424 | }, 425 | } 426 | for _, tt := range tests { 427 | tt := tt 428 | t.Run(tt.name, func(t *testing.T) { 429 | t.Parallel() 430 | 431 | got, err := json.Marshal(&tt.field) 432 | if (err != nil) != tt.wantMarshalErr { 433 | t.Fatal(err) 434 | } 435 | 436 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 437 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 438 | } 439 | }) 440 | } 441 | }) 442 | 443 | t.Run("Unmarshal", func(t *testing.T) { 444 | tests := []struct { 445 | name string 446 | field string 447 | want Unregistration 448 | wantUnmarshalErr bool 449 | wantErr bool 450 | }{ 451 | { 452 | name: "Valid", 453 | field: want, 454 | want: wantType, 455 | wantUnmarshalErr: false, 456 | wantErr: false, 457 | }, 458 | { 459 | name: "Invalid", 460 | field: wantInvalid, 461 | want: wantType, 462 | wantUnmarshalErr: false, 463 | wantErr: true, 464 | }, 465 | } 466 | for _, tt := range tests { 467 | tt := tt 468 | t.Run(tt.name, func(t *testing.T) { 469 | t.Parallel() 470 | 471 | var got Unregistration 472 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 473 | t.Fatal(err) 474 | } 475 | 476 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 477 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 478 | } 479 | }) 480 | } 481 | }) 482 | } 483 | 484 | func TestUnregistrationParams(t *testing.T) { 485 | t.Parallel() 486 | 487 | const ( 488 | want = `{"unregisterations":[{"id":"1","method":"testMethod"}]}` 489 | wantInvalid = `{"unregisterations":[{"id":"2","method":"invalidMethod"}]}` 490 | ) 491 | wantType := UnregistrationParams{ 492 | Unregisterations: []Unregistration{ 493 | { 494 | ID: "1", 495 | Method: "testMethod", 496 | }, 497 | }, 498 | } 499 | 500 | t.Run("Marshal", func(t *testing.T) { 501 | tests := []struct { 502 | name string 503 | field UnregistrationParams 504 | want string 505 | wantMarshalErr bool 506 | wantErr bool 507 | }{ 508 | { 509 | name: "Valid", 510 | field: wantType, 511 | want: want, 512 | wantMarshalErr: false, 513 | wantErr: false, 514 | }, 515 | { 516 | name: "Invalid", 517 | field: wantType, 518 | want: wantInvalid, 519 | wantMarshalErr: false, 520 | wantErr: true, 521 | }, 522 | } 523 | for _, tt := range tests { 524 | tt := tt 525 | t.Run(tt.name, func(t *testing.T) { 526 | t.Parallel() 527 | 528 | got, err := json.Marshal(&tt.field) 529 | if (err != nil) != tt.wantMarshalErr { 530 | t.Fatal(err) 531 | } 532 | 533 | if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { 534 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 535 | } 536 | }) 537 | } 538 | }) 539 | 540 | t.Run("Unmarshal", func(t *testing.T) { 541 | tests := []struct { 542 | name string 543 | field string 544 | want UnregistrationParams 545 | wantUnmarshalErr bool 546 | wantErr bool 547 | }{ 548 | { 549 | name: "Valid", 550 | field: want, 551 | want: wantType, 552 | wantUnmarshalErr: false, 553 | wantErr: false, 554 | }, 555 | { 556 | name: "Invalid", 557 | field: wantInvalid, 558 | want: wantType, 559 | wantUnmarshalErr: false, 560 | wantErr: true, 561 | }, 562 | } 563 | for _, tt := range tests { 564 | tt := tt 565 | t.Run(tt.name, func(t *testing.T) { 566 | t.Parallel() 567 | 568 | var got UnregistrationParams 569 | if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { 570 | t.Fatal(err) 571 | } 572 | 573 | if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { 574 | t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) 575 | } 576 | }) 577 | } 578 | }) 579 | } 580 | -------------------------------------------------------------------------------- /selectionrange.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // SelectionRangeProviderOptions selection range provider options interface. 7 | type SelectionRangeProviderOptions interface{} 8 | 9 | // SelectionRange represents a selection range represents a part of a selection hierarchy. 10 | // 11 | // A selection range may have a parent selection range that contains it. 12 | // 13 | // @since 3.15.0. 14 | type SelectionRange struct { 15 | // Range is the Range of this selection range. 16 | Range Range `json:"range"` 17 | 18 | // Parent is the parent selection range containing this range. Therefore `parent.range` must contain this Range. 19 | Parent *SelectionRange `json:"parent,omitempty"` 20 | } 21 | 22 | // EnableSelectionRange is the whether the selection range. 23 | type EnableSelectionRange bool 24 | 25 | // compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface. 26 | var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil) 27 | 28 | // Value implements SelectionRangeProviderOptions interface. 29 | func (v EnableSelectionRange) Value() interface{} { 30 | return bool(v) 31 | } 32 | 33 | // NewEnableSelectionRange returns the new EnableSelectionRange underlying types SelectionRangeProviderOptions. 34 | func NewEnableSelectionRange(enable bool) SelectionRangeProviderOptions { 35 | v := EnableSelectionRange(enable) 36 | 37 | return &v 38 | } 39 | 40 | // SelectionRangeOptions is the server capability of selection range. 41 | type SelectionRangeOptions struct { 42 | WorkDoneProgressOptions 43 | } 44 | 45 | // compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface. 46 | var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil) 47 | 48 | // Value implements SelectionRangeProviderOptions interface. 49 | func (v *SelectionRangeOptions) Value() interface{} { 50 | return v 51 | } 52 | 53 | // NewSelectionRangeOptions returns the new SelectionRangeOptions underlying types SelectionRangeProviderOptions. 54 | func NewSelectionRangeOptions(enableWorkDoneProgress bool) SelectionRangeProviderOptions { 55 | v := SelectionRangeOptions{ 56 | WorkDoneProgressOptions: WorkDoneProgressOptions{ 57 | WorkDoneProgress: enableWorkDoneProgress, 58 | }, 59 | } 60 | 61 | return &v 62 | } 63 | 64 | // SelectionRangeRegistrationOptions is the server capability of selection range registration. 65 | type SelectionRangeRegistrationOptions struct { 66 | SelectionRangeOptions 67 | TextDocumentRegistrationOptions 68 | StaticRegistrationOptions 69 | } 70 | 71 | // compile time check whether the SelectionRangeRegistrationOptions implements a SelectionRangeProviderOptions interface. 72 | var _ SelectionRangeProviderOptions = (*SelectionRangeRegistrationOptions)(nil) 73 | 74 | // Value implements SelectionRangeProviderOptions interface. 75 | func (v *SelectionRangeRegistrationOptions) Value() interface{} { 76 | return v 77 | } 78 | 79 | // NewSelectionRangeRegistrationOptions returns the new SelectionRangeRegistrationOptions underlying types SelectionRangeProviderOptions. 80 | func NewSelectionRangeRegistrationOptions(enableWorkDoneProgress bool, selector DocumentSelector, id string) SelectionRangeProviderOptions { 81 | v := SelectionRangeRegistrationOptions{ 82 | SelectionRangeOptions: SelectionRangeOptions{ 83 | WorkDoneProgressOptions: WorkDoneProgressOptions{ 84 | WorkDoneProgress: enableWorkDoneProgress, 85 | }, 86 | }, 87 | TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ 88 | DocumentSelector: selector, 89 | }, 90 | StaticRegistrationOptions: StaticRegistrationOptions{ 91 | ID: id, 92 | }, 93 | } 94 | 95 | return &v 96 | } 97 | 98 | // SelectionRangeParams represents a parameter literal used in selection range requests. 99 | // 100 | // @since 3.15.0. 101 | type SelectionRangeParams struct { 102 | WorkDoneProgressParams 103 | PartialResultParams 104 | 105 | // TextDocument is the text document. 106 | TextDocument TextDocumentIdentifier `json:"textDocument"` 107 | 108 | // Positions is the positions inside the text document. 109 | Positions []Position `json:"positions"` 110 | } 111 | -------------------------------------------------------------------------------- /semantic_token.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // SemanticTokenTypes represents a type of semantic token. 7 | // 8 | // @since 3.16.0. 9 | type SemanticTokenTypes string 10 | 11 | // list of SemanticTokenTypes. 12 | const ( 13 | SemanticTokenNamespace SemanticTokenTypes = "namespace" 14 | 15 | // Represents a generic type. Acts as a fallback for types which 16 | // can't be mapped to a specific type like class or enum. 17 | SemanticTokenType SemanticTokenTypes = "type" 18 | SemanticTokenClass SemanticTokenTypes = "class" 19 | SemanticTokenEnum SemanticTokenTypes = "enum" 20 | SemanticTokenInterface SemanticTokenTypes = "interface" 21 | SemanticTokenStruct SemanticTokenTypes = "struct" 22 | SemanticTokenTypeParameter SemanticTokenTypes = "typeParameter" 23 | SemanticTokenParameter SemanticTokenTypes = "parameter" 24 | SemanticTokenVariable SemanticTokenTypes = "variable" 25 | SemanticTokenProperty SemanticTokenTypes = "property" 26 | SemanticTokenEnumMember SemanticTokenTypes = "enumMember" 27 | SemanticTokenEvent SemanticTokenTypes = "event" 28 | SemanticTokenFunction SemanticTokenTypes = "function" 29 | SemanticTokenMethod SemanticTokenTypes = "method" 30 | SemanticTokenMacro SemanticTokenTypes = "macro" 31 | SemanticTokenKeyword SemanticTokenTypes = "keyword" 32 | SemanticTokenModifier SemanticTokenTypes = "modifier" 33 | SemanticTokenComment SemanticTokenTypes = "comment" 34 | SemanticTokenString SemanticTokenTypes = "string" 35 | SemanticTokenNumber SemanticTokenTypes = "number" 36 | SemanticTokenRegexp SemanticTokenTypes = "regexp" 37 | SemanticTokenOperator SemanticTokenTypes = "operator" 38 | ) 39 | 40 | // SemanticTokenModifiers represents a modifiers of semantic token. 41 | // 42 | // @since 3.16.0. 43 | type SemanticTokenModifiers string 44 | 45 | // list of SemanticTokenModifiers. 46 | const ( 47 | SemanticTokenModifierDeclaration SemanticTokenModifiers = "declaration" 48 | SemanticTokenModifierDefinition SemanticTokenModifiers = "definition" 49 | SemanticTokenModifierReadonly SemanticTokenModifiers = "readonly" 50 | SemanticTokenModifierStatic SemanticTokenModifiers = "static" 51 | SemanticTokenModifierDeprecated SemanticTokenModifiers = "deprecated" 52 | SemanticTokenModifierAbstract SemanticTokenModifiers = "abstract" 53 | SemanticTokenModifierAsync SemanticTokenModifiers = "async" 54 | SemanticTokenModifierModification SemanticTokenModifiers = "modification" 55 | SemanticTokenModifierDocumentation SemanticTokenModifiers = "documentation" 56 | SemanticTokenModifierDefaultLibrary SemanticTokenModifiers = "defaultLibrary" 57 | ) 58 | 59 | // TokenFormat is an additional token format capability to allow future extensions of the format. 60 | // 61 | // @since 3.16.0. 62 | type TokenFormat string 63 | 64 | // TokenFormatRelative described using relative positions. 65 | const TokenFormatRelative TokenFormat = "relative" 66 | 67 | // SemanticTokensLegend is the on the capability level types and modifiers are defined using strings. 68 | // 69 | // However the real encoding happens using numbers. 70 | // 71 | // The server therefore needs to let the client know which numbers it is using for which types and modifiers. 72 | // 73 | // @since 3.16.0. 74 | type SemanticTokensLegend struct { 75 | // TokenTypes is the token types a server uses. 76 | TokenTypes []SemanticTokenTypes `json:"tokenTypes"` 77 | 78 | // TokenModifiers is the token modifiers a server uses. 79 | TokenModifiers []SemanticTokenModifiers `json:"tokenModifiers"` 80 | } 81 | 82 | // SemanticTokensParams params for the SemanticTokensFull request. 83 | // 84 | // @since 3.16.0. 85 | type SemanticTokensParams struct { 86 | WorkDoneProgressParams 87 | PartialResultParams 88 | 89 | // TextDocument is the text document. 90 | TextDocument TextDocumentIdentifier `json:"textDocument"` 91 | } 92 | 93 | // SemanticTokens is the result of SemanticTokensFull request. 94 | // 95 | // @since 3.16.0. 96 | type SemanticTokens struct { 97 | // ResultID an optional result id. If provided and clients support delta updating 98 | // the client will include the result id in the next semantic token request. 99 | // 100 | // A server can then instead of computing all semantic tokens again simply 101 | // send a delta. 102 | ResultID string `json:"resultId,omitempty"` 103 | 104 | // Data is the actual tokens. 105 | Data []uint32 `json:"data"` 106 | } 107 | 108 | // SemanticTokensPartialResult is the partial result of SemanticTokensFull request. 109 | // 110 | // @since 3.16.0. 111 | type SemanticTokensPartialResult struct { 112 | // Data is the actual tokens. 113 | Data []uint32 `json:"data"` 114 | } 115 | 116 | // SemanticTokensDeltaParams params for the SemanticTokensFullDelta request. 117 | // 118 | // @since 3.16.0. 119 | type SemanticTokensDeltaParams struct { 120 | WorkDoneProgressParams 121 | PartialResultParams 122 | 123 | // TextDocument is the text document. 124 | TextDocument TextDocumentIdentifier `json:"textDocument"` 125 | 126 | // PreviousResultID is the result id of a previous response. 127 | // 128 | // The result Id can either point to a full response or a delta response depending on what was received last. 129 | PreviousResultID string `json:"previousResultId"` 130 | } 131 | 132 | // SemanticTokensDelta result of SemanticTokensFullDelta request. 133 | // 134 | // @since 3.16.0. 135 | type SemanticTokensDelta struct { 136 | // ResultID is the result id. 137 | // 138 | // This field is readonly. 139 | ResultID string `json:"resultId,omitempty"` 140 | 141 | // Edits is the semantic token edits to transform a previous result into a new 142 | // result. 143 | Edits []SemanticTokensEdit `json:"edits"` 144 | } 145 | 146 | // SemanticTokensDeltaPartialResult is the partial result of SemanticTokensFullDelta request. 147 | // 148 | // @since 3.16.0. 149 | type SemanticTokensDeltaPartialResult struct { 150 | Edits []SemanticTokensEdit `json:"edits"` 151 | } 152 | 153 | // SemanticTokensEdit is the semantic token edit. 154 | // 155 | // @since 3.16.0. 156 | type SemanticTokensEdit struct { 157 | // Start is the start offset of the edit. 158 | Start uint32 `json:"start"` 159 | 160 | // DeleteCount is the count of elements to remove. 161 | DeleteCount uint32 `json:"deleteCount"` 162 | 163 | // Data is the elements to insert. 164 | Data []uint32 `json:"data,omitempty"` 165 | } 166 | 167 | // SemanticTokensRangeParams params for the SemanticTokensRange request. 168 | // 169 | // @since 3.16.0. 170 | type SemanticTokensRangeParams struct { 171 | WorkDoneProgressParams 172 | PartialResultParams 173 | 174 | // TextDocument is the text document. 175 | TextDocument TextDocumentIdentifier `json:"textDocument"` 176 | 177 | // Range is the range the semantic tokens are requested for. 178 | Range Range `json:"range"` 179 | } 180 | -------------------------------------------------------------------------------- /text.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "strconv" 8 | ) 9 | 10 | // DidOpenTextDocumentParams params of DidOpenTextDocument notification. 11 | type DidOpenTextDocumentParams struct { 12 | // TextDocument is the document that was opened. 13 | TextDocument TextDocumentItem `json:"textDocument"` 14 | } 15 | 16 | // DidChangeTextDocumentParams params of DidChangeTextDocument notification. 17 | type DidChangeTextDocumentParams struct { 18 | // TextDocument is the document that did change. The version number points 19 | // to the version after all provided content changes have 20 | // been applied. 21 | TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` 22 | 23 | // ContentChanges is the actual content changes. The content changes describe single state changes 24 | // to the document. So if there are two content changes c1 and c2 for a document 25 | // in state S then c1 move the document to S' and c2 to S''. 26 | ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` // []TextDocumentContentChangeEvent | text 27 | } 28 | 29 | // TextDocumentSaveReason represents reasons why a text document is saved. 30 | type TextDocumentSaveReason float64 31 | 32 | const ( 33 | // TextDocumentSaveReasonManual is the manually triggered, e.g. by the user pressing save, by starting debugging, 34 | // or by an API call. 35 | TextDocumentSaveReasonManual TextDocumentSaveReason = 1 36 | 37 | // TextDocumentSaveReasonAfterDelay is the automatic after a delay. 38 | TextDocumentSaveReasonAfterDelay TextDocumentSaveReason = 2 39 | 40 | // TextDocumentSaveReasonFocusOut when the editor lost focus. 41 | TextDocumentSaveReasonFocusOut TextDocumentSaveReason = 3 42 | ) 43 | 44 | // String implements fmt.Stringer. 45 | func (t TextDocumentSaveReason) String() string { 46 | switch t { 47 | case TextDocumentSaveReasonManual: 48 | return "Manual" 49 | case TextDocumentSaveReasonAfterDelay: 50 | return "AfterDelay" 51 | case TextDocumentSaveReasonFocusOut: 52 | return "FocusOut" 53 | default: 54 | return strconv.FormatFloat(float64(t), 'f', -10, 64) 55 | } 56 | } 57 | 58 | // TextDocumentChangeRegistrationOptions describe options to be used when registering for text document change events. 59 | type TextDocumentChangeRegistrationOptions struct { 60 | TextDocumentRegistrationOptions 61 | 62 | // SyncKind how documents are synced to the server. See TextDocumentSyncKind.Full 63 | // and TextDocumentSyncKind.Incremental. 64 | SyncKind TextDocumentSyncKind `json:"syncKind"` 65 | } 66 | 67 | // WillSaveTextDocumentParams is the parameters send in a will save text document notification. 68 | type WillSaveTextDocumentParams struct { 69 | // TextDocument is the document that will be saved. 70 | TextDocument TextDocumentIdentifier `json:"textDocument"` 71 | 72 | // Reason is the 'TextDocumentSaveReason'. 73 | Reason TextDocumentSaveReason `json:"reason,omitempty"` 74 | } 75 | 76 | // DidSaveTextDocumentParams params of DidSaveTextDocument notification. 77 | type DidSaveTextDocumentParams struct { 78 | // Text optional the content when saved. Depends on the includeText value 79 | // when the save notification was requested. 80 | Text string `json:"text,omitempty"` 81 | 82 | // TextDocument is the document that was saved. 83 | TextDocument TextDocumentIdentifier `json:"textDocument"` 84 | } 85 | 86 | // TextDocumentContentChangeEvent an event describing a change to a text document. If range and rangeLength are omitted 87 | // the new text is considered to be the full content of the document. 88 | type TextDocumentContentChangeEvent struct { 89 | // Range is the range of the document that changed. 90 | Range *Range `json:"range,omitempty"` 91 | 92 | // RangeLength is the length of the range that got replaced. 93 | RangeLength uint32 `json:"rangeLength,omitempty"` 94 | 95 | // Text is the new text of the document. 96 | Text string `json:"text"` 97 | } 98 | 99 | // TextDocumentSaveRegistrationOptions TextDocumentSave Registration options. 100 | type TextDocumentSaveRegistrationOptions struct { 101 | TextDocumentRegistrationOptions 102 | 103 | // IncludeText is the client is supposed to include the content on save. 104 | IncludeText bool `json:"includeText,omitempty"` 105 | } 106 | 107 | // DidCloseTextDocumentParams params of DidCloseTextDocument notification. 108 | type DidCloseTextDocumentParams struct { 109 | // TextDocument the document that was closed. 110 | TextDocument TextDocumentIdentifier `json:"textDocument"` 111 | } 112 | -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module go.lsp.dev/protocol/tools 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/golangci/golangci-lint v1.57.2 7 | github.com/zchee/goimportz v1.1.0 8 | gotest.tools/gotestsum v1.11.0 9 | mvdan.cc/gofumpt v0.6.0 10 | ) 11 | 12 | require ( 13 | 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 14 | 4d63.com/gochecknoglobals v0.2.1 // indirect 15 | github.com/4meepo/tagalign v1.3.3 // indirect 16 | github.com/Abirdcfly/dupword v0.0.14 // indirect 17 | github.com/Antonboom/errname v0.1.12 // indirect 18 | github.com/Antonboom/nilnil v0.1.7 // indirect 19 | github.com/Antonboom/testifylint v1.2.0 // indirect 20 | github.com/BurntSushi/toml v1.3.2 // indirect 21 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect 22 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect 23 | github.com/Masterminds/semver v1.5.0 // indirect 24 | github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect 25 | github.com/alecthomas/go-check-sumtype v0.1.4 // indirect 26 | github.com/alexkohler/nakedret/v2 v2.0.4 // indirect 27 | github.com/alexkohler/prealloc v1.0.0 // indirect 28 | github.com/alingse/asasalint v0.0.11 // indirect 29 | github.com/ashanbrown/forbidigo v1.6.0 // indirect 30 | github.com/ashanbrown/makezero v1.1.1 // indirect 31 | github.com/beorn7/perks v1.0.1 // indirect 32 | github.com/bitfield/gotestdox v0.2.1 // indirect 33 | github.com/bkielbasa/cyclop v1.2.1 // indirect 34 | github.com/blizzy78/varnamelen v0.8.0 // indirect 35 | github.com/bombsimon/wsl/v4 v4.2.1 // indirect 36 | github.com/breml/bidichk v0.2.7 // indirect 37 | github.com/breml/errchkjson v0.3.6 // indirect 38 | github.com/butuzov/ireturn v0.3.0 // indirect 39 | github.com/butuzov/mirror v1.1.0 // indirect 40 | github.com/catenacyber/perfsprint v0.7.1 // indirect 41 | github.com/ccojocar/zxcvbn-go v1.0.2 // indirect 42 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 43 | github.com/charithe/durationcheck v0.0.10 // indirect 44 | github.com/chavacava/garif v0.1.0 // indirect 45 | github.com/ckaznocha/intrange v0.1.1 // indirect 46 | github.com/curioswitch/go-reassign v0.2.0 // indirect 47 | github.com/daixiang0/gci v0.12.3 // indirect 48 | github.com/davecgh/go-spew v1.1.1 // indirect 49 | github.com/denis-tingaikin/go-header v0.5.0 // indirect 50 | github.com/dnephin/pflag v1.0.7 // indirect 51 | github.com/ettle/strcase v0.2.0 // indirect 52 | github.com/fatih/color v1.16.0 // indirect 53 | github.com/fatih/structtag v1.2.0 // indirect 54 | github.com/firefart/nonamedreturns v1.0.4 // indirect 55 | github.com/fsnotify/fsnotify v1.5.4 // indirect 56 | github.com/fzipp/gocyclo v0.6.0 // indirect 57 | github.com/ghostiam/protogetter v0.3.5 // indirect 58 | github.com/go-critic/go-critic v0.11.2 // indirect 59 | github.com/go-toolsmith/astcast v1.1.0 // indirect 60 | github.com/go-toolsmith/astcopy v1.1.0 // indirect 61 | github.com/go-toolsmith/astequal v1.2.0 // indirect 62 | github.com/go-toolsmith/astfmt v1.1.0 // indirect 63 | github.com/go-toolsmith/astp v1.1.0 // indirect 64 | github.com/go-toolsmith/strparse v1.1.0 // indirect 65 | github.com/go-toolsmith/typep v1.1.0 // indirect 66 | github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect 67 | github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect 68 | github.com/gobwas/glob v0.2.3 // indirect 69 | github.com/gofrs/flock v0.8.1 // indirect 70 | github.com/golang/protobuf v1.5.3 // indirect 71 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect 72 | github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect 73 | github.com/golangci/misspell v0.4.1 // indirect 74 | github.com/golangci/plugin-module-register v0.1.1 // indirect 75 | github.com/golangci/revgrep v0.5.2 // indirect 76 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect 77 | github.com/google/go-cmp v0.6.0 // indirect 78 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 79 | github.com/gordonklaus/ineffassign v0.1.0 // indirect 80 | github.com/gostaticanalysis/analysisutil v0.7.1 // indirect 81 | github.com/gostaticanalysis/comment v1.4.2 // indirect 82 | github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect 83 | github.com/gostaticanalysis/nilerr v0.1.1 // indirect 84 | github.com/hashicorp/go-version v1.6.0 // indirect 85 | github.com/hashicorp/hcl v1.0.0 // indirect 86 | github.com/hexops/gotextdiff v1.0.3 // indirect 87 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 88 | github.com/jgautheron/goconst v1.7.1 // indirect 89 | github.com/jingyugao/rowserrcheck v1.1.1 // indirect 90 | github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect 91 | github.com/jjti/go-spancheck v0.5.3 // indirect 92 | github.com/julz/importas v0.1.0 // indirect 93 | github.com/karamaru-alpha/copyloopvar v1.0.10 // indirect 94 | github.com/kisielk/errcheck v1.7.0 // indirect 95 | github.com/kkHAIKE/contextcheck v1.1.5 // indirect 96 | github.com/kulti/thelper v0.6.3 // indirect 97 | github.com/kunwardeep/paralleltest v1.0.10 // indirect 98 | github.com/kyoh86/exportloopref v0.1.11 // indirect 99 | github.com/ldez/gomoddirectives v0.2.4 // indirect 100 | github.com/ldez/tagliatelle v0.5.0 // indirect 101 | github.com/leonklingele/grouper v1.1.1 // indirect 102 | github.com/lufeee/execinquery v1.2.1 // indirect 103 | github.com/macabu/inamedparam v0.1.3 // indirect 104 | github.com/magiconair/properties v1.8.6 // indirect 105 | github.com/maratori/testableexamples v1.0.0 // indirect 106 | github.com/maratori/testpackage v1.1.1 // indirect 107 | github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect 108 | github.com/mattn/go-colorable v0.1.13 // indirect 109 | github.com/mattn/go-isatty v0.0.20 // indirect 110 | github.com/mattn/go-runewidth v0.0.9 // indirect 111 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 112 | github.com/mgechev/revive v1.3.7 // indirect 113 | github.com/mitchellh/go-homedir v1.1.0 // indirect 114 | github.com/mitchellh/mapstructure v1.5.0 // indirect 115 | github.com/moricho/tparallel v0.3.1 // indirect 116 | github.com/nakabonne/nestif v0.3.1 // indirect 117 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 118 | github.com/nishanths/exhaustive v0.12.0 // indirect 119 | github.com/nishanths/predeclared v0.2.2 // indirect 120 | github.com/nunnatsa/ginkgolinter v0.16.2 // indirect 121 | github.com/olekukonko/tablewriter v0.0.5 // indirect 122 | github.com/pelletier/go-toml v1.9.5 // indirect 123 | github.com/pelletier/go-toml/v2 v2.2.0 // indirect 124 | github.com/pmezard/go-difflib v1.0.0 // indirect 125 | github.com/polyfloyd/go-errorlint v1.4.8 // indirect 126 | github.com/prometheus/client_golang v1.12.1 // indirect 127 | github.com/prometheus/client_model v0.2.0 // indirect 128 | github.com/prometheus/common v0.32.1 // indirect 129 | github.com/prometheus/procfs v0.7.3 // indirect 130 | github.com/quasilyte/go-ruleguard v0.4.2 // indirect 131 | github.com/quasilyte/gogrep v0.5.0 // indirect 132 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect 133 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect 134 | github.com/ryancurrah/gomodguard v1.3.1 // indirect 135 | github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect 136 | github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect 137 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect 138 | github.com/sashamelentyev/interfacebloat v1.1.0 // indirect 139 | github.com/sashamelentyev/usestdlibvars v1.25.0 // indirect 140 | github.com/securego/gosec/v2 v2.19.0 // indirect 141 | github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect 142 | github.com/sirupsen/logrus v1.9.3 // indirect 143 | github.com/sivchari/containedctx v1.0.3 // indirect 144 | github.com/sivchari/tenv v1.7.1 // indirect 145 | github.com/sonatard/noctx v0.0.2 // indirect 146 | github.com/sourcegraph/go-diff v0.7.0 // indirect 147 | github.com/spf13/afero v1.11.0 // indirect 148 | github.com/spf13/cast v1.5.0 // indirect 149 | github.com/spf13/cobra v1.7.0 // indirect 150 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 151 | github.com/spf13/pflag v1.0.5 // indirect 152 | github.com/spf13/viper v1.12.0 // indirect 153 | github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect 154 | github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect 155 | github.com/stretchr/objx v0.5.2 // indirect 156 | github.com/stretchr/testify v1.9.0 // indirect 157 | github.com/subosito/gotenv v1.4.1 // indirect 158 | github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect 159 | github.com/tdakkota/asciicheck v0.2.0 // indirect 160 | github.com/tetafro/godot v1.4.16 // indirect 161 | github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect 162 | github.com/timonwong/loggercheck v0.9.4 // indirect 163 | github.com/tomarrell/wrapcheck/v2 v2.8.3 // indirect 164 | github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect 165 | github.com/ultraware/funlen v0.1.0 // indirect 166 | github.com/ultraware/whitespace v0.1.0 // indirect 167 | github.com/uudashr/gocognit v1.1.2 // indirect 168 | github.com/xen0n/gosmopolitan v1.2.2 // indirect 169 | github.com/yagipy/maintidx v1.0.0 // indirect 170 | github.com/yeya24/promlinter v0.2.0 // indirect 171 | github.com/ykadowak/zerologlint v0.1.5 // indirect 172 | gitlab.com/bosi/decorder v0.4.1 // indirect 173 | go-simpler.org/musttag v0.9.0 // indirect 174 | go-simpler.org/sloglint v0.5.0 // indirect 175 | go.uber.org/atomic v1.7.0 // indirect 176 | go.uber.org/automaxprocs v1.5.3 // indirect 177 | go.uber.org/multierr v1.6.0 // indirect 178 | go.uber.org/zap v1.24.0 // indirect 179 | golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect 180 | golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect 181 | golang.org/x/mod v0.16.0 // indirect 182 | golang.org/x/sync v0.6.0 // indirect 183 | golang.org/x/sys v0.18.0 // indirect 184 | golang.org/x/term v0.10.0 // indirect 185 | golang.org/x/text v0.14.0 // indirect 186 | golang.org/x/tools v0.19.0 // indirect 187 | google.golang.org/protobuf v1.33.0 // indirect 188 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 189 | gopkg.in/ini.v1 v1.67.0 // indirect 190 | gopkg.in/yaml.v2 v2.4.0 // indirect 191 | gopkg.in/yaml.v3 v3.0.1 // indirect 192 | honnef.co/go/tools v0.4.7 // indirect 193 | mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 // indirect 194 | ) 195 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | //go:build tools 5 | // +build tools 6 | 7 | package tools 8 | 9 | // tools we use during development. 10 | import ( 11 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint" 12 | _ "github.com/zchee/goimportz/cmd/goimportz" 13 | _ "gotest.tools/gotestsum" 14 | _ "mvdan.cc/gofumpt" 15 | ) 16 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // NewVersion returns the int32 pointer converted i. 7 | func NewVersion(i int32) *int32 { 8 | return &i 9 | } 10 | -------------------------------------------------------------------------------- /util_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func TestNewVersion(t *testing.T) { 11 | t.Parallel() 12 | 13 | tests := []struct { 14 | name string 15 | i int32 16 | }{ 17 | { 18 | name: "Valid", 19 | i: 5000, 20 | }, 21 | } 22 | for _, tt := range tests { 23 | tt := tt 24 | t.Run(tt.name, func(t *testing.T) { 25 | t.Parallel() 26 | 27 | want := NewVersion(tt.i) 28 | if got := NewVersion(tt.i); *got != *want { 29 | t.Errorf("NewVersion(%v) = %v, want %v", tt.i, *got, *want) 30 | } 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2018 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | // Version is the version of the language-server-protocol specification being implemented. 7 | const Version = "3.15.3" 8 | -------------------------------------------------------------------------------- /window.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import "strconv" 7 | 8 | // ShowMessageParams params of ShowMessage notification. 9 | type ShowMessageParams struct { 10 | // Message is the actual message. 11 | Message string `json:"message"` 12 | 13 | // Type is the message type. 14 | Type MessageType `json:"type"` 15 | } 16 | 17 | // MessageType type of ShowMessageParams type. 18 | type MessageType float64 19 | 20 | const ( 21 | // MessageTypeError an error message. 22 | MessageTypeError MessageType = 1 23 | // MessageTypeWarning a warning message. 24 | MessageTypeWarning MessageType = 2 25 | // MessageTypeInfo an information message. 26 | MessageTypeInfo MessageType = 3 27 | // MessageTypeLog a log message. 28 | MessageTypeLog MessageType = 4 29 | ) 30 | 31 | // String implements fmt.Stringer. 32 | func (m MessageType) String() string { 33 | switch m { 34 | case MessageTypeError: 35 | return "error" 36 | case MessageTypeWarning: 37 | return "warning" 38 | case MessageTypeInfo: 39 | return "info" 40 | case MessageTypeLog: 41 | return "log" 42 | default: 43 | return strconv.FormatFloat(float64(m), 'f', -10, 64) 44 | } 45 | } 46 | 47 | // Enabled reports whether the level is enabled. 48 | func (m MessageType) Enabled(level MessageType) bool { 49 | return level > 0 && m >= level 50 | } 51 | 52 | // messageTypeMap map of MessageTypes. 53 | var messageTypeMap = map[string]MessageType{ 54 | "error": MessageTypeError, 55 | "warning": MessageTypeWarning, 56 | "info": MessageTypeInfo, 57 | "log": MessageTypeLog, 58 | } 59 | 60 | // ToMessageType converts level to the MessageType. 61 | func ToMessageType(level string) MessageType { 62 | mt, ok := messageTypeMap[level] 63 | if !ok { 64 | return MessageType(0) // unknown 65 | } 66 | 67 | return mt 68 | } 69 | 70 | // ShowMessageRequestParams params of ShowMessage request. 71 | type ShowMessageRequestParams struct { 72 | // Actions is the message action items to present. 73 | Actions []MessageActionItem `json:"actions"` 74 | 75 | // Message is the actual message 76 | Message string `json:"message"` 77 | 78 | // Type is the message type. See {@link MessageType} 79 | Type MessageType `json:"type"` 80 | } 81 | 82 | // MessageActionItem item of ShowMessageRequestParams action. 83 | type MessageActionItem struct { 84 | // Title a short title like 'Retry', 'Open Log' etc. 85 | Title string `json:"title"` 86 | } 87 | 88 | // LogMessageParams params of LogMessage notification. 89 | type LogMessageParams struct { 90 | // Message is the actual message 91 | Message string `json:"message"` 92 | 93 | // Type is the message type. See {@link MessageType} 94 | Type MessageType `json:"type"` 95 | } 96 | 97 | // WorkDoneProgressCreateParams params of WorkDoneProgressCreate request. 98 | // 99 | // @since 3.15.0. 100 | type WorkDoneProgressCreateParams struct { 101 | // Token is the token to be used to report progress. 102 | Token ProgressToken `json:"token"` 103 | } 104 | 105 | // WorkDoneProgressCancelParams params of WorkDoneProgressCancel request. 106 | // 107 | // @since 3.15.0. 108 | type WorkDoneProgressCancelParams struct { 109 | // Token is the token to be used to report progress. 110 | Token ProgressToken `json:"token"` 111 | } 112 | -------------------------------------------------------------------------------- /workspace.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019 The Go Language Server Authors 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | package protocol 5 | 6 | import ( 7 | "strconv" 8 | 9 | "go.lsp.dev/uri" 10 | ) 11 | 12 | // WorkspaceFolder response of Workspace folders request. 13 | type WorkspaceFolder struct { 14 | // URI is the associated URI for this workspace folder. 15 | URI string `json:"uri"` 16 | 17 | // Name is the name of the workspace folder. Used to refer to this 18 | // workspace folder in the user interface. 19 | Name string `json:"name"` 20 | } 21 | 22 | // DidChangeWorkspaceFoldersParams params of DidChangeWorkspaceFolders notification. 23 | type DidChangeWorkspaceFoldersParams struct { 24 | // Event is the actual workspace folder change event. 25 | Event WorkspaceFoldersChangeEvent `json:"event"` 26 | } 27 | 28 | // WorkspaceFoldersChangeEvent is the workspace folder change event. 29 | type WorkspaceFoldersChangeEvent struct { 30 | // Added is the array of added workspace folders 31 | Added []WorkspaceFolder `json:"added"` 32 | 33 | // Removed is the array of the removed workspace folders 34 | Removed []WorkspaceFolder `json:"removed"` 35 | } 36 | 37 | // DidChangeConfigurationParams params of DidChangeConfiguration notification. 38 | type DidChangeConfigurationParams struct { 39 | // Settings is the actual changed settings 40 | Settings interface{} `json:"settings,omitempty"` 41 | } 42 | 43 | // ConfigurationParams params of Configuration request. 44 | type ConfigurationParams struct { 45 | Items []ConfigurationItem `json:"items"` 46 | } 47 | 48 | // ConfigurationItem a ConfigurationItem consists of the configuration section to ask for and an additional scope URI. 49 | // The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to the configuration store used be the client. 50 | // So a server might ask for a configuration cpp.formatterOptions but the client stores the configuration in a XML store layout differently. 51 | // It is up to the client to do the necessary conversion. If a scope URI is provided the client should return the setting scoped to the provided resource. 52 | // If the client for example uses EditorConfig to manage its settings the configuration should be returned for the passed resource URI. If the client can’t provide a configuration setting for a given scope then null need to be present in the returned array. 53 | type ConfigurationItem struct { 54 | // ScopeURI is the scope to get the configuration section for. 55 | ScopeURI uri.URI `json:"scopeUri,omitempty"` 56 | 57 | // Section is the configuration section asked for. 58 | Section string `json:"section,omitempty"` 59 | } 60 | 61 | // DidChangeWatchedFilesParams params of DidChangeWatchedFiles notification. 62 | type DidChangeWatchedFilesParams struct { 63 | // Changes is the actual file events. 64 | Changes []*FileEvent `json:"changes,omitempty"` 65 | } 66 | 67 | // FileEvent an event describing a file change. 68 | type FileEvent struct { 69 | // Type is the change type. 70 | Type FileChangeType `json:"type"` 71 | 72 | // URI is the file's URI. 73 | URI uri.URI `json:"uri"` 74 | } 75 | 76 | // FileChangeType is the file event type. 77 | type FileChangeType float64 78 | 79 | const ( 80 | // FileChangeTypeCreated is the file got created. 81 | FileChangeTypeCreated FileChangeType = 1 82 | // FileChangeTypeChanged is the file got changed. 83 | FileChangeTypeChanged FileChangeType = 2 84 | // FileChangeTypeDeleted is the file got deleted. 85 | FileChangeTypeDeleted FileChangeType = 3 86 | ) 87 | 88 | // String implements fmt.Stringer. 89 | func (t FileChangeType) String() string { 90 | switch t { 91 | case FileChangeTypeCreated: 92 | return "Created" 93 | case FileChangeTypeChanged: 94 | return "Changed" 95 | case FileChangeTypeDeleted: 96 | return "Deleted" 97 | default: 98 | return strconv.FormatFloat(float64(t), 'f', -10, 64) 99 | } 100 | } 101 | 102 | // DidChangeWatchedFilesRegistrationOptions describe options to be used when registering for file system change events. 103 | type DidChangeWatchedFilesRegistrationOptions struct { 104 | // Watchers is the watchers to register. 105 | Watchers []FileSystemWatcher `json:"watchers"` 106 | } 107 | 108 | // FileSystemWatcher watchers of DidChangeWatchedFiles Registration options. 109 | type FileSystemWatcher struct { 110 | // GlobPattern is the glob pattern to watch. 111 | // 112 | // Glob patterns can have the following syntax: 113 | // - `*` to match one or more characters in a path segment 114 | // - `?` to match on one character in a path segment 115 | // - `**` to match any number of path segments, including none 116 | // - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) 117 | // - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) 118 | // - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) 119 | GlobPattern string `json:"globPattern"` 120 | 121 | // Kind is the kind of events of interest. If omitted it defaults 122 | // to WatchKind.Create | WatchKind.Change | WatchKind.Delete 123 | // which is 7. 124 | Kind WatchKind `json:"kind,omitempty"` 125 | } 126 | 127 | // WatchKind kind of FileSystemWatcher kind. 128 | type WatchKind float64 129 | 130 | const ( 131 | // WatchKindCreate interested in create events. 132 | WatchKindCreate WatchKind = 1 133 | 134 | // WatchKindChange interested in change events. 135 | WatchKindChange WatchKind = 2 136 | 137 | // WatchKindDelete interested in delete events. 138 | WatchKindDelete WatchKind = 4 139 | ) 140 | 141 | // String implements fmt.Stringer. 142 | func (k WatchKind) String() string { 143 | switch k { 144 | case WatchKindCreate: 145 | return "Create" 146 | case WatchKindChange: 147 | return "Change" 148 | case WatchKindDelete: 149 | return "Delete" 150 | default: 151 | return strconv.FormatFloat(float64(k), 'f', -10, 64) 152 | } 153 | } 154 | 155 | // WorkspaceSymbolParams is the parameters of a Workspace Symbol request. 156 | type WorkspaceSymbolParams struct { 157 | WorkDoneProgressParams 158 | PartialResultParams 159 | 160 | // Query a query string to filter symbols by. 161 | // 162 | // Clients may send an empty string here to request all symbols. 163 | Query string `json:"query"` 164 | } 165 | 166 | // ExecuteCommandParams params of Execute a command. 167 | type ExecuteCommandParams struct { 168 | WorkDoneProgressParams 169 | 170 | // Command is the identifier of the actual command handler. 171 | Command string `json:"command"` 172 | 173 | // Arguments that the command should be invoked with. 174 | Arguments []interface{} `json:"arguments,omitempty"` 175 | } 176 | 177 | // ExecuteCommandRegistrationOptions execute command registration options. 178 | type ExecuteCommandRegistrationOptions struct { 179 | // Commands is the commands to be executed on the server 180 | Commands []string `json:"commands"` 181 | } 182 | 183 | // ApplyWorkspaceEditParams params of Applies a WorkspaceEdit. 184 | type ApplyWorkspaceEditParams struct { 185 | // Label an optional label of the workspace edit. This label is 186 | // presented in the user interface for example on an undo 187 | // stack to undo the workspace edit. 188 | Label string `json:"label,omitempty"` 189 | 190 | // Edit is the edits to apply. 191 | Edit WorkspaceEdit `json:"edit"` 192 | } 193 | 194 | // ApplyWorkspaceEditResponse response of Applies a WorkspaceEdit. 195 | type ApplyWorkspaceEditResponse struct { 196 | // Applied indicates whether the edit was applied or not. 197 | Applied bool `json:"applied"` 198 | 199 | // FailureReason an optional textual description for why the edit was not applied. 200 | // This may be used by the server for diagnostic logging or to provide 201 | // a suitable error for a request that triggered the edit. 202 | // 203 | // @since 3.16.0. 204 | FailureReason string `json:"failureReason,omitempty"` 205 | 206 | // FailedChange depending on the client's failure handling strategy "failedChange" 207 | // might contain the index of the change that failed. This property is 208 | // only available if the client signals a "failureHandlingStrategy" 209 | // in its client capabilities. 210 | // 211 | // @since 3.16.0. 212 | FailedChange uint32 `json:"failedChange,omitempty"` 213 | } 214 | --------------------------------------------------------------------------------