aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/lsp.lua')
-rw-r--r--runtime/lua/vim/lsp.lua113
1 files changed, 64 insertions, 49 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 1592fd3151..60677554ce 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -3,7 +3,6 @@ local validate = vim.validate
local lsp = vim._defer_require('vim.lsp', {
_changetracking = ..., --- @module 'vim.lsp._changetracking'
- _completion = ..., --- @module 'vim.lsp._completion'
_dynamic = ..., --- @module 'vim.lsp._dynamic'
_snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar'
_tagfunc = ..., --- @module 'vim.lsp._tagfunc'
@@ -11,6 +10,7 @@ local lsp = vim._defer_require('vim.lsp', {
buf = ..., --- @module 'vim.lsp.buf'
client = ..., --- @module 'vim.lsp.client'
codelens = ..., --- @module 'vim.lsp.codelens'
+ completion = ..., --- @module 'vim.lsp.completion'
diagnostic = ..., --- @module 'vim.lsp.diagnostic'
handlers = ..., --- @module 'vim.lsp.handlers'
inlay_hint = ..., --- @module 'vim.lsp.inlay_hint'
@@ -33,43 +33,50 @@ lsp.rpc_response_error = lsp.rpc.rpc_response_error
-- maps request name to the required server_capability in the client.
lsp._request_name_to_capability = {
- [ms.textDocument_hover] = { 'hoverProvider' },
- [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' },
- [ms.textDocument_definition] = { 'definitionProvider' },
- [ms.textDocument_implementation] = { 'implementationProvider' },
- [ms.textDocument_declaration] = { 'declarationProvider' },
- [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' },
- [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' },
- [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' },
[ms.callHierarchy_incomingCalls] = { 'callHierarchyProvider' },
[ms.callHierarchy_outgoingCalls] = { 'callHierarchyProvider' },
- [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' },
- [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' },
- [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' },
- [ms.textDocument_rename] = { 'renameProvider' },
- [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' },
+ [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' },
+ [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' },
+ [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' },
+ [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' },
[ms.textDocument_codeAction] = { 'codeActionProvider' },
[ms.textDocument_codeLens] = { 'codeLensProvider' },
- [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' },
- [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' },
- [ms.workspace_executeCommand] = { 'executeCommandProvider' },
- [ms.workspace_symbol] = { 'workspaceSymbolProvider' },
- [ms.textDocument_references] = { 'referencesProvider' },
- [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' },
- [ms.textDocument_formatting] = { 'documentFormattingProvider' },
[ms.textDocument_completion] = { 'completionProvider' },
- [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' },
- [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' },
- [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' },
- [ms.textDocument_inlayHint] = { 'inlayHintProvider' },
+ [ms.textDocument_declaration] = { 'declarationProvider' },
+ [ms.textDocument_definition] = { 'definitionProvider' },
[ms.textDocument_diagnostic] = { 'diagnosticProvider' },
- [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' },
- [ms.textDocument_documentLink] = { 'documentLinkProvider' },
- [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' },
[ms.textDocument_didClose] = { 'textDocumentSync', 'openClose' },
[ms.textDocument_didOpen] = { 'textDocumentSync', 'openClose' },
- [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' },
+ [ms.textDocument_documentColor] = { 'colorProvider' },
+ [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' },
+ [ms.textDocument_documentLink] = { 'documentLinkProvider' },
+ [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' },
+ [ms.textDocument_formatting] = { 'documentFormattingProvider' },
+ [ms.textDocument_hover] = { 'hoverProvider' },
+ [ms.textDocument_implementation] = { 'implementationProvider' },
+ [ms.textDocument_inlayHint] = { 'inlayHintProvider' },
+ [ms.textDocument_inlineValue] = { 'inlineValueProvider' },
+ [ms.textDocument_linkedEditingRange] = { 'linkedEditingRangeProvider' },
+ [ms.textDocument_moniker] = { 'monikerProvider' },
+ [ms.textDocument_onTypeFormatting] = { 'documentOnTypeFormattingProvider' },
+ [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' },
+ [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' },
+ [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' },
+ [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' },
+ [ms.textDocument_rangesFormatting] = { 'documentRangeFormattingProvider', 'rangesSupport' },
+ [ms.textDocument_references] = { 'referencesProvider' },
+ [ms.textDocument_rename] = { 'renameProvider' },
+ [ms.textDocument_selectionRange] = { 'selectionRangeProvider' },
+ [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' },
+ [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' },
+ [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' },
+ [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' },
[ms.textDocument_willSaveWaitUntil] = { 'textDocumentSync', 'willSaveWaitUntil' },
+ [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' },
+ [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' },
+ [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' },
+ [ms.workspace_executeCommand] = { 'executeCommandProvider' },
+ [ms.workspace_symbol] = { 'workspaceSymbolProvider' },
}
-- TODO improve handling of scratch buffers with LSP attached.
@@ -201,10 +208,10 @@ end
--- Predicate used to decide if a client should be re-used. Used on all
--- running clients. The default implementation re-uses a client if name and
--- root_dir matches.
---- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
+--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- Buffer handle to attach to if starting or re-using a client (0 for current).
---- @field bufnr integer
+--- @field bufnr? integer
---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
@@ -351,7 +358,7 @@ function lsp._set_defaults(client, bufnr)
then
vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr()'
end
- api.nvim_buf_call(bufnr, function()
+ vim._with({ buf = bufnr }, function()
if
client.supports_method(ms.textDocument_hover)
and is_empty_or_default(bufnr, 'keywordprg')
@@ -377,9 +384,9 @@ local function reset_defaults(bufnr)
if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
vim.bo[bufnr].formatexpr = nil
end
- api.nvim_buf_call(bufnr, function()
+ vim._with({ buf = bufnr }, function()
local keymap = vim.fn.maparg('K', 'n', false, true)
- if keymap and keymap.callback == vim.lsp.buf.hover then
+ if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
vim.keymap.del('n', 'K', { buffer = bufnr })
end
end)
@@ -391,9 +398,9 @@ end
local function on_client_exit(code, signal, client_id)
local client = all_clients[client_id]
- for bufnr in pairs(client.attached_buffers) do
- vim.schedule(function()
- if client and client.attached_buffers[bufnr] then
+ vim.schedule(function()
+ for bufnr in pairs(client.attached_buffers) do
+ if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
api.nvim_exec_autocmds('LspDetach', {
buffer = bufnr,
modeline = false,
@@ -401,15 +408,16 @@ local function on_client_exit(code, signal, client_id)
})
end
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
- vim.diagnostic.reset(namespace, bufnr)
client.attached_buffers[bufnr] = nil
if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
reset_defaults(bufnr)
end
- end)
- end
+ end
+
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ vim.diagnostic.reset(namespace)
+ end)
local name = client.name or 'unknown'
@@ -519,7 +527,6 @@ local function buf_detach_client(bufnr, client)
end
client.attached_buffers[bufnr] = nil
- util.buf_versions[bufnr] = nil
local namespace = lsp.diagnostic.get_namespace(client.id)
vim.diagnostic.reset(namespace, bufnr)
@@ -577,7 +584,8 @@ local function buf_attach(bufnr)
api.nvim_buf_attach(bufnr, false, {
on_lines = function(_, _, changedtick, firstline, lastline, new_lastline)
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
- return true -- detach
+ -- detach if there are no clients
+ return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0
end
util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
@@ -603,6 +611,7 @@ local function buf_attach(bufnr)
buf_detach_client(bufnr, client)
end
attached_buffers[bufnr] = nil
+ util.buf_versions[bufnr] = nil
end,
-- TODO if we know all of the potential clients ahead of time, then we
@@ -852,17 +861,20 @@ api.nvim_create_autocmd('VimLeavePre', {
---@param params table|nil Parameters to send to the server
---@param handler? lsp.Handler See |lsp-handler|
--- If nil, follows resolution strategy defined in |lsp-handler-configuration|
----
+---@param on_unsupported? fun()
+--- The function to call when the buffer has no clients that support the given method.
+--- Defaults to an `ERROR` level notification.
---@return table<integer, integer> client_request_ids Map of client-id:request-id pairs
---for all successful requests.
---@return function _cancel_all_requests Function which can be used to
---cancel all the requests. You could instead
---iterate all clients and call their `cancel_request()` methods.
-function lsp.buf_request(bufnr, method, params, handler)
+function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
validate({
bufnr = { bufnr, 'n', true },
method = { method, 's' },
handler = { handler, 'f', true },
+ on_unsupported = { on_unsupported, 'f', true },
})
bufnr = resolve_bufnr(bufnr)
@@ -884,7 +896,11 @@ function lsp.buf_request(bufnr, method, params, handler)
-- if has client but no clients support the given method, notify the user
if next(clients) and not method_supported then
- vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR)
+ if on_unsupported == nil then
+ vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR)
+ else
+ on_unsupported()
+ end
vim.cmd.redraw()
return {}, function() end
end
@@ -1002,8 +1018,7 @@ end
--- - findstart=0: column where the completion starts, or -2 or -3
--- - findstart=1: list of matches (actually just calls |complete()|)
function lsp.omnifunc(findstart, base)
- log.debug('omnifunc.findstart', { findstart = findstart, base = base })
- return vim.lsp._completion.omnifunc(findstart, base)
+ return vim.lsp.completion._omnifunc(findstart, base)
end
--- @class vim.lsp.formatexpr.Opts
@@ -1016,7 +1031,7 @@ end
--- Provides an interface between the built-in client and a `formatexpr` function.
---
--- Currently only supports a single client. This can be set via
---- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach`
+--- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` or (more typically) in `on_attach`
--- via `vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'`.
---
---@param opts? vim.lsp.formatexpr.Opts