# HG changeset patch # User Bram Moolenaar # Date 1554747305 -7200 # Node ID 243cdc183ec947a2143afd8a3125e182d285f94f # Parent 749a7c03de8d86f69f459d04a009f7a500d5328a patch 8.1.1140: not easy to find out what neighbors a window has commit https://github.com/vim/vim/commit/46ad288b9b2a6eb0430cf802ff5ce68a58629897 Author: Bram Moolenaar Date: Mon Apr 8 20:01:47 2019 +0200 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 https://github.com/vim/vim/issues/3993) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -10198,17 +10198,30 @@ winline() The result is a Number, which *winnr()* winnr([{arg}]) The result is a Number, which is the number of the current window. The top window has number 1. - When the optional argument is "$", the number of the - last window is returned (the window count). > - let window_count = winnr('$') -< When the optional argument is "#", the number of the last - accessed window is returned (where |CTRL-W_p| goes to). - If there is no previous window or it is in another tab page 0 - is returned. + + The optional argument {arg} supports the following values: + $ the number of the last window (the window + count). + # the number of the last accessed window (where + |CTRL-W_p| goes to). If there is no previous + window or it is in another tab page 0 is + returned. + {N}j the number of the Nth window below the + current window (where |CTRL-W_j| goes to). + {N}k the number of the Nth window above the current + window (where |CTRL-W_k| goes to). + {N}h the number of the Nth window left of the + current window (where |CTRL-W_h| goes to). + {N}l the number of the Nth window right of the + current window (where |CTRL-W_l| goes to). The number can be used with |CTRL-W_w| and ":wincmd w" |:wincmd|. Also see |tabpagewinnr()| and |win_getid()|. - + Examples: > + let window_count = winnr('$') + let prev_window = winnr('#') + let wnum = winnr('3k') +< *winrestcmd()* winrestcmd() Returns a sequence of |:resize| commands that should restore the current window sizes. Only works properly when no windows diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -13982,6 +13982,8 @@ get_winnr(tabpage_T *tp, typval_T *argva twin = (tp == curtab) ? curwin : tp->tp_curwin; if (argvar->v_type != VAR_UNKNOWN) { + int invalid_arg = FALSE; + arg = tv_get_string_chk(argvar); if (arg == NULL) nr = 0; /* type error; errmsg already given */ @@ -13995,6 +13997,32 @@ get_winnr(tabpage_T *tp, typval_T *argva } else { + long count; + char_u *endp; + + // Extract the window count (if specified). e.g. winnr('3j') + count = strtol((char *)arg, (char **)&endp, 10); + if (count <= 0) + count = 1; // if count is not specified, default to 1 + if (endp != NULL && *endp != '\0') + { + if (STRCMP(endp, "j") == 0) + twin = win_vert_neighbor(tp, twin, FALSE, count); + else if (STRCMP(endp, "k") == 0) + twin = win_vert_neighbor(tp, twin, TRUE, count); + else if (STRCMP(endp, "h") == 0) + twin = win_horz_neighbor(tp, twin, TRUE, count); + else if (STRCMP(endp, "l") == 0) + twin = win_horz_neighbor(tp, twin, FALSE, count); + else + invalid_arg = TRUE; + } + else + invalid_arg = TRUE; + } + + if (invalid_arg) + { semsg(_(e_invexpr2), arg); nr = 0; } diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -37,6 +37,8 @@ void tabpage_move(int nr); void win_goto(win_T *wp); win_T *win_find_nr(int winnr); tabpage_T *win_find_tabpage(win_T *win); +win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count); +win_T *win_horz_neighbor(tabpage_T *tp, win_T * wp, int left, long count); void win_enter(win_T *wp, int undo_sync); win_T *buf_jump_open_win(buf_T *buf); win_T *buf_jump_open_tab(buf_T *buf); diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -743,4 +743,49 @@ func Test_relative_cursor_second_line_af let &so = so_save endfunc +" Tests for the winnr() function +func Test_winnr() + only | tabonly + call assert_equal(1, winnr('j')) + call assert_equal(1, winnr('k')) + call assert_equal(1, winnr('h')) + call assert_equal(1, winnr('l')) + + " create a set of horizontally and vertically split windows + leftabove new | wincmd p + leftabove new | wincmd p + rightbelow new | wincmd p + rightbelow new | wincmd p + leftabove vnew | wincmd p + leftabove vnew | wincmd p + rightbelow vnew | wincmd p + rightbelow vnew | wincmd p + + call assert_equal(8, winnr('j')) + call assert_equal(2, winnr('k')) + call assert_equal(4, winnr('h')) + call assert_equal(6, winnr('l')) + call assert_equal(9, winnr('2j')) + call assert_equal(1, winnr('2k')) + call assert_equal(3, winnr('2h')) + call assert_equal(7, winnr('2l')) + + " Error cases + call assert_fails("echo winnr('0.2k')", 'E15:') + call assert_equal(2, winnr('-2k')) + call assert_fails("echo winnr('-2xj')", 'E15:') + call assert_fails("echo winnr('j2j')", 'E15:') + call assert_fails("echo winnr('ll')", 'E15:') + call assert_fails("echo winnr('5')", 'E15:') + call assert_equal(4, winnr('0h')) + + tabnew + call assert_equal(8, tabpagewinnr(1, 'j')) + call assert_equal(2, tabpagewinnr(1, 'k')) + call assert_equal(4, tabpagewinnr(1, 'h')) + call assert_equal(6, tabpagewinnr(1, 'l')) + + only | tabonly +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -772,6 +772,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1140, +/**/ 1139, /**/ 1138, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -4218,18 +4218,19 @@ win_find_tabpage(win_T *win) #endif /* - * Move to window above or below "count" times. + * Get the above or below neighbor window of the specified window. + * up - TRUE for the above neighbor + * count - nth neighbor window + * Returns the specified window if the neighbor is not found. */ - static void -win_goto_ver( - int up, /* TRUE to go to win above */ - long count) + win_T * +win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count) { frame_T *fr; frame_T *nfr; frame_T *foundfr; - foundfr = curwin->w_frame; + foundfr = wp->w_frame; while (count--) { /* @@ -4239,7 +4240,7 @@ win_goto_ver( fr = foundfr; for (;;) { - if (fr == topframe) + if (fr == tp->tp_topframe) goto end; if (up) nfr = fr->fr_prev; @@ -4266,7 +4267,7 @@ win_goto_ver( /* Find the frame at the cursor row. */ while (fr->fr_next != NULL && frame2win(fr)->w_wincol + fr->fr_width - <= curwin->w_wincol + curwin->w_wcol) + <= wp->w_wincol + wp->w_wcol) fr = fr->fr_next; } if (nfr->fr_layout == FR_COL && up) @@ -4276,23 +4277,38 @@ win_goto_ver( } } end: - if (foundfr != NULL) - win_goto(foundfr->fr_win); + return foundfr != NULL ? foundfr->fr_win : NULL; } /* - * Move to left or right window. + * Move to window above or below "count" times. */ static void -win_goto_hor( - int left, /* TRUE to go to left win */ +win_goto_ver( + int up, // TRUE to go to win above long count) { + win_T *win; + + win = win_vert_neighbor(curtab, curwin, up, count); + if (win != NULL) + win_goto(win); +} + +/* + * Get the left or right neighbor window of the specified window. + * left - TRUE for the left neighbor + * count - nth neighbor window + * Returns the specified window if the neighbor is not found. + */ + win_T * +win_horz_neighbor(tabpage_T *tp, win_T * wp, int left, long count) +{ frame_T *fr; frame_T *nfr; frame_T *foundfr; - foundfr = curwin->w_frame; + foundfr = wp->w_frame; while (count--) { /* @@ -4302,7 +4318,7 @@ win_goto_hor( fr = foundfr; for (;;) { - if (fr == topframe) + if (fr == tp->tp_topframe) goto end; if (left) nfr = fr->fr_prev; @@ -4329,7 +4345,7 @@ win_goto_hor( /* Find the frame at the cursor row. */ while (fr->fr_next != NULL && frame2win(fr)->w_winrow + fr->fr_height - <= curwin->w_winrow + curwin->w_wrow) + <= wp->w_winrow + wp->w_wrow) fr = fr->fr_next; } if (nfr->fr_layout == FR_ROW && left) @@ -4339,8 +4355,22 @@ win_goto_hor( } } end: - if (foundfr != NULL) - win_goto(foundfr->fr_win); + return foundfr != NULL ? foundfr->fr_win : NULL; +} + +/* + * Move to left or right window. + */ + static void +win_goto_hor( + int left, // TRUE to go to left win + long count) +{ + win_T *win; + + win = win_horz_neighbor(curtab, curwin, left, count); + if (win != NULL) + win_goto(win); } /*