patch 9.0.1710: scrolloff options work slightly different

Problem: sidescrolloff and scrolloff options work slightly
         different than other global-local options
Solution: Make it behave consistent for all global-local options

It was noticed, that sidescrolloff and scrolloff options behave
differently in comparison to other global-local window options like
'listchars'

So make those two behave like other global-local options. Also add some
extra documentation for a few special local-window options.

Add a few tests to make sure all global-local window options behave
similar

closes: #12956
closes: #12643

Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/option.c b/src/option.c
index 3050dbc..a6d73d2 100644
--- a/src/option.c
+++ b/src/option.c
@@ -6652,6 +6652,8 @@
     to->wo_sms = from->wo_sms;
     to->wo_crb = from->wo_crb;
     to->wo_crb_save = from->wo_crb_save;
+    to->wo_siso = from->wo_siso;
+    to->wo_so = from->wo_so;
 #ifdef FEAT_SPELL
     to->wo_spell = from->wo_spell;
 #endif
diff --git a/src/structs.h b/src/structs.h
index ccef537..1b4308e 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -312,6 +312,10 @@
     char_u	*wo_scl;
 # define w_p_scl w_onebuf_opt.wo_scl	// 'signcolumn'
 #endif
+    long	wo_siso;
+# define w_p_siso w_onebuf_opt.wo_siso	// 'sidescrolloff' local value
+    long	wo_so;
+# define w_p_so w_onebuf_opt.wo_so	// 'scrolloff' local value
 #ifdef FEAT_TERMINAL
     char_u	*wo_twk;
 # define w_p_twk w_onebuf_opt.wo_twk	// 'termwinkey'
@@ -3977,8 +3981,6 @@
     int		*w_p_cc_cols;	    // array of columns to highlight or NULL
     char_u	w_p_culopt_flags;   // flags for cursorline highlighting
 #endif
-    long	w_p_siso;	    // 'sidescrolloff' local value
-    long	w_p_so;		    // 'scrolloff' local value
 
 #ifdef FEAT_LINEBREAK
     int		w_briopt_min;	    // minimum width for breakindent
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 0de5e25..5bacebc 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -1689,4 +1689,89 @@
   bw!
 endfunc
 
+func Test_set_option_window_global_local()
+  new Xbuffer1
+  let [ _gso, _lso ] = [ &g:scrolloff, &l:scrolloff ]
+  setlocal scrolloff=2
+  setglobal scrolloff=3
+  setl modified
+  " A new buffer has its own window-local options
+  hide enew
+  call assert_equal(-1, &l:scrolloff)
+  call assert_equal(3, &g:scrolloff)
+  " A new window opened with its own buffer-local options
+  new
+  call assert_equal(-1, &l:scrolloff)
+  call assert_equal(3, &g:scrolloff)
+  " Re-open Xbuffer1 and it should use
+  " the previous set window-local options
+  b Xbuffer1
+  call assert_equal(2, &l:scrolloff)
+  call assert_equal(3, &g:scrolloff)
+  bw!
+  bw!
+  let &g:scrolloff =  _gso
+endfunc
+
+func GetGlobalLocalWindowOptions()
+  new
+  sil! r $VIMRUNTIME/doc/options.txt
+  " Filter for global or local to window
+  v/^'.*'.*\n.*global or local to window |global-local/d
+  " get option value and type
+  sil %s/^'\([^']*\)'.*'\s\+\(\w\+\)\s\+(default \%(\(".*"\|\d\+\|empty\)\).*/\1 \2 \3/g
+  sil %s/empty/""/g
+  " split the result
+  let result=getline(1,'$')->map({_, val -> split(val, ' ')})
+  bw!
+  return result
+endfunc
+
+func Test_set_option_window_global_local_all()
+  new Xbuffer2
+
+  let optionlist = GetGlobalLocalWindowOptions()
+  for [opt, type, default] in optionlist
+    let _old = eval('&g:' .. opt)
+    if type == 'string'
+      if opt == 'fillchars'
+        exe 'setl ' .. opt .. '=vert:+'
+        exe 'setg ' .. opt .. '=vert:+,fold:+'
+      elseif opt == 'listchars'
+        exe 'setl ' .. opt .. '=tab:>>'
+        exe 'setg ' .. opt .. '=tab:++'
+      elseif opt == 'virtualedit'
+        exe 'setl ' .. opt .. '=all'
+        exe 'setg ' .. opt .. '=block'
+      else
+        exe 'setl ' .. opt .. '=Local'
+        exe 'setg ' .. opt .. '=Global'
+      endif
+    elseif type == 'number'
+      exe 'setl ' .. opt .. '=5'
+      exe 'setg ' .. opt .. '=10'
+    endif
+    setl modified
+    hide enew
+    if type == 'string'
+      call assert_equal('', eval('&l:' .. opt))
+      if opt == 'fillchars'
+        call assert_equal('vert:+,fold:+', eval('&g:' .. opt), 'option:' .. opt)
+      elseif opt == 'listchars'
+        call assert_equal('tab:++', eval('&g:' .. opt), 'option:' .. opt)
+      elseif opt == 'virtualedit'
+        call assert_equal('block', eval('&g:' .. opt), 'option:' .. opt)
+      else
+        call assert_equal('Global', eval('&g:' .. opt), 'option:' .. opt)
+      endif
+    elseif type == 'number'
+      call assert_equal(-1, eval('&l:' .. opt), 'option:' .. opt)
+      call assert_equal(10, eval('&g:' .. opt), 'option:' .. opt)
+    endif
+    bw!
+    exe 'let &g:' .. opt .. '=' .. default
+  endfor
+  bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 311bb8c..100dd95 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1710,
+/**/
     1709,
 /**/
     1708,
diff --git a/src/window.c b/src/window.c
index f02aa9f..33d19fa 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5546,8 +5546,8 @@
     new_wp->w_scbind_pos = 1;
 
     // use global option value for global-local options
-    new_wp->w_p_so = -1;
-    new_wp->w_p_siso = -1;
+    new_wp->w_allbuf_opt.wo_so = new_wp->w_p_so = -1;
+    new_wp->w_allbuf_opt.wo_siso = new_wp->w_p_siso = -1;
 
     // We won't calculate w_fraction until resizing the window
     new_wp->w_fraction = 0;