patch 8.2.3900: it is not easy to use a script-local function for an option

Problem:    It is not easy to use a script-local function for an option.
Solution:   recognize s: and <SID> at the start of the expression. (Yegappan
            Lakshmanan, closes #9401)
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 9338fe0..d4c44ce 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
@@ -681,8 +681,19 @@
   set diffexpr=NewDiffFunc()
   call assert_fails('windo diffthis', ['E117:', 'E97:'])
   diffoff!
+
+  " Using a script-local function
+  func s:NewDiffExpr()
+  endfunc
+  set diffexpr=s:NewDiffExpr()
+  call assert_equal(expand('<SID>') .. 'NewDiffExpr()', &diffexpr)
+  set diffexpr=<SID>NewDiffExpr()
+  call assert_equal(expand('<SID>') .. 'NewDiffExpr()', &diffexpr)
+
   %bwipe!
   set diffexpr& diffopt&
+  delfunc DiffExpr
+  delfunc s:NewDiffExpr
 endfunc
 
 func Test_diffpatch()
@@ -1216,10 +1227,19 @@
   call assert_equal(2, winnr('$'))
   call assert_true(&diff)
 
+  " Using a script-local function
+  func s:NewPatchExpr()
+  endfunc
+  set patchexpr=s:NewPatchExpr()
+  call assert_equal(expand('<SID>') .. 'NewPatchExpr()', &patchexpr)
+  set patchexpr=<SID>NewPatchExpr()
+  call assert_equal(expand('<SID>') .. 'NewPatchExpr()', &patchexpr)
+
   call delete('Xinput')
   call delete('Xdiff')
   set patchexpr&
   delfunc TPatch
+  delfunc s:NewPatchExpr
   %bwipe!
 endfunc
 
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 46a4752..c39c8a0 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -324,6 +324,16 @@
   set cinkeys&vim indentkeys&vim
   set nocindent indentexpr=
   delfu Do_Indent
+
+  " Using a script-local function
+  func s:NewIndentExpr()
+  endfunc
+  set indentexpr=s:NewIndentExpr()
+  call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+  set indentexpr=<SID>NewIndentExpr()
+  call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+  set indentexpr&
+
   bw!
 endfunc
 
diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim
index 85fa43d..d35b7c8 100644
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -1382,4 +1382,30 @@
   bw!
 endfunc
 
+" Test for using a script-local function for 'foldexpr'
+func Test_foldexpr_scriptlocal_func()
+  func! s:FoldFunc()
+    let g:FoldLnum = v:lnum
+  endfunc
+  new | only
+  call setline(1, 'abc')
+  let g:FoldLnum = 0
+  set foldmethod=expr foldexpr=s:FoldFunc()
+  redraw!
+  call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+  call assert_equal(1, g:FoldLnum)
+  set foldmethod& foldexpr=
+  bw!
+  new | only
+  call setline(1, 'abc')
+  let g:FoldLnum = 0
+  set foldmethod=expr foldexpr=<SID>FoldFunc()
+  redraw!
+  call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+  call assert_equal(1, g:FoldLnum)
+  set foldmethod& foldexpr=
+  delfunc s:FoldFunc
+  bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_gf.vim b/src/testdir/test_gf.vim
index 5e5de41..1b13c42 100644
--- a/src/testdir/test_gf.vim
+++ b/src/testdir/test_gf.vim
@@ -217,4 +217,30 @@
   delfunc IncFunc
 endfunc
 
+" Test for using a script-local function for 'includeexpr'
+func Test_includeexpr_scriptlocal_func()
+  func! s:IncludeFunc()
+    let g:IncludeFname = v:fname
+    return ''
+  endfunc
+  set includeexpr=s:IncludeFunc()
+  call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+  new | only
+  call setline(1, 'TestFile1')
+  let g:IncludeFname = ''
+  call assert_fails('normal! gf', 'E447:')
+  call assert_equal('TestFile1', g:IncludeFname)
+  bw!
+  set includeexpr=<SID>IncludeFunc()
+  call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+  new | only
+  call setline(1, 'TestFile2')
+  let g:IncludeFname = ''
+  call assert_fails('normal! gf', 'E447:')
+  call assert_equal('TestFile2', g:IncludeFname)
+  set includeexpr&
+  delfunc s:IncludeFunc
+  bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim
index 133298d..9055284 100644
--- a/src/testdir/test_gui.vim
+++ b/src/testdir/test_gui.vim
@@ -258,6 +258,15 @@
   setl balloonexpr&
   call assert_equal('', &balloonexpr)
   delfunc MyBalloonExpr
+
+  " Using a script-local function
+  func s:NewBalloonExpr()
+  endfunc
+  set balloonexpr=s:NewBalloonExpr()
+  call assert_equal(expand('<SID>') .. 'NewBalloonExpr()', &balloonexpr)
+  set balloonexpr=<SID>NewBalloonExpr()
+  call assert_equal(expand('<SID>') .. 'NewBalloonExpr()', &balloonexpr)
+  delfunc s:NewBalloonExpr
   bwipe!
 
   " Multiline support
diff --git a/src/testdir/test_hardcopy.vim b/src/testdir/test_hardcopy.vim
index e390bd5..be83728 100644
--- a/src/testdir/test_hardcopy.vim
+++ b/src/testdir/test_hardcopy.vim
@@ -125,6 +125,14 @@
   set printexpr=PrintFails(v:fname_in)
   call assert_fails('hardcopy', 'E365:')
 
+  " Using a script-local function
+  func s:NewPrintExpr()
+  endfunc
+  set printexpr=s:NewPrintExpr()
+  call assert_equal(expand('<SID>') .. 'NewPrintExpr()', &printexpr)
+  set printexpr=<SID>NewPrintExpr()
+  call assert_equal(expand('<SID>') .. 'NewPrintExpr()', &printexpr)
+
   set printexpr&
   bwipe
 endfunc
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index 57ea6d3..6458a1b 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -253,6 +253,45 @@
   close!
 endfunc
 
+" Test for using a script-local function for 'formatexpr'
+func Test_formatexpr_scriptlocal_func()
+  func! s:Format()
+    let g:FormatArgs = [v:lnum, v:count]
+  endfunc
+  set formatexpr=s:Format()
+  call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+  new | only
+  call setline(1, range(1, 40))
+  let g:FormatArgs = []
+  normal! 2GVjgq
+  call assert_equal([2, 2], g:FormatArgs)
+  bw!
+  set formatexpr=<SID>Format()
+  call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+  new | only
+  call setline(1, range(1, 40))
+  let g:FormatArgs = []
+  normal! 4GVjgq
+  call assert_equal([4, 2], g:FormatArgs)
+  bw!
+  let &formatexpr = 's:Format()'
+  new | only
+  call setline(1, range(1, 40))
+  let g:FormatArgs = []
+  normal! 6GVjgq
+  call assert_equal([6, 2], g:FormatArgs)
+  bw!
+  let &formatexpr = '<SID>Format()'
+  new | only
+  call setline(1, range(1, 40))
+  let g:FormatArgs = []
+  normal! 8GVjgq
+  call assert_equal([8, 2], g:FormatArgs)
+  setlocal formatexpr=
+  delfunc s:Format
+  bw!
+endfunc
+
 " basic test for formatprg
 func Test_normal06_formatprg()
   " only test on non windows platform