fix(terminal): autocmds leave terminal open to wiped buffer

Problem: if buf_free_all autocommands open a terminal, it will remain open after
the buffer is freed.

Solution: close terminals again later, this time while blocking autocommands.

Did consider terminal_open checking stuff like b_locked_split instead, but
that's set during BufHidden, etc., which doesn't mean the buffer's being wiped.
This commit is contained in:
Sean Dewar
2026-02-07 19:40:24 +00:00
parent da8de99d0b
commit 1519a34e43
2 changed files with 17 additions and 0 deletions

View File

@@ -902,6 +902,13 @@ void buf_freeall(buf_T *buf, int flags)
}
}
// Autocommands may have opened another terminal. Block them this time.
if (buf->terminal) {
block_autocmds();
buf_close_terminal(buf);
unblock_autocmds();
}
ml_close(buf, true); // close and delete the memline/memfile
buf->b_ml.ml_line_count = 0; // no lines in buffer
if ((flags & BFA_KEEP_UNDO) == 0) {

View File

@@ -34,6 +34,16 @@ describe('terminal channel is closed and later released if', function()
feed('<Ignore>') -- add input to separate two RPC requests
-- channel has been released after one main loop iteration
eq(chans - 1, eval('len(nvim_list_chans())'))
command('autocmd BufWipeout * ++once let id2 = nvim_open_term(str2nr(expand("<abuf>")), {})')
-- channel hasn't been released yet
eq(
"Vim(call):Can't send data to closed stream",
pcall_err(command, [[bdelete! | call chansend(id2, 'test')]])
)
feed('<Ignore>') -- add input to separate two RPC requests
-- channel has been released after one main loop iteration
eq(chans - 1, eval('len(nvim_list_chans())'))
end)
it('opened by nvim_open_term(), closed by chanclose(), and deleted by pressing a key', function()