diff options
author | Will Eccles <will@eccles.dev> | 2020-03-17 15:05:34 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-17 20:05:34 +0100 |
commit | 87d892afa0475644e91d9c8a57b7c35491c4dc32 (patch) | |
tree | a3d0f66e64156fbbb47864a6ed36129bd7c41318 /src | |
parent | 5a5c2f0290b5cdb8ccc1a06cb41f248ab25fd792 (diff) | |
download | rneovim-87d892afa0475644e91d9c8a57b7c35491c4dc32.tar.gz rneovim-87d892afa0475644e91d9c8a57b7c35491c4dc32.tar.bz2 rneovim-87d892afa0475644e91d9c8a57b7c35491c4dc32.zip |
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
https://github.com/vim/vim/commit/375e3390078e740d3c83b0c118c50d9a920036c7
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer_defs.h | 22 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 12 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/move.c | 120 | ||||
-rw-r--r-- | src/nvim/normal.c | 19 | ||||
-rw-r--r-- | src/nvim/option.c | 75 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 6 | ||||
-rw-r--r-- | src/nvim/search.c | 35 | ||||
-rw-r--r-- | src/nvim/testdir/test_options.vim | 35 | ||||
-rw-r--r-- | src/nvim/window.c | 9 |
12 files changed, 218 insertions, 121 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 1f943b25b6..3993f61a3d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1278,16 +1278,18 @@ struct window_S { winopt_T w_onebuf_opt; winopt_T w_allbuf_opt; - /* A few options have local flags for P_INSECURE. */ - uint32_t w_p_stl_flags; /* flags for 'statusline' */ - uint32_t w_p_fde_flags; /* flags for 'foldexpr' */ - uint32_t w_p_fdt_flags; /* flags for 'foldtext' */ - int *w_p_cc_cols; /* array of columns to highlight or NULL */ - int w_p_brimin; /* minimum width for breakindent */ - int w_p_brishift; /* additional shift for breakindent */ - bool w_p_brisbr; /* sbr in 'briopt' */ - - /* transform a pointer to a "onebuf" option into a "allbuf" option */ + // A few options have local flags for P_INSECURE. + uint32_t w_p_stl_flags; // flags for 'statusline' + uint32_t w_p_fde_flags; // flags for 'foldexpr' + uint32_t w_p_fdt_flags; // flags for 'foldtext' + int *w_p_cc_cols; // array of columns to highlight or NULL + int w_p_brimin; // minimum width for breakindent + int w_p_brishift; // additional shift for breakindent + 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 #define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T)) long w_scbind_pos; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index f938607f17..c7867f22c5 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -593,7 +593,7 @@ static int insert_check(VimState *state) if (curwin->w_wcol < s->mincol - curbuf->b_p_ts && 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_topfill > 0)) { if (curwin->w_topfill > 0) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a2c4435014..1cd95f2ed9 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2177,6 +2177,7 @@ int do_ecmd( int did_get_winopts = FALSE; int readfile_flags = 0; bool did_inc_redrawing_disabled = false; + long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; if (eap != NULL) command = eap->do_ecmd_cmd; @@ -2678,13 +2679,14 @@ int do_ecmd( RedrawingDisabled--; did_inc_redrawing_disabled = false; if (!skip_redraw) { - n = p_so; - if (topline == 0 && command == NULL) - p_so = 999; // force cursor to be vertically centered in the window + n = *so_ptr; + if (topline == 0 && command == NULL) { + *so_ptr = 999; // force cursor to be vertically centered in the window + } update_topline(); curwin->w_scbind_pos = curwin->w_topline; - p_so = n; - redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */ + *so_ptr = n; + redraw_curbuf_later(NOT_VALID); // redraw this buffer later } if (p_im) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index abe394dc3a..4f8bf63ffe 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7367,7 +7367,7 @@ static void ex_syncbind(exarg_T *eap) topline = curwin->w_topline; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 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) { topline = y; } diff --git a/src/nvim/move.c b/src/nvim/move.c index f47853e9cb..e7ed98d4f0 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -142,7 +142,8 @@ void update_topline(void) int old_topfill; bool check_topline = 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 // the cursor line. @@ -158,9 +159,10 @@ void update_topline(void) if (curwin->w_valid & VALID_TOPLINE) return; - /* When dragging with the mouse, don't scroll that quickly */ - if (mouse_dragging > 0) - p_so = mouse_dragging - 1; + // When dragging with the mouse, don't scroll that quickly + if (mouse_dragging > 0) { + *so_ptr = mouse_dragging - 1; + } old_topline = curwin->w_topline; old_topfill = curwin->w_topfill; @@ -206,15 +208,17 @@ void update_topline(void) * scrolled). */ n = 0; for (linenr_T lnum = curwin->w_cursor.lnum; - lnum < curwin->w_topline + p_so; ++lnum) { - ++n; - /* stop at end of file or when we know we are far off */ - if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) + lnum < curwin->w_topline + *so_ptr; lnum++) { + n++; + // stop at end of file or when we know we are far off + if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) { break; + } (void)hasFolding(lnum, NULL, &lnum); } - } else - n = curwin->w_topline + p_so - curwin->w_cursor.lnum; + } else { + n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum; + } /* 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 @@ -247,7 +251,7 @@ void update_topline(void) if (curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_cursor.lnum < curwin->w_botline) { if (((long)curwin->w_cursor.lnum - >= (long)curwin->w_botline - p_so + >= (long)curwin->w_botline - *so_ptr || hasAnyFolding(curwin) )) { lineoff_T loff; @@ -266,13 +270,15 @@ void update_topline(void) && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0) ) { n += loff.height; - if (n >= p_so) + if (n >= *so_ptr) { break; + } botline_forw(&loff); } - if (n >= p_so) - /* sufficient context, no need to scroll */ + if (n >= *so_ptr) { + // sufficient context, no need to scroll check_botline = false; + } } else { /* sufficient context, no need to scroll */ check_botline = false; @@ -285,7 +291,7 @@ void update_topline(void) * botline - p_so (approximation of how much will be * scrolled). */ for (linenr_T lnum = curwin->w_cursor.lnum; - lnum >= curwin->w_botline - p_so; lnum--) { + lnum >= curwin->w_botline - *so_ptr; lnum--) { line_count++; // stop at end of file or when we know we are far off if (lnum <= 0 || line_count > curwin->w_height_inner + 1) { @@ -295,7 +301,7 @@ void update_topline(void) } } else line_count = curwin->w_cursor.lnum - curwin->w_botline - + 1 + p_so; + + 1 + *so_ptr; if (line_count <= curwin->w_height_inner + 1) { scroll_cursor_bot(scrolljump_value(), false); } else { @@ -324,7 +330,7 @@ void update_topline(void) validate_cursor(); } - p_so = save_so; + *so_ptr = save_so; } /* @@ -356,25 +362,28 @@ static int scrolljump_value(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) ) { lineoff_T loff; loff.lnum = curwin->w_cursor.lnum; loff.fill = 0; - int n = curwin->w_topfill; /* always have this context */ - /* Count the visible screen lines above the cursor line. */ - while (n < p_so) { + int n = curwin->w_topfill; // always have this context + // Count the visible screen lines above the cursor line. + while (n < so) { 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 || (loff.lnum == curwin->w_topline && loff.fill > 0) - ) + ) { break; + } n += loff.height; } - if (n < p_so) + if (n < so) { return true; + } } return false; } @@ -714,6 +723,8 @@ void curs_columns( colnr_T startcol; colnr_T endcol; 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). @@ -785,10 +796,10 @@ void curs_columns( * If we get closer to the edge than 'sidescrolloff', scroll a little * extra */ - assert(p_siso <= INT_MAX); - int off_left = startcol - curwin->w_leftcol - (int)p_siso; + assert(siso <= INT_MAX); + int off_left = startcol - curwin->w_leftcol - (int)siso; 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) { int diff = (off_left < 0) ? -off_left: off_right; @@ -834,7 +845,7 @@ void curs_columns( int plines = 0; if ((curwin->w_wrow >= curwin->w_height_inner || ((prev_skipcol > 0 - || curwin->w_wrow + p_so >= curwin->w_height_inner) + || curwin->w_wrow + so >= curwin->w_height_inner) && (plines = plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1 >= curwin->w_height_inner)) @@ -850,17 +861,18 @@ void curs_columns( * 2: Less than "p_so" lines below * 3: both of them */ extra = 0; - if (curwin->w_skipcol + p_so * width > curwin->w_virtcol) + if (curwin->w_skipcol + so * width > curwin->w_virtcol) { 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) { plines = plines_win(curwin, curwin->w_cursor.lnum, false); } plines--; - if (plines > curwin->w_wrow + p_so) { - assert(p_so <= INT_MAX); - n = curwin->w_wrow + (int)p_so; + if (plines > curwin->w_wrow + so) { + assert(so <= INT_MAX); + n = curwin->w_wrow + (int)so; } else { n = plines; } @@ -868,7 +880,7 @@ void curs_columns( 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 n = curwin->w_virtcol / width; if (n > curwin->w_height_inner / 2) { @@ -882,9 +894,9 @@ void curs_columns( } curwin->w_skipcol = n * width; } else if (extra == 1) { - /* less then 'scrolloff' lines above, decrease skipcol */ - assert(p_so <= INT_MAX); - extra = (curwin->w_skipcol + (int)p_so * width - curwin->w_virtcol + // less then 'scrolloff' lines above, decrease skipcol + assert(so <= INT_MAX); + extra = (curwin->w_skipcol + (int)so * width - curwin->w_virtcol + width - 1) / width; if (extra > 0) { if ((colnr_T)(extra * width) > curwin->w_skipcol) @@ -1206,7 +1218,7 @@ void scrolldown_clamp(void) end_row += curwin->w_cline_height - 1 - 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) { ++curwin->w_topfill; check_topfill(curwin, true); @@ -1246,14 +1258,14 @@ void scrollup_clamp(void) validate_virtcol(); start_row -= curwin->w_virtcol / curwin->w_width_inner; } - if (start_row >= p_so) { - if (curwin->w_topfill > 0) - --curwin->w_topfill; - else { + if (start_row >= get_scrolloff_value()) { + if (curwin->w_topfill > 0) { + curwin->w_topfill--; + } else { (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); } } @@ -1349,8 +1361,7 @@ void scroll_cursor_top(int min_scroll, int always) linenr_T old_topline = curwin->w_topline; linenr_T old_topfill = curwin->w_topfill; linenr_T new_topline; - assert(p_so <= INT_MAX); - int off = (int)p_so; + int off = (int)get_scrolloff_value(); if (mouse_dragging > 0) 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; int old_valid = curwin->w_valid; 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) { 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" * context for 'scrolloff' and counted all lines below the window. */ 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) && 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) { break; } - if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : p_so) + if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : so) || scrolled < min_scroll) { extra += boff.height; 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 * whether the first/last line of the file is on screen. */ - assert(p_so <= INT_MAX); - int above_wanted = (int)p_so; - int below_wanted = (int)p_so; + int above_wanted = (int)get_scrolloff_value(); + int below_wanted = (int)get_scrolloff_value(); if (mouse_dragging > 0) { above_wanted = mouse_dragging - 1; below_wanted = mouse_dragging - 1; @@ -1821,6 +1832,7 @@ int onepage(Direction dir, long count) int retval = OK; lineoff_T loff; linenr_T old_topline = curwin->w_topline; + long so = get_scrolloff_value(); if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */ beep_flush(); @@ -1836,7 +1848,7 @@ int onepage(Direction dir, long count) * last line. */ 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_topline == 1 && curwin->w_topfill == diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 6434bd00d8..6c92b136da 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -2584,12 +2584,13 @@ do_mouse ( /* Set global flag that we are extending the Visual area with mouse * dragging; temporarily minimize 'scrolloff'. */ - if (VIsual_active && is_drag && p_so) { - /* In the very first line, allow scrolling one line */ - if (mouse_row == 0) + if (VIsual_active && is_drag && get_scrolloff_value()) { + // In the very first line, allow scrolling one line + if (mouse_row == 0) { mouse_dragging = 2; - else + } else { mouse_dragging = 1; + } } /* When dragging the mouse above the window, scroll down. */ @@ -4089,9 +4090,9 @@ void scroll_redraw(int up, long count) scrollup(count, true); else scrolldown(count, true); - if (p_so) { - /* Adjust the cursor position for 'scrolloff'. Mark w_topline as - * valid, otherwise the screen jumps back at the end of the file. */ + if (get_scrolloff_value()) { + // Adjust the cursor position for 'scrolloff'. Mark w_topline as + // valid, otherwise the screen jumps back at the end of the file. cursor_correct(); check_cursor_moved(curwin); curwin->w_valid |= VALID_TOPLINE; @@ -4135,8 +4136,8 @@ static void nv_zet(cmdarg_T *cap) int old_fen = curwin->w_p_fen; bool undo = false; - assert(p_siso <= INT_MAX); - int l_p_siso = (int)p_siso; + int l_p_siso = (int)get_sidescrolloff_value(); + assert(l_p_siso <= INT_MAX); if (ascii_isdigit(nchar)) { /* diff --git a/src/nvim/option.c b/src/nvim/option.c index 5a27ff21cc..43a4a9fdf9 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -904,11 +904,19 @@ set_option_default( if (options[opt_idx].indir == PV_SCROLL) { win_comp_scroll(curwin); } 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. if (both) { *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = - *(long *)varp; + def_val; } } } 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) { if (value < 0 && full_screen) { - errmsg = e_scroll; + errmsg = e_positive; } } else if (pp == &p_siso) { if (value < 0 && full_screen) { @@ -5326,20 +5334,20 @@ showoneopt( * Write modified options as ":set" commands to a file. * * There are three values for "opt_flags": - * OPT_GLOBAL: Write global option values and fresh values of - * buffer-local options (used for start of a session - * file). + * OPT_GLOBAL: Write global option values and fresh values of + * buffer-local options (used for start of a session + * file). * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for - * curwin (used for a vimrc file). - * OPT_LOCAL: Write buffer-local option values for curbuf, fresh - * and local values for window-local options of - * curwin. Local values are also written when at the - * default value, because a modeline or autocommand - * may have set them when doing ":edit file" and the - * user has set them back at the default or fresh - * value. - * When "local_only" is true, don't write fresh - * values, only local values (for ":mkview"). + * curwin (used for a vimrc file). + * OPT_LOCAL: Write buffer-local option values for curbuf, fresh + * and local values for window-local options of + * curwin. Local values are also written when at the + * default value, because a modeline or autocommand + * may have set them when doing ":edit file" and the + * user has set them back at the default or fresh + * value. + * When "local_only" is true, don't write fresh + * values, only local values (for ":mkview"). * (fresh value = value used for a new buffer or window for a local option). * * Return FAIL on error, OK otherwise. @@ -5634,6 +5642,12 @@ void unset_global_local_option(char *name, void *from) clear_string_option(&buf->b_p_tc); buf->b_tc_flags = 0; break; + case PV_SISO: + curwin->w_p_siso = -1; + break; + case PV_SO: + curwin->w_p_so = -1; + break; case PV_DEF: clear_string_option(&buf->b_p_def); 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_TAGS: return (char_u *)&(curbuf->b_p_tags); 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_INC: return (char_u *)&(curbuf->b_p_inc); 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; case PV_TC: return *curbuf->b_p_tc != NUL ? (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 ? (char_u *)&(curbuf->b_p_bkc) : p->var; case PV_DEF: return *curbuf->b_p_def != NUL @@ -6034,10 +6054,10 @@ void didset_window_options(win_T *wp) * Copy global option values to local options for one buffer. * Used when creating a new buffer and sometimes when entering a buffer. * flags: - * BCO_ENTER We will enter the buf buffer. - * BCO_ALWAYS Always copy the options, but only set b_p_initialized when - * appropriate. - * BCO_NOHELP Don't copy the values to a help buffer. + * BCO_ENTER We will enter the buf buffer. + * BCO_ALWAYS Always copy the options, but only set b_p_initialized when + * appropriate. + * BCO_NOHELP Don't copy the values to a help buffer. */ void buf_copy_options(buf_T *buf, int flags) { @@ -7485,3 +7505,18 @@ dict_T *get_winbuf_options(const int bufopt) 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; +} + diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index c5d8b134c4..192e57a642 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -835,6 +835,8 @@ enum { , WV_RLC , WV_SCBIND , WV_SCROLL + , WV_SISO + , WV_SO , WV_SPELL , WV_CUC , WV_CUL diff --git a/src/nvim/options.lua b/src/nvim/options.lua index c18b9e0697..02102fc168 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1990,7 +1990,7 @@ return { }, { full_name='scrolloff', abbreviation='so', - type='number', scope={'global'}, + type='number', scope={'global', 'window'}, vi_def=true, vim=true, redraw={'all_windows'}, @@ -2229,10 +2229,10 @@ return { }, { full_name='sidescrolloff', abbreviation='siso', - type='number', scope={'global'}, + type='number', scope={'global', 'window'}, vi_def=true, vim=true, - redraw={'current_buffer'}, + redraw={'all_windows'}, varname='p_siso', defaults={if_true={vi=0}} }, diff --git a/src/nvim/search.c b/src/nvim/search.c index 3ee9777805..7d00785c74 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -2227,6 +2227,8 @@ showmatch( pos_T *lpos, save_cursor; pos_T mpos; 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_siso; int save_state; @@ -2262,23 +2264,24 @@ showmatch( && vcol < curwin->w_leftcol + curwin->w_width_inner)) { mpos = *lpos; // save the pos, update_screen() may change it save_cursor = curwin->w_cursor; - save_so = p_so; - save_siso = p_siso; - /* Handle "$" in 'cpo': If the ')' is typed on top of the "$", - * stop displaying the "$". */ - if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) + save_so = *so; + save_siso = *siso; + // Handle "$" in 'cpo': If the ')' is typed on top of the "$", + // stop displaying the "$". + if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) { 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_state = State; State = SHOWMATCH; - ui_cursor_shape(); /* may show different cursor shape */ - curwin->w_cursor = mpos; /* move to matching char */ - p_so = 0; /* don't use 'scrolloff' here */ - p_siso = 0; /* don't use 'sidescrolloff' here */ - showruler(FALSE); + ui_cursor_shape(); // may show different cursor shape + curwin->w_cursor = mpos; // move to matching char + *so = 0; // don't use 'scrolloff' here + *siso = 0; // don't use 'sidescrolloff' here + showruler(false); setcursor(); ui_flush(); /* Restore dollar_vcol(), because setcursor() may call curs_rows() @@ -2294,11 +2297,11 @@ showmatch( os_delay(p_mat * 100L, true); else if (!char_avail()) os_delay(p_mat * 100L, false); - curwin->w_cursor = save_cursor; /* restore cursor position */ - p_so = save_so; - p_siso = save_siso; + curwin->w_cursor = save_cursor; // restore cursor position + *so = save_so; + *siso = save_siso; State = save_state; - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape } } } diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index c2f710358b..41f1710faf 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -512,6 +512,41 @@ func Test_shortmess_F2() bwipe 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() set belloff= set visualbell diff --git a/src/nvim/window.c b/src/nvim/window.c index f61a46996d..fb3f1e0c9f 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4689,6 +4689,10 @@ static win_T *win_alloc(win_T *after, int hidden) new_wp->w_floating = 0; 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 */ new_wp->w_fraction = 0; 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 (p_so) + if (get_scrolloff_value()) { update_topline(); - curs_columns(FALSE); /* validate w_wrow */ + } + curs_columns(false); // validate w_wrow } if (prev_height > 0) { wp->w_prev_fraction_row = wp->w_wrow; |