diff options
author | Luuk van Baal <luukvbaal@gmail.com> | 2024-03-26 19:06:39 +0100 |
---|---|---|
committer | Luuk van Baal <luukvbaal@gmail.com> | 2024-03-28 10:18:09 +0100 |
commit | 4147302f4be3fe8a5dae3f20a336477cb5f507a4 (patch) | |
tree | 694d7ad69b0ef3e3158c9bee7d6812be9ed2db83 /src | |
parent | 19b443251fe0405628a0aa90583e6c6512dd0fd0 (diff) | |
download | rneovim-4147302f4be3fe8a5dae3f20a336477cb5f507a4.tar.gz rneovim-4147302f4be3fe8a5dae3f20a336477cb5f507a4.tar.bz2 rneovim-4147302f4be3fe8a5dae3f20a336477cb5f507a4.zip |
vim-patch:9.1.0211: page-wise scrolling does not support smooth-scrolling
Problem: Page-wise scrolling with Ctrl-F/Ctrl-B implements
it's own logic to change the topline and cursor.
In doing so, skipcol is not handled properly for
'smoothscroll', and virtual lines.
Solution: Re-use the logic from Ctrl-E/Ctrl-Y while staying
backward compatible as much as possible.
https://github.com/vim/vim/commit/b9f5b95b7bec2414a5a96010514702d99afea18e
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/move.c | 290 | ||||
-rw-r--r-- | src/nvim/options.lua | 4 |
2 files changed, 29 insertions, 265 deletions
diff --git a/src/nvim/move.c b/src/nvim/move.c index 3c4da7f8ac..ebb27337f7 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -36,6 +36,7 @@ #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/plines.h" @@ -1552,21 +1553,6 @@ void check_topfill(win_T *wp, bool down) win_check_anchored_floats(wp); } -// Use as many filler lines as possible for w_topline. Make sure w_topline -// is still visible. -static void max_topfill(void) -{ - int n = plines_win_nofill(curwin, curwin->w_topline, true); - if (n >= curwin->w_height_inner) { - curwin->w_topfill = 0; - } else { - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - if (curwin->w_topfill + n > curwin->w_height_inner) { - curwin->w_topfill = curwin->w_height_inner - n; - } - } -} - // Scroll the screen one line down, but don't do it if it would move the // cursor off the screen. void scrolldown_clamp(void) @@ -1697,28 +1683,6 @@ static void botline_forw(win_T *wp, lineoff_T *lp) } } -// Switch from including filler lines below lp->lnum to including filler -// lines above loff.lnum + 1. This keeps pointing to the same line. -// When there are no filler lines nothing changes. -static void botline_topline(lineoff_T *lp) -{ - if (lp->fill > 0) { - lp->lnum++; - lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1; - } -} - -// Switch from including filler lines above lp->lnum to including filler -// lines below loff.lnum - 1. This keeps pointing to the same line. -// When there are no filler lines nothing changes. -static void topline_botline(lineoff_T *lp) -{ - if (lp->fill > 0) { - lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1; - lp->lnum--; - } -} - // Recompute topline to put the cursor at the top of the window. // Scroll at least "min_scroll" lines. // If "always" is true, always set topline (for "zt"). @@ -2320,241 +2284,41 @@ void cursor_correct(win_T *wp) /// @return FAIL for failure, OK otherwise. int onepage(Direction dir, int count) { - int retval = OK; - lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - int so = get_scrolloff_value(curwin); - - if (curbuf->b_ml.ml_line_count == 1) { // nothing to do - beep_flush(); - return FAIL; - } - - for (; count > 0; count--) { - validate_botline(curwin); - // It's an error to move a page up when the first line is already on - // the screen. It's an error to move a page down when the last line - // is on the screen and the topline is 'scrolloff' lines from the - // last line. - if (dir == FORWARD - ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so) - && curwin->w_botline > curbuf->b_ml.ml_line_count) - : (curwin->w_topline == 1 - && curwin->w_topfill == win_get_fill(curwin, curwin->w_topline))) { - beep_flush(); - retval = FAIL; - break; - } - - loff.fill = 0; - if (dir == FORWARD) { - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { - // Vi compatible scrolling - if (p_window <= 2) { - curwin->w_topline++; - } else { - curwin->w_topline += (linenr_T)p_window - 2; - } - if (curwin->w_topline > curbuf->b_ml.ml_line_count) { - curwin->w_topline = curbuf->b_ml.ml_line_count; - } - curwin->w_cursor.lnum = curwin->w_topline; - } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - // at end of file - curwin->w_topline = curbuf->b_ml.ml_line_count; - curwin->w_topfill = 0; - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } else { - // For the overlap, start with the line just below the window - // and go upwards. - loff.lnum = curwin->w_botline; - loff.fill = win_get_fill(curwin, loff.lnum) - - curwin->w_filler_rows; - get_scroll_overlap(&loff, -1); - curwin->w_topline = loff.lnum; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - curwin->w_cursor.lnum = curwin->w_topline; - curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW| - VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - } - } else { // dir == BACKWARDS - if (curwin->w_topline == 1) { - // Include max number of filler lines - max_topfill(); - continue; - } - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { - // Vi compatible scrolling (sort of) - if (p_window <= 2) { - curwin->w_topline--; - } else { - curwin->w_topline -= (linenr_T)p_window - 2; - } - if (curwin->w_topline < 1) { - curwin->w_topline = 1; - } - curwin->w_cursor.lnum = curwin->w_topline + (linenr_T)p_window - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } - continue; - } + int prev_topfill = curwin->w_topfill; + linenr_T prev_topline = curwin->w_topline; + colnr_T prev_skipcol = curwin->w_skipcol; - // Find the line at the top of the window that is going to be the - // line at the bottom of the window. Make sure this results in - // the same line as before doing CTRL-F. - loff.lnum = curwin->w_topline - 1; - loff.fill = win_get_fill(curwin, loff.lnum + 1) - curwin->w_topfill; - get_scroll_overlap(&loff, 1); + // Scroll 'window' or current window height lines. + count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) + ? (int)p_window - 2 : curwin->w_height - 1); - if (loff.lnum >= curbuf->b_ml.ml_line_count) { - loff.lnum = curbuf->b_ml.ml_line_count; - loff.fill = 0; - } else { - botline_topline(&loff); - } - curwin->w_cursor.lnum = loff.lnum; + 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); - // Find the line just above the new topline to get the right line - // at the bottom of the window. - int n = 0; - while (n <= curwin->w_height_inner && loff.lnum >= 1) { - topline_back(curwin, &loff); - if (loff.height == MAXCOL) { - n = MAXCOL; - } else { - n += loff.height; - } - } - if (loff.lnum < 1) { // at begin of file - curwin->w_topline = 1; - max_topfill(); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } else { - // Go two lines forward again. - topline_botline(&loff); - botline_forw(curwin, &loff); - botline_forw(curwin, &loff); - botline_topline(&loff); - // We're at the wrong end of a fold now. - hasFolding(curwin, loff.lnum, &loff.lnum, NULL); - - // Always scroll at least one line. Avoid getting stuck on - // very long lines. - if (loff.lnum >= curwin->w_topline - && (loff.lnum > curwin->w_topline - || loff.fill >= curwin->w_topfill)) { - // First try using the maximum number of filler lines. If - // that's not enough, backup one line. - loff.fill = curwin->w_topfill; - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { - max_topfill(); - } - if (curwin->w_topfill == loff.fill) { - curwin->w_topline--; - curwin->w_topfill = 0; - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } - comp_botline(curwin); - curwin->w_cursor.lnum = curwin->w_botline - 1; - curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW); - } else { - curwin->w_topline = loff.lnum; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } - } - } - } - foldAdjustCursor(curwin); - cursor_correct(curwin); - check_cursor_col(curwin); - if (retval == OK) { - beginline(BL_SOL | BL_FIX); - } - curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); - - if (retval == OK && dir == FORWARD) { - // Avoid the screen jumping up and down when 'scrolloff' is non-zero. - // But make sure we scroll at least one line (happens with mix of long - // wrapping lines and non-wrapping line). - if (check_top_offset()) { - scroll_cursor_top(curwin, 1, false); - if (curwin->w_topline <= old_topline - && old_topline < curbuf->b_ml.ml_line_count) { - curwin->w_topline = old_topline + 1; - hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); - } - } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); + // 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); } + curwin->w_p_sms = false; } - redraw_later(curwin, UPD_VALID); - return retval; -} - -// Decide how much overlap to use for page-up or page-down scrolling. -// This is symmetric, so that doing both keeps the same lines displayed. -// Three lines are examined: -// -// before CTRL-F after CTRL-F / before CTRL-B -// etc. l1 -// l1 last but one line ------------ -// l2 last text line l2 top text line -// ------------- l3 second text line -// l3 etc. -static void get_scroll_overlap(lineoff_T *lp, int dir) -{ - int min_height = curwin->w_height_inner - 2; - - if (lp->fill > 0) { - lp->height = 1; - } else { - lp->height = plines_win_nofill(curwin, lp->lnum, true); - } - int h1 = lp->height; - if (h1 > min_height) { - return; // no overlap - } - lineoff_T loff0 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int h2 = lp->height; - if (h2 == MAXCOL || h2 + h1 > min_height) { - *lp = loff0; // no overlap - return; - } + int nochange = curwin->w_topline == prev_topline + && curwin->w_topfill == prev_topfill + && curwin->w_skipcol == prev_skipcol; - lineoff_T loff1 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int h3 = lp->height; - if (h3 == MAXCOL || h3 + h2 > min_height) { - *lp = loff0; // no overlap - return; + if (nochange) { + beep_flush(); + } else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) { + beginline(BL_SOL | BL_FIX); } - lineoff_T loff2 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int h4 = lp->height; - if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) { - *lp = loff1; // 1 line overlap - } else { - *lp = loff2; // 2 lines overlap - } + return nochange; } // Scroll 'scroll' lines up or down. diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 6bfeee75e6..a7c5a97d02 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7663,8 +7663,8 @@ return { highlighted with |hl-NonText|. You may also want to add "lastline" to the 'display' option to show as much of the last line as possible. - NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y - and scrolling with the mouse. + NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y, + CTRL-B, CTRL-F and scrolling with the mouse. ]=], full_name = 'smoothscroll', pv_name = 'p_sms', |