diff options
author | Lewis Russell <lewis6991@gmail.com> | 2024-04-26 14:58:17 +0100 |
---|---|---|
committer | Lewis Russell <me@lewisr.dev> | 2024-04-26 16:21:37 +0100 |
commit | b2c26a875b9dfd17fd05cf01cf5cc13eb2a10dfd (patch) | |
tree | 5e58c5b1bac7333acd2662dd41eac1e0d62e558f | |
parent | b8273c9a339626078d49e706d882878090b07d42 (diff) | |
download | rneovim-b2c26a875b9dfd17fd05cf01cf5cc13eb2a10dfd.tar.gz rneovim-b2c26a875b9dfd17fd05cf01cf5cc13eb2a10dfd.tar.bz2 rneovim-b2c26a875b9dfd17fd05cf01cf5cc13eb2a10dfd.zip |
fix(lsp): ensure buffer is not attached more than once
Fixes regression introduced in #28030
If an LSP server is restarted, then the associated `nvim_buf_attach`
call will not detach if no buffer changes are sent between the client
stopping and a new one being created. This leads to `nvim_buf_attach`
being called multiple times for the same buffer, which then leads to
changetracking sending duplicate requests to the server (one per
attach).
To solve this, introduce separate tracking (client agnostic) on which
buffers have had calls to `nvim_buf_attach`.
-rw-r--r-- | runtime/lua/vim/lsp.lua | 55 |
1 files changed, 23 insertions, 32 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index fcb1ad5b4b..25feeb0e8d 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -451,30 +451,6 @@ function lsp.start_client(config) return client.id, nil 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) -end - ---Buffer lifecycle handler for textDocument/didSave --- @param bufnr integer local function text_document_did_save_handler(bufnr) @@ -516,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, @@ -559,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 @@ -570,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 @@ -582,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; @@ -608,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 |