mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
fix(eval): winnrs of unfocusable/hidden windows #35474
Problem: various functions may return incorrect window numbers for unfocusable or hidden windows. Solution: fix the checks. Make sure current windows in non-current tabpages have a window number. Fixes #35453
This commit is contained in:
@@ -380,8 +380,8 @@ 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 += win_has_winnr(wp);
|
||||
if (wp->w_buffer == buf) {
|
||||
winnr += win_has_winnr(wp, curtab);
|
||||
if (wp->w_buffer == buf && (!get_nr || win_has_winnr(wp, curtab))) {
|
||||
found_buf = true;
|
||||
winid = wp->handle;
|
||||
break;
|
||||
|
@@ -38,9 +38,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)
|
||||
bool win_has_winnr(win_T *wp, tabpage_T *tp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
return wp == curwin || (!wp->w_config.hide && wp->w_config.focusable);
|
||||
return (wp == (tp == curtab ? curwin : tp->tp_curwin))
|
||||
|| (!wp->w_config.hide && wp->w_config.focusable);
|
||||
}
|
||||
|
||||
static int win_getid(typval_T *argvars)
|
||||
@@ -54,10 +56,11 @@ static int win_getid(typval_T *argvars)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tabpage_T *tp = NULL;
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
tp = curtab;
|
||||
wp = firstwin;
|
||||
} else {
|
||||
tabpage_T *tp = NULL;
|
||||
int tabnr = (int)tv_get_number(&argvars[1]);
|
||||
FOR_ALL_TABS(tp2) {
|
||||
if (--tabnr == 0) {
|
||||
@@ -75,7 +78,7 @@ static int win_getid(typval_T *argvars)
|
||||
}
|
||||
}
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
if ((winnr -= win_has_winnr(wp)) == 0) {
|
||||
if ((winnr -= win_has_winnr(wp, tp)) == 0) {
|
||||
return wp->handle;
|
||||
}
|
||||
}
|
||||
@@ -123,9 +126,9 @@ static int win_id2win(typval_T *argvars)
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->handle == id) {
|
||||
return (win_has_winnr(wp) ? nr : 0);
|
||||
return (win_has_winnr(wp, curtab) ? nr : 0);
|
||||
}
|
||||
nr += win_has_winnr(wp);
|
||||
nr += win_has_winnr(wp, curtab);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -296,7 +299,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
|
||||
semsg(_(e_invexpr2), arg);
|
||||
nr = 0;
|
||||
}
|
||||
} else if (!win_has_winnr(twin)) {
|
||||
} else if (!win_has_winnr(twin, tp)) {
|
||||
nr = 0;
|
||||
}
|
||||
|
||||
@@ -307,7 +310,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
|
||||
nr = 0;
|
||||
win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
nr += win_has_winnr(wp);
|
||||
nr += win_has_winnr(wp, tp);
|
||||
if (wp == twin) {
|
||||
break;
|
||||
}
|
||||
@@ -423,11 +426,11 @@ void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
tabnr++;
|
||||
int16_t winnr = 0;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
winnr += win_has_winnr(wp);
|
||||
winnr += win_has_winnr(wp, tp);
|
||||
if (wparg != NULL && wp != wparg) {
|
||||
continue;
|
||||
}
|
||||
dict_T *const d = get_win_info(wp, tabnr, winnr);
|
||||
dict_T *const d = get_win_info(wp, tabnr, win_has_winnr(wp, tp) ? winnr : 0);
|
||||
tv_list_append_dict(rettv->vval.v_list, d);
|
||||
if (wparg != NULL) {
|
||||
// found information about a specific window
|
||||
@@ -842,7 +845,7 @@ 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)) {
|
||||
if (!win_has_winnr(wp, curtab)) {
|
||||
continue;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%dresize %d|", winnr,
|
||||
|
@@ -7501,11 +7501,13 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
|
||||
FOR_ALL_TABS(tp) {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
if (wp->handle == id) {
|
||||
*winnr = wnum;
|
||||
*tabnr = tnum;
|
||||
if (win_has_winnr(wp, tp)) {
|
||||
*winnr = wnum;
|
||||
*tabnr = tnum;
|
||||
}
|
||||
return;
|
||||
}
|
||||
wnum += win_has_winnr(wp);
|
||||
wnum += win_has_winnr(wp, tp);
|
||||
}
|
||||
tnum++;
|
||||
wnum = 1;
|
||||
|
@@ -9,6 +9,7 @@ local command, feed_command = n.command, n.feed_command
|
||||
local eval = n.eval
|
||||
local eq = t.eq
|
||||
local neq = t.neq
|
||||
local matches = t.matches
|
||||
local expect = n.expect
|
||||
local exec = n.exec
|
||||
local exec_lua = n.exec_lua
|
||||
@@ -899,14 +900,54 @@ 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 })
|
||||
command('tabnew')
|
||||
local tp = api.nvim_get_current_tabpage()
|
||||
local split_win = api.nvim_get_current_win()
|
||||
local float_buf = api.nvim_create_buf(true, true)
|
||||
local win = api.nvim_open_win(float_buf, 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))
|
||||
eq(0, fn.getwininfo(win)[1].winnr)
|
||||
eq({ 0, 0 }, fn.win_id2tabwin(win))
|
||||
eq(2, fn.tabpagewinnr(2, '$'))
|
||||
eq(0, fn.win_getid(3))
|
||||
eq(0, fn.win_getid(3, 2))
|
||||
eq(-1, fn.bufwinnr(float_buf))
|
||||
eq(win, fn.bufwinid(float_buf)) -- bufwinid unaffected.
|
||||
eq(nil, fn.winrestcmd():match('3resize'))
|
||||
|
||||
-- Unless it is the current window.
|
||||
api.nvim_set_current_win(win)
|
||||
eq({ 3, 3 }, { fn.winnr(), fn.win_id2win(win) })
|
||||
eq(3, fn.winnr('$'))
|
||||
eq(3, fn.winnr())
|
||||
eq(3, fn.win_id2win(win))
|
||||
eq(3, fn.getwininfo(win)[1].winnr)
|
||||
eq({ 2, 3 }, fn.win_id2tabwin(win))
|
||||
eq(3, fn.tabpagewinnr(2, '$'))
|
||||
eq(3, fn.tabpagewinnr(2))
|
||||
eq(win, fn.win_getid(3))
|
||||
eq(win, fn.win_getid(3, 2))
|
||||
eq(3, fn.bufwinnr(float_buf))
|
||||
matches('3resize', fn.winrestcmd())
|
||||
|
||||
-- When switching tabpages it should still have a winnr, as it's current in the other tabpage.
|
||||
command('tabfirst')
|
||||
eq({ 2, 3 }, fn.win_id2tabwin(win))
|
||||
eq(3, fn.getwininfo(win)[1].winnr)
|
||||
eq(win, fn.win_getid(3, 2))
|
||||
eq(3, fn.tabpagewinnr(2, '$'))
|
||||
eq(3, fn.tabpagewinnr(2))
|
||||
|
||||
-- ...but not if it's non-current in that tabpage.
|
||||
api.nvim_tabpage_set_win(tp, split_win)
|
||||
eq({ 0, 0 }, fn.win_id2tabwin(win))
|
||||
eq(0, fn.getwininfo(win)[1].winnr)
|
||||
eq(0, fn.win_getid(3, 2))
|
||||
eq(2, fn.tabpagewinnr(2, '$'))
|
||||
eq(1, fn.tabpagewinnr(2))
|
||||
end)
|
||||
|
||||
it('no crash for unallocated relative window grid', function()
|
||||
|
Reference in New Issue
Block a user