go: x/tools/gopls: not returning semanticTokensProvider capability

gopls version

ben@BenMBP2021 ycmd % /Users/ben/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/go/bin/gopls version
golang.org/x/tools/gopls v0.9.4
    golang.org/x/tools/gopls@v0.9.4 h1:YhHOxVi++ILnY+QnH9FGtRKZZrunSaR7OW8/dCp7bBk=

go env

ben@BenMBP2021 golang-tools % go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/ben/Library/Caches/go-build"
GOENV="/Users/ben/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS="-modcacherw"
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/ben/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/ben/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.19/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.19/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.19"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/ben/Development/YouCompleteMe/golang-tools/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/g3/2g6b5vgj3pz55jg8__0yr6nh0000gn/T/go-build426307582=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

  1. initialise gopls, specifying client capabilities indicating semanticTokens are supported, and enable semanticTokens: true
[Trace - 20:48:52.151 PM] Sending request 'initialize - (1)'.
Params: {"capabilities":{"textDocument":{"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"completion":{"completionItem":{"documentationFormat":["plaintext","markdown"]},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"documentSymbol":{"hierarchicalDocumentSymbolSupport":false,"labelSupport":false,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"hover":{"contentFormat":["plaintext","markdown"]},"inlay_hint":{},"semanticTokens":{"augmentSyntaxTokens":true,"formats":["relative"],"requests":{"full":{"delta":false},"range":true},"tokenModifiers":[],"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","member","macro","keyword","modifier","comment","string","number","regexp","operator"]},"signatureHelp":{"signatureInformation":{"documentationFormat":["plaintext","markdown"],"parameterInformation":{"labelOffsetSupport":true}}},"synchronization":{"didSave":true}},"workspace":{"applyEdit":true,"configuration":true,"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"workspaceEdit":{"documentChanges":true},"workspaceFolders":true}},"initializationOptions":{"hints":{"assignVariableTypes":true,"compositeLiteralFields":true,"compositeLiteralTypes":true,"constantValues":true,"functionTypeParameters":true,"parameterNames":true,"rangeVariableTypes":true},"hoverKind":"Structured","semanticTokens":true},"processId":50805,"rootPath":"/Users/ben/Development/YouCompleteMe/golang-tools","rootUri":"file:///Users/ben/Development/YouCompleteMe/golang-tools","workspaceFolders":[{"name":"golang-tools","uri":"file:///Users/ben/Development/YouCompleteMe/golang-tools"}]}

What did you expect to see?

The initialise response should include semanticTokensProvider including the legend required to decode the tokens:

export interface SemanticTokensOptions extends WorkDoneProgressOptions {
	/**
	 * The legend used by the server
	 */
	legend: [SemanticTokensLegend](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#semanticTokensLegend);

	/**
	 * Server supports providing semantic tokens for a specific range
	 * of a document.
	 */
	range?: boolean | {
	};

	/**
	 * Server supports providing semantic tokens for a full document.
	 */
	full?: boolean | {
		/**
		 * The server supports deltas for full documents.
		 */
		delta?: boolean;
	};
}

What did you see instead?

gopls does not declare that it supports semantic Tokens.

Editor and settings

ycmd

Settings:

--   gopls Settings: {
--   "hints": {
--     "assignVariableTypes": true,
--     "compositeLiteralFields": true,
--     "compositeLiteralTypes": true,
--     "constantValues": true,
--     "functionTypeParameters": true,
--     "parameterNames": true,
--     "rangeVariableTypes": true
--   },
--   "hoverKind": "Structured",
--   "semanticTokens": true
-- }

Logs

https://gist.github.com/puremourning/6a531965b8a6ef2bcde713e6cf9f2ae2

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 17 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Even though this issue is closed, it seems that Neovim does not pick up on gopls’ semantic token support (see LuaLS for a working example).

I figured out a workaround which avoids hard-coding the existing token modifiers and types:

if client.name == 'gopls' and not client.server_capabilities.semanticTokensProvider then
  local semantic = client.config.capabilities.textDocument.semanticTokens
  client.server_capabilities.semanticTokensProvider = {
    full = true,
    legend = {tokenModifiers = semantic.tokenModifiers, tokenTypes = semantic.tokenTypes},
    range = true,
  }
end

I am the author of a language server protocol client. The impact is that semantic highlighting doesn’t work without gopls-specific hacks.

I have made this work for our users, but would like to remove hacks or undocumented deviations from the specification, as any new version of gopls could break this workaround.