Skip to content

Commit 8fcb60f

Browse files
committed
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.
1 parent 772153f commit 8fcb60f

5 files changed

Lines changed: 144 additions & 9 deletions

File tree

runtime/doc/eval.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5228,6 +5228,7 @@ getwininfo([{winid}]) *getwininfo()*
52285228
tab pages is returned.
52295229

52305230
Each List item is a Dictionary with the following entries:
5231+
botline last displayed buffer line
52315232
bufnr number of buffer in the window
52325233
height window height (excluding winbar)
52335234
loclist 1 if showing a location list
@@ -5237,6 +5238,7 @@ getwininfo([{winid}]) *getwininfo()*
52375238
terminal 1 if a terminal window
52385239
{only with the +terminal feature}
52395240
tabnr tab page number
5241+
topline first displayed buffer line
52405242
variables a reference to the dictionary with
52415243
window-local variables
52425244
width window width

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5762,6 +5762,8 @@ get_win_info(win_T *wp, short tpnr, short winnr)
57625762
dict_add_number(dict, "winid", wp->w_id);
57635763
dict_add_number(dict, "height", wp->w_height);
57645764
dict_add_number(dict, "winrow", wp->w_winrow + 1);
5765+
dict_add_number(dict, "topline", wp->w_topline);
5766+
dict_add_number(dict, "botline", wp->w_botline - 1);
57655767
#ifdef FEAT_MENU
57665768
dict_add_number(dict, "winbar", wp->w_winbar_height);
57675769
#endif

src/testdir/test_window_cmd.vim

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,4 +615,132 @@ func Test_window_prevwin()
615615
delfunc Fun_RenewFile
616616
endfunc
617617

618+
func Test_relative_cursor_position_in_one_line_window()
619+
new
620+
only
621+
call setline(1, range(1, 10000))
622+
normal 50%
623+
let lnum = getcurpos()[1]
624+
split
625+
split
626+
" make third window take as many lines as possible, other windows will
627+
" become one line
628+
3wincmd w
629+
for i in range(1, &lines - 6)
630+
wincmd +
631+
redraw!
632+
endfor
633+
634+
" first and second window should show cursor line
635+
let wininfo = getwininfo()
636+
call assert_equal(lnum, wininfo[0].topline)
637+
call assert_equal(lnum, wininfo[1].topline)
638+
639+
only!
640+
bwipe!
641+
endfunc
642+
643+
func Test_relative_cursor_position_after_move_and_resize()
644+
let so_save = &so
645+
set so=0
646+
enew
647+
call setline(1, range(1, 10000))
648+
normal 50%
649+
split
650+
1wincmd w
651+
" Move cursor to first line in window
652+
normal H
653+
redraw!
654+
" Reduce window height to two lines
655+
let height = winheight(0)
656+
while winheight(0) > 2
657+
wincmd -
658+
redraw!
659+
endwhile
660+
" move cursor to second/last line in window
661+
normal j
662+
" restore previous height
663+
while winheight(0) < height
664+
wincmd +
665+
redraw!
666+
endwhile
667+
" make window two lines again
668+
while winheight(0) > 2
669+
wincmd -
670+
redraw!
671+
endwhile
672+
673+
" cursor should be at bottom line
674+
let info = getwininfo(win_getid())[0]
675+
call assert_equal(info.topline + 1, getcurpos()[1])
676+
677+
only!
678+
bwipe!
679+
let &so = so_save
680+
endfunc
681+
682+
func Test_relative_cursor_position_after_resize()
683+
let so_save = &so
684+
set so=0
685+
enew
686+
call setline(1, range(1, 10000))
687+
normal 50%
688+
split
689+
1wincmd w
690+
let winid1 = win_getid()
691+
let info = getwininfo(winid1)[0]
692+
" Move cursor to second line in window
693+
exe "normal " . (info.topline + 1) . "G"
694+
redraw!
695+
let lnum = getcurpos()[1]
696+
697+
" Make the window only two lines high, cursor should end up in top line
698+
2wincmd w
699+
exe (info.height - 2) . "wincmd +"
700+
redraw!
701+
let info = getwininfo(winid1)[0]
702+
call assert_equal(lnum, info.topline)
703+
704+
only!
705+
bwipe!
706+
let &so = so_save
707+
endfunc
708+
709+
func Test_relative_cursor_second_line_after_resize()
710+
let so_save = &so
711+
set so=0
712+
enew
713+
call setline(1, range(1, 10000))
714+
normal 50%
715+
split
716+
1wincmd w
717+
let winid1 = win_getid()
718+
let info = getwininfo(winid1)[0]
719+
720+
" Make the window only two lines high
721+
2wincmd _
722+
723+
" Move cursor to second line in window
724+
normal H
725+
normal j
726+
727+
" Make window size bigger, then back to 2 lines
728+
for i in range(1, 10)
729+
wincmd +
730+
redraw!
731+
endfor
732+
for i in range(1, 10)
733+
wincmd -
734+
redraw!
735+
endfor
736+
737+
" cursor should end up in bottom line
738+
let info = getwininfo(winid1)[0]
739+
call assert_equal(info.topline + 1, getcurpos()[1])
740+
741+
only!
742+
bwipe!
743+
let &so = so_save
744+
endfunc
745+
618746
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

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

780780
static int included_patches[] =
781781
{ /* Add new patch number below this line */
782+
/**/
783+
994,
782784
/**/
783785
993,
784786
/**/

src/window.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5719,8 +5719,11 @@ win_drag_vsep_line(win_T *dragwin, int offset)
57195719
set_fraction(win_T *wp)
57205720
{
57215721
if (wp->w_height > 1)
5722+
// When cursor is in the first line the percentage is computed as if
5723+
// it's halfway that line. Thus with two lines it is 25%, with three
5724+
// lines 17%, etc. Similarly for the last line: 75%, 83%, etc.
57225725
wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
5723-
+ wp->w_height / 2) / (long)wp->w_height;
5726+
+ FRACTION_MULT / 2) / (long)wp->w_height;
57245727
}
57255728

57265729
/*
@@ -5770,8 +5773,8 @@ scroll_to_fraction(win_T *wp, int prev_height)
57705773
int sline, line_size;
57715774
int height = wp->w_height;
57725775

5773-
/* Don't change w_topline when height is zero. Don't set w_topline when
5774-
* 'scrollbind' is set and this isn't the current window. */
5776+
// Don't change w_topline when height is zero. Don't set w_topline when
5777+
// 'scrollbind' is set and this isn't the current window.
57755778
if (height > 0 && (!wp->w_p_scb || wp == curwin))
57765779
{
57775780
/*
@@ -5781,8 +5784,8 @@ scroll_to_fraction(win_T *wp, int prev_height)
57815784
lnum = wp->w_cursor.lnum;
57825785
if (lnum < 1) /* can happen when starting up */
57835786
lnum = 1;
5784-
wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L
5785-
+ FRACTION_MULT / 2) / FRACTION_MULT;
5787+
wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L)
5788+
/ FRACTION_MULT;
57865789
line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
57875790
sline = wp->w_wrow - line_size;
57885791

@@ -5818,7 +5821,6 @@ scroll_to_fraction(win_T *wp, int prev_height)
58185821
--wp->w_wrow;
58195822
}
58205823
}
5821-
set_topline(wp, lnum);
58225824
}
58235825
else if (sline > 0)
58245826
{
@@ -5859,13 +5861,12 @@ scroll_to_fraction(win_T *wp, int prev_height)
58595861
}
58605862
else if (sline > 0)
58615863
{
5862-
/* First line of file reached, use that as topline. */
5864+
// First line of file reached, use that as topline.
58635865
lnum = 1;
58645866
wp->w_wrow -= sline;
58655867
}
5866-
5867-
set_topline(wp, lnum);
58685868
}
5869+
set_topline(wp, lnum);
58695870
}
58705871

58715872
if (wp == curwin)

0 commit comments

Comments
 (0)