commit 403fcacfc16fb3a1fbb4be22f77389e0f0616a6e
parent 03d378fda68fc5942660707cdd2314c0e12fb0a0
Author: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Date: Sat, 3 May 2025 19:30:24 +0100
fix(window): skip unfocusable and hidden floats with "{count}<C-W>w" #33810
Problem: Using `<C-W>w`, `<C-W>W` or the ":wincmd" variants with a count can
enter unfocusable or hidden floating windows. This is especially problematic
when using the new in-development extui, which creates many unfocusable floats
for various UI elements.
Solution: Skip unfocusable and hidden floating windows. Instead, skip to the
next focusable, non-hidden window in the current tabpage's window list. Reword
the documentation a bit (hopefully an improvement?)
Diffstat:
3 files changed, 72 insertions(+), 9 deletions(-)
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
@@ -439,18 +439,17 @@ CTRL-W l Move cursor to Nth window right of current one. Uses the
CTRL-W w *CTRL-W_w* *CTRL-W_CTRL-W*
CTRL-W CTRL-W Without count: move cursor to the |focusable| window
- below/right of the current one. If there is no (focusable)
- window below or right, go to top-left window. With count: go
- to Nth window (windows are numbered from top-left to
- bottom-right). To obtain the window number see |bufwinnr()|
- and |winnr()|. When N is larger than the number of windows go
- to the last window.
+ below/right of the current one. If none, go to the top-left
+ window. With count: go to Nth window (numbered top-left to
+ bottom-right), skipping unfocusable windows. To obtain the
+ window number see |bufwinnr()| and |winnr()|. When N is
+ larger than the number of windows go to the last focusable
+ window.
*CTRL-W_W*
CTRL-W W Without count: move cursor to the |focusable| window
- above/left of current one. If there is no window above or
- left, go to bottom-right window. With count: go to Nth
- window, like with CTRL-W w.
+ above/left of current one. If none, go to the bottom-right
+ window. With count: go to Nth window, like CTRL-W w.
CTRL-W t *CTRL-W_t* *CTRL-W_CTRL-T*
CTRL-W CTRL-T Move cursor to top-left window.
diff --git a/src/nvim/window.c b/src/nvim/window.c
@@ -348,12 +348,23 @@ newwindow:
} else {
win_T *wp;
if (Prenum) { // go to specified window
+ win_T *last_focusable = firstwin;
for (wp = firstwin; --Prenum > 0;) {
+ if (!wp->w_floating || (!wp->w_config.hide && wp->w_config.focusable)) {
+ last_focusable = wp;
+ }
if (wp->w_next == NULL) {
break;
}
wp = wp->w_next;
}
+ while (wp != NULL && wp->w_floating
+ && (wp->w_config.hide || !wp->w_config.focusable)) {
+ wp = wp->w_next;
+ }
+ if (wp == NULL) { // went past the last focusable window
+ wp = last_focusable;
+ }
} else {
if (nchar == 'W') { // go to previous window
wp = curwin->w_prev;
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
@@ -5846,6 +5846,59 @@ describe('float window', function()
|
]])
end
+
+ api.nvim_open_win(
+ 0,
+ false,
+ { relative = "editor", width = 1, height = 1, row = 0, col = 0 }
+ )
+ api.nvim_open_win(
+ 0,
+ false,
+ { relative = "editor", width = 1, height = 1, row = 0, col = 0, focusable = false }
+ )
+ api.nvim_open_win(
+ 0,
+ false,
+ { relative = "editor", width = 1, height = 1, row = 0, col = 0, focusable = false }
+ )
+ api.nvim_open_win(
+ 0,
+ false,
+ { relative = "editor", width = 1, height = 1, row = 0, col = 0, focusable = true }
+ )
+ api.nvim_open_win(
+ 0,
+ false,
+ { relative = "editor", width = 1, height = 1, row = 0, col = 0, focusable = false }
+ )
+ local nr_focusable = {}
+ for nr = 1, fn.winnr("$") do
+ table.insert(nr_focusable, api.nvim_win_get_config(fn.win_getid(nr)).focusable)
+ end
+ eq({true, false, true, false, false, true, false}, nr_focusable)
+
+ command("1wincmd w")
+ eq(1, fn.winnr())
+ command("2wincmd w")
+ eq(3, fn.winnr())
+ command("3wincmd w")
+ eq(3, fn.winnr())
+ command("4wincmd w")
+ eq(6, fn.winnr())
+ command("5wincmd w")
+ eq(6, fn.winnr())
+ command("6wincmd w")
+ eq(6, fn.winnr())
+ command("7wincmd w")
+ eq(6, fn.winnr())
+
+ feed("1<c-w>w")
+ eq(1, fn.winnr())
+ feed("2<c-w>w")
+ eq(3, fn.winnr())
+ feed("999<c-w>w")
+ eq(6, fn.winnr())
end)
it("W", function()