vim-patch:8.1.0864 Make 'scrolloff' and 'sidescrolloff' options window local (#11854)

Problem: cannot have a local value for 'scrolloff' and 'sidescrolloff'

Author: Bram Moolenar

375e339007
This commit is contained in:
Will Eccles
2020-03-17 15:05:34 -04:00
committed by GitHub
parent 5a5c2f0290
commit 87d892afa0
14 changed files with 245 additions and 126 deletions

View File

@@ -4900,13 +4900,17 @@ A jump table for the options with a short description can be found at |Q_op|.
*'scrolloff'* *'so'* *'scrolloff'* *'so'*
'scrolloff' 'so' number (default 0) 'scrolloff' 'so' number (default 0)
global global or local to window |global-local|
Minimal number of screen lines to keep above and below the cursor. Minimal number of screen lines to keep above and below the cursor.
This will make some context visible around where you are working. If This will make some context visible around where you are working. If
you set it to a very large value (999) the cursor line will always be you set it to a very large value (999) the cursor line will always be
in the middle of the window (except at the start or end of the file or in the middle of the window (except at the start or end of the file or
when long lines wrap). when long lines wrap).
For scrolling horizontally see 'sidescrolloff'. After using the local value, go back the global value with one of
these two: >
setlocal scrolloff<
setlocal scrolloff=-1
< For scrolling horizontally see 'sidescrolloff'.
*'scrollopt'* *'sbo'* *'scrollopt'* *'sbo'*
'scrollopt' 'sbo' string (default "ver,jump") 'scrollopt' 'sbo' string (default "ver,jump")
@@ -5515,7 +5519,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'sidescrolloff'* *'siso'* *'sidescrolloff'* *'siso'*
'sidescrolloff' 'siso' number (default 0) 'sidescrolloff' 'siso' number (default 0)
global global or local to window |global-local|
The minimal number of screen columns to keep to the left and to the The minimal number of screen columns to keep to the left and to the
right of the cursor if 'nowrap' is set. Setting this option to a right of the cursor if 'nowrap' is set. Setting this option to a
value greater than 0 while having |'sidescroll'| also at a non-zero value greater than 0 while having |'sidescroll'| also at a non-zero
@@ -5524,7 +5528,11 @@ A jump table for the options with a short description can be found at |Q_op|.
to a large value (like 999) has the effect of keeping the cursor to a large value (like 999) has the effect of keeping the cursor
horizontally centered in the window, as long as one does not come too horizontally centered in the window, as long as one does not come too
close to the beginning of the line. close to the beginning of the line.
After using the local value, go back the global value with one of
these two: >
setlocal sidescrolloff<
setlocal sidescrolloff=-1
<
Example: Try this together with 'sidescroll' and 'listchars' as Example: Try this together with 'sidescroll' and 'listchars' as
in the following example to never allow the cursor to move in the following example to never allow the cursor to move
onto the "extends" character: > onto the "extends" character: >

View File

@@ -1278,16 +1278,18 @@ struct window_S {
winopt_T w_onebuf_opt; winopt_T w_onebuf_opt;
winopt_T w_allbuf_opt; winopt_T w_allbuf_opt;
/* A few options have local flags for P_INSECURE. */ // A few options have local flags for P_INSECURE.
uint32_t w_p_stl_flags; /* flags for 'statusline' */ uint32_t w_p_stl_flags; // flags for 'statusline'
uint32_t w_p_fde_flags; /* flags for 'foldexpr' */ uint32_t w_p_fde_flags; // flags for 'foldexpr'
uint32_t w_p_fdt_flags; /* flags for 'foldtext' */ uint32_t w_p_fdt_flags; // flags for 'foldtext'
int *w_p_cc_cols; /* array of columns to highlight or NULL */ int *w_p_cc_cols; // array of columns to highlight or NULL
int w_p_brimin; /* minimum width for breakindent */ int w_p_brimin; // minimum width for breakindent
int w_p_brishift; /* additional shift for breakindent */ int w_p_brishift; // additional shift for breakindent
bool w_p_brisbr; /* sbr in 'briopt' */ bool w_p_brisbr; // sbr in 'briopt'
long w_p_siso; // 'sidescrolloff' local value
long w_p_so; // 'scrolloff' local value
/* transform a pointer to a "onebuf" option into a "allbuf" option */ // transform a pointer to a "onebuf" option into a "allbuf" option
#define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T)) #define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T))
long w_scbind_pos; long w_scbind_pos;

View File

@@ -593,7 +593,7 @@ static int insert_check(VimState *state)
if (curwin->w_wcol < s->mincol - curbuf->b_p_ts if (curwin->w_wcol < s->mincol - curbuf->b_p_ts
&& curwin->w_wrow == curwin->w_winrow && curwin->w_wrow == curwin->w_winrow
+ curwin->w_height_inner - 1 - p_so + curwin->w_height_inner - 1 - get_scrolloff_value()
&& (curwin->w_cursor.lnum != curwin->w_topline && (curwin->w_cursor.lnum != curwin->w_topline
|| curwin->w_topfill > 0)) { || curwin->w_topfill > 0)) {
if (curwin->w_topfill > 0) { if (curwin->w_topfill > 0) {

View File

@@ -2177,6 +2177,7 @@ int do_ecmd(
int did_get_winopts = FALSE; int did_get_winopts = FALSE;
int readfile_flags = 0; int readfile_flags = 0;
bool did_inc_redrawing_disabled = false; bool did_inc_redrawing_disabled = false;
long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
if (eap != NULL) if (eap != NULL)
command = eap->do_ecmd_cmd; command = eap->do_ecmd_cmd;
@@ -2678,13 +2679,14 @@ int do_ecmd(
RedrawingDisabled--; RedrawingDisabled--;
did_inc_redrawing_disabled = false; did_inc_redrawing_disabled = false;
if (!skip_redraw) { if (!skip_redraw) {
n = p_so; n = *so_ptr;
if (topline == 0 && command == NULL) if (topline == 0 && command == NULL) {
p_so = 999; // force cursor to be vertically centered in the window *so_ptr = 999; // force cursor to be vertically centered in the window
}
update_topline(); update_topline();
curwin->w_scbind_pos = curwin->w_topline; curwin->w_scbind_pos = curwin->w_topline;
p_so = n; *so_ptr = n;
redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */ redraw_curbuf_later(NOT_VALID); // redraw this buffer later
} }
if (p_im) if (p_im)

View File

@@ -7367,7 +7367,7 @@ static void ex_syncbind(exarg_T *eap)
topline = curwin->w_topline; topline = curwin->w_topline;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_scb && wp->w_buffer) { if (wp->w_p_scb && wp->w_buffer) {
y = wp->w_buffer->b_ml.ml_line_count - p_so; y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value();
if (topline > y) { if (topline > y) {
topline = y; topline = y;
} }

View File

@@ -142,7 +142,8 @@ void update_topline(void)
int old_topfill; int old_topfill;
bool check_topline = false; bool check_topline = false;
bool check_botline = false; bool check_botline = false;
long save_so = p_so; long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
long save_so = *so_ptr;
// If there is no valid screen and when the window height is zero just use // If there is no valid screen and when the window height is zero just use
// the cursor line. // the cursor line.
@@ -158,9 +159,10 @@ void update_topline(void)
if (curwin->w_valid & VALID_TOPLINE) if (curwin->w_valid & VALID_TOPLINE)
return; return;
/* When dragging with the mouse, don't scroll that quickly */ // When dragging with the mouse, don't scroll that quickly
if (mouse_dragging > 0) if (mouse_dragging > 0) {
p_so = mouse_dragging - 1; *so_ptr = mouse_dragging - 1;
}
old_topline = curwin->w_topline; old_topline = curwin->w_topline;
old_topfill = curwin->w_topfill; old_topfill = curwin->w_topfill;
@@ -206,15 +208,17 @@ void update_topline(void)
* scrolled). */ * scrolled). */
n = 0; n = 0;
for (linenr_T lnum = curwin->w_cursor.lnum; for (linenr_T lnum = curwin->w_cursor.lnum;
lnum < curwin->w_topline + p_so; ++lnum) { lnum < curwin->w_topline + *so_ptr; lnum++) {
++n; n++;
/* stop at end of file or when we know we are far off */ // stop at end of file or when we know we are far off
if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) {
break; break;
}
(void)hasFolding(lnum, NULL, &lnum); (void)hasFolding(lnum, NULL, &lnum);
} }
} else } else {
n = curwin->w_topline + p_so - curwin->w_cursor.lnum; n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum;
}
/* If we weren't very close to begin with, we scroll to put the /* If we weren't very close to begin with, we scroll to put the
* cursor in the middle of the window. Otherwise put the cursor * cursor in the middle of the window. Otherwise put the cursor
@@ -247,7 +251,7 @@ void update_topline(void)
if (curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_botline <= curbuf->b_ml.ml_line_count) {
if (curwin->w_cursor.lnum < curwin->w_botline) { if (curwin->w_cursor.lnum < curwin->w_botline) {
if (((long)curwin->w_cursor.lnum if (((long)curwin->w_cursor.lnum
>= (long)curwin->w_botline - p_so >= (long)curwin->w_botline - *so_ptr
|| hasAnyFolding(curwin) || hasAnyFolding(curwin)
)) { )) {
lineoff_T loff; lineoff_T loff;
@@ -266,13 +270,15 @@ void update_topline(void)
&& (loff.lnum + 1 < curwin->w_botline || loff.fill == 0) && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
) { ) {
n += loff.height; n += loff.height;
if (n >= p_so) if (n >= *so_ptr) {
break; break;
}
botline_forw(&loff); botline_forw(&loff);
} }
if (n >= p_so) if (n >= *so_ptr) {
/* sufficient context, no need to scroll */ // sufficient context, no need to scroll
check_botline = false; check_botline = false;
}
} else { } else {
/* sufficient context, no need to scroll */ /* sufficient context, no need to scroll */
check_botline = false; check_botline = false;
@@ -285,7 +291,7 @@ void update_topline(void)
* botline - p_so (approximation of how much will be * botline - p_so (approximation of how much will be
* scrolled). */ * scrolled). */
for (linenr_T lnum = curwin->w_cursor.lnum; for (linenr_T lnum = curwin->w_cursor.lnum;
lnum >= curwin->w_botline - p_so; lnum--) { lnum >= curwin->w_botline - *so_ptr; lnum--) {
line_count++; line_count++;
// stop at end of file or when we know we are far off // stop at end of file or when we know we are far off
if (lnum <= 0 || line_count > curwin->w_height_inner + 1) { if (lnum <= 0 || line_count > curwin->w_height_inner + 1) {
@@ -295,7 +301,7 @@ void update_topline(void)
} }
} else } else
line_count = curwin->w_cursor.lnum - curwin->w_botline line_count = curwin->w_cursor.lnum - curwin->w_botline
+ 1 + p_so; + 1 + *so_ptr;
if (line_count <= curwin->w_height_inner + 1) { if (line_count <= curwin->w_height_inner + 1) {
scroll_cursor_bot(scrolljump_value(), false); scroll_cursor_bot(scrolljump_value(), false);
} else { } else {
@@ -324,7 +330,7 @@ void update_topline(void)
validate_cursor(); validate_cursor();
} }
p_so = save_so; *so_ptr = save_so;
} }
/* /*
@@ -356,26 +362,29 @@ static int scrolljump_value(void)
*/ */
static bool check_top_offset(void) static bool check_top_offset(void)
{ {
if (curwin->w_cursor.lnum < curwin->w_topline + p_so long so = get_scrolloff_value();
if (curwin->w_cursor.lnum < curwin->w_topline + so
|| hasAnyFolding(curwin) || hasAnyFolding(curwin)
) { ) {
lineoff_T loff; lineoff_T loff;
loff.lnum = curwin->w_cursor.lnum; loff.lnum = curwin->w_cursor.lnum;
loff.fill = 0; loff.fill = 0;
int n = curwin->w_topfill; /* always have this context */ int n = curwin->w_topfill; // always have this context
/* Count the visible screen lines above the cursor line. */ // Count the visible screen lines above the cursor line.
while (n < p_so) { while (n < so) {
topline_back(&loff); topline_back(&loff);
/* Stop when included a line above the window. */ // Stop when included a line above the window.
if (loff.lnum < curwin->w_topline if (loff.lnum < curwin->w_topline
|| (loff.lnum == curwin->w_topline && loff.fill > 0) || (loff.lnum == curwin->w_topline && loff.fill > 0)
) ) {
break; break;
}
n += loff.height; n += loff.height;
} }
if (n < p_so) if (n < so) {
return true; return true;
} }
}
return false; return false;
} }
@@ -714,6 +723,8 @@ void curs_columns(
colnr_T startcol; colnr_T startcol;
colnr_T endcol; colnr_T endcol;
colnr_T prev_skipcol; colnr_T prev_skipcol;
long so = get_scrolloff_value();
long siso = get_sidescrolloff_value();
/* /*
* First make sure that w_topline is valid (after moving the cursor). * First make sure that w_topline is valid (after moving the cursor).
@@ -785,10 +796,10 @@ void curs_columns(
* If we get closer to the edge than 'sidescrolloff', scroll a little * If we get closer to the edge than 'sidescrolloff', scroll a little
* extra * extra
*/ */
assert(p_siso <= INT_MAX); assert(siso <= INT_MAX);
int off_left = startcol - curwin->w_leftcol - (int)p_siso; int off_left = startcol - curwin->w_leftcol - (int)siso;
int off_right = int off_right =
endcol - curwin->w_leftcol - curwin->w_width_inner + (int)p_siso + 1; endcol - curwin->w_leftcol - curwin->w_width_inner + (int)siso + 1;
if (off_left < 0 || off_right > 0) { if (off_left < 0 || off_right > 0) {
int diff = (off_left < 0) ? -off_left: off_right; int diff = (off_left < 0) ? -off_left: off_right;
@@ -834,7 +845,7 @@ void curs_columns(
int plines = 0; int plines = 0;
if ((curwin->w_wrow >= curwin->w_height_inner if ((curwin->w_wrow >= curwin->w_height_inner
|| ((prev_skipcol > 0 || ((prev_skipcol > 0
|| curwin->w_wrow + p_so >= curwin->w_height_inner) || curwin->w_wrow + so >= curwin->w_height_inner)
&& (plines = && (plines =
plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1 plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1
>= curwin->w_height_inner)) >= curwin->w_height_inner))
@@ -850,17 +861,18 @@ void curs_columns(
* 2: Less than "p_so" lines below * 2: Less than "p_so" lines below
* 3: both of them */ * 3: both of them */
extra = 0; extra = 0;
if (curwin->w_skipcol + p_so * width > curwin->w_virtcol) if (curwin->w_skipcol + so * width > curwin->w_virtcol) {
extra = 1; extra = 1;
/* Compute last display line of the buffer line that we want at the }
* bottom of the window. */ // Compute last display line of the buffer line that we want at the
// bottom of the window.
if (plines == 0) { if (plines == 0) {
plines = plines_win(curwin, curwin->w_cursor.lnum, false); plines = plines_win(curwin, curwin->w_cursor.lnum, false);
} }
plines--; plines--;
if (plines > curwin->w_wrow + p_so) { if (plines > curwin->w_wrow + so) {
assert(p_so <= INT_MAX); assert(so <= INT_MAX);
n = curwin->w_wrow + (int)p_so; n = curwin->w_wrow + (int)so;
} else { } else {
n = plines; n = plines;
} }
@@ -868,7 +880,7 @@ void curs_columns(
extra += 2; extra += 2;
} }
if (extra == 3 || plines < p_so * 2) { if (extra == 3 || plines < so * 2) {
// not enough room for 'scrolloff', put cursor in the middle // not enough room for 'scrolloff', put cursor in the middle
n = curwin->w_virtcol / width; n = curwin->w_virtcol / width;
if (n > curwin->w_height_inner / 2) { if (n > curwin->w_height_inner / 2) {
@@ -882,9 +894,9 @@ void curs_columns(
} }
curwin->w_skipcol = n * width; curwin->w_skipcol = n * width;
} else if (extra == 1) { } else if (extra == 1) {
/* less then 'scrolloff' lines above, decrease skipcol */ // less then 'scrolloff' lines above, decrease skipcol
assert(p_so <= INT_MAX); assert(so <= INT_MAX);
extra = (curwin->w_skipcol + (int)p_so * width - curwin->w_virtcol extra = (curwin->w_skipcol + (int)so * width - curwin->w_virtcol
+ width - 1) / width; + width - 1) / width;
if (extra > 0) { if (extra > 0) {
if ((colnr_T)(extra * width) > curwin->w_skipcol) if ((colnr_T)(extra * width) > curwin->w_skipcol)
@@ -1206,7 +1218,7 @@ void scrolldown_clamp(void)
end_row += curwin->w_cline_height - 1 - end_row += curwin->w_cline_height - 1 -
curwin->w_virtcol / curwin->w_width_inner; curwin->w_virtcol / curwin->w_width_inner;
} }
if (end_row < curwin->w_height_inner - p_so) { if (end_row < curwin->w_height_inner - get_scrolloff_value()) {
if (can_fill) { if (can_fill) {
++curwin->w_topfill; ++curwin->w_topfill;
check_topfill(curwin, true); check_topfill(curwin, true);
@@ -1246,14 +1258,14 @@ void scrollup_clamp(void)
validate_virtcol(); validate_virtcol();
start_row -= curwin->w_virtcol / curwin->w_width_inner; start_row -= curwin->w_virtcol / curwin->w_width_inner;
} }
if (start_row >= p_so) { if (start_row >= get_scrolloff_value()) {
if (curwin->w_topfill > 0) if (curwin->w_topfill > 0) {
--curwin->w_topfill; curwin->w_topfill--;
else { } else {
(void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline); (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
++curwin->w_topline; curwin->w_topline++;
} }
++curwin->w_botline; /* approximate w_botline */ curwin->w_botline++; // approximate w_botline
curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
} }
} }
@@ -1349,8 +1361,7 @@ void scroll_cursor_top(int min_scroll, int always)
linenr_T old_topline = curwin->w_topline; linenr_T old_topline = curwin->w_topline;
linenr_T old_topfill = curwin->w_topfill; linenr_T old_topfill = curwin->w_topfill;
linenr_T new_topline; linenr_T new_topline;
assert(p_so <= INT_MAX); int off = (int)get_scrolloff_value();
int off = (int)p_so;
if (mouse_dragging > 0) if (mouse_dragging > 0)
off = mouse_dragging - 1; off = mouse_dragging - 1;
@@ -1492,7 +1503,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
linenr_T old_botline = curwin->w_botline; linenr_T old_botline = curwin->w_botline;
int old_valid = curwin->w_valid; int old_valid = curwin->w_valid;
int old_empty_rows = curwin->w_empty_rows; int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; /* Cursor Line Number */ linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
long so = get_scrolloff_value();
if (set_topbot) { if (set_topbot) {
used = 0; used = 0;
@@ -1551,7 +1563,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
/* Stop when scrolled nothing or at least "min_scroll", found "extra" /* Stop when scrolled nothing or at least "min_scroll", found "extra"
* context for 'scrolloff' and counted all lines below the window. */ * context for 'scrolloff' and counted all lines below the window. */
if ((((scrolled <= 0 || scrolled >= min_scroll) if ((((scrolled <= 0 || scrolled >= min_scroll)
&& extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : p_so)) && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : so))
|| boff.lnum + 1 > curbuf->b_ml.ml_line_count) || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
&& loff.lnum <= curwin->w_botline && loff.lnum <= curwin->w_botline
&& (loff.lnum < curwin->w_botline && (loff.lnum < curwin->w_botline
@@ -1589,7 +1601,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
if (used > curwin->w_height_inner) { if (used > curwin->w_height_inner) {
break; break;
} }
if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : p_so) if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : so)
|| scrolled < min_scroll) { || scrolled < min_scroll) {
extra += boff.height; extra += boff.height;
if (boff.lnum >= curwin->w_botline if (boff.lnum >= curwin->w_botline
@@ -1724,9 +1736,8 @@ void cursor_correct(void)
* How many lines we would like to have above/below the cursor depends on * How many lines we would like to have above/below the cursor depends on
* whether the first/last line of the file is on screen. * whether the first/last line of the file is on screen.
*/ */
assert(p_so <= INT_MAX); int above_wanted = (int)get_scrolloff_value();
int above_wanted = (int)p_so; int below_wanted = (int)get_scrolloff_value();
int below_wanted = (int)p_so;
if (mouse_dragging > 0) { if (mouse_dragging > 0) {
above_wanted = mouse_dragging - 1; above_wanted = mouse_dragging - 1;
below_wanted = mouse_dragging - 1; below_wanted = mouse_dragging - 1;
@@ -1821,6 +1832,7 @@ int onepage(Direction dir, long count)
int retval = OK; int retval = OK;
lineoff_T loff; lineoff_T loff;
linenr_T old_topline = curwin->w_topline; linenr_T old_topline = curwin->w_topline;
long so = get_scrolloff_value();
if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */ if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */
beep_flush(); beep_flush();
@@ -1836,7 +1848,7 @@ int onepage(Direction dir, long count)
* last line. * last line.
*/ */
if (dir == FORWARD if (dir == FORWARD
? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so) ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
&& curwin->w_botline > curbuf->b_ml.ml_line_count) && curwin->w_botline > curbuf->b_ml.ml_line_count)
: (curwin->w_topline == 1 : (curwin->w_topline == 1
&& curwin->w_topfill == && curwin->w_topfill ==

View File

@@ -2584,13 +2584,14 @@ do_mouse (
/* Set global flag that we are extending the Visual area with mouse /* Set global flag that we are extending the Visual area with mouse
* dragging; temporarily minimize 'scrolloff'. */ * dragging; temporarily minimize 'scrolloff'. */
if (VIsual_active && is_drag && p_so) { if (VIsual_active && is_drag && get_scrolloff_value()) {
/* In the very first line, allow scrolling one line */ // In the very first line, allow scrolling one line
if (mouse_row == 0) if (mouse_row == 0) {
mouse_dragging = 2; mouse_dragging = 2;
else } else {
mouse_dragging = 1; mouse_dragging = 1;
} }
}
/* When dragging the mouse above the window, scroll down. */ /* When dragging the mouse above the window, scroll down. */
if (is_drag && mouse_row < 0 && !in_status_line) { if (is_drag && mouse_row < 0 && !in_status_line) {
@@ -4089,9 +4090,9 @@ void scroll_redraw(int up, long count)
scrollup(count, true); scrollup(count, true);
else else
scrolldown(count, true); scrolldown(count, true);
if (p_so) { if (get_scrolloff_value()) {
/* Adjust the cursor position for 'scrolloff'. Mark w_topline as // Adjust the cursor position for 'scrolloff'. Mark w_topline as
* valid, otherwise the screen jumps back at the end of the file. */ // valid, otherwise the screen jumps back at the end of the file.
cursor_correct(); cursor_correct();
check_cursor_moved(curwin); check_cursor_moved(curwin);
curwin->w_valid |= VALID_TOPLINE; curwin->w_valid |= VALID_TOPLINE;
@@ -4135,8 +4136,8 @@ static void nv_zet(cmdarg_T *cap)
int old_fen = curwin->w_p_fen; int old_fen = curwin->w_p_fen;
bool undo = false; bool undo = false;
assert(p_siso <= INT_MAX); int l_p_siso = (int)get_sidescrolloff_value();
int l_p_siso = (int)p_siso; assert(l_p_siso <= INT_MAX);
if (ascii_isdigit(nchar)) { if (ascii_isdigit(nchar)) {
/* /*

View File

@@ -904,11 +904,19 @@ set_option_default(
if (options[opt_idx].indir == PV_SCROLL) { if (options[opt_idx].indir == PV_SCROLL) {
win_comp_scroll(curwin); win_comp_scroll(curwin);
} else { } else {
*(long *)varp = (long)(intptr_t)options[opt_idx].def_val[dvi]; long def_val = (long)options[opt_idx].def_val[dvi];
if ((long *)varp == &curwin->w_p_so
|| (long *)varp == &curwin->w_p_siso) {
// 'scrolloff' and 'sidescrolloff' local values have a
// different default value than the global default.
*(long *)varp = -1;
} else {
*(long *)varp = def_val;
}
// May also set global value for local option. // May also set global value for local option.
if (both) { if (both) {
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
*(long *)varp; def_val;
} }
} }
} else { // P_BOOL } else { // P_BOOL
@@ -4349,7 +4357,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
} }
} else if (pp == &p_so) { } else if (pp == &p_so) {
if (value < 0 && full_screen) { if (value < 0 && full_screen) {
errmsg = e_scroll; errmsg = e_positive;
} }
} else if (pp == &p_siso) { } else if (pp == &p_siso) {
if (value < 0 && full_screen) { if (value < 0 && full_screen) {
@@ -5634,6 +5642,12 @@ void unset_global_local_option(char *name, void *from)
clear_string_option(&buf->b_p_tc); clear_string_option(&buf->b_p_tc);
buf->b_tc_flags = 0; buf->b_tc_flags = 0;
break; break;
case PV_SISO:
curwin->w_p_siso = -1;
break;
case PV_SO:
curwin->w_p_so = -1;
break;
case PV_DEF: case PV_DEF:
clear_string_option(&buf->b_p_def); clear_string_option(&buf->b_p_def);
break; break;
@@ -5706,6 +5720,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
case PV_AR: return (char_u *)&(curbuf->b_p_ar); case PV_AR: return (char_u *)&(curbuf->b_p_ar);
case PV_TAGS: return (char_u *)&(curbuf->b_p_tags); case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
case PV_TC: return (char_u *)&(curbuf->b_p_tc); case PV_TC: return (char_u *)&(curbuf->b_p_tc);
case PV_SISO: return (char_u *)&(curwin->w_p_siso);
case PV_SO: return (char_u *)&(curwin->w_p_so);
case PV_DEF: return (char_u *)&(curbuf->b_p_def); case PV_DEF: return (char_u *)&(curbuf->b_p_def);
case PV_INC: return (char_u *)&(curbuf->b_p_inc); case PV_INC: return (char_u *)&(curbuf->b_p_inc);
case PV_DICT: return (char_u *)&(curbuf->b_p_dict); case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
@@ -5750,6 +5766,10 @@ static char_u *get_varp(vimoption_T *p)
? (char_u *)&(curbuf->b_p_tags) : p->var; ? (char_u *)&(curbuf->b_p_tags) : p->var;
case PV_TC: return *curbuf->b_p_tc != NUL case PV_TC: return *curbuf->b_p_tc != NUL
? (char_u *)&(curbuf->b_p_tc) : p->var; ? (char_u *)&(curbuf->b_p_tc) : p->var;
case PV_SISO: return curwin->w_p_siso >= 0
? (char_u *)&(curwin->w_p_siso) : p->var;
case PV_SO: return curwin->w_p_so >= 0
? (char_u *)&(curwin->w_p_so) : p->var;
case PV_BKC: return *curbuf->b_p_bkc != NUL case PV_BKC: return *curbuf->b_p_bkc != NUL
? (char_u *)&(curbuf->b_p_bkc) : p->var; ? (char_u *)&(curbuf->b_p_bkc) : p->var;
case PV_DEF: return *curbuf->b_p_def != NUL case PV_DEF: return *curbuf->b_p_def != NUL
@@ -7485,3 +7505,18 @@ dict_T *get_winbuf_options(const int bufopt)
return d; return d;
} }
/// Return the effective 'scrolloff' value for the current window, using the
/// global value when appropriate.
long get_scrolloff_value(void)
{
return curwin->w_p_so < 0 ? p_so : curwin->w_p_so;
}
/// Return the effective 'sidescrolloff' value for the current window, using the
/// global value when appropriate.
long get_sidescrolloff_value(void)
{
return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso;
}

View File

@@ -835,6 +835,8 @@ enum {
, WV_RLC , WV_RLC
, WV_SCBIND , WV_SCBIND
, WV_SCROLL , WV_SCROLL
, WV_SISO
, WV_SO
, WV_SPELL , WV_SPELL
, WV_CUC , WV_CUC
, WV_CUL , WV_CUL

View File

@@ -1990,7 +1990,7 @@ return {
}, },
{ {
full_name='scrolloff', abbreviation='so', full_name='scrolloff', abbreviation='so',
type='number', scope={'global'}, type='number', scope={'global', 'window'},
vi_def=true, vi_def=true,
vim=true, vim=true,
redraw={'all_windows'}, redraw={'all_windows'},
@@ -2229,10 +2229,10 @@ return {
}, },
{ {
full_name='sidescrolloff', abbreviation='siso', full_name='sidescrolloff', abbreviation='siso',
type='number', scope={'global'}, type='number', scope={'global', 'window'},
vi_def=true, vi_def=true,
vim=true, vim=true,
redraw={'current_buffer'}, redraw={'all_windows'},
varname='p_siso', varname='p_siso',
defaults={if_true={vi=0}} defaults={if_true={vi=0}}
}, },

View File

@@ -2227,6 +2227,8 @@ showmatch(
pos_T *lpos, save_cursor; pos_T *lpos, save_cursor;
pos_T mpos; pos_T mpos;
colnr_T vcol; colnr_T vcol;
long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
long *siso = curwin->w_p_siso >= 0 ? &curwin->w_p_siso : &p_siso;
long save_so; long save_so;
long save_siso; long save_siso;
int save_state; int save_state;
@@ -2262,23 +2264,24 @@ showmatch(
&& vcol < curwin->w_leftcol + curwin->w_width_inner)) { && vcol < curwin->w_leftcol + curwin->w_width_inner)) {
mpos = *lpos; // save the pos, update_screen() may change it mpos = *lpos; // save the pos, update_screen() may change it
save_cursor = curwin->w_cursor; save_cursor = curwin->w_cursor;
save_so = p_so; save_so = *so;
save_siso = p_siso; save_siso = *siso;
/* Handle "$" in 'cpo': If the ')' is typed on top of the "$", // Handle "$" in 'cpo': If the ')' is typed on top of the "$",
* stop displaying the "$". */ // stop displaying the "$".
if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) {
dollar_vcol = -1; dollar_vcol = -1;
++curwin->w_virtcol; /* do display ')' just before "$" */ }
update_screen(VALID); /* show the new char first */ curwin->w_virtcol++; // do display ')' just before "$"
update_screen(VALID); // show the new char first
save_dollar_vcol = dollar_vcol; save_dollar_vcol = dollar_vcol;
save_state = State; save_state = State;
State = SHOWMATCH; State = SHOWMATCH;
ui_cursor_shape(); /* may show different cursor shape */ ui_cursor_shape(); // may show different cursor shape
curwin->w_cursor = mpos; /* move to matching char */ curwin->w_cursor = mpos; // move to matching char
p_so = 0; /* don't use 'scrolloff' here */ *so = 0; // don't use 'scrolloff' here
p_siso = 0; /* don't use 'sidescrolloff' here */ *siso = 0; // don't use 'sidescrolloff' here
showruler(FALSE); showruler(false);
setcursor(); setcursor();
ui_flush(); ui_flush();
/* Restore dollar_vcol(), because setcursor() may call curs_rows() /* Restore dollar_vcol(), because setcursor() may call curs_rows()
@@ -2294,11 +2297,11 @@ showmatch(
os_delay(p_mat * 100L, true); os_delay(p_mat * 100L, true);
else if (!char_avail()) else if (!char_avail())
os_delay(p_mat * 100L, false); os_delay(p_mat * 100L, false);
curwin->w_cursor = save_cursor; /* restore cursor position */ curwin->w_cursor = save_cursor; // restore cursor position
p_so = save_so; *so = save_so;
p_siso = save_siso; *siso = save_siso;
State = save_state; State = save_state;
ui_cursor_shape(); /* may show different cursor shape */ ui_cursor_shape(); // may show different cursor shape
} }
} }
} }

View File

@@ -512,6 +512,41 @@ func Test_shortmess_F2()
bwipe bwipe
endfunc endfunc
func Test_local_scrolloff()
set so=5
set siso=7
split
call assert_equal(5, &so)
setlocal so=3
call assert_equal(3, &so)
wincmd w
call assert_equal(5, &so)
wincmd w
setlocal so<
call assert_equal(5, &so)
setlocal so=0
call assert_equal(0, &so)
setlocal so=-1
call assert_equal(5, &so)
call assert_equal(7, &siso)
setlocal siso=3
call assert_equal(3, &siso)
wincmd w
call assert_equal(7, &siso)
wincmd w
setlocal siso<
call assert_equal(7, &siso)
setlocal siso=0
call assert_equal(0, &siso)
setlocal siso=-1
call assert_equal(7, &siso)
close
set so&
set siso&
endfunc
func Test_visualbell() func Test_visualbell()
set belloff= set belloff=
set visualbell set visualbell

View File

@@ -4689,6 +4689,10 @@ static win_T *win_alloc(win_T *after, int hidden)
new_wp->w_floating = 0; new_wp->w_floating = 0;
new_wp->w_float_config = FLOAT_CONFIG_INIT; new_wp->w_float_config = FLOAT_CONFIG_INIT;
// use global option for global-local options
new_wp->w_p_so = -1;
new_wp->w_p_siso = -1;
/* We won't calculate w_fraction until resizing the window */ /* We won't calculate w_fraction until resizing the window */
new_wp->w_fraction = 0; new_wp->w_fraction = 0;
new_wp->w_prev_fraction_row = -1; new_wp->w_prev_fraction_row = -1;
@@ -5799,9 +5803,10 @@ void scroll_to_fraction(win_T *wp, int prev_height)
} }
if (wp == curwin) { if (wp == curwin) {
if (p_so) if (get_scrolloff_value()) {
update_topline(); update_topline();
curs_columns(FALSE); /* validate w_wrow */ }
curs_columns(false); // validate w_wrow
} }
if (prev_height > 0) { if (prev_height > 0) {
wp->w_prev_fraction_row = wp->w_wrow; wp->w_prev_fraction_row = wp->w_wrow;

View File

@@ -65,8 +65,6 @@ describe(':set validation', function()
should_succeed('regexpengine', 2) should_succeed('regexpengine', 2)
should_fail('report', -1, 'E487') should_fail('report', -1, 'E487')
should_succeed('report', 0) should_succeed('report', 0)
should_fail('scrolloff', -1, 'E49')
should_fail('sidescrolloff', -1, 'E487')
should_fail('sidescroll', -1, 'E487') should_fail('sidescroll', -1, 'E487')
should_fail('cmdwinheight', 0, 'E487') should_fail('cmdwinheight', 0, 'E487')
should_fail('updatetime', -1, 'E487') should_fail('updatetime', -1, 'E487')
@@ -82,6 +80,22 @@ describe(':set validation', function()
meths.set_option('window', -10) meths.set_option('window', -10)
eq(23, meths.get_option('window')) eq(23, meths.get_option('window'))
eq('', eval("v:errmsg")) eq('', eval("v:errmsg"))
-- 'scrolloff' and 'sidescrolloff' can have a -1 value when
-- set for the current window, but not globally
feed_command('setglobal scrolloff=-1')
eq('E487', eval("v:errmsg"):match("E%d*"))
feed_command('setglobal sidescrolloff=-1')
eq('E487', eval("v:errmsg"):match("E%d*"))
feed_command('let v:errmsg=""')
feed_command('setlocal scrolloff=-1')
eq('', eval("v:errmsg"))
feed_command('setlocal sidescrolloff=-1')
eq('', eval("v:errmsg"))
end) end)
it('set wmh/wh wmw/wiw checks', function() it('set wmh/wh wmw/wiw checks', function()