Merge pull request #28044 from luukvbaal/vim-9.1.0211

vim-patch:9.1.{0211,0215}
This commit is contained in:
zeertzjq 2024-03-28 19:47:40 +08:00 committed by GitHub
commit dde2cc65fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 232 additions and 453 deletions

View File

@ -5693,8 +5693,8 @@ A jump table for the options with a short description can be found at |Q_op|.
highlighted with |hl-NonText|. highlighted with |hl-NonText|.
You may also want to add "lastline" to the 'display' option to show as You may also want to add "lastline" to the 'display' option to show as
much of the last line as possible. much of the last line as possible.
NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
and scrolling with the mouse. CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse.
*'softtabstop'* *'sts'* *'softtabstop'* *'sts'*
'softtabstop' 'sts' number (default 0) 'softtabstop' 'sts' number (default 0)
@ -7164,8 +7164,8 @@ A jump table for the options with a short description can be found at |Q_op|.
will scroll 'window' minus two lines, with a minimum of one. 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 When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll
in a much smarter way, taking care of wrapping lines. in a much smarter way, taking care of wrapping lines.
When resizing the Vim window, the value is smaller than 1 or more than When resizing the Vim window, and the value is smaller than 1 or more
or equal to 'lines' it will be set to 'lines' minus 1. 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 Note: Do not confuse this with the height of the Vim window, use
'lines' for that. 'lines' for that.

View File

@ -6075,8 +6075,8 @@ vim.go.sta = vim.go.smarttab
--- highlighted with `hl-NonText`. --- highlighted with `hl-NonText`.
--- You may also want to add "lastline" to the 'display' option to show as --- You may also want to add "lastline" to the 'display' option to show as
--- much of the last line as possible. --- much of the last line as possible.
--- NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y --- NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
--- and scrolling with the mouse. --- CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse.
--- ---
--- @type boolean --- @type boolean
vim.o.smoothscroll = false vim.o.smoothscroll = false
@ -7861,8 +7861,8 @@ vim.wo.winbl = vim.wo.winblend
--- will scroll 'window' minus two lines, with a minimum of one. --- 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 --- When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll
--- in a much smarter way, taking care of wrapping lines. --- in a much smarter way, taking care of wrapping lines.
--- When resizing the Vim window, the value is smaller than 1 or more than --- When resizing the Vim window, and the value is smaller than 1 or more
--- or equal to 'lines' it will be set to 'lines' minus 1. --- 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 --- Note: Do not confuse this with the height of the Vim window, use
--- 'lines' for that. --- 'lines' for that.
--- ---

View File

@ -4192,7 +4192,7 @@ static void ins_pageup(void)
} }
pos_T tpos = curwin->w_cursor; pos_T tpos = curwin->w_cursor;
if (onepage(BACKWARD, 1) == OK) { if (pagescroll(BACKWARD, 1, false) == OK) {
start_arrow(&tpos); start_arrow(&tpos);
can_cindent = true; can_cindent = true;
} else { } else {
@ -4237,7 +4237,7 @@ static void ins_pagedown(void)
} }
pos_T tpos = curwin->w_cursor; pos_T tpos = curwin->w_cursor;
if (onepage(FORWARD, 1) == OK) { if (pagescroll(FORWARD, 1, false) == OK) {
start_arrow(&tpos); start_arrow(&tpos);
can_cindent = true; can_cindent = true;
} else { } else {

View File

@ -1024,7 +1024,7 @@ void do_mousescroll(cmdarg_T *cap)
// Vertical scrolling // Vertical scrolling
if ((State & MODE_NORMAL) && shift_or_ctrl) { if ((State & MODE_NORMAL) && shift_or_ctrl) {
// whole page up or down // whole page up or down
onepage(cap->arg ? FORWARD : BACKWARD, 1); pagescroll(cap->arg ? FORWARD : BACKWARD, 1, false);
} else { } else {
if (shift_or_ctrl) { if (shift_or_ctrl) {
// whole page up or down // whole page up or down

View File

@ -36,6 +36,7 @@
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/mouse.h" #include "nvim/mouse.h"
#include "nvim/move.h" #include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h" #include "nvim/option.h"
#include "nvim/option_vars.h" #include "nvim/option_vars.h"
#include "nvim/plines.h" #include "nvim/plines.h"
@ -1552,21 +1553,6 @@ void check_topfill(win_T *wp, bool down)
win_check_anchored_floats(wp); 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 // Scroll the screen one line down, but don't do it if it would move the
// cursor off the screen. // cursor off the screen.
void scrolldown_clamp(void) 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. // Recompute topline to put the cursor at the top of the window.
// Scroll at least "min_scroll" lines. // Scroll at least "min_scroll" lines.
// If "always" is true, always set topline (for "zt"). // If "always" is true, always set topline (for "zt").
@ -2314,371 +2278,127 @@ void cursor_correct(win_T *wp)
wp->w_viewport_invalid = true; wp->w_viewport_invalid = true;
} }
/// 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 int get_scroll_overlap(Direction dir)
{
lineoff_T loff;
int min_height = curwin->w_height_inner - 2;
validate_botline(curwin);
if (dir == FORWARD && curwin->w_botline > curbuf->b_ml.ml_line_count) {
return min_height + 2; // no overlap, still handle 'smoothscroll'
}
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);
int h1 = loff.height;
if (h1 > min_height) {
return min_height + 2; // no overlap
}
if (dir == FORWARD) {
topline_back(curwin, &loff);
} else {
botline_forw(curwin, &loff);
}
int h2 = loff.height;
if (h2 == MAXCOL || h2 + h1 > min_height) {
return min_height + 2; // no overlap
}
if (dir == FORWARD) {
topline_back(curwin, &loff);
} else {
botline_forw(curwin, &loff);
}
int h3 = loff.height;
if (h3 == MAXCOL || h3 + h2 > min_height) {
return min_height + 2; // no overlap
}
if (dir == FORWARD) {
topline_back(curwin, &loff);
} else {
botline_forw(curwin, &loff);
}
int h4 = loff.height;
if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) {
return min_height + 1; // 1 line overlap
} else {
return min_height; // 2 lines overlap
}
}
/// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD) /// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
/// and update the screen. /// and update the screen.
/// ///
/// @return FAIL for failure, OK otherwise. /// @return FAIL for failure, OK otherwise.
int onepage(Direction dir, int count) int pagescroll(Direction dir, int count, bool half)
{ {
int retval = OK; int prev_topfill = curwin->w_topfill;
lineoff_T loff; linenr_T prev_topline = curwin->w_topline;
linenr_T old_topline = curwin->w_topline; colnr_T prev_skipcol = curwin->w_skipcol;
int so = get_scrolloff_value(curwin);
if (curbuf->b_ml.ml_line_count == 1) { // nothing to do if (half) {
beep_flush(); // Scroll [count], 'scroll' or current window height lines.
return FAIL; if (count) {
} curwin->w_p_scr = MIN(curwin->w_height_inner, count);
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;
} }
count = MIN(curwin->w_height_inner, (int)curwin->w_p_scr);
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;
// 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);
}
}
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 { } else {
lp->height = plines_win_nofill(curwin, lp->lnum, true); // 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));
} }
int h1 = lp->height;
if (h1 > min_height) { if (curwin->w_p_sms) {
return; // no overlap scroll_redraw(dir == FORWARD, count);
}
lineoff_T loff0 = *lp;
if (dir > 0) {
botline_forw(curwin, lp);
} else { } else {
topline_back(curwin, lp); // Scroll at least one full line without 'smoothscroll'.
} count -= plines_win_nofill(curwin, curwin->w_topline, false);
int h2 = lp->height; scroll_redraw(dir == FORWARD, 1);
if (h2 == MAXCOL || h2 + h1 > min_height) {
*lp = loff0; // no overlap
return;
}
lineoff_T loff1 = *lp; // Temporarily set 'smoothscroll' so that scrolling count lines
if (dir > 0) { // does not skip over parts of the buffer with wrapped lines.
botline_forw(curwin, lp); curwin->w_p_sms = true;
} else { if (count > 0) {
topline_back(curwin, lp); scroll_redraw(dir == FORWARD, count);
}
int h3 = lp->height;
if (h3 == MAXCOL || h3 + h2 > min_height) {
*lp = loff0; // no overlap
return;
}
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
}
}
// Scroll 'scroll' lines up or down.
void halfpage(bool flag, linenr_T Prenum)
{
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;
// 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);
}
}
// 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);
}
} 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);
}
}
// 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;
}
} }
curwin->w_p_sms = false;
} }
// Move cursor to first line of closed fold. // Move cursor to first line of closed fold.
foldAdjustCursor(curwin); foldAdjustCursor(curwin);
check_topfill(curwin, !flag);
cursor_correct(curwin); int nochange = curwin->w_topline == prev_topline
beginline(BL_SOL | BL_FIX); && curwin->w_topfill == prev_topfill
redraw_later(curwin, UPD_VALID); && 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) void do_check_cursorbind(void)

View File

@ -2258,7 +2258,7 @@ static void nv_page(cmdarg_T *cap)
goto_tabpage(cap->count0); goto_tabpage(cap->count0);
} }
} else { } 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. /// Handle the CTRL-U and CTRL-D commands.
static void nv_halfpage(cmdarg_T *cap) static void nv_halfpage(cmdarg_T *cap)
{ {
if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1) if (!checkclearop(cap->oap)) {
|| (cap->cmdchar == Ctrl_D pagescroll(cap->cmdchar == Ctrl_D, cap->count0, true);
&& 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);
} }
} }

View File

@ -7663,8 +7663,8 @@ return {
highlighted with |hl-NonText|. highlighted with |hl-NonText|.
You may also want to add "lastline" to the 'display' option to show as You may also want to add "lastline" to the 'display' option to show as
much of the last line as possible. much of the last line as possible.
NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
and scrolling with the mouse. CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse.
]=], ]=],
full_name = 'smoothscroll', full_name = 'smoothscroll',
pv_name = 'p_sms', pv_name = 'p_sms',
@ -9806,8 +9806,8 @@ return {
will scroll 'window' minus two lines, with a minimum of one. 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 When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll
in a much smarter way, taking care of wrapping lines. in a much smarter way, taking care of wrapping lines.
When resizing the Vim window, the value is smaller than 1 or more than When resizing the Vim window, and the value is smaller than 1 or more
or equal to 'lines' it will be set to 'lines' minus 1. 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 Note: Do not confuse this with the height of the Vim window, use
'lines' for that. 'lines' for that.
]=], ]=],

View File

@ -19,7 +19,7 @@ describe('matchparen', function()
call cursor(5, 1) call cursor(5, 1)
]]) ]])
feed('V<c-d><c-d>') feed('V<c-d><c-d>3j')
screen:expect([[ screen:expect([[
{17:{} | {17:{} |
{17:}} | {17:}} |

View File

@ -740,7 +740,7 @@ describe('smoothscroll', function()
| |
]]) ]])
exec("call setline(92, 'a'->repeat(100))") exec("call setline(92, 'a'->repeat(100))")
feed('<C-B>G') feed('<C-L><C-B>G')
-- cursor is not placed below window -- cursor is not placed below window
screen:expect([[ screen:expect([[
{1:<<<}aaaaaaaaaaaaaaaaa | {1:<<<}aaaaaaaaaaaaaaaaa |

View File

@ -1632,34 +1632,38 @@ endfunc
func Test_diff_scroll_many_filler() func Test_diff_scroll_many_filler()
20new 20new
vnew vnew
call setline(1, ['^^^', '^^^', '$$$', '$$$']) call setline(1, range(1, 40))
diffthis diffthis
setlocal scrolloff=0 setlocal scrolloff=0
wincmd p wincmd p
call setline(1, ['^^^', '^^^'] + repeat(['###'], 41) + ['$$$', '$$$']) call setline(1, range(1, 20)->reverse() + ['###']->repeat(41) + range(21, 40)->reverse())
diffthis diffthis
setlocal scrolloff=0 setlocal scrolloff=0
wincmd p wincmd p
redraw redraw
" Note: need a redraw after each scroll, otherwise the test always passes. " Note: need a redraw after each scroll, otherwise the test always passes.
normal! G for _ in range(2)
redraw normal! G
call assert_equal(3, winsaveview().topline) redraw
call assert_equal(18, winsaveview().topfill) call assert_equal(40, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(19, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(3, winsaveview().topline) redraw
call assert_equal(19, winsaveview().topfill) call assert_equal(22, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(0, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(2, winsaveview().topline) redraw
call assert_equal(0, winsaveview().topfill) call assert_equal(4, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(0, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(1, winsaveview().topline) redraw
call assert_equal(0, winsaveview().topfill) call assert_equal(1, winsaveview().topline)
call assert_equal(0, winsaveview().topfill)
set smoothscroll
endfor
set smoothscroll&
bwipe! bwipe!
bwipe! bwipe!
endfunc endfunc

View File

@ -1318,9 +1318,9 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 13, 1, 0], getpos('.')) call assert_equal([0, 13, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 5, 1, 0], getpos('.')) call assert_equal([0, 10, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 2, 11, 0], getpos('.'))
" <S-Up> is the same as <PageUp> " <S-Up> is the same as <PageUp>
" <S-Down> is the same as <PageDown> " <S-Down> is the same as <PageDown>
call cursor(1, 1) call cursor(1, 1)
@ -1341,9 +1341,9 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 13, 1, 0], getpos('.')) call assert_equal([0, 13, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 5, 1, 0], getpos('.')) call assert_equal([0, 10, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 2, 11, 0], getpos('.'))
set nostartofline set nostartofline
call cursor(30, 11) call cursor(30, 11)
norm! zt norm! zt
@ -1354,9 +1354,9 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 13, 11, 0], getpos('.')) call assert_equal([0, 13, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 10, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix') call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 2, 11, 0], getpos('.'))
call cursor(1, 1) call cursor(1, 1)
call feedkeys("A\<PageDown>\<esc>", 'tnix') call feedkeys("A\<PageDown>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.')) call assert_equal([0, 9, 11, 0], getpos('.'))
@ -1379,9 +1379,9 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 13, 11, 0], getpos('.')) call assert_equal([0, 13, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 10, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix') call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 2, 11, 0], getpos('.'))
call cursor(1, 1) call cursor(1, 1)
call feedkeys("A\<S-Down>\<esc>", 'tnix') call feedkeys("A\<S-Down>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.')) call assert_equal([0, 9, 11, 0], getpos('.'))

View File

@ -131,7 +131,7 @@ func Test_normal01_keymodel()
call assert_equal([0, 1, 1, 0], getpos("'<")) call assert_equal([0, 1, 1, 0], getpos("'<"))
call assert_equal([0, 3, 1, 0], getpos("'>")) call assert_equal([0, 3, 1, 0], getpos("'>"))
call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt') call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt')
call assert_equal([0, 2, 1, 0], getpos("'<")) call assert_equal([0, 3, 1, 0], getpos("'<"))
call assert_equal([0, 3, 8, 0], getpos("'>")) call assert_equal([0, 3, 8, 0], getpos("'>"))
" Test for <S-C-Home> and <S-C-End> " Test for <S-C-Home> and <S-C-End>
call cursor(2, 12) call cursor(2, 12)
@ -915,12 +915,10 @@ func Test_normal14_page()
set scrolloff=0 set scrolloff=0
100 100
exe "norm! $\<c-b>" exe "norm! $\<c-b>"
call assert_equal('92', getline('.'))
call assert_equal([0, 92, 1, 0, 1], getcurpos()) call assert_equal([0, 92, 1, 0, 1], getcurpos())
100 100
set nostartofline set nostartofline
exe "norm! $\<c-b>" exe "norm! $\<c-b>"
call assert_equal('92', getline('.'))
call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos()) call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos())
" cleanup " cleanup
set startofline set startofline
@ -1285,9 +1283,13 @@ func Test_vert_scroll_cmds()
exe "normal \<C-D>" exe "normal \<C-D>"
call assert_equal(46, line('.')) call assert_equal(46, line('.'))
exe "normal \<C-U>" exe "normal \<C-U>"
call assert_equal(36, line('.')) call assert_equal(36, line('w0'))
call assert_equal(46, line('.'))
exe "normal \<C-U>" exe "normal \<C-U>"
call assert_equal(10, line('.')) call assert_equal(1, line('w0'))
call assert_equal(40, line('.'))
exe "normal \<C-U>"
call assert_equal(30, line('.'))
exe "normal \<C-U>" exe "normal \<C-U>"
call assert_equal(1, line('.')) call assert_equal(1, line('.'))
set scroll& set scroll&
@ -1308,9 +1310,8 @@ func Test_vert_scroll_cmds()
call assert_equal(50, line('.')) call assert_equal(50, line('.'))
call assert_equal(100, line('w$')) call assert_equal(100, line('w$'))
normal z. normal z.
let lnum = winline()
exe "normal \<C-D>" exe "normal \<C-D>"
call assert_equal(lnum, winline()) call assert_equal(1, winline())
call assert_equal(50, line('.')) call assert_equal(50, line('.'))
normal zt normal zt
exe "normal \<C-D>" exe "normal \<C-D>"
@ -3079,7 +3080,8 @@ func Test_normal42_halfpage()
call assert_equal(2, &scroll) call assert_equal(2, &scroll)
set scroll=5 set scroll=5
exe "norm! \<c-u>" exe "norm! \<c-u>"
call assert_equal('3', getline('.')) call assert_equal('3', getline('w0'))
call assert_equal('8', getline('.'))
1 1
set scrolloff=5 set scrolloff=5
exe "norm! \<c-d>" exe "norm! \<c-d>"
@ -3826,7 +3828,7 @@ func Test_normal_vert_scroll_longline()
call assert_equal(1, winline()) call assert_equal(1, winline())
exe "normal \<C-B>" exe "normal \<C-B>"
call assert_equal(10, line('.')) call assert_equal(10, line('.'))
call assert_equal(3, winline()) call assert_equal(10, winline())
exe "normal \<C-B>\<C-B>" exe "normal \<C-B>\<C-B>"
call assert_equal(5, line('.')) call assert_equal(5, line('.'))
call assert_equal(5, winline()) call assert_equal(5, winline())
@ -4182,20 +4184,34 @@ func Test_normal34_zet_large()
norm! z9765405999999999999 norm! z9765405999999999999
endfunc endfunc
" Test for { and } paragraph movements in a single line " Test for { and } paragraph movements and Ctrl-B in buffer with a single line
func Test_brace_single_line() func Test_single_line_scroll()
let text =<< trim [DATA] CheckFeature textprop
foobar one two three
[DATA]
new new
call setline(1, text) call setline(1, ['foobar one two three'])
let vt = 'virt_above'
call prop_type_add(vt, {'highlight': 'IncSearch'})
call prop_add(1, 0, {'type': vt, 'text': '---', 'text_align': 'above'})
1 1
norm! 0} norm! 0}
call assert_equal([0, 1, 20, 0], getpos('.')) call assert_equal([0, 1, 20, 0], getpos('.'))
norm! { norm! {
call assert_equal([0, 1, 1, 0], getpos('.')) call assert_equal([0, 1, 1, 0], getpos('.'))
" Ctrl-B/Ctrl-U scroll up with hidden "above" virtual text.
set smoothscroll
exe "normal \<C-E>"
call assert_notequal(0, winsaveview().skipcol)
exe "normal \<C-B>"
call assert_equal(0, winsaveview().skipcol)
exe "normal \<C-E>"
call assert_notequal(0, winsaveview().skipcol)
exe "normal \<C-U>"
call assert_equal(0, winsaveview().skipcol)
set smoothscroll&
bw! bw!
endfunc endfunc

View File

@ -832,7 +832,7 @@ func Test_smoothscroll_eob()
call VerifyScreenDump(buf, 'Test_smooth_eob_1', {}) call VerifyScreenDump(buf, 'Test_smooth_eob_1', {})
" cursor is not placed below window " cursor is not placed below window
call term_sendkeys(buf, ":call setline(92, 'a'->repeat(100))\<CR>\<C-B>G") call term_sendkeys(buf, ":call setline(92, 'a'->repeat(100))\<CR>\<C-L>\<C-B>G")
call VerifyScreenDump(buf, 'Test_smooth_eob_2', {}) call VerifyScreenDump(buf, 'Test_smooth_eob_2', {})
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
@ -1001,4 +1001,47 @@ func Test_smoothscroll_textoff_small_winwidth()
set smoothscroll& number& set smoothscroll& number&
endfunc endfunc
func Test_smoothscroll_page()
set smoothscroll
10split | 40vsplit
call setline(1, 'abcde '->repeat(150))
exe "norm! \<C-F>"
call assert_equal(400, winsaveview().skipcol)
exe "norm! \<C-F>"
call assert_equal(800, winsaveview().skipcol)
exe "norm! \<C-F>"
call assert_equal(880, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(480, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(80, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(0, winsaveview().skipcol)
exe "norm! \<C-D>"
call assert_equal(200, winsaveview().skipcol)
exe "norm! \<C-D>"
call assert_equal(400, winsaveview().skipcol)
exe "norm! \<C-D>"
call assert_equal(600, winsaveview().skipcol)
exe "norm! \<C-D>"
call assert_equal(800, winsaveview().skipcol)
exe "norm! \<C-D>"
call assert_equal(880, winsaveview().skipcol)
exe "norm! \<C-U>"
call assert_equal(680, winsaveview().skipcol)
exe "norm! \<C-U>"
call assert_equal(480, winsaveview().skipcol)
exe "norm! \<C-U>"
call assert_equal(280, winsaveview().skipcol)
exe "norm! \<C-U>"
call assert_equal(80, winsaveview().skipcol)
exe "norm! \<C-U>"
call assert_equal(0, winsaveview().skipcol)
set smoothscroll&
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab