aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2024-04-26 14:58:17 +0100
committerLewis Russell <me@lewisr.dev>2024-04-26 16:21:37 +0100
commitb2c26a875b9dfd17fd05cf01cf5cc13eb2a10dfd (patch)
tree5e58c5b1bac7333acd2662dd41eac1e0d62e558f /runtime/lua/vim
parentb8273c9a339626078d49e706d882878090b07d42 (diff)
downloadrneovim-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`.
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/lsp.lua55
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