vim-patch:8.1.1140: not easy to find out what neighbors a window has (#9873)

Problem:    Not easy to find out what neighbors a window has.
Solution:   Add more arguments to winnr(). (Yegappan Lakshmanan)

46ad288b9b
This commit is contained in:
Marco Hinz
2019-04-10 10:16:32 +02:00
committed by GitHub
parent ddd0eb6f51
commit 21b108fe44
4 changed files with 162 additions and 47 deletions

View File

@@ -8405,17 +8405,30 @@ winline() The result is a Number, which is the screen line of the cursor
*winnr()* *winnr()*
winnr([{arg}]) The result is a Number, which is the number of the current winnr([{arg}]) The result is a Number, which is the number of the current
window. The top window has number 1. window. The top window has number 1.
When the optional argument is "$", the number of the
last window is returned (the window count). > The optional argument {arg} supports the following values:
let window_count = winnr('$') $ the number of the last window (the window
< When the optional argument is "#", the number of the last count).
accessed window is returned (where |CTRL-W_p| goes to). # the number of the last accessed window (where
If there is no previous window or it is in another tab page 0 |CTRL-W_p| goes to). If there is no previous
is returned. 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" The number can be used with |CTRL-W_w| and ":wincmd w"
|:wincmd|. |:wincmd|.
Also see |tabpagewinnr()| and |win_getid()|. Also see |tabpagewinnr()| and |win_getid()|.
Examples: >
let window_count = winnr('$')
let prev_window = winnr('#')
let wnum = winnr('3k')
<
*winrestcmd()* *winrestcmd()*
winrestcmd() Returns a sequence of |:resize| commands that should restore winrestcmd() Returns a sequence of |:resize| commands that should restore
the current window sizes. Only works properly when no windows the current window sizes. Only works properly when no windows

View File

@@ -16755,6 +16755,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
twin = (tp == curtab) ? curwin : tp->tp_curwin; twin = (tp == curtab) ? curwin : tp->tp_curwin;
if (argvar->v_type != VAR_UNKNOWN) { if (argvar->v_type != VAR_UNKNOWN) {
bool invalid_arg = false;
const char *const arg = tv_get_string_chk(argvar); const char *const arg = tv_get_string_chk(argvar);
if (arg == NULL) { if (arg == NULL) {
nr = 0; // Type error; errmsg already given. nr = 0; // Type error; errmsg already given.
@@ -16766,6 +16767,31 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
nr = 0; nr = 0;
} }
} else { } else {
// Extract the window count (if specified). e.g. winnr('3j')
char_u *endp;
long count = strtol((char *)arg, (char **)&endp, 10);
if (count <= 0) {
// if count is not specified, default to 1
count = 1;
}
if (endp != NULL && *endp != '\0') {
if (strequal((char *)endp, "j")) {
twin = win_vert_neighbor(tp, twin, false, count);
} else if (strequal((char *)endp, "k")) {
twin = win_vert_neighbor(tp, twin, true, count);
} else if (strequal((char *)endp, "h")) {
twin = win_horz_neighbor(tp, twin, true, count);
} else if (strequal((char *)endp, "l")) {
twin = win_horz_neighbor(tp, twin, false, count);
} else {
invalid_arg = true;
}
} else {
invalid_arg = true;
}
}
if (invalid_arg) {
EMSG2(_(e_invexpr2), arg); EMSG2(_(e_invexpr2), arg);
nr = 0; nr = 0;
} }

View File

@@ -646,4 +646,49 @@ func Test_relative_cursor_second_line_after_resize()
let &so = so_save let &so = so_save
endfunc 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 " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -4019,24 +4019,25 @@ tabpage_T *win_find_tabpage(win_T *win)
return NULL; return NULL;
} }
/* /// Get the above or below neighbor window of the specified window.
* Move to window above or below "count" times. ///
*/ /// Returns the specified window if the neighbor is not found.
static void /// Returns the previous window if the specifiecied window is a floating window.
win_goto_ver ( ///
int up, /* TRUE to go to win above */ /// @param up true for the above neighbor
long count /// @param count nth neighbor window
) ///
/// @return found window
win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count)
{ {
frame_T *fr; frame_T *fr;
frame_T *nfr; frame_T *nfr;
frame_T *foundfr; frame_T *foundfr;
foundfr = curwin->w_frame; foundfr = wp->w_frame;
if (curwin->w_floating) { if (wp->w_floating) {
win_goto(prevwin); return prevwin;
return;
} }
while (count--) { while (count--) {
@@ -4046,14 +4047,17 @@ win_goto_ver (
*/ */
fr = foundfr; fr = foundfr;
for (;; ) { for (;; ) {
if (fr == topframe) if (fr == tp->tp_topframe) {
goto end; goto end;
if (up) }
if (up) {
nfr = fr->fr_prev; nfr = fr->fr_prev;
else } else {
nfr = fr->fr_next; nfr = fr->fr_next;
if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL) }
if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL) {
break; break;
}
fr = fr->fr_parent; fr = fr->fr_parent;
} }
@@ -4067,12 +4071,13 @@ win_goto_ver (
} }
fr = nfr->fr_child; fr = nfr->fr_child;
if (nfr->fr_layout == FR_ROW) { if (nfr->fr_layout == FR_ROW) {
/* Find the frame at the cursor row. */ // Find the frame at the cursor row.
while (fr->fr_next != NULL while (fr->fr_next != NULL
&& frame2win(fr)->w_wincol + fr->fr_width && frame2win(fr)->w_wincol + fr->fr_width
<= curwin->w_wincol + curwin->w_wcol) <= wp->w_wincol + wp->w_wcol) {
fr = fr->fr_next; fr = fr->fr_next;
} }
}
if (nfr->fr_layout == FR_COL && up) if (nfr->fr_layout == FR_COL && up)
while (fr->fr_next != NULL) while (fr->fr_next != NULL)
fr = fr->fr_next; fr = fr->fr_next;
@@ -4080,28 +4085,40 @@ win_goto_ver (
} }
} }
end: end:
if (foundfr != NULL) return foundfr != NULL ? foundfr->fr_win : NULL;
win_goto(foundfr->fr_win);
} }
/* /// Move to window above or below "count" times.
* Move to left or right window. ///
*/ /// @param up true to go to win above
static void /// @param count go count times into direction
win_goto_hor ( static void win_goto_ver(bool up, long count)
int left, /* TRUE to go to left win */ {
long count win_T *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.
///
/// Returns the specified window if the neighbor is not found.
/// Returns the previous window if the specifiecied window is a floating window.
///
/// @param left true for the left neighbor
/// @param count nth neighbor window
///
/// @return found window
win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count)
{ {
frame_T *fr; frame_T *fr;
frame_T *nfr; frame_T *nfr;
frame_T *foundfr; frame_T *foundfr;
foundfr = curwin->w_frame; foundfr = wp->w_frame;
if (curwin->w_floating) { if (wp->w_floating) {
win_goto(prevwin); return prevwin;
return;
} }
while (count--) { while (count--) {
@@ -4111,14 +4128,17 @@ win_goto_hor (
*/ */
fr = foundfr; fr = foundfr;
for (;; ) { for (;; ) {
if (fr == topframe) if (fr == tp->tp_topframe) {
goto end; goto end;
if (left) }
if (left) {
nfr = fr->fr_prev; nfr = fr->fr_prev;
else } else {
nfr = fr->fr_next; nfr = fr->fr_next;
if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL) }
if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL) {
break; break;
}
fr = fr->fr_parent; fr = fr->fr_parent;
} }
@@ -4135,7 +4155,7 @@ win_goto_hor (
/* Find the frame at the cursor row. */ /* Find the frame at the cursor row. */
while (fr->fr_next != NULL while (fr->fr_next != NULL
&& frame2win(fr)->w_winrow + fr->fr_height && frame2win(fr)->w_winrow + fr->fr_height
<= curwin->w_winrow + curwin->w_wrow) <= wp->w_winrow + wp->w_wrow)
fr = fr->fr_next; fr = fr->fr_next;
} }
if (nfr->fr_layout == FR_ROW && left) if (nfr->fr_layout == FR_ROW && left)
@@ -4145,8 +4165,19 @@ win_goto_hor (
} }
} }
end: end:
if (foundfr != NULL) return foundfr != NULL ? foundfr->fr_win : NULL;
win_goto(foundfr->fr_win); }
/// Move to left or right window.
///
/// @param left true to go to left window
/// @param count go count times into direction
static void win_goto_hor(bool left, long count)
{
win_T *win = win_horz_neighbor(curtab, curwin, left, count);
if (win != NULL) {
win_goto(win);
}
} }
/* /*