mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
fix(eval): winnr('$') counts non-current hidden/unfocusable windows #34207
Problem: Non-visible/focusable windows are assigned a window number,
whereas commands that use this window number skip over them.
Solution: Skip over non-visible/focusable windows when computing
the window number, unless it is made the current window
through the API in which case an identifiable window number
is still useful. This also ensures it matches the window
number of the window entered by `<winnr>wincmd w` since
403fcacf
.
This commit is contained in:
@ -12124,7 +12124,8 @@ winline() *winline()*
|
||||
winnr([{arg}]) *winnr()*
|
||||
The result is a Number, which is the number of the current
|
||||
window. The top window has number 1.
|
||||
Returns zero for a popup window.
|
||||
Returns zero for a hidden or non |focusable| window, unless
|
||||
it is the current window.
|
||||
|
||||
The optional argument {arg} supports the following values:
|
||||
$ the number of the last window (the window
|
||||
|
@ -68,10 +68,11 @@ The main Vim window can hold several split windows. There are also tab pages
|
||||
If a window is focusable, it is part of the "navigation stack", that is,
|
||||
editor commands such as :windo, |CTRL-W|, etc., will consider the window as
|
||||
one that can be made the "current window". A non-focusable window will be
|
||||
skipped by such commands (though it can be explicitly focused by
|
||||
|nvim_set_current_win()|). Non-focusable windows are not listed by |:tabs|,
|
||||
or counted by the default 'tabline'. Their buffer content is not included
|
||||
in 'complete' "w" completion.
|
||||
skipped by such commands as it isn't assigned a window number. It can be
|
||||
explicitly focused by |nvim_set_current_win()|, because it is still
|
||||
assigned a |window-ID|. If it is focused, it will also have a window number.
|
||||
Non-focusable windows are not listed by |:tabs|, or counted by the default
|
||||
'tabline'. Their buffer content is not included in 'complete' "w" completion.
|
||||
|
||||
Windows (especially floating windows) can have many other |api-win_config|
|
||||
properties such as "hide" and "fixed" which also affect behavior.
|
||||
|
3
runtime/lua/vim/_meta/vimfn.lua
generated
3
runtime/lua/vim/_meta/vimfn.lua
generated
@ -11019,7 +11019,8 @@ function vim.fn.winline() end
|
||||
|
||||
--- The result is a Number, which is the number of the current
|
||||
--- window. The top window has number 1.
|
||||
--- Returns zero for a popup window.
|
||||
--- Returns zero for a hidden or non |focusable| window, unless
|
||||
--- it is the current window.
|
||||
---
|
||||
--- The optional argument {arg} supports the following values:
|
||||
--- $ the number of the last window (the window
|
||||
|
@ -13347,7 +13347,8 @@ M.funcs = {
|
||||
desc = [=[
|
||||
The result is a Number, which is the number of the current
|
||||
window. The top window has number 1.
|
||||
Returns zero for a popup window.
|
||||
Returns zero for a hidden or non |focusable| window, unless
|
||||
it is the current window.
|
||||
|
||||
The optional argument {arg} supports the following values:
|
||||
$ the number of the last window (the window
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/memline.h"
|
||||
@ -381,7 +382,7 @@ static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
|
||||
int winid;
|
||||
bool found_buf = false;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
winnr++;
|
||||
winnr += win_has_winnr(wp);
|
||||
if (wp->w_buffer == buf) {
|
||||
found_buf = true;
|
||||
winid = wp->handle;
|
||||
|
@ -40,6 +40,11 @@ static const char *e_invalwindow = N_("E957: Invalid window number");
|
||||
static const char e_cannot_resize_window_in_another_tab_page[]
|
||||
= N_("E1308: Cannot resize a window in another tab page");
|
||||
|
||||
bool win_has_winnr(win_T *wp)
|
||||
{
|
||||
return wp == curwin || (!wp->w_config.hide && wp->w_config.focusable);
|
||||
}
|
||||
|
||||
static int win_getid(typval_T *argvars)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
@ -72,7 +77,7 @@ static int win_getid(typval_T *argvars)
|
||||
}
|
||||
}
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
if (--winnr == 0) {
|
||||
if ((winnr -= win_has_winnr(wp)) == 0) {
|
||||
return wp->handle;
|
||||
}
|
||||
}
|
||||
@ -120,9 +125,9 @@ static int win_id2win(typval_T *argvars)
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->handle == id) {
|
||||
return nr;
|
||||
return (win_has_winnr(wp) ? nr : 0);
|
||||
}
|
||||
nr++;
|
||||
nr += win_has_winnr(wp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -292,20 +297,24 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
|
||||
semsg(_(e_invexpr2), arg);
|
||||
nr = 0;
|
||||
}
|
||||
} else if (!win_has_winnr(twin)) {
|
||||
nr = 0;
|
||||
}
|
||||
|
||||
if (nr <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
|
||||
wp != twin; wp = wp->w_next) {
|
||||
if (wp == NULL) {
|
||||
// didn't find it in this tabpage
|
||||
nr = 0;
|
||||
nr = 0;
|
||||
win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
nr += win_has_winnr(wp);
|
||||
if (wp == twin) {
|
||||
break;
|
||||
}
|
||||
nr++;
|
||||
}
|
||||
if (wp == NULL) {
|
||||
nr = 0; // didn't find it in this tabpage
|
||||
}
|
||||
return nr;
|
||||
}
|
||||
@ -415,7 +424,7 @@ void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
tabnr++;
|
||||
int16_t winnr = 0;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
winnr++;
|
||||
winnr += win_has_winnr(wp);
|
||||
if (wparg != NULL && wp != wparg) {
|
||||
continue;
|
||||
}
|
||||
@ -834,6 +843,9 @@ void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int winnr = 1;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (!win_has_winnr(wp)) {
|
||||
continue;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%dresize %d|", winnr,
|
||||
wp->w_height);
|
||||
ga_concat(&ga, buf);
|
||||
|
@ -7468,7 +7468,7 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
|
||||
*tabnr = tnum;
|
||||
return;
|
||||
}
|
||||
wnum++;
|
||||
wnum += win_has_winnr(wp);
|
||||
}
|
||||
tnum++;
|
||||
wnum = 1;
|
||||
|
@ -377,7 +377,7 @@ describe('autocmd', function()
|
||||
-- Also check with win_splitmove().
|
||||
exec_lua [[
|
||||
vim._with({buf = _G.buf}, function()
|
||||
vim.fn.win_splitmove(vim.fn.winnr(), vim.fn.win_getid(1))
|
||||
vim.fn.win_splitmove(vim.fn.win_getid(), vim.fn.win_getid(1))
|
||||
end)
|
||||
]]
|
||||
screen:expect_unchanged()
|
||||
|
@ -761,7 +761,7 @@ describe('startup', function()
|
||||
\ 'row': 3,
|
||||
\ 'col': 3
|
||||
\ }
|
||||
autocmd WinEnter * call nvim_open_win(bufnr, v:false, config)]]
|
||||
autocmd WinEnter * let g:float_win = nvim_open_win(bufnr, v:false, config)]]
|
||||
)
|
||||
finally(function()
|
||||
os.remove('Xdiff.vim')
|
||||
@ -769,7 +769,7 @@ describe('startup', function()
|
||||
clear { args = { '-u', 'Xdiff.vim', '-d', 'Xdiff.vim', 'Xdiff.vim' } }
|
||||
eq(true, api.nvim_get_option_value('diff', { win = fn.win_getid(1) }))
|
||||
eq(true, api.nvim_get_option_value('diff', { win = fn.win_getid(2) }))
|
||||
local float_win = fn.win_getid(3)
|
||||
local float_win = eval('g:float_win')
|
||||
eq('editor', api.nvim_win_get_config(float_win).relative)
|
||||
eq(false, api.nvim_get_option_value('diff', { win = float_win }))
|
||||
end)
|
||||
|
@ -1090,6 +1090,17 @@ describe('float window', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('non-visible/focusable are not assigned a window number', function()
|
||||
local win = api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2, focusable = false })
|
||||
api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2, hide = true })
|
||||
api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2 })
|
||||
eq(2, fn.winnr('$'))
|
||||
eq(0, fn.win_id2win(win))
|
||||
-- Unless it is the current window.
|
||||
api.nvim_set_current_win(win)
|
||||
eq({ 3, 3 }, { fn.winnr(), fn.win_id2win(win) })
|
||||
end)
|
||||
|
||||
local function with_ext_multigrid(multigrid)
|
||||
local screen, attrs
|
||||
before_each(function()
|
||||
@ -6417,32 +6428,32 @@ describe('float window', function()
|
||||
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)
|
||||
for _, winid in ipairs(api.nvim_tabpage_list_wins(0)) do
|
||||
table.insert(nr_focusable, api.nvim_win_get_config(winid).focusable)
|
||||
end
|
||||
eq({ true, false, true, false, false, true, false }, nr_focusable)
|
||||
|
||||
command('1wincmd w')
|
||||
eq(1, fn.winnr())
|
||||
eq({ 1, 1000 }, { fn.winnr(), fn.win_getid() })
|
||||
command('2wincmd w')
|
||||
eq(3, fn.winnr())
|
||||
eq({ 2, 1005 }, { fn.winnr(), fn.win_getid() })
|
||||
command('3wincmd w')
|
||||
eq(3, fn.winnr())
|
||||
eq({ 2, 1005 }, { fn.winnr(), fn.win_getid() })
|
||||
command('4wincmd w')
|
||||
eq(6, fn.winnr())
|
||||
eq({ 3, 1002 }, { fn.winnr(), fn.win_getid() })
|
||||
command('5wincmd w')
|
||||
eq(6, fn.winnr())
|
||||
eq({ 3, 1002 }, { fn.winnr(), fn.win_getid() })
|
||||
command('6wincmd w')
|
||||
eq(6, fn.winnr())
|
||||
eq({ 3, 1002 }, { fn.winnr(), fn.win_getid() })
|
||||
command('7wincmd w')
|
||||
eq(6, fn.winnr())
|
||||
eq({ 3, 1002 }, { fn.winnr(), fn.win_getid() })
|
||||
|
||||
feed('1<c-w>w')
|
||||
eq(1, fn.winnr())
|
||||
eq({ 1, 1000 }, { fn.winnr(), fn.win_getid() })
|
||||
feed('2<c-w>w')
|
||||
eq(3, fn.winnr())
|
||||
eq({ 2, 1005 }, { fn.winnr(), fn.win_getid() })
|
||||
feed('999<c-w>w')
|
||||
eq(6, fn.winnr())
|
||||
eq({ 3, 1002 }, { fn.winnr(), fn.win_getid() })
|
||||
end)
|
||||
|
||||
it('W', function()
|
||||
|
Reference in New Issue
Block a user