aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-03-28 19:47:40 +0800
committerGitHub <noreply@github.com>2024-03-28 19:47:40 +0800
commitdde2cc65fd2ac89ad88b19df08dc03cf1da50316 (patch)
tree8a4f3e3165e071639598fed73981ffa05b1c4b0d /src
parent346a6390286cf58d8a618fd9d803523e497c8af1 (diff)
parent2f638c0ac6275bebacd12671481642fa43d7ba10 (diff)
downloadrneovim-dde2cc65fd2ac89ad88b19df08dc03cf1da50316.tar.gz
rneovim-dde2cc65fd2ac89ad88b19df08dc03cf1da50316.tar.bz2
rneovim-dde2cc65fd2ac89ad88b19df08dc03cf1da50316.zip
Merge pull request #28044 from luukvbaal/vim-9.1.0211
vim-patch:9.1.{0211,0215}
Diffstat (limited to 'src')
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/mouse.c2
-rw-r--r--src/nvim/move.c456
-rw-r--r--src/nvim/normal.c10
-rw-r--r--src/nvim/options.lua8
5 files changed, 98 insertions, 382 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 8e9649b6b1..8b8345657c 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -4192,7 +4192,7 @@ static void ins_pageup(void)
}
pos_T tpos = curwin->w_cursor;
- if (onepage(BACKWARD, 1) == OK) {
+ if (pagescroll(BACKWARD, 1, false) == OK) {
start_arrow(&tpos);
can_cindent = true;
} else {
@@ -4237,7 +4237,7 @@ static void ins_pagedown(void)
}
pos_T tpos = curwin->w_cursor;
- if (onepage(FORWARD, 1) == OK) {
+ if (pagescroll(FORWARD, 1, false) == OK) {
start_arrow(&tpos);
can_cindent = true;
} else {
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index a2b4042f30..1e70462700 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -1024,7 +1024,7 @@ void do_mousescroll(cmdarg_T *cap)
// Vertical scrolling
if ((State & MODE_NORMAL) && shift_or_ctrl) {
// whole page up or down
- onepage(cap->arg ? FORWARD : BACKWARD, 1);
+ pagescroll(cap->arg ? FORWARD : BACKWARD, 1, false);
} else {
if (shift_or_ctrl) {
// whole page up or down
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 3c4da7f8ac..52b65c0fef 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").
@@ -2314,371 +2278,127 @@ void cursor_correct(win_T *wp)
wp->w_viewport_invalid = true;
}
-/// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
-/// and update the screen.
+/// 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:
///
-/// @return FAIL for failure, OK otherwise.
-int onepage(Direction dir, int count)
+/// 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 int get_scroll_overlap(Direction dir)
{
- 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;
- }
-
- // 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);
-
- 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;
+ int min_height = curwin->w_height_inner - 2;
- // 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);
- }
+ validate_botline(curwin);
+ if (dir == FORWARD && curwin->w_botline > curbuf->b_ml.ml_line_count) {
+ return min_height + 2; // no overlap, still handle 'smoothscroll'
}
- 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;
+ loff.lnum = dir == FORWARD ? curwin->w_botline : curwin->w_topline - 1;
+ loff.fill = win_get_fill(curwin, loff.lnum + dir == BACKWARD)
+ - (dir == FORWARD ? curwin->w_filler_rows : curwin->w_topfill);
+ loff.height = loff.fill > 0 ? 1 : plines_win_nofill(curwin, loff.lnum, true);
- if (lp->fill > 0) {
- lp->height = 1;
- } else {
- lp->height = plines_win_nofill(curwin, lp->lnum, true);
- }
- int h1 = lp->height;
+ int h1 = loff.height;
if (h1 > min_height) {
- return; // no overlap
+ return min_height + 2; // no overlap
}
- lineoff_T loff0 = *lp;
- if (dir > 0) {
- botline_forw(curwin, lp);
+ if (dir == FORWARD) {
+ topline_back(curwin, &loff);
} else {
- topline_back(curwin, lp);
+ botline_forw(curwin, &loff);
}
- int h2 = lp->height;
+
+ int h2 = loff.height;
if (h2 == MAXCOL || h2 + h1 > min_height) {
- *lp = loff0; // no overlap
- return;
+ return min_height + 2; // no overlap
}
-
- lineoff_T loff1 = *lp;
- if (dir > 0) {
- botline_forw(curwin, lp);
+ if (dir == FORWARD) {
+ topline_back(curwin, &loff);
} else {
- topline_back(curwin, lp);
+ botline_forw(curwin, &loff);
}
- int h3 = lp->height;
+
+ int h3 = loff.height;
if (h3 == MAXCOL || h3 + h2 > min_height) {
- *lp = loff0; // no overlap
- return;
+ return min_height + 2; // no overlap
}
-
- lineoff_T loff2 = *lp;
- if (dir > 0) {
- botline_forw(curwin, lp);
+ if (dir == FORWARD) {
+ topline_back(curwin, &loff);
} else {
- topline_back(curwin, lp);
+ botline_forw(curwin, &loff);
}
- int h4 = lp->height;
+
+ int h4 = loff.height;
if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) {
- *lp = loff1; // 1 line overlap
+ return min_height + 1; // 1 line overlap
} else {
- *lp = loff2; // 2 lines overlap
+ return min_height; // 2 lines overlap
}
}
-// Scroll 'scroll' lines up or down.
-void halfpage(bool flag, linenr_T Prenum)
+/// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
+/// and update the screen.
+///
+/// @return FAIL for failure, OK otherwise.
+int pagescroll(Direction dir, int count, bool half)
{
- int scrolled = 0;
- int i;
-
- if (Prenum) {
- curwin->w_p_scr = (Prenum > curwin->w_height_inner) ? curwin->w_height_inner
- : Prenum;
- }
- assert(curwin->w_p_scr <= INT_MAX);
- int n = curwin->w_p_scr <= curwin->w_height_inner ? (int)curwin->w_p_scr
- : curwin->w_height_inner;
-
- update_topline(curwin);
- validate_botline(curwin);
- int room = curwin->w_empty_rows + curwin->w_filler_rows;
- if (flag) {
- // scroll the text up
- while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) {
- if (curwin->w_topfill > 0) {
- i = 1;
- n--;
- curwin->w_topfill--;
- } else {
- i = plines_win_nofill(curwin, curwin->w_topline, true);
- n -= i;
- if (n < 0 && scrolled > 0) {
- break;
- }
- hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline);
- curwin->w_topline++;
- curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
-
- if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- curwin->w_cursor.lnum++;
- curwin->w_valid &=
- ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
- }
- }
- curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
- scrolled += i;
+ int prev_topfill = curwin->w_topfill;
+ linenr_T prev_topline = curwin->w_topline;
+ colnr_T prev_skipcol = curwin->w_skipcol;
- // Correct w_botline for changed w_topline.
- // Won't work when there are filler lines.
- if (win_may_fill(curwin)) {
- curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
- } else {
- room += i;
- do {
- i = plines_win(curwin, curwin->w_botline, true);
- if (i > room) {
- break;
- }
- hasFolding(curwin, curwin->w_botline, NULL, &curwin->w_botline);
- curwin->w_botline++;
- room -= i;
- } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
- }
+ if (half) {
+ // Scroll [count], 'scroll' or current window height lines.
+ if (count) {
+ 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));
+ }
- // When hit bottom of the file: move cursor down.
- if (n > 0) {
- if (hasAnyFolding(curwin)) {
- while (--n >= 0
- && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- hasFolding(curwin, curwin->w_cursor.lnum, NULL,
- &curwin->w_cursor.lnum);
- curwin->w_cursor.lnum++;
- }
- } else {
- curwin->w_cursor.lnum += n;
- }
- check_cursor_lnum(curwin);
- }
+ if (curwin->w_p_sms) {
+ scroll_redraw(dir == FORWARD, count);
} else {
- // scroll the text down
- while (n > 0 && curwin->w_topline > 1) {
- if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
- i = 1;
- n--;
- curwin->w_topfill++;
- } else {
- i = plines_win_nofill(curwin, curwin->w_topline - 1, true);
- n -= i;
- if (n < 0 && scrolled > 0) {
- break;
- }
- curwin->w_topline--;
- hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL);
- curwin->w_topfill = 0;
- }
- curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
- VALID_BOTLINE|VALID_BOTLINE_AP);
- scrolled += i;
- if (curwin->w_cursor.lnum > 1) {
- curwin->w_cursor.lnum--;
- curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
- }
- }
+ // Scroll at least one full line without 'smoothscroll'.
+ count -= plines_win_nofill(curwin, curwin->w_topline, false);
+ scroll_redraw(dir == FORWARD, 1);
- // When hit top of the file: move cursor up.
- if (n > 0) {
- if (curwin->w_cursor.lnum <= (linenr_T)n) {
- curwin->w_cursor.lnum = 1;
- } else if (hasAnyFolding(curwin)) {
- while (--n >= 0 && curwin->w_cursor.lnum > 1) {
- curwin->w_cursor.lnum--;
- hasFolding(curwin, curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
- }
- } else {
- curwin->w_cursor.lnum -= n;
- }
+ // 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;
}
// Move cursor to first line of closed fold.
foldAdjustCursor(curwin);
- check_topfill(curwin, !flag);
- cursor_correct(curwin);
- beginline(BL_SOL | BL_FIX);
- redraw_later(curwin, UPD_VALID);
+
+ int nochange = curwin->w_topline == prev_topline
+ && curwin->w_topfill == prev_topfill
+ && curwin->w_skipcol == prev_skipcol;
+
+ // Error if the viewport did not change and the cursor is already
+ // at the boundary.
+ 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) {
+ beginline(BL_SOL | BL_FIX);
+ }
+
+ return nochange;
}
void do_check_cursorbind(void)
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 12f0bb631e..bbba8069c7 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2258,7 +2258,7 @@ static void nv_page(cmdarg_T *cap)
goto_tabpage(cap->count0);
}
} else {
- onepage(cap->arg, cap->count1);
+ pagescroll(cap->arg, cap->count1, false);
}
}
@@ -6394,12 +6394,8 @@ static void nv_at(cmdarg_T *cap)
/// Handle the CTRL-U and CTRL-D commands.
static void nv_halfpage(cmdarg_T *cap)
{
- if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1)
- || (cap->cmdchar == Ctrl_D
- && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)) {
- clearopbeep(cap->oap);
- } else if (!checkclearop(cap->oap)) {
- halfpage(cap->cmdchar == Ctrl_D, cap->count0);
+ if (!checkclearop(cap->oap)) {
+ pagescroll(cap->cmdchar == Ctrl_D, cap->count0, true);
}
}
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 6bfeee75e6..e7acf6f6ef 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-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse.
]=],
full_name = 'smoothscroll',
pv_name = 'p_sms',
@@ -9806,8 +9806,8 @@ return {
will scroll 'window' minus two lines, with a minimum of one.
When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll
in a much smarter way, taking care of wrapping lines.
- When resizing the Vim window, the value is smaller than 1 or more than
- or equal to 'lines' it will be set to 'lines' minus 1.
+ When resizing the Vim window, and the value is smaller than 1 or more
+ than or equal to 'lines' it will be set to 'lines' minus 1.
Note: Do not confuse this with the height of the Vim window, use
'lines' for that.
]=],