commit e70452990935fedd7de6ca84dde4a0ac16807fd9
parent 1196bf8f401433994a9aaf3f07b1ce8e9da8a243
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sat, 7 Feb 2026 23:03:21 +0800
vim-patch:9.1.2136: :tab sbuffer may close old tabpage (#37765)
Problem: :tab sbuffer may close old tabpage if BufLeave autocommand
splits window (after 9.1.0143).
Solution: Only close other windows if the buffer will be unloaded
(zeertzjq).
related: neovim/neovim#37749
closes: vim/vim#19352
https://github.com/vim/vim/commit/6da9f757c48ce87df381d726b165bed6fa301423
Diffstat:
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
@@ -1680,6 +1680,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist)
bufref_T prevbufref;
set_bufref(&prevbufref, prevbuf);
set_bufref(&newbufref, buf);
+ const int prev_nwindows = prevbuf->b_nwindows;
// Autocommands may delete the current buffer and/or the buffer we want to
// go to. In those cases don't close the buffer.
@@ -1692,8 +1693,8 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist)
// autocommands may have opened a new window
// with prevbuf, grr
if (unload
- || (last_winid != get_last_winid()
- && strchr("wdu", prevbuf->b_p_bh[0]) != NULL)) {
+ || (prev_nwindows <= 1 && last_winid != get_last_winid()
+ && action == DOBUF_GOTO && !buf_hide(prevbuf))) {
close_windows(prevbuf, false);
}
if (bufref_valid(&prevbufref) && !aborting()) {
diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim
@@ -4247,7 +4247,7 @@ func Test_autocmd_invalidates_undo_on_textchanged()
call StopVimInTerminal(buf)
endfunc
-func Test_autocmd_creates_new_buffer_on_bufleave()
+func Test_autocmd_creates_new_window_on_bufleave()
e a.txt
e b.txt
setlocal bufhidden=wipe
diff --git a/test/old/testdir/test_buffer.vim b/test/old/testdir/test_buffer.vim
@@ -882,4 +882,37 @@ func Test_bdelete_skip_closing_bufs()
%bw!
endfunc
+func Test_split_window_in_BufLeave_from_tab_sbuffer()
+ tabnew Xa
+ setlocal bufhidden=wipe
+ let t0 = tabpagenr()
+ let b0 = bufnr()
+ let b1 = bufadd('Xb')
+ autocmd BufLeave Xa ++once split
+ exe 'tab sbuffer' b1
+ call assert_equal(t0 + 1, tabpagenr())
+ call assert_equal([b1, b0], tabpagebuflist())
+ call assert_equal([b0], tabpagebuflist(t0))
+ tabclose
+ call assert_equal(t0, tabpagenr())
+ call assert_equal([b0], tabpagebuflist())
+
+ bwipe! Xa
+ bwipe! Xb
+endfunc
+
+func Test_split_window_in_BufLeave_from_switching_buffer()
+ tabnew Xa
+ setlocal bufhidden=wipe
+ split
+ let b0 = bufnr()
+ let b1 = bufadd('Xb')
+ autocmd BufLeave Xa ++once split
+ exe 'buffer' b1
+ call assert_equal([b1, b0, b0], tabpagebuflist())
+
+ bwipe! Xa
+ bwipe! Xb
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab