From 08b51bd249a3ba42fb300c129d4e08c5ba06df29 Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Fri, 15 May 2026 10:16:44 -0700 Subject: [PATCH] Only advertise `semanticTokens` if there's a handler Neovim 0.12 and above will make `semanticTokens` requests on every cursor movement. Currently, the `lsp` library advertises `semanticTokens` capabilities, even if the LSP server implemented with this library doesn't a handler. This means that every time I move my cursor I get a blocking error in my editor, making it essentially unusable! Let's only advertise the capability if there's a handler registered. Here's a workaround in my Neovim config: ``` vim.lsp.config("hls", { cmd = { "static-ls" }, on_init = function(client) -- static-ls (via the `lsp` Haskell library) falsely advertises -- semanticTokensProvider but registers no handler, producing a -- "no handler for: textDocument/semanticTokens/full" message on -- every cursor move. Strip it. client.server_capabilities.semanticTokensProvider = nil end, }) ``` --- lsp/src/Language/LSP/Server/Processing.hs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lsp/src/Language/LSP/Server/Processing.hs b/lsp/src/Language/LSP/Server/Processing.hs index 4a2e46e2..5497ee76 100644 --- a/lsp/src/Language/LSP/Server/Processing.hs +++ b/lsp/src/Language/LSP/Server/Processing.hs @@ -399,12 +399,18 @@ inferServerCapabilities _clientCaps o h = Just cmds -> ExecuteCommandOptions clientInitiatedProgress cmds Nothing -> error "executeCommandCommands needs to be set if a executeCommandHandler is set" - -- Always provide the default legend + -- Only advertise semantic tokens if the server has registered a handler for + -- at least one of the semantic-token request methods. Otherwise clients that + -- honor server capabilities (e.g. Neovim's built-in LSP client) will fire + -- requests we can't answer, producing spurious "no handler for" errors. -- TODO: allow user-provided legend via 'Options', or at least user-provided types - semanticTokensProvider = - Just $ - InL $ - SemanticTokensOptions clientInitiatedProgress defaultSemanticTokensLegend semanticTokenRangeProvider semanticTokenFullProvider + semanticTokensProvider + | supported_b SMethod_TextDocumentSemanticTokensFull + || supported_b SMethod_TextDocumentSemanticTokensRange = + Just $ + InL $ + SemanticTokensOptions clientInitiatedProgress defaultSemanticTokensLegend semanticTokenRangeProvider semanticTokenFullProvider + | otherwise = Nothing semanticTokenRangeProvider | supported_b SMethod_TextDocumentSemanticTokensRange = Just $ InL True | otherwise = Nothing