Neovim LSP client ↔ external language servers: formatting selection with overlapping capabilities
0 reputation · 26 Jun 2022, 17:16 UTC
0 reputation · 26 Jun 2022, 17:16 UTC
Neovim's built-in LSP client communicates with external language servers over msgpack-RPC and exposes vim.lsp functions for diagnostics, completion and formatting. During initialization the client merges server-declared capabilities with client settings and registers handlers for LSP requests and notifications.
When multiple language servers attach to the same buffer, capability overlap such as textDocument/formatting and diagnostics can occur. The documented behavior for selecting a formatter is via vim.lsp.buf.format with an optional filter, and the default selection is tied to the internal client list order. The merge order and deduplication for diagnostics is implementation dependent and varies by version.
What attribute determines the ordering of clients in the internal list used for formatting when no filter is provided? Is capability merging for overlapping features defined deterministically across Neovim 0.9 to 0.11? How are diagnostics from multiple servers merged when ranges overlap?
34275 reputation · 26 Jun 2022, 19:43 UTC
No user-facing priority attribute determines the ordering of clients for formatting. When no filter is provided to vim.lsp.buf.format(), Neovim iterates through the internal client list based on client ID, which is assigned sequentially as servers start. Consequently, the first server that attached to the buffer and supports textDocument/formatting is typically selected. This is an implementation detail and should not be relied upon for deterministic configuration.
Capability merging is not performed across different servers; it is per-client. Each client merges its own server-declared capabilities with the client-side settings during initialization. When multiple servers offer the same feature, Neovim resolves this at the request level (e.g., picking the first available formatter or aggregating all completion items). This dispatch logic has evolved between versions 0.9 and 0.11, particularly regarding how client.supports_method is evaluated.
Diagnostics from multiple servers are not merged or deduplicated. Each server publishes diagnostics into its own unique namespace. If two servers report an error for the same range, both will be stored and displayed, resulting in overlapping signs or duplicate virtual text.
Confirmed Behavior:
vim.lsp.buf.format() supports a filter function to explicitly select a server.vim.diagnostic API.Version-Specific Variance:
The method for disabling overlapping capabilities in on_attach varies. In versions 0.9 and 0.10, users commonly set client.server_capabilities.documentFormattingProvider = false. In version 0.11, the internal handling of capabilities and the supports_method check have been refined, making explicit filters the preferred approach over manual capability mutation.
:lua print(vim.inspect(vim.lsp.get_clients({bufnr=0})))
(Use vim.lsp.get_active_clients() for Neovim 0.9).vim.lsp.buf.format({ filter = function(c) return c.name == 'lua_ls' end })
:lua print(vim.inspect(vim.diagnostic.get(0)))
Check the namespace field to confirm multiple servers are contributing to the same range.To provide the exact syntax for disabling capabilities in your on_attach function, please specify your exact Neovim version (e.g., 0.10.2), as the API for overriding server_capabilities has shifted toward supports_method in the latest releases.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.