aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/move.c
diff options
context:
space:
mode:
authorLuuk van Baal <luukvbaal@gmail.com>2024-04-02 20:58:49 +0200
committerLuuk van Baal <luukvbaal@gmail.com>2024-04-08 23:15:43 +0200
commite6cfa22c4cd5b3b422aa4f8350c8e73a3eb2a090 (patch)
tree51781c0f14c0870b55e56e4ae8e119c6cdb28d15 /src/nvim/move.c
parent7035125b2b26aa68fcfb7cda39377ac79926a0f9 (diff)
downloadrneovim-e6cfa22c4cd5b3b422aa4f8350c8e73a3eb2a090.tar.gz
rneovim-e6cfa22c4cd5b3b422aa4f8350c8e73a3eb2a090.tar.bz2
rneovim-e6cfa22c4cd5b3b422aa4f8350c8e73a3eb2a090.zip
vim-patch:9.1.0258: half-page scrolling broke backward compatibility
Problem: Support for 'smoothscroll' in (half-)page scrolling broke backward compatibility and can be made to work better. (after v9.1.215) Solution: Restore the previous cursor and end-of-buffer behavior for half-page scrolling and improve 'smoothscroll' support. (Luuk van Baal) https://github.com/vim/vim/commit/cb204e688e5c9d56a78b621ef27c35d91860cb09
Diffstat (limited to 'src/nvim/move.c')
-rw-r--r--src/nvim/move.c144
1 files changed, 104 insertions, 40 deletions
diff --git a/src/nvim/move.c b/src/nvim/move.c
index e7416549f5..63505c72ab 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -190,11 +190,14 @@ static void redraw_for_cursorcolumn(win_T *wp)
/// Calculates how much the 'listchars' "precedes" or 'smoothscroll' "<<<"
/// marker overlaps with buffer text for window "wp".
/// Parameter "extra2" should be the padding on the 2nd line, not the first
-/// line.
+/// line. When "extra2" is -1 calculate the padding.
/// Returns the number of columns of overlap with buffer text, excluding the
/// extra padding on the ledge.
int sms_marker_overlap(win_T *wp, int extra2)
{
+ if (extra2 == -1) {
+ extra2 = win_col_off(wp) - win_col_off2(wp);
+ }
// There is no marker overlap when in showbreak mode, thus no need to
// account for it. See wlv_put_linebuf().
if (*get_showbreak_value(wp) != NUL) {
@@ -303,7 +306,7 @@ void update_topline(win_T *wp)
// Check that the cursor position is visible. Add columns for
// the marker displayed in the top-left if needed.
getvvcol(wp, &wp->w_cursor, &vcol, NULL, NULL);
- int overlap = sms_marker_overlap(wp, win_col_off(wp) - win_col_off2(wp));
+ int overlap = sms_marker_overlap(wp, -1);
if (wp->w_skipcol + overlap > vcol) {
check_topline = true;
}
@@ -1382,6 +1385,9 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
wp->w_topline = lnum;
wp->w_topfill = win_get_fill(wp, lnum);
wp->w_skipcol = 0;
+ // Adjusting the cursor later should not adjust skipcol:
+ // bring it to the first screenline on this new topline.
+ wp->w_curswant %= width1;
if (todo > 1 && do_sms) {
size = linetabsize(wp, wp->w_topline);
}
@@ -1494,7 +1500,7 @@ void adjust_skipcol(void)
}
validate_virtcol(curwin);
- int overlap = sms_marker_overlap(curwin, win_col_off(curwin) - win_col_off2(curwin));
+ int overlap = sms_marker_overlap(curwin, -1);
while (curwin->w_skipcol > 0
&& curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
// scroll a screen line down
@@ -1860,10 +1866,12 @@ void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot)
// of it.
if (used < wp->w_height_inner) {
int plines_offset = used + loff.height - wp->w_height_inner;
+ int overlap = sms_marker_overlap(wp, -1);
used = wp->w_height_inner;
wp->w_topfill = loff.fill;
wp->w_topline = loff.lnum;
wp->w_skipcol = skipcol_from_plines(wp, plines_offset);
+ wp->w_cursor.col = wp->w_skipcol + overlap;
set_skipcol = true;
}
}
@@ -1872,6 +1880,9 @@ void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot)
used += loff.height;
wp->w_topfill = loff.fill;
}
+ if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) {
+ wp->w_topline = wp->w_buffer->b_ml.ml_line_count;
+ }
set_empty_rows(wp, used);
wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
if (wp->w_topline != old_topline
@@ -2341,15 +2352,57 @@ static int get_scroll_overlap(Direction dir)
}
}
-/// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
-/// and update the screen.
+/// Scroll "count" lines with 'smoothscroll' in direction "dir". Adjust "count"
+/// when scrolling more than "count" and return true when scrolling happened.
+static bool scroll_with_sms(Direction dir, int *count)
+{
+ int prev_sms = curwin->w_p_sms;
+ colnr_T prev_skipcol = curwin->w_skipcol;
+ linenr_T prev_topline = curwin->w_topline;
+ int prev_topfill = curwin->w_topfill;
+
+ curwin->w_p_sms = true;
+ scroll_redraw(dir == FORWARD, *count);
+
+ // Not actually smoothscrolling but ended up with partially visible line.
+ // Continue scrolling and update "count" so that cursor can be moved
+ // accordingly for half-page scrolling.
+ if (!prev_sms && curwin->w_skipcol > 0) {
+ int fixdir = dir;
+ // Reverse the scroll direction when topline already changed. One line
+ // extra for scrolling backward so that consuming skipcol is symmetric.
+ if (labs(curwin->w_topline - prev_topline) > (dir == BACKWARD)) {
+ fixdir = dir * -1;
+ }
+ validate_cursor(curwin);
+ while (curwin->w_skipcol > 0
+ && curwin->w_topline < curbuf->b_ml.ml_line_count) {
+ scroll_redraw(fixdir == FORWARD, 1);
+ *count += (fixdir == dir ? 1 : -1);
+ }
+ }
+ curwin->w_p_sms = prev_sms;
+
+ return curwin->w_topline == prev_topline
+ && curwin->w_topfill == prev_topfill
+ && curwin->w_skipcol == prev_skipcol;
+}
+
+/// Move screen "count" (half) pages up ("dir" is BACKWARD) or down ("dir" is
+/// FORWARD) and update the screen. Handle moving the cursor and not scrolling
+/// to reveal end of buffer lines for half-page scrolling with CTRL-D and CTRL-U.
///
/// @return FAIL for failure, OK otherwise.
int pagescroll(Direction dir, int count, bool half)
{
- int prev_topfill = curwin->w_topfill;
- linenr_T prev_topline = curwin->w_topline;
- colnr_T prev_skipcol = curwin->w_skipcol;
+ int nochange = true;
+ int buflen = curbuf->b_ml.ml_line_count;
+ colnr_T prev_col = curwin->w_cursor.col;
+ colnr_T prev_curswant = curwin->w_curswant;
+ linenr_T prev_lnum = curwin->w_cursor.lnum;
+ oparg_T oa = { 0 };
+ cmdarg_T ca = { 0 };
+ ca.oap = &oa;
if (half) {
// Scroll [count], 'scroll' or current window height lines.
@@ -2357,45 +2410,56 @@ int pagescroll(Direction dir, int count, bool half)
curwin->w_p_scr = MIN(curwin->w_height_inner, count);
}
count = MIN(curwin->w_height_inner, (int)curwin->w_p_scr);
- } else {
- // Scroll 'window' or current window height lines.
- count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
- ? (int)p_window - 2 : get_scroll_overlap(dir));
- }
+ // Don't scroll if we already know that it will reveal end of buffer lines.
+ if (dir == BACKWARD
+ || (curwin->w_botline - 1 < buflen)
+ || (curwin->w_p_sms && curwin->w_botline - 1 == buflen
+ && curwin->w_skipcol < linetabsize(curwin, buflen))) {
+ nochange = scroll_with_sms(dir, &count);
+ validate_botline(curwin);
+ // Hide any potentially revealed end of buffer lines.
+ if (!nochange && curwin->w_botline - 1 == buflen) {
+ curwin->w_cursor.lnum = buflen;
+ scroll_cursor_bot(curwin, 0, true);
+ }
+ }
- if (curwin->w_p_sms) {
- scroll_redraw(dir == FORWARD, count);
- } else {
- // Scroll at least one full line without 'smoothscroll'.
- count -= plines_win_nofill(curwin, curwin->w_topline, false);
- scroll_redraw(dir == FORWARD, 1);
+ // Move the cursor "count" screen lines.
+ curwin->w_curswant = MAXCOL;
+ curwin->w_cursor.col = prev_col;
+ curwin->w_cursor.lnum = prev_lnum;
+ if (curwin->w_p_wrap) {
+ nv_screengo(&oa, dir, count);
+ } else if (dir == FORWARD) {
+ cursor_down_inner(curwin, count);
+ } else {
+ cursor_up_inner(curwin, count);
+ }
+ curwin->w_curswant = prev_curswant;
- // Temporarily set 'smoothscroll' so that scrolling count lines
- // does not skip over parts of the buffer with wrapped lines.
- curwin->w_p_sms = true;
- if (count > 0) {
- scroll_redraw(dir == FORWARD, count);
+ if (get_scrolloff_value(curwin)) {
+ cursor_correct(curwin);
}
- curwin->w_p_sms = false;
- }
- // Move cursor to first line of closed fold.
- foldAdjustCursor(curwin);
+ // Move cursor to first line of closed fold.
+ foldAdjustCursor(curwin);
- int nochange = curwin->w_topline == prev_topline
- && curwin->w_topfill == prev_topfill
- && curwin->w_skipcol == prev_skipcol;
+ nochange = nochange
+ && prev_col == curwin->w_cursor.col
+ && prev_lnum == curwin->w_cursor.lnum;
+ } else {
+ // Scroll [count] times 'window' or current window height lines.
+ count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
+ ? MAX(1, p_window - 2) : get_scroll_overlap(dir));
+ nochange = scroll_with_sms(dir, &count);
+ }
- // Error if the viewport did not change and the cursor is already
- // at the boundary.
+ // Error if both the viewport and cursor did not change.
if (nochange) {
- int prev_cursor = curwin->w_cursor.lnum;
- curwin->w_cursor.lnum += (count + 1) * (dir == FORWARD ? 1 : -1);
- check_cursor(curwin);
- if (curwin->w_cursor.lnum == prev_cursor) {
- beep_flush();
- }
- } else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) {
+ beep_flush();
+ } else if (!curwin->w_p_sms) {
beginline(BL_SOL | BL_FIX);
+ } else if (p_sol) {
+ nv_g_home_m_cmd(&ca);
}
return nochange;