diff options
Diffstat (limited to 'runtime/lua/vim/lsp.lua')
-rw-r--r-- | runtime/lua/vim/lsp.lua | 100 |
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 |