Skip to content

Commit

Permalink
fix(lsp): ensure buffers are re-attached on rename (#16266)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mfussenegger committed Nov 14, 2021
1 parent 2ef9d2a commit ee3a58d
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
6 changes: 5 additions & 1 deletion runtime/lua/vim/lsp.lua
Expand Up @@ -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

Expand Down
21 changes: 16 additions & 5 deletions runtime/lua/vim/lsp/util.lua
Expand Up @@ -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


Expand Down
1 change: 1 addition & 0 deletions test/functional/plugin/lsp_spec.lua
Expand Up @@ -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)
Expand Down

0 comments on commit ee3a58d

Please sign in to comment.