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.lua100
1 files changed, 51 insertions, 49 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 8403aa0ee6..c6d6c8a0cd 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -195,10 +195,13 @@ 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: table): 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
+---
+--- Suppress error reporting if the LSP server fails to start (default false).
+--- @field silent? boolean
--- Create a new LSP client and start a language server or reuses an already
--- running client if one is found matching `name` and `root_dir`.
@@ -246,19 +249,25 @@ function lsp.start(config, opts)
for _, client in pairs(all_clients) do
if reuse_client(client, config) then
- lsp.buf_attach_client(bufnr, client.id)
- return client.id
+ if lsp.buf_attach_client(bufnr, client.id) then
+ return client.id
+ end
end
end
- local client_id = lsp.start_client(config)
+ local client_id, err = lsp.start_client(config)
+ if err then
+ if not opts.silent then
+ vim.notify(err, vim.log.levels.WARN)
+ end
+ return nil
+ end
- if not client_id then
- return -- lsp.start_client will have printed an error
+ if client_id and lsp.buf_attach_client(bufnr, client_id) then
+ return client_id
end
- lsp.buf_attach_client(bufnr, client_id)
- return client_id
+ return nil
end
--- Consumes the latest progress messages from all clients and formats them as a string.
@@ -339,7 +348,7 @@ function lsp._set_defaults(client, bufnr)
and is_empty_or_default(bufnr, 'keywordprg')
and vim.fn.maparg('K', 'n', false, false) == ''
then
- vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr })
+ vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'vim.lsp.buf.hover()' })
end
end)
if client.supports_method(ms.textDocument_diagnostic) then
@@ -420,16 +429,18 @@ end
--- Starts and initializes a client with the given configuration.
--- @param config vim.lsp.ClientConfig Configuration for the server.
---- @return integer|nil client_id |vim.lsp.get_client_by_id()| Note: client may not be
---- fully initialized. Use `on_init` to do any actions once
---- the client has been initialized.
+--- @return integer? client_id |vim.lsp.get_client_by_id()| Note: client may not be
+--- fully initialized. Use `on_init` to do any actions once
+--- the client has been initialized.
+--- @return string? # Error message, if any
function lsp.start_client(config)
- local client = require('vim.lsp.client').create(config)
-
- if not client then
- return
+ local ok, res = pcall(require('vim.lsp.client').create, config)
+ if not ok then
+ return nil, res --[[@as string]]
end
+ local client = assert(res)
+
--- @diagnostic disable-next-line: invisible
table.insert(client._on_exit_cbs, on_client_exit)
@@ -437,31 +448,7 @@ function lsp.start_client(config)
client:initialize()
- return client.id
-end
-
---- Notify all attached clients that a buffer has changed.
----@param _ integer
----@param bufnr integer
----@param changedtick integer
----@param firstline integer
----@param lastline integer
----@param new_lastline integer
----@return true?
-local function text_document_did_change_handler(
- _,
- bufnr,
- changedtick,
- firstline,
- lastline,
- new_lastline
-)
- -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached
- if #lsp.get_clients({ bufnr = bufnr }) == 0 then
- return true
- end
- util.buf_versions[bufnr] = changedtick
- changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
+ return client.id, nil
end
---Buffer lifecycle handler for textDocument/didSave
@@ -505,11 +492,18 @@ local function text_document_did_save_handler(bufnr)
end
end
+--- @type table<integer,true>
+local attached_buffers = {}
+
--- @param bufnr integer
---- @param client_id integer
-local function buf_attach(bufnr, client_id)
+local function buf_attach(bufnr)
+ if attached_buffers[bufnr] then
+ return
+ end
+ attached_buffers[bufnr] = true
+
local uri = vim.uri_from_bufnr(bufnr)
- local augroup = ('lsp_c_%d_b_%d_save'):format(client_id, bufnr)
+ local augroup = ('lsp_b_%d_save'):format(bufnr)
local group = api.nvim_create_augroup(augroup, { clear = true })
api.nvim_create_autocmd('BufWritePre', {
group = group,
@@ -548,7 +542,14 @@ local function buf_attach(bufnr, client_id)
})
-- First time, so attach and set up stuff.
api.nvim_buf_attach(bufnr, false, {
- on_lines = text_document_did_change_handler,
+ on_lines = function(_, _, changedtick, firstline, lastline, new_lastline)
+ if #lsp.get_clients({ bufnr = bufnr }) == 0 then
+ return true -- detach
+ end
+ util.buf_versions[bufnr] = changedtick
+ changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
+ end,
+
on_reload = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@@ -559,6 +560,7 @@ local function buf_attach(bufnr, client_id)
client:_text_document_did_open_handler(bufnr)
end
end,
+
on_detach = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@@ -571,7 +573,9 @@ local function buf_attach(bufnr, client_id)
client.attached_buffers[bufnr] = nil
end
util.buf_versions[bufnr] = nil
+ attached_buffers[bufnr] = nil
end,
+
-- TODO if we know all of the potential clients ahead of time, then we
-- could conditionally set this.
-- utf_sizes = size_index > 1;
@@ -597,16 +601,14 @@ function lsp.buf_attach_client(bufnr, client_id)
log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
return false
end
- -- This is our first time attaching to this buffer.
- if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
- buf_attach(bufnr, client_id)
- end
local client = lsp.get_client_by_id(client_id)
if not client then
return false
end
+ buf_attach(bufnr)
+
if client.attached_buffers[bufnr] then
return true
end