aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Fußenegger <mfussenegger@users.noreply.github.com>2021-11-14 12:55:16 +0100
committerGitHub <noreply@github.com>2021-11-14 12:55:16 +0100
commitee3a58d42e7fce666eef570db6f2944c29303d98 (patch)
tree9421bec34f8700525c77f1a931643583b5d6aa7f
parent2ef9d2a663db35c73b93606dbe882ca697072cc3 (diff)
downloadrneovim-ee3a58d42e7fce666eef570db6f2944c29303d98.tar.gz
rneovim-ee3a58d42e7fce666eef570db6f2944c29303d98.tar.bz2
rneovim-ee3a58d42e7fce666eef570db6f2944c29303d98.zip
fix(lsp): ensure buffers are re-attached on rename (#16266)
If a LSP server sent a workspace edit containing a rename the buffers file name changed without the server receiving a close notification for the old buffer and without the client properly re-attaching on the new file. This affected `Move` code-actions in nvim-jdtls, but also `vim.lsp.buf.rename` on a class level.
-rw-r--r--runtime/lua/vim/lsp.lua6
-rw-r--r--runtime/lua/vim/lsp/util.lua21
-rw-r--r--test/functional/plugin/lsp_spec.lua1
3 files changed, 22 insertions, 6 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 7fa70af779..0fc0a7a7aa 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -472,7 +472,11 @@ local function text_document_did_open_handler(bufnr, client)
-- Next chance we get, we should re-do the diagnostics
vim.schedule(function()
- vim.lsp.diagnostic.redraw(bufnr, client.id)
+ -- Protect against a race where the buffer disappears
+ -- between `did_open_handler` and the scheduled function firing.
+ if vim.api.nvim_buf_is_valid(bufnr) then
+ vim.lsp.diagnostic.redraw(bufnr, client.id)
+ end
end)
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 27210dc385..a4b7b9922b 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -549,18 +549,29 @@ end
-- ignoreIfExists? bool
function M.rename(old_fname, new_fname, opts)
opts = opts or {}
- local bufnr = vim.fn.bufadd(old_fname)
- vim.fn.bufload(bufnr)
local target_exists = vim.loop.fs_stat(new_fname) ~= nil
if target_exists and not opts.overwrite or opts.ignoreIfExists then
vim.notify('Rename target already exists. Skipping rename.')
return
end
+ local oldbuf = vim.fn.bufadd(old_fname)
+ vim.fn.bufload(oldbuf)
+
+ -- The there may be pending changes in the buffer
+ api.nvim_buf_call(oldbuf, function()
+ vim.cmd('w!')
+ end)
+
local ok, err = os.rename(old_fname, new_fname)
assert(ok, err)
- api.nvim_buf_call(bufnr, function()
- vim.cmd('saveas! ' .. vim.fn.fnameescape(new_fname))
- end)
+
+ local newbuf = vim.fn.bufadd(new_fname)
+ for _, win in pairs(api.nvim_list_wins()) do
+ if api.nvim_win_get_buf(win) == oldbuf then
+ api.nvim_win_set_buf(win, newbuf)
+ end
+ end
+ api.nvim_buf_delete(oldbuf, { force = true })
end
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index ae7612ab08..228fc06e9b 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -1735,6 +1735,7 @@ describe('LSP', function()
-- after rename the target file must have the contents of the source file
local bufnr = vim.fn.bufadd(new)
+ vim.fn.bufload(new)
return vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
]], old, new)
eq({'Test content'}, lines)