# HG changeset patch # User Bram Moolenaar # Date 1551702608 -3600 # Node ID 7fbdceabad64e14dc050dad53b2c9fbd47d077cc # Parent 50aa746472f64a0bc66fcd744dc3124a211fe400 patch 8.1.0994: relative cursor position is not calculated correctly commit https://github.com/vim/vim/commit/8fcb60f961bdd134599fb016c6537fd496e800f5 Author: Bram Moolenaar Date: Mon Mar 4 13:18:30 2019 +0100 patch 8.1.0994: relative cursor position is not calculated correctly Problem: Relative cursor position is not calculated correctly. Solution: Always set topline, also when window is one line only. (Robert Webb) Add more info to getwininfo() for testing. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -5228,6 +5228,7 @@ getwininfo([{winid}]) *getwininfo()* tab pages is returned. Each List item is a Dictionary with the following entries: + botline last displayed buffer line bufnr number of buffer in the window height window height (excluding winbar) loclist 1 if showing a location list @@ -5237,6 +5238,7 @@ getwininfo([{winid}]) *getwininfo()* terminal 1 if a terminal window {only with the +terminal feature} tabnr tab page number + topline first displayed buffer line variables a reference to the dictionary with window-local variables width window width diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5762,6 +5762,8 @@ get_win_info(win_T *wp, short tpnr, shor dict_add_number(dict, "winid", wp->w_id); dict_add_number(dict, "height", wp->w_height); dict_add_number(dict, "winrow", wp->w_winrow + 1); + dict_add_number(dict, "topline", wp->w_topline); + dict_add_number(dict, "botline", wp->w_botline - 1); #ifdef FEAT_MENU dict_add_number(dict, "winbar", wp->w_winbar_height); #endif 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 @@ -615,4 +615,132 @@ func Test_window_prevwin() delfunc Fun_RenewFile endfunc +func Test_relative_cursor_position_in_one_line_window() + new + only + call setline(1, range(1, 10000)) + normal 50% + let lnum = getcurpos()[1] + split + split + " make third window take as many lines as possible, other windows will + " become one line + 3wincmd w + for i in range(1, &lines - 6) + wincmd + + redraw! + endfor + + " first and second window should show cursor line + let wininfo = getwininfo() + call assert_equal(lnum, wininfo[0].topline) + call assert_equal(lnum, wininfo[1].topline) + + only! + bwipe! +endfunc + +func Test_relative_cursor_position_after_move_and_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + " Move cursor to first line in window + normal H + redraw! + " Reduce window height to two lines + let height = winheight(0) + while winheight(0) > 2 + wincmd - + redraw! + endwhile + " move cursor to second/last line in window + normal j + " restore previous height + while winheight(0) < height + wincmd + + redraw! + endwhile + " make window two lines again + while winheight(0) > 2 + wincmd - + redraw! + endwhile + + " cursor should be at bottom line + let info = getwininfo(win_getid())[0] + call assert_equal(info.topline + 1, getcurpos()[1]) + + only! + bwipe! + let &so = so_save +endfunc + +func Test_relative_cursor_position_after_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + let winid1 = win_getid() + let info = getwininfo(winid1)[0] + " Move cursor to second line in window + exe "normal " . (info.topline + 1) . "G" + redraw! + let lnum = getcurpos()[1] + + " Make the window only two lines high, cursor should end up in top line + 2wincmd w + exe (info.height - 2) . "wincmd +" + redraw! + let info = getwininfo(winid1)[0] + call assert_equal(lnum, info.topline) + + only! + bwipe! + let &so = so_save +endfunc + +func Test_relative_cursor_second_line_after_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + let winid1 = win_getid() + let info = getwininfo(winid1)[0] + + " Make the window only two lines high + 2wincmd _ + + " Move cursor to second line in window + normal H + normal j + + " Make window size bigger, then back to 2 lines + for i in range(1, 10) + wincmd + + redraw! + endfor + for i in range(1, 10) + wincmd - + redraw! + endfor + + " cursor should end up in bottom line + let info = getwininfo(winid1)[0] + call assert_equal(info.topline + 1, getcurpos()[1]) + + only! + bwipe! + let &so = so_save +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 @@ -780,6 +780,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 994, +/**/ 993, /**/ 992, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -5719,8 +5719,11 @@ win_drag_vsep_line(win_T *dragwin, int o set_fraction(win_T *wp) { if (wp->w_height > 1) + // When cursor is in the first line the percentage is computed as if + // it's halfway that line. Thus with two lines it is 25%, with three + // lines 17%, etc. Similarly for the last line: 75%, 83%, etc. wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT - + wp->w_height / 2) / (long)wp->w_height; + + FRACTION_MULT / 2) / (long)wp->w_height; } /* @@ -5770,8 +5773,8 @@ scroll_to_fraction(win_T *wp, int prev_h int sline, line_size; int height = wp->w_height; - /* Don't change w_topline when height is zero. Don't set w_topline when - * 'scrollbind' is set and this isn't the current window. */ + // Don't change w_topline when height is zero. Don't set w_topline when + // 'scrollbind' is set and this isn't the current window. if (height > 0 && (!wp->w_p_scb || wp == curwin)) { /* @@ -5781,8 +5784,8 @@ scroll_to_fraction(win_T *wp, int prev_h lnum = wp->w_cursor.lnum; if (lnum < 1) /* can happen when starting up */ lnum = 1; - wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L - + FRACTION_MULT / 2) / FRACTION_MULT; + wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) + / FRACTION_MULT; line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1; sline = wp->w_wrow - line_size; @@ -5818,7 +5821,6 @@ scroll_to_fraction(win_T *wp, int prev_h --wp->w_wrow; } } - set_topline(wp, lnum); } else if (sline > 0) { @@ -5859,13 +5861,12 @@ scroll_to_fraction(win_T *wp, int prev_h } else if (sline > 0) { - /* First line of file reached, use that as topline. */ + // First line of file reached, use that as topline. lnum = 1; wp->w_wrow -= sline; } - - set_topline(wp, lnum); } + set_topline(wp, lnum); } if (wp == curwin)