Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/gopls: not returning semanticTokensProvider capability #54531

Closed
puremourning opened this issue Aug 18, 2022 · 17 comments
Closed

x/tools/gopls: not returning semanticTokensProvider capability #54531

puremourning opened this issue Aug 18, 2022 · 17 comments
Assignees
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@puremourning
Copy link

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

@gopherbot gopherbot added Tools This label describes issues relating to any tools in the x/tools repository. gopls Issues related to the Go language server, gopls. labels Aug 18, 2022
@gopherbot gopherbot added this to the Unreleased milestone Aug 18, 2022
@puremourning
Copy link
Author

Just to be clear, the specification states:

The server therefore needs to let the client know which numbers it is using for which types and modifiers. They do so using a legend, which is defined as follows:

https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens

@suzmue suzmue modified the milestones: Unreleased, gopls/later Aug 19, 2022
@adonovan
Copy link
Member

Thanks for the bug report. For our own prioritization, could you tell us what problem this protocol issue presents to the end user?

@puremourning
Copy link
Author

puremourning commented Aug 25, 2022

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.

@adonovan
Copy link
Member

Thanks for clarifying. It doesn't sound like your need is urgent, but rest assured that we consider it a bug too.

@puremourning
Copy link
Author

sure, it's not urgent - thought I'd point it out as other clients may also benefit if they don't have the capability to do something bespoke.

@FelipeLema
Copy link

FelipeLema commented Nov 23, 2022

I tried to force semantic tokens with neovim's built-in client copying @puremourning 's code in ycm, but no dice

  require  'lspconfig'.gopls.setup({
    --
    settings = {
      gopls = {
        hints = {
          assignVariableTypes = true,
          compositeLiteralFields = true,
          compositeLiteralTypes = true,
          constantValues = true,
          functionTypeParameters = true,
          parameterNames = true,
          rangeVariableTypes = true,
        },
        semanticTokens = true,
      },
    },
  })

gopls version says it's v0.10.1

@puremourning
Copy link
Author

"no dice" is kinda hard to debug.

@FelipeLema
Copy link

FelipeLema commented Nov 30, 2022

here's the filtered log ( grep -i semantic lsp.log )

[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  jsonrpc = "2.0",  method = "workspace/didChangeConfiguration",  params = {    settings = {      gopls = {        hints = {          assignVariableTypes = true,          compositeLiteralFields = true,          compositeLiteralTypes = true,          constantValues = true,          functionTypeParameters = true,          parameterNames = true,          rangeVariableTypes = true        },        semanticTokens = true      }    }  }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  jsonrpc = "2.0",  method = "workspace/didChangeConfiguration",  params = {    settings = {      gopls = {        hints = {          assignVariableTypes = true,          compositeLiteralFields = true,          compositeLiteralTypes = true,          constantValues = true,          functionTypeParameters = true,          parameterNames = true,          rangeVariableTypes = true        },        semanticTokens = true      }    }  }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:403	"server_request: callback result"	{  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } },  status = true}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:403	"server_request: callback result"	{  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } },  status = true}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 3,  jsonrpc = "2.0",  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:403	"server_request: callback result"	{  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } },  status = true}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 4,  jsonrpc = "2.0",  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:388	"rpc.receive"	{  id = 5,  jsonrpc = "2.0",  method = "client/registerCapability",  params = {    registrations = { {        id = "textDocument/semanticTokens",        method = "textDocument/semanticTokens",        registerOptions = {          full = true,          legend = {},          range = true        }      } }  }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:403	"server_request: callback result"	{  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } },  status = true}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 6,  jsonrpc = "2.0",  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } }}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:403	"server_request: callback result"	{  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } },  status = true}
[DEBUG][2022-11-30 10:36:25] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 7,  jsonrpc = "2.0",  result = { {      hints = {        assignVariableTypes = true,        compositeLiteralFields = true,        compositeLiteralTypes = true,        constantValues = true,        functionTypeParameters = true,        parameterNames = true,        rangeVariableTypes = true      },      semanticTokens = true    } }}
[DEBUG][2022-11-30 10:36:26] .../lua/vim/lsp.lua:1381	"LSP[gopls]"	"client.request"	1	"textDocument/semanticTokens/full"	{  textDocument = {    uri = "file:///Users/….go"  }}	<function 1>	1
[DEBUG][2022-11-30 10:36:26] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 4,  jsonrpc = "2.0",  method = "textDocument/semanticTokens/full",  params = {    textDocument = {      uri = "file:///Users/….go"    }  }}
[DEBUG][2022-11-30 10:37:23] .../lua/vim/lsp.lua:1381	"LSP[gopls]"	"client.request"	1	"textDocument/semanticTokens/full"	{  textDocument = {    uri = "file:///Users/….go"  }}	<function 1>	1
[DEBUG][2022-11-30 10:37:23] .../vim/lsp/rpc.lua:285	"rpc.send"	{  id = 5,  jsonrpc = "2.0",  method = "textDocument/semanticTokens/full",  params = {    textDocument = {      uri = "file:///Users/….go"    }  }}
[INFO][2022-11-30 10:37:53] .../lua/vim/lsp.lua:1807	"exit_handler"	{ {    _on_attach = <function 1>,    attached_buffers = { true },    cancel_request = <function 2>,    commands = {},    config = {      _on_attach = <function 3>,      autostart = true,      capabilities = {        callHierarchy = {          dynamicRegistration = false        },        textDocument = {          codeAction = {            codeActionLiteralSupport = {              codeActionKind = {                valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }              }            },            dataSupport = true,            dynamicRegistration = false,            isPreferredSupport = true,            resolveSupport = {              properties = { "edit" }            }          },          completion = {            completionItem = {              commitCharactersSupport = true,              deprecatedSupport = true,              documentationFormat = { "markdown", "plaintext" },              insertReplaceSupport = true,              insertTextModeSupport = {                valueSet = { 1, 2 }              },              labelDetailsSupport = true,              preselectSupport = true,              resolveSupport = {                properties = { "documentation", "detail", "additionalTextEdits" }              },              snippetSupport = true,              tagSupport = {                valueSet = { 1 }              }            },            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 }            },            completionList = {              itemDefaults = { "commitCharacters", "editRange", "insertTextFormat", "insertTextMode", "data" }            },            contextSupport = true,            dynamicRegistration = false,            insertTextMode = 1          },          declaration = {            linkSupport = true          },          definition = {            linkSupport = true          },          documentHighlight = {            dynamicRegistration = false          },          documentSymbol = {            dynamicRegistration = false,            hierarchicalDocumentSymbolSupport = true,            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 = { "markdown", "plaintext" },            dynamicRegistration = false          },          implementation = {            linkSupport = true          },          publishDiagnostics = {            relatedInformation = true,            tagSupport = {              valueSet = { 1, 2 }            }          },          references = {            dynamicRegistration = false          },          rename = {            dynamicRegistration = false,            prepareSupport = true          },          signatureHelp = {            dynamicRegistration = false,            signatureInformation = {              activeParameterSupport = true,              documentationFormat = { "markdown", "plaintext" },              parameterInformation = {                labelOffsetSupport = true              }            }          },          synchronization = {            didSave = true,            dynamicRegistration = false,            willSave = false,            willSaveWaitUntil = false          },          typeDefinition = {            linkSupport = true          }        },        window = {          showDocument = {            support = false          },          showMessage = {            messageActionItem = {              additionalPropertiesSupport = false            }          },          workDoneProgress = true        },        workspace = {          applyEdit = true,          configuration = true,          symbol = {            dynamicRegistration = false,            hierarchicalWorkspaceSymbolSupport = true,            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 = {            resourceOperations = { "rename", "create", "delete" }          },          workspaceFolders = true        }      },      cmd = { "/Users/…/bin/gopls" },      cmd_cwd = "/Users/…/project",      filetypes = { "go", "gomod", "gowork", "gotmpl" },      flags = {},      get_language_id = <function 4>,      handlers = <1>{},      init_options = vim.empty_dict(),      log_level = 2,      message_level = 2,      name = "gopls",      on_attach = <function 5>,      on_exit = <function 6>,      on_init = <function 7>,      root_dir = "/Users/…/project",      settings = {        gopls = {          hints = {            assignVariableTypes = true,            compositeLiteralFields = true,            compositeLiteralTypes = true,            constantValues = true,            functionTypeParameters = true,            parameterNames = true,            rangeVariableTypes = true          },          semanticTokens = true        }      },      single_file_support = true,      workspace_folders = <2>{ {          name = "/Users/…/project",          uri = "file:///Users/…/project"        } },      <metatable> = <3>{        __tostring = <function 8>      }    },    handlers = <table 1>,    id = 1,    initialized = true,    is_stopped = <function 9>,    messages = {      messages = {},      name = "gopls",      progress = {        ["5577006791947779410"] = {          done = true,          message = "Finished loading packages.",          title = "Setting up workspace"        }      },      status = {}    },    name = "gopls",    notify = <function 10>,    offset_encoding = "utf-16",    request = <function 11>,    request_sync = <function 12>,    requests = {},    rpc = {      is_closing = <function 13>,      notify = <function 14>,      request = <function 15>,      terminate = <function 16>    },    server_capabilities = {      callHierarchyProvider = true,      codeActionProvider = {        codeActionKinds = { "quickfix", "refactor.extract", "refactor.rewrite", "source.fixAll", "source.organizeImports" }      },      codeLensProvider = vim.empty_dict(),      completionProvider = {        triggerCharacters = { "." }      },      definitionProvider = true,      documentFormattingProvider = true,      documentHighlightProvider = true,      documentLinkProvider = vim.empty_dict(),      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "gopls.add_dependency", "gopls.add_import", "gopls.apply_fix", "gopls.check_upgrades", "gopls.edit_go_directive", "gopls.gc_details", "gopls.generate", "gopls.generate_gopls_mod", "gopls.go_get_package", "gopls.list_imports", "gopls.list_known_packages", "gopls.regenerate_cgo", "gopls.remove_dependency", "gopls.reset_go_mod_diagnostics", "gopls.run_tests", "gopls.run_vulncheck_exp", "gopls.start_debugging", "gopls.test", "gopls.tidy", "gopls.toggle_gc_details", "gopls.update_go_sum", "gopls.upgrade_dependency", "gopls.vendor" }      },      foldingRangeProvider = true,      hoverProvider = true,      implementationProvider = true,      inlayHintProvider = vim.empty_dict(),      referencesProvider = true,      renameProvider = {        prepareProvider = true      },      semanticTokensProvider = {        full = true,        legend = {          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" }        }      },      signatureHelpProvider = {        triggerCharacters = { "(", "," }      },      textDocumentSync = {        change = 2,        openClose = true,        save = vim.empty_dict()      },      typeDefinitionProvider = true,      workspace = {        fileOperations = vim.empty_dict(),        workspaceFolders = {          changeNotifications = "workspace/didChangeWorkspaceFolders",          supported = true        }      },      workspaceSymbolProvider = true    },    stop = <function 17>,    supports_method = <function 18>,    workspaceFolders = <table 2>,    workspace_did_change_configuration = <function 19>,    workspace_folders = <table 2>,    <metatable> = {      __index = <function 20>    }  } }

@aktau
Copy link
Contributor

aktau commented Dec 13, 2022

I tried to force semantic tokens with neovim's built-in client copying @puremourning 's #54531 (comment), but no dice

You'd still need to manually amend the server capabilities. Copying the YCM stuff I'd get:

vim.lsp.start({
  -- ...
  settings = {
    gopls = {
      semanticTokens = true,
    },
  }
)

Then, in your on_attach or LspAttach handler:

    if client.name == "gopls" and not client.server_capabilities.semanticTokensProvider then
      -- Generate a synthetic semanticTokensProvider (https://github.com/golang/go/issues/54531).
      -- WARNING: This is wrong, it seems to be mismatched with what gopls actually provides.
      client.server_capabilities.semanticTokensProvider = {
        full = true,
        legend = {
          tokenModifiers = {},
          tokenTypes = {
            "class",
            "comment",
            "enum",
            "enumMember",
            "event",
            "function",
            "interface",
            "keyword",
            "macro",
            "member",
            "method",
            "modifier",
            "namespace",
            "number",
            "operator",
            "parameter",
            "property",
            "regexp",
            "string",
            "struct",
            "type",
            "typeParameter",
            "variable",
          },
        }
      }
    end

Which makes my editor light up like a Christmas tree (so gopls is actually sending semantic tokens), but not in a good way. Comparing this with a company-internal LSP that also provides semantic tokens for Go and a proper semanticTokensProvider I can see that the gopls results are wrong.

@jdrouhard
Copy link

@aktau Manually adding the legend won’t work if the indexes for the types don’t match the encoding used internally by the server (ordering is important). So you probably just don’t have a 1:1 mapping in your legend vs the one gopls is using.

gopls definitely needs to be updated to send its legend back in the initialize response.

@hyangah
Copy link
Contributor

hyangah commented Dec 16, 2022

cc @pjweinb

@pjweinb
Copy link

pjweinb commented Dec 16, 2022

Presently gopls is supposed to be using the information it gets from the client. That is, it is supposed to be using the ordering the client sent in the 'initialize' message for the tokens and the modifiers. Is that not what it seems to be doing, or should it be doing something else, or is the problem just that it is not echoing back in its response what the client sent it? [I'd believe any of these, and it we'd like to get it right.]

@puremourning
Copy link
Author

What the client sends in capabilities and the legend returned by the server are not the same thing technically, but a valid approach would be for gopls to return the clients supported token types and modifiers as its legend and complete the semanticTokensProvider interface.

This would work, as that’s what is happening now (my YCM hack does essentially exactly that: pretends that what gopls returned was what we sent at client capability.)

@pjweinb
Copy link

pjweinb commented Dec 17, 2022

Gopls sends a Semantic Token legend in a client/registerCapability message, if the client supports dynamic registration, as vscode does. But it doesn't respond with a legend if not, which is a bug. We'll try to get this right.

@gopherbot
Copy link

Change https://go.dev/cl/459561 mentions this issue: tools/gopls: register semantic tokens statically and honor client capabilities

@gopherbot
Copy link

Change https://go.dev/cl/462215 mentions this issue: tools/gopls: register semantic tokens statically

@Iron-E
Copy link

Iron-E commented Mar 11, 2023

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

ray-x added a commit to ray-x/go.nvim that referenced this issue Mar 12, 2023
waiting on gopls new version release
antoineco added a commit to antoineco/dotfiles that referenced this issue Apr 11, 2023
https://go.googlesource.com/tools/+/refs/tags/v0.8.0/gopls/doc/semantictokens.md

The necessity for a custom on_attach callback function is temporary. In
the next release of gopls, semantic tokens will be registered
statically (golang/go#54531).
@golang golang locked and limited conversation to collaborators Mar 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

10 participants