changeset 15977:7fbdceabad64 v8.1.0994

patch 8.1.0994: relative cursor position is not calculated correctly commit https://github.com/vim/vim/commit/8fcb60f961bdd134599fb016c6537fd496e800f5 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Mon, 04 Mar 2019 13:30:08 +0100
parents 50aa746472f6
children c036f95274c6
files runtime/doc/eval.txt src/evalfunc.c src/testdir/test_window_cmd.vim src/version.c src/window.c
diffstat 5 files changed, 144 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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
--- 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
--- 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,
--- 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)