Skip to content

Commit 1e1619d

Browse files
authored
fix(eval): winnrs of unfocusable/hidden windows neovim#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 neovim#35453
1 parent 6a409e0 commit 1e1619d

File tree

4 files changed

+64
-18
lines changed

4 files changed

+64
-18
lines changed

src/nvim/eval/buffer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
380380
int winid;
381381
bool found_buf = false;
382382
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
383-
winnr += win_has_winnr(wp);
384-
if (wp->w_buffer == buf) {
383+
winnr += win_has_winnr(wp, curtab);
384+
if (wp->w_buffer == buf && (!get_nr || win_has_winnr(wp, curtab))) {
385385
found_buf = true;
386386
winid = wp->handle;
387387
break;

src/nvim/eval/window.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ static const char *e_invalwindow = N_("E957: Invalid window number");
3838
static const char e_cannot_resize_window_in_another_tab_page[]
3939
= N_("E1308: Cannot resize a window in another tab page");
4040

41-
bool win_has_winnr(win_T *wp)
41+
bool win_has_winnr(win_T *wp, tabpage_T *tp)
42+
FUNC_ATTR_NONNULL_ALL
4243
{
43-
return wp == curwin || (!wp->w_config.hide && wp->w_config.focusable);
44+
return (wp == (tp == curtab ? curwin : tp->tp_curwin))
45+
|| (!wp->w_config.hide && wp->w_config.focusable);
4446
}
4547

4648
static int win_getid(typval_T *argvars)
@@ -54,10 +56,11 @@ static int win_getid(typval_T *argvars)
5456
return 0;
5557
}
5658

59+
tabpage_T *tp = NULL;
5760
if (argvars[1].v_type == VAR_UNKNOWN) {
61+
tp = curtab;
5862
wp = firstwin;
5963
} else {
60-
tabpage_T *tp = NULL;
6164
int tabnr = (int)tv_get_number(&argvars[1]);
6265
FOR_ALL_TABS(tp2) {
6366
if (--tabnr == 0) {
@@ -75,7 +78,7 @@ static int win_getid(typval_T *argvars)
7578
}
7679
}
7780
for (; wp != NULL; wp = wp->w_next) {
78-
if ((winnr -= win_has_winnr(wp)) == 0) {
81+
if ((winnr -= win_has_winnr(wp, tp)) == 0) {
7982
return wp->handle;
8083
}
8184
}
@@ -123,9 +126,9 @@ static int win_id2win(typval_T *argvars)
123126

124127
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
125128
if (wp->handle == id) {
126-
return (win_has_winnr(wp) ? nr : 0);
129+
return (win_has_winnr(wp, curtab) ? nr : 0);
127130
}
128-
nr += win_has_winnr(wp);
131+
nr += win_has_winnr(wp, curtab);
129132
}
130133
return 0;
131134
}
@@ -296,7 +299,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
296299
semsg(_(e_invexpr2), arg);
297300
nr = 0;
298301
}
299-
} else if (!win_has_winnr(twin)) {
302+
} else if (!win_has_winnr(twin, tp)) {
300303
nr = 0;
301304
}
302305

@@ -307,7 +310,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
307310
nr = 0;
308311
win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
309312
for (; wp != NULL; wp = wp->w_next) {
310-
nr += win_has_winnr(wp);
313+
nr += win_has_winnr(wp, tp);
311314
if (wp == twin) {
312315
break;
313316
}
@@ -423,11 +426,11 @@ void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
423426
tabnr++;
424427
int16_t winnr = 0;
425428
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
426-
winnr += win_has_winnr(wp);
429+
winnr += win_has_winnr(wp, tp);
427430
if (wparg != NULL && wp != wparg) {
428431
continue;
429432
}
430-
dict_T *const d = get_win_info(wp, tabnr, winnr);
433+
dict_T *const d = get_win_info(wp, tabnr, win_has_winnr(wp, tp) ? winnr : 0);
431434
tv_list_append_dict(rettv->vval.v_list, d);
432435
if (wparg != NULL) {
433436
// found information about a specific window
@@ -842,7 +845,7 @@ void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
842845
for (int i = 0; i < 2; i++) {
843846
int winnr = 1;
844847
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
845-
if (!win_has_winnr(wp)) {
848+
if (!win_has_winnr(wp, curtab)) {
846849
continue;
847850
}
848851
snprintf(buf, sizeof(buf), "%dresize %d|", winnr,

src/nvim/window.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7501,11 +7501,13 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
75017501
FOR_ALL_TABS(tp) {
75027502
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
75037503
if (wp->handle == id) {
7504-
*winnr = wnum;
7505-
*tabnr = tnum;
7504+
if (win_has_winnr(wp, tp)) {
7505+
*winnr = wnum;
7506+
*tabnr = tnum;
7507+
}
75067508
return;
75077509
}
7508-
wnum += win_has_winnr(wp);
7510+
wnum += win_has_winnr(wp, tp);
75097511
}
75107512
tnum++;
75117513
wnum = 1;

test/functional/ui/float_spec.lua

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ local command, feed_command = n.command, n.feed_command
99
local eval = n.eval
1010
local eq = t.eq
1111
local neq = t.neq
12+
local matches = t.matches
1213
local expect = n.expect
1314
local exec = n.exec
1415
local exec_lua = n.exec_lua
@@ -899,14 +900,54 @@ describe('float window', function()
899900
end)
900901

901902
it('non-visible/focusable are not assigned a window number', function()
902-
local win = api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2, focusable = false })
903+
command('tabnew')
904+
local tp = api.nvim_get_current_tabpage()
905+
local split_win = api.nvim_get_current_win()
906+
local float_buf = api.nvim_create_buf(true, true)
907+
local win = api.nvim_open_win(float_buf, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2, focusable = false })
903908
api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2, hide = true })
904909
api.nvim_open_win(0, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2 })
910+
905911
eq(2, fn.winnr('$'))
906912
eq(0, fn.win_id2win(win))
913+
eq(0, fn.getwininfo(win)[1].winnr)
914+
eq({ 0, 0 }, fn.win_id2tabwin(win))
915+
eq(2, fn.tabpagewinnr(2, '$'))
916+
eq(0, fn.win_getid(3))
917+
eq(0, fn.win_getid(3, 2))
918+
eq(-1, fn.bufwinnr(float_buf))
919+
eq(win, fn.bufwinid(float_buf)) -- bufwinid unaffected.
920+
eq(nil, fn.winrestcmd():match('3resize'))
921+
907922
-- Unless it is the current window.
908923
api.nvim_set_current_win(win)
909-
eq({ 3, 3 }, { fn.winnr(), fn.win_id2win(win) })
924+
eq(3, fn.winnr('$'))
925+
eq(3, fn.winnr())
926+
eq(3, fn.win_id2win(win))
927+
eq(3, fn.getwininfo(win)[1].winnr)
928+
eq({ 2, 3 }, fn.win_id2tabwin(win))
929+
eq(3, fn.tabpagewinnr(2, '$'))
930+
eq(3, fn.tabpagewinnr(2))
931+
eq(win, fn.win_getid(3))
932+
eq(win, fn.win_getid(3, 2))
933+
eq(3, fn.bufwinnr(float_buf))
934+
matches('3resize', fn.winrestcmd())
935+
936+
-- When switching tabpages it should still have a winnr, as it's current in the other tabpage.
937+
command('tabfirst')
938+
eq({ 2, 3 }, fn.win_id2tabwin(win))
939+
eq(3, fn.getwininfo(win)[1].winnr)
940+
eq(win, fn.win_getid(3, 2))
941+
eq(3, fn.tabpagewinnr(2, '$'))
942+
eq(3, fn.tabpagewinnr(2))
943+
944+
-- ...but not if it's non-current in that tabpage.
945+
api.nvim_tabpage_set_win(tp, split_win)
946+
eq({ 0, 0 }, fn.win_id2tabwin(win))
947+
eq(0, fn.getwininfo(win)[1].winnr)
948+
eq(0, fn.win_getid(3, 2))
949+
eq(2, fn.tabpagewinnr(2, '$'))
950+
eq(1, fn.tabpagewinnr(2))
910951
end)
911952

912953
it('no crash for unallocated relative window grid', function()

0 commit comments

Comments
 (0)