From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:27:55 +0000 (+0000) Subject: patch 9.1.2068: :bd/bw may try to switch to a closing buffer X-Git-Tag: v9.1.2068^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63d53de72d94b53172070acb2b1c50489d1133bd;p=thirdparty%2Fvim.git 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+seandewar@users.noreply.github.com> Signed-off-by: Christian Brabandt --- diff --git a/src/buffer.c b/src/buffer.c index 9bb13da8f3..62b57e8f65 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 3fdb5fc4e1..4ededa15d4 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 003b58ab07..c922944be7 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, /**/