fix(float): :bufdelete in floatwin may change focus #39858

Problem:
(Followup to 54f22a8f01c0feb27a531b52aedf5cdbd5e51b24.)
Deleting another buffer from a floatwin could move focus into the holder
window and fire BufEnter for the buffer being deleted.

Solution:
Use switch_win_noblock() instead of buf_jump_open_win() before
recursing into do_buffer_ext().
This commit is contained in:
glepnir
2026-05-21 17:06:50 +08:00
committed by GitHub
parent 7337e02563
commit 26df751add
3 changed files with 51 additions and 10 deletions

View File

@@ -46,6 +46,7 @@
#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_cmds_defs.h"
@@ -1462,11 +1463,21 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags)
}
close_windows(buf, false);
// close_windows keeps the last non-float window. If it still
// shows buf, jump there and retry so curbuf gets replaced.
if (bufref_valid(&bufref) && buf->b_nwindows > 0) {
win_T *holder = buf_jump_open_win(buf);
if (holder != NULL && !holder->w_floating) {
// close_windows() refuses to close curtab's last non-float window.
// If it still shows buf, retry the delete from there.
win_T *holder = close_windows(buf, false);
if (buf != curbuf && bufref_valid(&bufref) && holder != NULL) {
if (curwin->w_floating) {
// swap into holder without entering it: caller keeps focus,
// BufEnter doesn't fire for the deleted buffer.
switchwin_T switchwin;
const int rv = switch_win_noblock(&switchwin, holder, curtab, true);
assert(rv == OK);
(void)rv;
do_buffer_ext(action, start, dir, count, flags);
restore_win_noblock(&switchwin, true);
} else {
buf_jump_open_win(buf);
return do_buffer_ext(action, start, dir, count, flags);
}
}