mirror of
https://github.com/neovim/neovim.git
synced 2025-09-30 15:08:35 +00:00
fix(api,lsp): call on_detach before wiping out the buffer #35355
Problem: Buffer-updates on_detach callback is invoked before buf_freeall(), which deletes autocmds of the buffer (via apply_autocmds(EVENT_BUFWIPEOUT, ...)). Due to this, buffer-local autocmds executed in on_detach (e.g., LspDetach) are not actually invoked. Solution: Call buf_updates_unload() before buf_freeall().
This commit is contained in:
@@ -1426,3 +1426,44 @@ describe('lua: nvim_buf_attach on_bytes', function()
|
||||
do_both(false)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_buf_attach on_detach', function()
|
||||
it('is invoked before unloading buffer', function()
|
||||
exec_lua(function()
|
||||
_G.logs = {} ---@type table<integer, string[]>
|
||||
end)
|
||||
local function setup(bufnr)
|
||||
exec_lua(function()
|
||||
_G.logs[bufnr] = {}
|
||||
vim.api.nvim_create_autocmd({ 'BufUnload', 'BufWipeout' }, {
|
||||
buffer = bufnr,
|
||||
callback = function(ev)
|
||||
table.insert(_G.logs[bufnr], ev.event)
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_buf_attach(bufnr, false, {
|
||||
on_detach = function()
|
||||
table.insert(_G.logs[bufnr], 'on_detach')
|
||||
end,
|
||||
})
|
||||
end)
|
||||
end
|
||||
-- Test with two buffers because the :bw works differently for the last buffer.
|
||||
-- Before #35355, the order was as follows:
|
||||
-- * non-last buffers: BufUnload → BufWipeout → on_detach
|
||||
-- * the last buffer (with text): BufUnload → on_detach → BufWipeout
|
||||
local buf1 = api.nvim_get_current_buf()
|
||||
local buf2 = api.nvim_create_buf(true, false)
|
||||
api.nvim_open_win(buf2, false, { split = 'below' })
|
||||
api.nvim_buf_set_lines(buf1, 0, -1, true, { 'abc' })
|
||||
api.nvim_buf_set_lines(buf2, 0, -1, true, { 'abc' })
|
||||
setup(buf1)
|
||||
setup(buf2)
|
||||
api.nvim_buf_delete(buf1, { force = true })
|
||||
api.nvim_buf_delete(buf2, { force = true })
|
||||
local logs = exec_lua('return _G.logs')
|
||||
local order = { 'on_detach', 'BufUnload', 'BufWipeout' }
|
||||
eq(order, logs[buf1])
|
||||
eq(order, logs[buf2])
|
||||
end)
|
||||
end)
|
||||
|
@@ -624,6 +624,37 @@ describe('LSP', function()
|
||||
eq(true, result.detach_called)
|
||||
end)
|
||||
|
||||
it('should detach buffer on bufwipe 2', function()
|
||||
exec_lua(create_server_definition)
|
||||
local result = exec_lua(function()
|
||||
local server = _G._create_server()
|
||||
local bufnr1 = vim.api.nvim_create_buf(false, true)
|
||||
local bufnr2 = vim.api.nvim_create_buf(false, true)
|
||||
local detach_called1 = false
|
||||
local detach_called2 = false
|
||||
vim.api.nvim_create_autocmd('LspDetach', {
|
||||
buffer = bufnr1,
|
||||
callback = function()
|
||||
detach_called1 = true
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd('LspDetach', {
|
||||
buffer = bufnr2,
|
||||
callback = function()
|
||||
detach_called2 = true
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_set_current_buf(bufnr1)
|
||||
vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd })
|
||||
vim.api.nvim_set_current_buf(bufnr2)
|
||||
vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd })
|
||||
vim.api.nvim_buf_delete(bufnr1, { force = true })
|
||||
vim.api.nvim_buf_delete(bufnr2, { force = true })
|
||||
return detach_called1 and detach_called2
|
||||
end)
|
||||
eq(true, result)
|
||||
end)
|
||||
|
||||
it('should not re-attach buffer if it was deleted in on_init #28575', function()
|
||||
exec_lua(create_server_definition)
|
||||
exec_lua(function()
|
||||
|
Reference in New Issue
Block a user