Skip to content

Commit a109f39

Browse files
luukvbaalbrammool
authored andcommitted
patch 9.0.1599: Cursor not adjusted when 'splitkeep' is not "cursor"
Problem: Cursor not adjusted when near top or bottom of window and 'splitkeep' is not "cursor". Solution: Move boundary checks to outer cursor move functions, inner functions should only return valid cursor positions. (Luuk van Baal, closes #12480)
1 parent 47eec67 commit a109f39

6 files changed

Lines changed: 77 additions & 59 deletions

File tree

src/edit.c

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,17 +2755,12 @@ oneleft(void)
27552755
/*
27562756
* Move the cursor up "n" lines in window "wp".
27572757
* Takes care of closed folds.
2758-
* Returns the new cursor line or zero for failure.
27592758
*/
2760-
linenr_T
2759+
void
27612760
cursor_up_inner(win_T *wp, long n)
27622761
{
27632762
linenr_T lnum = wp->w_cursor.lnum;
27642763

2765-
// This fails if the cursor is already in the first line or the count is
2766-
// larger than the line number and '-' is in 'cpoptions'
2767-
if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
2768-
return 0;
27692764
if (n >= lnum)
27702765
lnum = 1;
27712766
else
@@ -2798,16 +2793,20 @@ cursor_up_inner(win_T *wp, long n)
27982793
lnum -= n;
27992794

28002795
wp->w_cursor.lnum = lnum;
2801-
return lnum;
28022796
}
28032797

28042798
int
28052799
cursor_up(
28062800
long n,
28072801
int upd_topline) // When TRUE: update topline
28082802
{
2809-
if (n > 0 && cursor_up_inner(curwin, n) == 0)
2803+
// This fails if the cursor is already in the first line or the count is
2804+
// larger than the line number and '-' is in 'cpoptions'
2805+
linenr_T lnum = curwin->w_cursor.lnum;
2806+
if (n > 0 && (lnum <= 1
2807+
|| (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL)))
28102808
return FAIL;
2809+
cursor_up_inner(curwin, n);
28112810

28122811
// try to advance to the column we want to be at
28132812
coladvance(curwin->w_curswant);
@@ -2821,23 +2820,13 @@ cursor_up(
28212820
/*
28222821
* Move the cursor down "n" lines in window "wp".
28232822
* Takes care of closed folds.
2824-
* Returns the new cursor line or zero for failure.
28252823
*/
2826-
linenr_T
2824+
void
28272825
cursor_down_inner(win_T *wp, long n)
28282826
{
28292827
linenr_T lnum = wp->w_cursor.lnum;
28302828
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
28312829

2832-
#ifdef FEAT_FOLDING
2833-
// Move to last line of fold, will fail if it's the end-of-file.
2834-
(void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
2835-
#endif
2836-
// This fails if the cursor is already in the last line or would move
2837-
// beyond the last line and '-' is in 'cpoptions'
2838-
if (lnum >= line_count
2839-
|| (lnum + n > line_count && vim_strchr(p_cpo, CPO_MINUS) != NULL))
2840-
return FAIL;
28412830
if (lnum + n >= line_count)
28422831
lnum = line_count;
28432832
else
@@ -2849,6 +2838,7 @@ cursor_down_inner(win_T *wp, long n)
28492838
// count each sequence of folded lines as one logical line
28502839
while (n--)
28512840
{
2841+
// Move to last line of fold, will fail if it's the end-of-file.
28522842
if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
28532843
lnum = last + 1;
28542844
else
@@ -2864,7 +2854,6 @@ cursor_down_inner(win_T *wp, long n)
28642854
lnum += n;
28652855

28662856
wp->w_cursor.lnum = lnum;
2867-
return lnum;
28682857
}
28692858

28702859
/*
@@ -2875,8 +2864,16 @@ cursor_down(
28752864
long n,
28762865
int upd_topline) // When TRUE: update topline
28772866
{
2878-
if (n > 0 && cursor_down_inner(curwin, n) == 0)
2867+
linenr_T lnum = curwin->w_cursor.lnum;
2868+
linenr_T line_count = curwin->w_buffer->b_ml.ml_line_count;
2869+
// This fails if the cursor is already in the last line or would move
2870+
// beyond the last line and '-' is in 'cpoptions'
2871+
if (n > 0
2872+
&& (lnum >= line_count
2873+
|| (lnum + n > line_count
2874+
&& vim_strchr(p_cpo, CPO_MINUS) != NULL)))
28792875
return FAIL;
2876+
cursor_down_inner(curwin, n);
28802877

28812878
// try to advance to the column we want to be at
28822879
coladvance(curwin->w_curswant);

src/normal.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,11 +2359,13 @@ nv_screengo(oparg_T *oap, int dir, long dist)
23592359
else
23602360
{
23612361
// to previous line
2362-
if (!cursor_up_inner(curwin, 1))
2362+
if (curwin->w_cursor.lnum <= 1)
23632363
{
23642364
retval = FAIL;
23652365
break;
23662366
}
2367+
cursor_up_inner(curwin, 1);
2368+
23672369
linelen = linetabsize_str(ml_get_curline());
23682370
if (linelen > width1)
23692371
curwin->w_curswant += (((linelen - width1 - 1) / width2)
@@ -2386,12 +2388,15 @@ nv_screengo(oparg_T *oap, int dir, long dist)
23862388
else
23872389
{
23882390
// to next line
2389-
if (!cursor_down_inner(curwin, 1))
2391+
if (curwin->w_cursor.lnum
2392+
>= curwin->w_buffer->b_ml.ml_line_count)
23902393
{
23912394
retval = FAIL;
23922395
break;
23932396
}
2397+
cursor_down_inner(curwin, 1);
23942398
curwin->w_curswant %= width2;
2399+
23952400
// Check if the cursor has moved below the number display
23962401
// when width1 < width2 (with cpoptions+=n). Subtract width2
23972402
// to get a negative value for w_curswant, which will get

src/proto/edit.pro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ char_u *add_char2buf(int c, char_u *s);
1919
void beginline(int flags);
2020
int oneright(void);
2121
int oneleft(void);
22-
linenr_T cursor_up_inner(win_T *wp, long n);
22+
void cursor_up_inner(win_T *wp, long n);
2323
int cursor_up(long n, int upd_topline);
24-
linenr_T cursor_down_inner(win_T *wp, long n);
24+
void cursor_down_inner(win_T *wp, long n);
2525
int cursor_down(long n, int upd_topline);
2626
int stuff_inserted(int c, long count, int no_esc);
2727
char_u *get_last_insert(void);

src/testdir/test_window_cmd.vim

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,9 +1819,20 @@ endfunc
18191819

18201820
func Test_splitkeep_misc()
18211821
set splitkeep=screen
1822-
set splitbelow
18231822

18241823
call setline(1, range(1, &lines))
1824+
" Cursor is adjusted to start and end of buffer
1825+
norm M
1826+
wincmd s
1827+
resize 1
1828+
call assert_equal(1, line('.'))
1829+
wincmd j
1830+
norm GM
1831+
resize 1
1832+
call assert_equal(&lines, line('.'))
1833+
only!
1834+
1835+
set splitbelow
18251836
norm Gzz
18261837
let top = line('w0')
18271838
" No scroll when aucmd_win is opened

src/version.c

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

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
1599,
698700
/**/
699701
1598,
700702
/**/

src/window.c

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ win_split_ins(
14061406
win_equal(wp, TRUE,
14071407
(flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
14081408
: dir == 'h' ? 'b' : 'v');
1409-
else if (*p_spk != 'c' && !is_aucmd_win(wp))
1409+
else if (!is_aucmd_win(wp))
14101410
win_fix_scroll(FALSE);
14111411

14121412
// Don't change the window height/width to 'winheight' / 'winwidth' if a
@@ -2012,7 +2012,7 @@ win_equal(
20122012
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
20132013
topframe, dir, 0, tabline_height(),
20142014
(int)Columns, topframe->fr_height);
2015-
if (*p_spk != 'c' && !is_aucmd_win(next_curwin))
2015+
if (!is_aucmd_win(next_curwin))
20162016
win_fix_scroll(TRUE);
20172017
}
20182018

@@ -2822,8 +2822,7 @@ win_close(win_T *win, int free_buf)
28222822
else
28232823
{
28242824
win_comp_pos();
2825-
if (*p_spk != 'c')
2826-
win_fix_scroll(FALSE);
2825+
win_fix_scroll(FALSE);
28272826
}
28282827
if (close_curwin)
28292828
{
@@ -5906,7 +5905,7 @@ shell_new_rows(void)
59065905
compute_cmdrow();
59075906
curtab->tp_ch_used = p_ch;
59085907

5909-
if (*p_spk != 'c' && !skip_win_fix_scroll)
5908+
if (!skip_win_fix_scroll)
59105909
win_fix_scroll(TRUE);
59115910

59125911
#if 0
@@ -6111,8 +6110,7 @@ win_setheight_win(int height, win_T *win)
61116110
msg_row = row;
61126111
msg_col = 0;
61136112

6114-
if (*p_spk != 'c')
6115-
win_fix_scroll(TRUE);
6113+
win_fix_scroll(TRUE);
61166114

61176115
redraw_all_later(UPD_NOT_VALID);
61186116
}
@@ -6642,8 +6640,7 @@ win_drag_status_line(win_T *dragwin, int offset)
66426640
p_ch = MAX(Rows - cmdline_row, 1);
66436641
curtab->tp_ch_used = p_ch;
66446642

6645-
if (*p_spk != 'c')
6646-
win_fix_scroll(TRUE);
6643+
win_fix_scroll(TRUE);
66476644

66486645
redraw_all_later(UPD_SOME_VALID);
66496646
showmode();
@@ -6772,21 +6769,22 @@ set_fraction(win_T *wp)
67726769
}
67736770

67746771
/*
6775-
* Handle scroll position for 'splitkeep'. Replaces scroll_to_fraction()
6776-
* call from win_new_height(). Instead we iterate over all windows in a
6777-
* tabpage and calculate the new scroll position.
6772+
* Handle scroll position, depending on 'splitkeep'. Replaces the
6773+
* scroll_to_fraction() call from win_new_height() if 'splitkeep' is "screen"
6774+
* or "topline". Instead we iterate over all windows in a tabpage and
6775+
* calculate the new scroll position.
67786776
* TODO: Ensure this also works with wrapped lines.
6779-
* Requires topline to be able to be set to a bufferline with some
6780-
* offset(row-wise scrolling/smoothscroll).
6777+
* Requires a not fully visible cursor line to be allowed at the bottom of
6778+
* a window("zb"), probably only when 'smoothscroll' is also set.
67816779
*/
67826780
static void
67836781
win_fix_scroll(int resize)
67846782
{
6785-
int diff;
6786-
win_T *wp;
6787-
linenr_T lnum;
6783+
if (*p_spk == 'c')
6784+
return; // 'splitkeep' is "cursor"
67886785

67896786
skip_update_topline = TRUE;
6787+
win_T *wp;
67906788
FOR_ALL_WINDOWS(wp)
67916789
{
67926790
// Skip when window height has not changed.
@@ -6796,18 +6794,22 @@ win_fix_scroll(int resize)
67966794
if (*p_spk == 's' && wp->w_winrow != wp->w_prev_winrow
67976795
&& wp->w_botline - 1 <= wp->w_buffer->b_ml.ml_line_count)
67986796
{
6799-
lnum = wp->w_cursor.lnum;
6800-
diff = (wp->w_winrow - wp->w_prev_winrow)
6801-
+ (wp->w_height - wp->w_prev_height);
6797+
int diff = (wp->w_winrow - wp->w_prev_winrow)
6798+
+ (wp->w_height - wp->w_prev_height);
6799+
linenr_T lnum = wp->w_cursor.lnum;
68026800
wp->w_cursor.lnum = wp->w_botline - 1;
6801+
68036802
// Add difference in height and row to botline.
68046803
if (diff > 0)
68056804
cursor_down_inner(wp, diff);
68066805
else
68076806
cursor_up_inner(wp, -diff);
6808-
// Bring the new cursor position to the bottom of the screen.
6807+
6808+
// Scroll to put the new cursor position at the bottom of the
6809+
// screen.
68096810
wp->w_fraction = FRACTION_MULT;
68106811
scroll_to_fraction(wp, wp->w_prev_height);
6812+
68116813
wp->w_cursor.lnum = lnum;
68126814
}
68136815
else if (wp == curwin)
@@ -6835,32 +6837,33 @@ win_fix_scroll(int resize)
68356837
static void
68366838
win_fix_cursor(int normal)
68376839
{
6838-
long so = get_scrolloff_value();
68396840
win_T *wp = curwin;
6840-
linenr_T nlnum = 0;
6841-
linenr_T lnum = wp->w_cursor.lnum;
6842-
linenr_T bot;
6843-
linenr_T top;
68446841

6845-
if (wp->w_buffer->b_ml.ml_line_count < wp->w_height)
6846-
return;
6847-
if (skip_win_fix_cursor)
6842+
if (skip_win_fix_cursor || wp->w_buffer->b_ml.ml_line_count < wp->w_height)
68486843
return;
68496844

68506845
// Determine valid cursor range.
6851-
so = MIN(wp->w_height / 2, so);
6846+
long so = MIN(wp->w_height / 2, get_scrolloff_value());
6847+
linenr_T lnum = wp->w_cursor.lnum;
6848+
68526849
wp->w_cursor.lnum = wp->w_topline;
6853-
top = cursor_down_inner(wp, so);
6850+
cursor_down_inner(wp, so);
6851+
linenr_T top = wp->w_cursor.lnum;
6852+
68546853
wp->w_cursor.lnum = wp->w_botline - 1;
6855-
bot = cursor_up_inner(wp, so);
6854+
cursor_up_inner(wp, so);
6855+
linenr_T bot = wp->w_cursor.lnum;
6856+
68566857
wp->w_cursor.lnum = lnum;
6858+
68576859
// Check if cursor position is above or below valid cursor range.
6860+
linenr_T nlnum = 0;
68586861
if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
68596862
nlnum = bot;
68606863
else if (lnum < top && wp->w_topline != 1)
68616864
nlnum = (so == wp->w_height / 2) ? bot : top;
68626865

6863-
if (nlnum) // Cursor is invalid for current scroll position.
6866+
if (nlnum != 0) // Cursor is invalid for current scroll position.
68646867
{
68656868
if (normal) // Save to jumplist and set cursor to avoid scrolling.
68666869
{

0 commit comments

Comments
 (0)