neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 0d658660c29e920e74c4dade3819d80dccad0dde
parent c7f38e3bc8fb99a490a0575ed7ce0624bd7b975a
Author: luukvbaal <luukvbaal@gmail.com>
Date:   Sat, 14 Jun 2025 23:42:23 +0200

fix(window): don't enter unfocusable or hidden prevwin (#34486)

Problem:  When closing a floating window, the next window to be entered
          may be unfocusable or hidden.
Solution: Don't enter prevwin when it is unfocusable or hidden. Enter
          firstwin instead (like for when prevwin is no longer valid).
Diffstat:
Msrc/nvim/window.c | 10+---------
Msrc/nvim/winfloat.c | 8+++++---
Mtest/functional/api/window_spec.lua | 26++++++++++++++++++++++++++
3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/src/nvim/window.c b/src/nvim/window.c @@ -2753,15 +2753,7 @@ int win_close(win_T *win, bool free_buf, bool force) // Guess which window is going to be the new current window. // This may change because of the autocommands (sigh). - if (!win->w_floating) { - wp = frame2win(win_altframe(win, NULL)); - } else { - if (win_valid(prevwin) && prevwin != win) { - wp = prevwin; - } else { - wp = firstwin; - } - } + wp = win->w_floating ? win_float_find_altwin(win, NULL) : frame2win(win_altframe(win, NULL)); // Be careful: If autocommands delete the window or cause this window // to be the last one left, return now. diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c @@ -362,13 +362,15 @@ win_T *win_float_find_preview(void) win_T *win_float_find_altwin(const win_T *win, const tabpage_T *tp) FUNC_ATTR_NONNULL_ARG(1) { + win_T *wp = prevwin; if (tp == NULL) { - return (win_valid(prevwin) && prevwin != win) ? prevwin : firstwin; + return (win_valid(wp) && wp != win && wp->w_config.focusable + && !wp->w_config.hide) ? wp : firstwin; } assert(tp != curtab); - return (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) ? tp->tp_prevwin - : tp->tp_firstwin; + wp = tabpage_win_valid(tp, tp->tp_prevwin) ? tp->tp_prevwin : tp->tp_firstwin; + return (wp->w_config.focusable && !wp->w_config.hide) ? wp : tp->tp_firstwin; } /// Inline helper function for handling errors and cleanup in win_float_create. diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua @@ -730,6 +730,32 @@ describe('API/win', function() eq(prevwin, api.nvim_tabpage_get_win(tab)) assert_alive() end) + + it('closing a float does not enter unfocusable or hidden prevwin', function() + local firstwin = api.nvim_get_current_win() + local wins = {} ---@type integer[] + for _ = 1, 4 do + wins[#wins + 1] = api.nvim_open_win(0, true, { + relative = 'editor', + row = 10, + col = 10, + width = 50, + height = 10, + }) + end + api.nvim_win_set_config(wins[3], { hide = true }) + api.nvim_win_close(0, false) + eq(firstwin, api.nvim_get_current_win()) + api.nvim_set_current_win(wins[2]) + api.nvim_set_current_win(wins[3]) + api.nvim_win_set_config(wins[2], { focusable = false }) + api.nvim_win_close(0, false) + eq(firstwin, api.nvim_get_current_win()) + api.nvim_set_current_win(wins[1]) + api.nvim_set_current_win(wins[2]) + api.nvim_win_close(0, false) + eq(wins[1], api.nvim_get_current_win()) + end) end) describe('hide', function()