-*options.txt* For Vim version 9.1. Last change: 2024 Mar 26
+*options.txt* For Vim version 9.1. Last change: 2024 Mar 28
VIM REFERENCE MANUAL by Bram Moolenaar
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,
- CTRL-B, CTRL-F and scrolling with the mouse.
+ CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse.
*'softtabstop'* *'sts'*
'softtabstop' 'sts' number (default 0)
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.
-*version9.txt* For Vim version 9.1. Last change: 2024 Mar 26
+*version9.txt* For Vim version 9.1. Last change: 2024 Mar 28
VIM REFERENCE MANUAL by Bram Moolenaar
-------
- use 'smoothscroll' logic for CTRL-F and CTRL-B for pagewise scrolling
+- use 'smoothscroll' logic for CTRL-D and CTRL-U for half-pagewise scrolling
Added *added-9.2*
-----
}
tpos = curwin->w_cursor;
- if (onepage(BACKWARD, 1L) == OK)
+ if (pagescroll(BACKWARD, 1L, FALSE) == OK)
{
start_arrow(&tpos);
can_cindent = TRUE;
}
tpos = curwin->w_cursor;
- if (onepage(FORWARD, 1L) == OK)
+ if (pagescroll(FORWARD, 1L, FALSE) == OK)
{
start_arrow(&tpos);
can_cindent = TRUE;
if (!(State & MODE_INSERT) && (mouse_vert_step < 0 || shift_or_ctrl))
{
// whole page up or down
- onepage(cap->arg == MSCR_UP ? FORWARD : BACKWARD, 1L);
+ pagescroll(cap->arg == MSCR_UP ? FORWARD : BACKWARD, 1L, FALSE);
}
else
{
curwin->w_valid |= VALID_TOPLINE;
}
+/*
+ * 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(int dir)
+{
+ lineoff_T loff;
+ int min_height = curwin->w_height - 2;
+
+ validate_botline();
+ 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;
+#ifdef FEAT_DIFF
+ loff.fill = diff_check_fill(curwin, loff.lnum + dir == BACKWARD)
+ - (dir == FORWARD ? curwin->w_filler_rows : curwin->w_topfill);
+ loff.height = loff.fill > 0 ? 1 : plines_nofill(loff.lnum);
+#else
+ loff.height = plines(loff.lnum);
+#endif
+
+ int h1 = loff.height;
+ if (h1 > min_height)
+ return min_height + 2; // no overlap
+ if (dir == FORWARD)
+ topline_back(&loff);
+ else
+ botline_forw(&loff);
+
+ int h2 = loff.height;
+ if (h2 == MAXCOL || h2 + h1 > min_height)
+ return min_height + 2; // no overlap
+ if (dir == FORWARD)
+ topline_back(&loff);
+ else
+ botline_forw(&loff);
+
+ int h3 = loff.height;
+ if (h3 == MAXCOL || h3 + h2 > min_height)
+ return min_height + 2; // no overlap
+ if (dir == FORWARD)
+ topline_back(&loff);
+ else
+ botline_forw(&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)
* and update the screen.
* Return FAIL for failure, OK otherwise.
*/
int
-onepage(int dir, long count)
+pagescroll(int dir, long count, int half)
{
#ifdef FEAT_DIFF
int prev_topfill = curwin->w_topfill;
linenr_T prev_topline = curwin->w_topline;
colnr_T prev_skipcol = curwin->w_skipcol;
- // Scroll 'window' or current window height lines.
- count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ?
- p_window : curwin->w_height) - 2;
+ if (half)
+ {
+ // Scroll [count], 'scroll' or current window height lines.
+ if (count)
+ curwin->w_p_scr = MIN(curwin->w_height, count);
+ count = MIN(curwin->w_height, curwin->w_p_scr);
+ }
+ else
+ // Scroll 'window' or current window height lines.
+ count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ?
+ p_window - 2 : get_scroll_overlap(dir));
if (curwin->w_p_sms)
scroll_redraw(dir == FORWARD, count);
scroll_redraw(dir == FORWARD, count);
curwin->w_p_sms = FALSE;
}
+#ifdef FEAT_FOLDING
+ // Move cursor to first line of closed fold.
+ foldAdjustCursor();
+#endif
int nochange = curwin->w_topline == prev_topline
#ifdef FEAT_DIFF
#endif
&& curwin->w_skipcol == prev_skipcol;
+ // Error if the viewport did not change and the cursor is already
+ // at the boundary.
if (nochange)
- beep_flush();
+ {
+ int prev_cursor = curwin->w_cursor.lnum;
+ curwin->w_cursor.lnum += (count + 1) * (dir == FORWARD ? 1 : -1);
+ check_cursor();
+ 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;
}
-/*
- * Scroll 'scroll' lines up or down.
- */
- void
-halfpage(int flag, linenr_T Prenum)
-{
- long scrolled = 0;
- int i;
- int n;
- int room;
-
- if (Prenum)
- curwin->w_p_scr = (Prenum > curwin->w_height) ?
- curwin->w_height : Prenum;
- n = (curwin->w_p_scr <= curwin->w_height) ?
- curwin->w_p_scr : curwin->w_height;
-
- update_topline();
- validate_botline();
- room = curwin->w_empty_rows;
-#ifdef FEAT_DIFF
- room += curwin->w_filler_rows;
-#endif
- if (flag)
- {
- /*
- * scroll the text up
- */
- while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
- {
-#ifdef FEAT_DIFF
- if (curwin->w_topfill > 0)
- {
- i = 1;
- --n;
- --curwin->w_topfill;
- }
- else
-#endif
- {
- i = PLINES_NOFILL(curwin->w_topline);
- n -= i;
- if (n < 0 && scrolled > 0)
- break;
-#ifdef FEAT_FOLDING
- (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
-#endif
- ++curwin->w_topline;
-#ifdef FEAT_DIFF
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
-#endif
-
- 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.
- */
-#ifdef FEAT_DIFF
- if (curwin->w_p_diff)
- curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
- else
-#endif
- {
- room += i;
- do
- {
- i = plines(curwin->w_botline);
- if (i > room)
- break;
-#ifdef FEAT_FOLDING
- (void)hasFolding(curwin->w_botline, NULL,
- &curwin->w_botline);
-#endif
- ++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)
- {
-# ifdef FEAT_FOLDING
- if (hasAnyFolding(curwin))
- {
- while (--n >= 0
- && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
- {
- (void)hasFolding(curwin->w_cursor.lnum, NULL,
- &curwin->w_cursor.lnum);
- ++curwin->w_cursor.lnum;
- }
- }
- else
-# endif
- curwin->w_cursor.lnum += n;
- check_cursor_lnum();
- }
- }
- else
- {
- /*
- * scroll the text down
- */
- while (n > 0 && curwin->w_topline > 1)
- {
-#ifdef FEAT_DIFF
- if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
- {
- i = 1;
- --n;
- ++curwin->w_topfill;
- }
- else
-#endif
- {
- i = PLINES_NOFILL(curwin->w_topline - 1);
- n -= i;
- if (n < 0 && scrolled > 0)
- break;
- --curwin->w_topline;
-#ifdef FEAT_FOLDING
- (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
-#endif
-#ifdef FEAT_DIFF
- curwin->w_topfill = 0;
-#endif
- }
- 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
-# ifdef FEAT_FOLDING
- if (hasAnyFolding(curwin))
- {
- while (--n >= 0 && curwin->w_cursor.lnum > 1)
- {
- --curwin->w_cursor.lnum;
- (void)hasFolding(curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
- }
- }
- else
-# endif
- curwin->w_cursor.lnum -= n;
- }
- }
-# ifdef FEAT_FOLDING
- // Move cursor to first line of closed fold.
- foldAdjustCursor();
-# endif
-#ifdef FEAT_DIFF
- check_topfill(curwin, !flag);
-#endif
- cursor_correct();
- beginline(BL_SOL | BL_FIX);
- redraw_later(UPD_VALID);
-}
-
void
do_check_cursorbind(void)
{
goto_tabpage((int)cap->count0);
}
else
- (void)onepage(cap->arg, cap->count1);
+ (void)pagescroll(cap->arg, cap->count1, FALSE);
}
/*
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);
}
/*
void scroll_cursor_bot(int min_scroll, int set_topbot);
void scroll_cursor_halfway(int atend, int prefer_above);
void cursor_correct(void);
-int onepage(int dir, long count);
-void halfpage(int flag, linenr_T Prenum);
+int pagescroll(int dir, long count, int half);
void do_check_cursorbind(void);
/* vim: set ft=c : */
-| +0&#ffffff0@39
-|T|h|e| |{|o|p|t|i|o|n|}| |a|r|g|u|m|e|n|t|s| |t|o| |"|:|s|e|t|"| |m|a|y| |b|e|
+|T+0&#ffffff0|h|e| |{|o|p|t|i|o|n|}| |a|r|g|u|m|e|n|t|s| |t|o| |"|:|s|e|t|"| |m|a|y| |b|e|
|r|e|p|e|a|t|e|d|.| @1|F|o|r| |e|x|a|m|p|l|e|:| |>| @14
-| +8&&@7>:|s|e|t| |a|i| |n|o|s|i| |s|w|=|3| |t|s|=|3| @9
-|I+0&&|f| |y|o|u| |m|a|k|e| |a|n| |e|r@1|o|r| |i|n| |o|n|e| |o|f| |t|h|e| |a|r|g|u|m
+@8|:|s|e|t| |a|i| |n|o|s|i| |s|w|=|3| |t|s|=|3| @9
+|I|f| |y|o|u| |m|a|k|e| |a|n| |e|r@1|o|r| |i|n| |o|n|e| |o|f| |t|h|e| |a|r|g|u|m
|e|n|t|s|,| |a|n| |e|r@1|o|r| |m|e|s@1|a|g|e| |w|i|l@1| |b|e| |g|i|v|e|n| @3
|a|n|d| |t|h|e| |f|o|l@1|o|w|i|n|g| |a|r|g|u|m|e|n|t|s| |w|i|l@1| |b|e| |i|g|n|o
|r|e|d|.| @35
@40
@40
@16|*|:|s|e|t|-|v|e|r|b|o|s|e|*| @9
-|W|h|e|n| |'|v|e|r|b|o|s|e|'| |i|s| |n|o|n|-|z|e|r|o|,| |d|i|s|p|l|a|y|i|n|g| |a
+>W+8&&|h|e|n| |'|v|e|r|b|o|s|e|'| |i|s| |n|o|n|-|z|e|r|o|,| |d|i|s|p|l|a|y|i|n|g| |a
|n| |o|p|t|i|o|n| |v|a|l|u|e| |w|i|l@1| |a|l|s|o| |t|e|l@1| |w|h|e|r|e| |i|t| @1
-|w|a|s| |l|a|s|t| |s|e|t|.| @1|E|x|a|m|p|l|e|:| |>| @14
+|w+0&&|a|s| |l|a|s|t| |s|e|t|.| @1|E|x|a|m|p|l|e|:| |>| @14
@8|:|v|e|r|b|o|s|e| |s|e|t| |s|h|i|f|t|w|i|d|t|h| |c|i|n|d|e|n|t|?
|<| @1|s|h|i|f|t|w|i|d|t|h|=|4| |~| @22
@10|L|a|s|t| |s|e|t| |f|r|o|m| |m|o|d|e|l|i|n|e| |l|i|n|e| |1|
|~| @38
@2|c|i|n|d|e|n|t| |~| @28
-@22|7|,|2|-|9| @8|4@1|%|
+|@+0#4040ff13&@2| @36
+| +0#0000000&@21|1|2|,|1| @9|5|0|%|
call feedkeys("i\<PageDown>\<esc>", 'tnix')
call assert_equal([0, 30, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 30, 1, 0], getpos('.'))
+ call assert_equal([0, 29, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 23, 1, 0], getpos('.'))
+ call assert_equal([0, 21, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 15, 1, 0], getpos('.'))
+ call assert_equal([0, 13, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 10, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 10, 11, 0], getpos('.'))
+ call assert_equal([0, 2, 11, 0], getpos('.'))
" <S-Up> is the same as <PageUp>
" <S-Down> is the same as <PageDown>
call cursor(1, 1)
call feedkeys("i\<S-Down>\<esc>", 'tnix')
call assert_equal([0, 30, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 30, 1, 0], getpos('.'))
+ call assert_equal([0, 29, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 23, 1, 0], getpos('.'))
+ call assert_equal([0, 21, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 15, 1, 0], getpos('.'))
+ call assert_equal([0, 13, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 10, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 10, 11, 0], getpos('.'))
+ call assert_equal([0, 2, 11, 0], getpos('.'))
set nostartofline
call cursor(30, 11)
norm! zt
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 30, 11, 0], getpos('.'))
+ call assert_equal([0, 29, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 23, 11, 0], getpos('.'))
+ call assert_equal([0, 21, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 15, 11, 0], getpos('.'))
+ call assert_equal([0, 13, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
call assert_equal([0, 10, 11, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix')
- call assert_equal([0, 10, 11, 0], getpos('.'))
+ call assert_equal([0, 2, 11, 0], getpos('.'))
call cursor(1, 1)
call feedkeys("A\<PageDown>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.'))
call cursor(30, 11)
norm! zt
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 30, 11, 0], getpos('.'))
+ call assert_equal([0, 29, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 23, 11, 0], getpos('.'))
+ call assert_equal([0, 21, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 15, 11, 0], getpos('.'))
+ call assert_equal([0, 13, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 10, 11, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix')
- call assert_equal([0, 10, 11, 0], getpos('.'))
+ call assert_equal([0, 2, 11, 0], getpos('.'))
call cursor(1, 1)
call feedkeys("A\<S-Down>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.'))
exe "normal \<C-D>"
call assert_equal(46, line('.'))
exe "normal \<C-U>"
- call assert_equal(36, line('.'))
+ call assert_equal(36, line('w0'))
+ call assert_equal(46, line('.'))
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>"
call assert_equal(1, line('.'))
set scroll&
call assert_equal(50, line('.'))
call assert_equal(100, line('w$'))
normal z.
- let lnum = winline()
exe "normal \<C-D>"
- call assert_equal(lnum, winline())
+ call assert_equal(1, winline())
call assert_equal(50, line('.'))
normal zt
exe "normal \<C-D>"
call assert_equal(2, &scroll)
set scroll=5
exe "norm! \<c-u>"
- call assert_equal('3', getline('.'))
+ call assert_equal('3', getline('w0'))
+ call assert_equal('8', getline('.'))
1
set scrolloff=5
exe "norm! \<c-d>"
call assert_equal(11, line('.'))
call assert_equal(1, winline())
exe "normal \<C-B>"
- call assert_equal(11, line('.'))
- call assert_equal(9, winline())
+ call assert_equal(10, line('.'))
+ call assert_equal(10, winline())
exe "normal \<C-B>\<C-B>"
call assert_equal(5, line('.'))
- call assert_equal(1, winline())
+ call assert_equal(5, winline())
bwipe!
endfunc
norm! {
call assert_equal([0, 1, 1, 0], getpos('.'))
- " Ctrl-B scrolls up with hidden "above" virtual text.
+ " 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!
call setline(1, 'abcde '->repeat(150))
exe "norm! \<C-F>"
- call assert_equal(320, winsaveview().skipcol)
+ call assert_equal(400, winsaveview().skipcol)
exe "norm! \<C-F>"
- call assert_equal(640, winsaveview().skipcol)
+ call assert_equal(800, winsaveview().skipcol)
exe "norm! \<C-F>"
call assert_equal(880, winsaveview().skipcol)
exe "norm! \<C-B>"
- call assert_equal(560, winsaveview().skipcol)
+ call assert_equal(480, winsaveview().skipcol)
exe "norm! \<C-B>"
- call assert_equal(240, winsaveview().skipcol)
+ 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
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 215,
/**/
214,
/**/