Skip to content

Commit 46ad288

Browse files
committed
patch 8.1.1140: not easy to find out what neighbors a window has
Problem: Not easy to find out what neighbors a window has. Solution: Add more arguments to winnr(). (Yegappan Lakshmanan, closes #3993)
1 parent 9845f36 commit 46ad288

File tree

6 files changed

+146
-26
lines changed

6 files changed

+146
-26
lines changed

runtime/doc/eval.txt

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10198,17 +10198,30 @@ winline() The result is a Number, which is the screen line of the cursor
1019810198
*winnr()*
1019910199
winnr([{arg}]) The result is a Number, which is the number of the current
1020010200
window. The top window has number 1.
10201-
When the optional argument is "$", the number of the
10202-
last window is returned (the window count). >
10203-
let window_count = winnr('$')
10204-
< When the optional argument is "#", the number of the last
10205-
accessed window is returned (where |CTRL-W_p| goes to).
10206-
If there is no previous window or it is in another tab page 0
10207-
is returned.
10201+
10202+
The optional argument {arg} supports the following values:
10203+
$ the number of the last window (the window
10204+
count).
10205+
# the number of the last accessed window (where
10206+
|CTRL-W_p| goes to). If there is no previous
10207+
window or it is in another tab page 0 is
10208+
returned.
10209+
{N}j the number of the Nth window below the
10210+
current window (where |CTRL-W_j| goes to).
10211+
{N}k the number of the Nth window above the current
10212+
window (where |CTRL-W_k| goes to).
10213+
{N}h the number of the Nth window left of the
10214+
current window (where |CTRL-W_h| goes to).
10215+
{N}l the number of the Nth window right of the
10216+
current window (where |CTRL-W_l| goes to).
1020810217
The number can be used with |CTRL-W_w| and ":wincmd w"
1020910218
|:wincmd|.
1021010219
Also see |tabpagewinnr()| and |win_getid()|.
10211-
10220+
Examples: >
10221+
let window_count = winnr('$')
10222+
let prev_window = winnr('#')
10223+
let wnum = winnr('3k')
10224+
<
1021210225
*winrestcmd()*
1021310226
winrestcmd() Returns a sequence of |:resize| commands that should restore
1021410227
the current window sizes. Only works properly when no windows

src/evalfunc.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13982,6 +13982,8 @@ get_winnr(tabpage_T *tp, typval_T *argvar)
1398213982
twin = (tp == curtab) ? curwin : tp->tp_curwin;
1398313983
if (argvar->v_type != VAR_UNKNOWN)
1398413984
{
13985+
int invalid_arg = FALSE;
13986+
1398513987
arg = tv_get_string_chk(argvar);
1398613988
if (arg == NULL)
1398713989
nr = 0; /* type error; errmsg already given */
@@ -13994,6 +13996,32 @@ get_winnr(tabpage_T *tp, typval_T *argvar)
1399413996
nr = 0;
1399513997
}
1399613998
else
13999+
{
14000+
long count;
14001+
char_u *endp;
14002+
14003+
// Extract the window count (if specified). e.g. winnr('3j')
14004+
count = strtol((char *)arg, (char **)&endp, 10);
14005+
if (count <= 0)
14006+
count = 1; // if count is not specified, default to 1
14007+
if (endp != NULL && *endp != '\0')
14008+
{
14009+
if (STRCMP(endp, "j") == 0)
14010+
twin = win_vert_neighbor(tp, twin, FALSE, count);
14011+
else if (STRCMP(endp, "k") == 0)
14012+
twin = win_vert_neighbor(tp, twin, TRUE, count);
14013+
else if (STRCMP(endp, "h") == 0)
14014+
twin = win_horz_neighbor(tp, twin, TRUE, count);
14015+
else if (STRCMP(endp, "l") == 0)
14016+
twin = win_horz_neighbor(tp, twin, FALSE, count);
14017+
else
14018+
invalid_arg = TRUE;
14019+
}
14020+
else
14021+
invalid_arg = TRUE;
14022+
}
14023+
14024+
if (invalid_arg)
1399714025
{
1399814026
semsg(_(e_invexpr2), arg);
1399914027
nr = 0;

src/proto/window.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ void tabpage_move(int nr);
3737
void win_goto(win_T *wp);
3838
win_T *win_find_nr(int winnr);
3939
tabpage_T *win_find_tabpage(win_T *win);
40+
win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count);
41+
win_T *win_horz_neighbor(tabpage_T *tp, win_T * wp, int left, long count);
4042
void win_enter(win_T *wp, int undo_sync);
4143
win_T *buf_jump_open_win(buf_T *buf);
4244
win_T *buf_jump_open_tab(buf_T *buf);

src/testdir/test_window_cmd.vim

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,4 +743,49 @@ func Test_relative_cursor_second_line_after_resize()
743743
let &so = so_save
744744
endfunc
745745

746+
" Tests for the winnr() function
747+
func Test_winnr()
748+
only | tabonly
749+
call assert_equal(1, winnr('j'))
750+
call assert_equal(1, winnr('k'))
751+
call assert_equal(1, winnr('h'))
752+
call assert_equal(1, winnr('l'))
753+
754+
" create a set of horizontally and vertically split windows
755+
leftabove new | wincmd p
756+
leftabove new | wincmd p
757+
rightbelow new | wincmd p
758+
rightbelow new | wincmd p
759+
leftabove vnew | wincmd p
760+
leftabove vnew | wincmd p
761+
rightbelow vnew | wincmd p
762+
rightbelow vnew | wincmd p
763+
764+
call assert_equal(8, winnr('j'))
765+
call assert_equal(2, winnr('k'))
766+
call assert_equal(4, winnr('h'))
767+
call assert_equal(6, winnr('l'))
768+
call assert_equal(9, winnr('2j'))
769+
call assert_equal(1, winnr('2k'))
770+
call assert_equal(3, winnr('2h'))
771+
call assert_equal(7, winnr('2l'))
772+
773+
" Error cases
774+
call assert_fails("echo winnr('0.2k')", 'E15:')
775+
call assert_equal(2, winnr('-2k'))
776+
call assert_fails("echo winnr('-2xj')", 'E15:')
777+
call assert_fails("echo winnr('j2j')", 'E15:')
778+
call assert_fails("echo winnr('ll')", 'E15:')
779+
call assert_fails("echo winnr('5')", 'E15:')
780+
call assert_equal(4, winnr('0h'))
781+
782+
tabnew
783+
call assert_equal(8, tabpagewinnr(1, 'j'))
784+
call assert_equal(2, tabpagewinnr(1, 'k'))
785+
call assert_equal(4, tabpagewinnr(1, 'h'))
786+
call assert_equal(6, tabpagewinnr(1, 'l'))
787+
788+
only | tabonly
789+
endfunc
790+
746791
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ static char *(features[]) =
771771

772772
static int included_patches[] =
773773
{ /* Add new patch number below this line */
774+
/**/
775+
1140,
774776
/**/
775777
1139,
776778
/**/

src/window.c

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4218,18 +4218,19 @@ win_find_tabpage(win_T *win)
42184218
#endif
42194219

42204220
/*
4221-
* Move to window above or below "count" times.
4221+
* Get the above or below neighbor window of the specified window.
4222+
* up - TRUE for the above neighbor
4223+
* count - nth neighbor window
4224+
* Returns the specified window if the neighbor is not found.
42224225
*/
4223-
static void
4224-
win_goto_ver(
4225-
int up, /* TRUE to go to win above */
4226-
long count)
4226+
win_T *
4227+
win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count)
42274228
{
42284229
frame_T *fr;
42294230
frame_T *nfr;
42304231
frame_T *foundfr;
42314232

4232-
foundfr = curwin->w_frame;
4233+
foundfr = wp->w_frame;
42334234
while (count--)
42344235
{
42354236
/*
@@ -4239,7 +4240,7 @@ win_goto_ver(
42394240
fr = foundfr;
42404241
for (;;)
42414242
{
4242-
if (fr == topframe)
4243+
if (fr == tp->tp_topframe)
42434244
goto end;
42444245
if (up)
42454246
nfr = fr->fr_prev;
@@ -4266,7 +4267,7 @@ win_goto_ver(
42664267
/* Find the frame at the cursor row. */
42674268
while (fr->fr_next != NULL
42684269
&& frame2win(fr)->w_wincol + fr->fr_width
4269-
<= curwin->w_wincol + curwin->w_wcol)
4270+
<= wp->w_wincol + wp->w_wcol)
42704271
fr = fr->fr_next;
42714272
}
42724273
if (nfr->fr_layout == FR_COL && up)
@@ -4276,23 +4277,38 @@ win_goto_ver(
42764277
}
42774278
}
42784279
end:
4279-
if (foundfr != NULL)
4280-
win_goto(foundfr->fr_win);
4280+
return foundfr != NULL ? foundfr->fr_win : NULL;
42814281
}
42824282

42834283
/*
4284-
* Move to left or right window.
4284+
* Move to window above or below "count" times.
42854285
*/
42864286
static void
4287-
win_goto_hor(
4288-
int left, /* TRUE to go to left win */
4287+
win_goto_ver(
4288+
int up, // TRUE to go to win above
42894289
long count)
4290+
{
4291+
win_T *win;
4292+
4293+
win = win_vert_neighbor(curtab, curwin, up, count);
4294+
if (win != NULL)
4295+
win_goto(win);
4296+
}
4297+
4298+
/*
4299+
* Get the left or right neighbor window of the specified window.
4300+
* left - TRUE for the left neighbor
4301+
* count - nth neighbor window
4302+
* Returns the specified window if the neighbor is not found.
4303+
*/
4304+
win_T *
4305+
win_horz_neighbor(tabpage_T *tp, win_T * wp, int left, long count)
42904306
{
42914307
frame_T *fr;
42924308
frame_T *nfr;
42934309
frame_T *foundfr;
42944310

4295-
foundfr = curwin->w_frame;
4311+
foundfr = wp->w_frame;
42964312
while (count--)
42974313
{
42984314
/*
@@ -4302,7 +4318,7 @@ win_goto_hor(
43024318
fr = foundfr;
43034319
for (;;)
43044320
{
4305-
if (fr == topframe)
4321+
if (fr == tp->tp_topframe)
43064322
goto end;
43074323
if (left)
43084324
nfr = fr->fr_prev;
@@ -4329,7 +4345,7 @@ win_goto_hor(
43294345
/* Find the frame at the cursor row. */
43304346
while (fr->fr_next != NULL
43314347
&& frame2win(fr)->w_winrow + fr->fr_height
4332-
<= curwin->w_winrow + curwin->w_wrow)
4348+
<= wp->w_winrow + wp->w_wrow)
43334349
fr = fr->fr_next;
43344350
}
43354351
if (nfr->fr_layout == FR_ROW && left)
@@ -4339,8 +4355,22 @@ win_goto_hor(
43394355
}
43404356
}
43414357
end:
4342-
if (foundfr != NULL)
4343-
win_goto(foundfr->fr_win);
4358+
return foundfr != NULL ? foundfr->fr_win : NULL;
4359+
}
4360+
4361+
/*
4362+
* Move to left or right window.
4363+
*/
4364+
static void
4365+
win_goto_hor(
4366+
int left, // TRUE to go to left win
4367+
long count)
4368+
{
4369+
win_T *win;
4370+
4371+
win = win_horz_neighbor(curtab, curwin, left, count);
4372+
if (win != NULL)
4373+
win_goto(win);
43444374
}
43454375

43464376
/*

0 commit comments

Comments
 (0)