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 <[email protected]>
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 <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

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,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1vdxa2-003Fmi-GH%40256bit.org.

Raspunde prin e-mail lui