patch 9.1.2068: :bd/bw may try to switch to a closing buffer
Commit:
https://github.com/vim/vim/commit/63d53de72d94b53172070acb2b1c50489d1133bd
Author: Sean Dewar <
6256228+...@users.noreply.github.com>
Date: Thu Jan 8 21:27:55 2026 +0000
patch 9.1.2068: :bd/bw may try to switch to a closing buffer
Problem: :bdelete/bunload/bwipeout may attempt to switch to a closing
buffer, which fails. (after 9.1.2058)
Solution: don't consider switching to closing buffers (Sean Dewar)
closes: #19107
Signed-off-by: Sean Dewar <
6256228+...@users.noreply.github.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/buffer.c b/src/buffer.c
index 9bb13da8f..62b57e8f6 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1542,11 +1542,12 @@ do_buffer_ext(
* Then prefer the buffer we most recently visited.
* Else try to find one that is loaded, after the current buffer,
* then before the current buffer.
- * Finally use any buffer.
+ * Finally use any buffer. Skip buffers that are closing throughout.
*/
buf = NULL; // selected buffer
bp = NULL; // used when no loaded buffer found
- if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf))
+ if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)
+ && !au_new_curbuf.br_buf->b_locked_split)
buf = au_new_curbuf.br_buf;
else if (curwin->w_jumplistlen > 0)
{
@@ -1563,8 +1564,9 @@ do_buffer_ext(
if (buf != NULL)
{
// Skip current and unlisted bufs. Also skip a quickfix
- // buffer, it might be deleted soon.
- if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf))
+ // or closing buffer, it might be deleted soon.
+ if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)
+ || buf->b_locked_split)
buf = NULL;
else if (buf->b_ml.ml_mfp == NULL)
{
@@ -1602,7 +1604,7 @@ do_buffer_ext(
}
// in non-help buffer, try to skip help buffers, and vv
if (buf->b_help == curbuf->b_help && buf->b_p_bl
- && !bt_quickfix(buf))
+ && !bt_quickfix(buf) && !buf->b_locked_split)
{
if (buf->b_ml.ml_mfp != NULL) // found loaded buffer
break;
@@ -1620,7 +1622,8 @@ do_buffer_ext(
if (buf == NULL) // No loaded buffer, find listed one
{
FOR_ALL_BUFFERS(buf)
- if (buf->b_p_bl && buf != curbuf && !bt_quickfix(buf))
+ if (buf->b_p_bl && buf != curbuf && !bt_quickfix(buf)
+ && !buf->b_locked_split)
break;
}
if (buf == NULL) // Still no buffer, just take one
@@ -1629,7 +1632,7 @@ do_buffer_ext(
buf = curbuf->b_next;
else
buf = curbuf->b_prev;
- if (bt_quickfix(buf))
+ if (bt_quickfix(buf) || (buf != curbuf && buf->b_locked_split))
buf = NULL;
}
}
diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim
index 3fdb5fc4e..4ededa15d 100644
--- a/src/testdir/test_buffer.vim
+++ b/src/testdir/test_buffer.vim
@@ -734,4 +734,150 @@ func Test_switch_to_previously_viewed_buffer()
set startofline&
endfunc
+func Test_bdelete_skip_closing_bufs()
+ set hidden
+ let s:fired = 0
+
+ edit foo
+ edit bar
+ let s:next_new_bufnr = bufnr('$') + 1
+ augroup SkipClosing
+ autocmd!
+ " Only window and other buffer is closing.
+ " No choice but to switch to a new, empty buffer.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('bar', bufname())
+ \| bdelete
+ \| call assert_equal('', bufname())
+ \| call assert_equal(s:next_new_bufnr, bufnr())
+ augroup END
+ bdelete foo
+ call assert_equal(1, s:fired)
+ unlet! s:next_new_bufnr
+ %bw!
+
+ edit baz
+ edit bar
+ edit fleb
+ edit foo
+ augroup SkipClosing
+ autocmd!
+ " Only window, au_new_curbuf is NOT closing; should end up there.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('foo', bufname())
+ \| bwipeout
+ \| call assert_equal('bar', bufname())
+ augroup END
+ buffer baz
+ buffer foo
+ augroup SkipClosing
+ autocmd BufLeave * ++once ++nested bdelete baz
+ augroup END
+ edit bar
+ call assert_equal(2, s:fired)
+ %bw!
+
+ edit baz
+ edit bar
+ edit fleb
+ edit foo
+ augroup SkipClosing
+ autocmd!
+ " Like above, but au_new_curbuf IS closing.
+ " Should use the most recent jumplist buffer instead.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('foo', bufname())
+ \| bwipeout
+ \| call assert_equal('baz', bufname())
+ augroup END
+ buffer baz
+ buffer foo
+ augroup SkipClosing
+ autocmd BufLeave * ++once ++nested bdelete bar
+ augroup END
+ edit bar
+ call assert_equal(3, s:fired)
+ %bw!
+
+ edit foo
+ edit floob
+ edit baz
+ edit bar
+ augroup SkipClosing
+ autocmd!
+ " Only window, most recent buffer in jumplist is closing.
+ " Should switch to the next most-recent buffer in the jumplist instead.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('bar', bufname())
+ \| bdelete
+ \| call assert_equal('floob', bufname())
+ augroup END
+ buffer baz
+ buffer floob
+ buffer foo
+ buffer bar
+ bdelete foo
+ call assert_equal(4, s:fired)
+ %bw!
+
+ edit foo
+ edit baz
+ edit bar
+ edit floob
+ edit bazinga
+ augroup SkipClosing
+ autocmd!
+ " Only window, most recent jumplist buffer is gone, next most-recent is
+ " closing. Should switch to the 3rd most-recent jumplist buffer.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('bar', bufname())
+ \| bwipeout
+ \| call assert_equal('baz', bufname())
+ augroup END
+ buffer bazinga
+ buffer baz
+ buffer floob
+ buffer foo
+ buffer bar
+ noautocmd bdelete foo
+ bdelete floob
+ call assert_equal(5, s:fired)
+ %bw!
+
+ edit foo
+ edit baz
+ edit floob
+ edit bazinga
+ edit bar
+ augroup SkipClosing
+ autocmd!
+ " Like above, but jumplist cleared, no next buffer in the buffer list and
+ " previous buffer is closing. Should switch to the buffer before previous.
+ autocmd BufDelete * ++once let s:fired += 1
+ \| call assert_equal(1, winnr('$'))
+ \| call assert_equal('bar', bufname())
+ \| bunload
+ \| call assert_equal('floob', bufname())
+ augroup END
+ buffer bazinga
+ buffer baz
+ buffer floob
+ buffer foo
+ buffer bar
+ noautocmd bdelete foo
+ clearjumps
+ bdelete bazinga
+ call assert_equal(6, s:fired)
+
+ unlet! s:fired
+ autocmd! SkipClosing
+ set hidden&
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 003b58ab0..c922944be 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2068,
/**/
2067,
/**/