aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluukvbaal <luukvbaal@gmail.com>2023-06-02 17:26:41 +0200
committerGitHub <noreply@github.com>2023-06-02 23:26:41 +0800
commitc45a111e35478d2173d8ed5bab2eb73ab2de590c (patch)
treec3227d91efb331e903c15f09cdd8f63725d3d0e3
parentaa130d0c7ea69a05330d0b054b414cc3a15dac45 (diff)
downloadrneovim-c45a111e35478d2173d8ed5bab2eb73ab2de590c.tar.gz
rneovim-c45a111e35478d2173d8ed5bab2eb73ab2de590c.tar.bz2
rneovim-c45a111e35478d2173d8ed5bab2eb73ab2de590c.zip
vim-patch:9.0.1599: Cursor not adjusted when 'splitkeep' is not "cursor" (#23884)
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 vim/vim#12480) https://github.com/vim/vim/commit/a109f39ef54bc3894768170f02c1b6ac56164488
-rw-r--r--src/nvim/edit.c27
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/window.c69
-rw-r--r--test/old/testdir/test_window_cmd.vim13
4 files changed, 62 insertions, 55 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index d6d5ff8ac7..6b90c40c7c 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -2549,15 +2549,10 @@ int oneleft(void)
/// Move the cursor up "n" lines in window "wp".
/// Takes care of closed folds.
-/// Returns the new cursor line or zero for failure.
-linenr_T cursor_up_inner(win_T *wp, long n)
+void cursor_up_inner(win_T *wp, long n)
{
linenr_T lnum = wp->w_cursor.lnum;
- // This fails if the cursor is already in the first line.
- if (lnum <= 1) {
- return 0;
- }
if (n >= lnum) {
lnum = 1;
} else if (hasAnyFolding(wp)) {
@@ -2587,15 +2582,16 @@ linenr_T cursor_up_inner(win_T *wp, long n)
}
wp->w_cursor.lnum = lnum;
- return lnum;
}
/// @param upd_topline When true: update topline
int cursor_up(long n, int upd_topline)
{
- if (n > 0 && cursor_up_inner(curwin, n) == 0) {
+ // This fails if the cursor is already in the first line.
+ if (n > 0 && curwin->w_cursor.lnum <= 1) {
return FAIL;
}
+ cursor_up_inner(curwin, n);
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
@@ -2609,18 +2605,11 @@ int cursor_up(long n, int upd_topline)
/// Move the cursor down "n" lines in window "wp".
/// Takes care of closed folds.
-/// Returns the new cursor line or zero for failure.
-linenr_T cursor_down_inner(win_T *wp, long n)
+void cursor_down_inner(win_T *wp, long n)
{
linenr_T lnum = wp->w_cursor.lnum;
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
- // Move to last line of fold, will fail if it's the end-of-file.
- (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL);
- // This fails if the cursor is already in the last line.
- if (lnum >= line_count) {
- return FAIL;
- }
if (lnum + n >= line_count) {
lnum = line_count;
} else if (hasAnyFolding(wp)) {
@@ -2628,6 +2617,7 @@ linenr_T cursor_down_inner(win_T *wp, long n)
// count each sequence of folded lines as one logical line
while (n--) {
+ // Move to last line of fold, will fail if it's the end-of-file.
if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) {
lnum = last + 1;
} else {
@@ -2645,15 +2635,16 @@ linenr_T cursor_down_inner(win_T *wp, long n)
}
wp->w_cursor.lnum = lnum;
- return lnum;
}
/// @param upd_topline When true: update topline
int cursor_down(long n, int upd_topline)
{
- if (n > 0 && cursor_down_inner(curwin, n) == 0) {
+ // This fails if the cursor is already in the last line.
+ if (n > 0 && curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
return FAIL;
}
+ cursor_down_inner(curwin, n);
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 60fff45323..f3909030c9 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2493,10 +2493,12 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant -= width2;
} else {
// to previous line
- if (!cursor_up_inner(curwin, 1)) {
+ if (curwin->w_cursor.lnum <= 1) {
retval = false;
break;
}
+ cursor_up_inner(curwin, 1);
+
linelen = linetabsize_str(get_cursor_line_ptr());
if (linelen > width1) {
int w = (((linelen - width1 - 1) / width2) + 1) * width2;
@@ -2516,11 +2518,13 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant += width2;
} else {
// to next line
- if (!cursor_down_inner(curwin, 1)) {
+ if (curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
retval = false;
break;
}
+ cursor_down_inner(curwin, 1);
curwin->w_curswant %= width2;
+
// Check if the cursor has moved below the number display
// when width1 < width2 (with cpoptions+=n). Subtract width2
// to get a negative value for w_curswant, which will get
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 90c8ba92f9..ebfa538afb 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1581,7 +1581,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// equalize the window sizes.
if (do_equal || dir != 0) {
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
- } else if (*p_spk != 'c' && !is_aucmd_win(wp)) {
+ } else if (!is_aucmd_win(wp)) {
win_fix_scroll(false);
}
@@ -2174,7 +2174,7 @@ void win_equal(win_T *next_curwin, bool current, int dir)
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
topframe, dir, 0, tabline_height(),
Columns, topframe->fr_height);
- if (*p_spk != 'c' && !is_aucmd_win(next_curwin)) {
+ if (!is_aucmd_win(next_curwin)) {
win_fix_scroll(true);
}
}
@@ -2970,9 +2970,7 @@ int win_close(win_T *win, bool free_buf, bool force)
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
} else {
(void)win_comp_pos();
- if (*p_spk != 'c') {
- win_fix_scroll(false);
- }
+ win_fix_scroll(false);
}
}
@@ -5364,7 +5362,7 @@ void win_new_screen_rows(void)
compute_cmdrow();
curtab->tp_ch_used = p_ch;
- if (*p_spk != 'c' && !skip_win_fix_scroll) {
+ if (!skip_win_fix_scroll) {
win_fix_scroll(true);
}
}
@@ -5811,9 +5809,7 @@ void win_setheight_win(int height, win_T *win)
msg_row = row;
msg_col = 0;
- if (*p_spk != 'c') {
- win_fix_scroll(true);
- }
+ win_fix_scroll(true);
redraw_all_later(UPD_NOT_VALID);
redraw_cmdline = true;
@@ -6293,9 +6289,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
curtab->tp_ch_used = p_ch;
- if (*p_spk != 'c') {
- win_fix_scroll(true);
- }
+ win_fix_scroll(true);
redraw_all_later(UPD_SOME_VALID);
showmode();
@@ -6414,15 +6408,18 @@ void set_fraction(win_T *wp)
}
}
-/// Handle scroll position for 'splitkeep'. Replaces scroll_to_fraction()
-/// call from win_set_inner_size(). Instead we iterate over all windows in a
-/// tabpage and calculate the new scroll position.
-/// TODO(luukvbaal): Ensure this also works with wrapped lines.
-/// Requires topline to be able to be set to a bufferline with some
-/// offset(row-wise scrolling/smoothscroll).
+/// Handle scroll position, depending on 'splitkeep'. Replaces the
+/// scroll_to_fraction() call from win_new_height() if 'splitkeep' is "screen"
+/// or "topline". Instead we iterate over all windows in a tabpage and
+/// calculate the new scroll position.
+/// TODO(vim): Ensure this also works with wrapped lines.
+/// Requires a not fully visible cursor line to be allowed at the bottom of
+/// a window("zb"), probably only when 'smoothscroll' is also set.
void win_fix_scroll(int resize)
{
- linenr_T lnum;
+ if (*p_spk == 'c') {
+ return; // 'splitkeep' is "cursor"
+ }
skip_update_topline = true;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -6431,17 +6428,20 @@ void win_fix_scroll(int resize)
// If window has moved update botline to keep the same screenlines.
if (*p_spk == 's' && wp->w_winrow != wp->w_prev_winrow
&& wp->w_botline - 1 <= wp->w_buffer->b_ml.ml_line_count) {
- lnum = wp->w_cursor.lnum;
int diff = (wp->w_winrow - wp->w_prev_winrow)
+ (wp->w_height - wp->w_prev_height);
+ linenr_T lnum = wp->w_cursor.lnum;
wp->w_cursor.lnum = wp->w_botline - 1;
+
// Add difference in height and row to botline.
if (diff > 0) {
cursor_down_inner(wp, diff);
} else {
cursor_up_inner(wp, -diff);
}
- // Bring the new cursor position to the bottom of the screen.
+
+ // Scroll to put the new cursor position at the bottom of the
+ // screen.
wp->w_fraction = FRACTION_MULT;
scroll_to_fraction(wp, wp->w_prev_height);
wp->w_cursor.lnum = lnum;
@@ -6470,36 +6470,37 @@ void win_fix_scroll(int resize)
static void win_fix_cursor(int normal)
{
win_T *wp = curwin;
- long so = get_scrolloff_value(wp);
- linenr_T nlnum = 0;
- linenr_T lnum = wp->w_cursor.lnum;
- if (wp->w_buffer->b_ml.ml_line_count < wp->w_height
- || skip_win_fix_cursor) {
+ if (skip_win_fix_cursor || wp->w_buffer->b_ml.ml_line_count < wp->w_height) {
return;
}
// Determine valid cursor range.
- so = MIN(wp->w_height_inner / 2, so);
+ long so = MIN(wp->w_height_inner / 2, get_scrolloff_value(wp));
+ linenr_T lnum = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = wp->w_topline;
- linenr_T top = cursor_down_inner(wp, so);
+ cursor_down_inner(wp, so);
+ linenr_T top = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = wp->w_botline - 1;
- linenr_T bot = cursor_up_inner(wp, so);
+ cursor_up_inner(wp, so);
+ linenr_T bot = wp->w_cursor.lnum;
+
wp->w_cursor.lnum = lnum;
// Check if cursor position is above or below valid cursor range.
+ linenr_T nlnum = 0;
if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1) {
nlnum = bot;
} else if (lnum < top && wp->w_topline != 1) {
nlnum = (so == wp->w_height / 2) ? bot : top;
}
- if (nlnum) { // Cursor is invalid for current scroll position.
- if (normal) {
- // Save to jumplist and set cursor to avoid scrolling.
+ if (nlnum != 0) { // Cursor is invalid for current scroll position.
+ if (normal) { // Save to jumplist and set cursor to avoid scrolling.
setmark('\'');
wp->w_cursor.lnum = nlnum;
- } else {
- // Scroll instead when not in normal mode.
+ } else { // Scroll instead when not in normal mode.
wp->w_fraction = (nlnum == bot) ? FRACTION_MULT : 0;
scroll_to_fraction(wp, wp->w_prev_height);
validate_botline(curwin);
diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim
index d4ff241366..7d4932a2b5 100644
--- a/test/old/testdir/test_window_cmd.vim
+++ b/test/old/testdir/test_window_cmd.vim
@@ -1763,9 +1763,20 @@ endfunc
func Test_splitkeep_misc()
set splitkeep=screen
- set splitbelow
call setline(1, range(1, &lines))
+ " Cursor is adjusted to start and end of buffer
+ norm M
+ wincmd s
+ resize 1
+ call assert_equal(1, line('.'))
+ wincmd j
+ norm GM
+ resize 1
+ call assert_equal(&lines, line('.'))
+ only!
+
+ set splitbelow
norm Gzz
let top = line('w0')
" No scroll when aucmd_win is opened