]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.3900: it is not easy to use a script-local function for an option v8.2.3900
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 26 Dec 2021 10:51:39 +0000 (10:51 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 26 Dec 2021 10:51:39 +0000 (10:51 +0000)
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)

13 files changed:
runtime/doc/diff.txt
runtime/doc/fold.txt
runtime/doc/options.txt
runtime/doc/print.txt
src/optionstr.c
src/testdir/test_diffmode.vim
src/testdir/test_edit.vim
src/testdir/test_fold.vim
src/testdir/test_gf.vim
src/testdir/test_gui.vim
src/testdir/test_hardcopy.vim
src/testdir/test_normal.vim
src/version.c

index 2a231b15bb3d987fc59238c2ef9d7742497df7ed..e3d8f53c4699220f19e10efc68868026be8f24e7 100644 (file)
@@ -398,6 +398,11 @@ mode, so that a CTRL-Z doesn't end the text on DOS.
 The `redraw!` command may not be needed, depending on whether executing a
 shell command shows something on the display or not.
 
+If the 'diffexpr' expression starts with s: or |<SID>|, then it is replaced
+with the script ID (|local-function|). Example: >
+               set diffexpr=s:MyDiffExpr()
+               set diffexpr=<SID>SomeDiffExpr()
+<
                                                *E810* *E97*
 Vim will do a test if the diff output looks alright.  If it doesn't, you will
 get an error message.  Possible causes:
@@ -449,4 +454,9 @@ evaluating 'patchexpr'.  This hopefully avoids that files in the current
 directory are accidentally patched.  Vim will also delete files starting with
 v:fname_in and ending in ".rej" and ".orig".
 
+If the 'patchexpr' expression starts with s: or |<SID>|, then it is replaced
+with the script ID (|local-function|). Example: >
+               set patchexpr=s:MyPatchExpr()
+               set patchexpr=<SID>SomePatchExpr()
+<
  vim:tw=78:ts=8:noet:ft=help:norl:
index 274e472a5dde1bd7303a7fee323eae5440d26005..56c3c75c35f88e02d033d9906bb56db5ced8718d 100644 (file)
@@ -121,6 +121,11 @@ method can be very slow!
 Try to avoid the "=", "a" and "s" return values, since Vim often has to search
 backwards for a line for which the fold level is defined.  This can be slow.
 
+If the 'foldexpr' expression starts with s: or |<SID>|, then it is replaced
+with the script ID (|local-function|). Example: >
+               set foldexpr=s:MyFoldExpr()
+               set foldexpr=<SID>SomeFoldExpr()
+<
 An example of using "a1" and "s1": For a multi-line C comment, a line
 containing "/*" would return "a1" to start a fold, and a line containing "*/"
 would return "s1" to end the fold after that line: >
@@ -543,6 +548,8 @@ A closed fold is indicated with a '+'.
 
 These characters can be changed with the 'fillchars' option.
 
+These characters can be changed with the 'fillchars' option.
+
 Where the fold column is too narrow to display all nested folds, digits are
 shown to indicate the nesting level.
 
index 845351d08f15393fc70903a9685be0276ac44d5f..f0939e61bb0d146acbd4d58c89b304336ec29d9d 100644 (file)
@@ -1225,6 +1225,11 @@ A jump table for the options with a short description can be found at |Q_op|.
        Vim does not try to send a message to an external debugger (Netbeans
        or Sun Workshop).
 
+       If the expression starts with s: or |<SID>|, then it is replaced with
+       the script ID (|local-function|). Example: >
+               set bexpr=s:MyBalloonExpr()
+               set bexpr=<SID>SomeBalloonExpr()
+<
        The expression will be evaluated in the |sandbox| when set from a
        modeline, see |sandbox-option|.
        This option cannot be set in a modeline when 'modelineexpr' is off.
@@ -3596,6 +3601,11 @@ A jump table for the options with a short description can be found at |Q_op|.
        When the expression evaluates to non-zero Vim will fall back to using
        the internal format mechanism.
 
+       If the expression starts with s: or |<SID>|, then it is replaced with
+       the script ID (|local-function|). Example: >
+               set formatexpr=s:MyFormatExpr()
+               set formatexpr=<SID>SomeFormatExpr()
+<
        The expression will be evaluated in the |sandbox| when set from a
        modeline, see |sandbox-option|.  That stops the option from working,
        since changing the buffer text is not allowed.
@@ -4438,6 +4448,11 @@ A jump table for the options with a short description can be found at |Q_op|.
        found.  Allows doing "gf" on the name after an 'include' statement.
        Also used for |<cfile>|.
 
+       If the expression starts with s: or |<SID>|, then it is replaced with
+       the script ID (|local-function|). Example: >
+               set includeexpr=s:MyIncludeExpr(v:fname)
+               set includeexpr=<SID>SomeIncludeExpr(v:fname)
+<
        The expression will be evaluated in the |sandbox| when set from a
        modeline, see |sandbox-option|.
        This option cannot be set in a modeline when 'modelineexpr' is off.
@@ -4511,6 +4526,11 @@ A jump table for the options with a short description can be found at |Q_op|.
        The expression is evaluated with |v:lnum| set to the line number for
        which the indent is to be computed.  The cursor is also in this line
        when the expression is evaluated (but it may be moved around).
+       If the expression starts with s: or |<SID>|, then it is replaced with
+       the script ID (|local-function|). Example: >
+               set indentexpr=s:MyIndentExpr()
+               set indentexpr=<SID>SomeIndentExpr()
+<
        The expression must return the number of spaces worth of indent.  It
        can return "-1" to keep the current indent (this means 'autoindent' is
        used for the indent).
index aaa004c93e18cbb8833c57a025d618df418bf0c8..eebdf7ea02706d0b1d24ae620eb9fcf59c162438 100644 (file)
@@ -174,6 +174,11 @@ an error message.  In that case Vim will delete the file.  In the default
 value for non-MS-Windows a trick is used: Adding "v:shell_error" will result
 in a non-zero number when the system() call fails.
 
+If the expression starts with s: or |<SID>|, then it is replaced with the
+script ID (|local-function|). Example: >
+               set printexpr=s:MyPrintFile()
+               set printexpr=<SID>SomePrintFile()
+<
 This option cannot be set from a |modeline| or in the |sandbox|, for security
 reasons.
 
index dbb93cdc97ed782cf6f7fd4cab7b8ddef6981b6b..c69354eced3bba25043e936931ebe1c30381cb3a 100644 (file)
@@ -2026,14 +2026,6 @@ ambw_end:
                newFoldLevel();
        }
     }
-# ifdef FEAT_EVAL
-    // 'foldexpr'
-    else if (varp == &curwin->w_p_fde)
-    {
-       if (foldmethodIsExpr(curwin))
-           foldUpdateAll(curwin);
-    }
-# endif
     // 'foldmarker'
     else if (gvarp == &curwin->w_allbuf_opt.wo_fmr)
     {
@@ -2307,6 +2299,89 @@ ambw_end:
 # endif
 #endif
 
+#ifdef FEAT_EVAL
+    // '*expr' options
+    else if (
+# ifdef FEAT_BEVAL
+           varp == &p_bexpr ||
+# endif
+# ifdef FEAT_DIFF
+           varp == &p_dex ||
+# endif
+# ifdef FEAT_FOLDING
+           varp == &curwin->w_p_fde ||
+# endif
+           gvarp == &p_fex ||
+# ifdef FEAT_FIND_ID
+           gvarp == &p_inex ||
+# endif
+# ifdef FEAT_CINDENT
+           gvarp == &p_inde ||
+# endif
+# ifdef FEAT_DIFF
+           varp == &p_pex ||
+# endif
+# ifdef FEAT_POSTSCRIPT
+           varp == &p_pexpr ||
+# endif
+           FALSE
+           )
+    {
+       char_u  **p_opt = NULL;
+       char_u  *name;
+
+       // If the option value starts with <SID> or s:, then replace that with
+       // the script identifier.
+# ifdef FEAT_BEVAL
+       if (varp == &p_bexpr)           // 'balloonexpr'
+           p_opt = (opt_flags & OPT_LOCAL) ? &curbuf->b_p_bexpr : &p_bexpr;
+# endif
+# ifdef FEAT_DIFF
+       if (varp == &p_dex)     // 'diffexpr'
+           p_opt = &p_dex;
+# endif
+# ifdef FEAT_FOLDING
+       if(varp == &curwin->w_p_fde)    // 'foldexpr'
+           p_opt = &curwin->w_p_fde;
+# endif
+       if (gvarp == &p_fex)    // 'formatexpr'
+           p_opt = &curbuf->b_p_fex;
+# ifdef FEAT_FIND_ID
+       if (gvarp == &p_inex)   // 'includeexpr'
+           p_opt = &curbuf->b_p_inex;
+# endif
+# ifdef FEAT_CINDENT
+       if (gvarp == &p_inde)   // 'indentexpr'
+           p_opt = &curbuf->b_p_inde;
+# endif
+# ifdef FEAT_DIFF
+       if (varp == &p_pex)     // 'patchexpr'
+           p_opt = &p_pex;
+# endif
+# ifdef FEAT_POSTSCRIPT
+       if (varp == &p_pexpr)   // 'printexpr'
+           p_opt = &p_pexpr;
+# endif
+
+       if (p_opt != NULL)
+       {
+           name = get_scriptlocal_funcname(*p_opt);
+           if (name != NULL)
+           {
+               if (new_value_alloced)
+                   free_string_option(*p_opt);
+               *p_opt = name;
+               new_value_alloced = TRUE;
+           }
+       }
+
+# ifdef FEAT_FOLDING
+       if (varp == &curwin->w_p_fde && foldmethodIsExpr(curwin))
+           foldUpdateAll(curwin);
+# endif
+    }
+#endif
+
 #ifdef FEAT_COMPL_FUNC
     // 'completefunc'
     else if (gvarp == &p_cfu)
index 9338fe0503c6fd1a03640b77a0ad543c1f9d43c2..d4c44ce3768bd8c29be186f503aa396063298622 100644 (file)
@@ -681,8 +681,19 @@ func Test_diffexpr()
   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 @@ func Test_patchexpr()
   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
 
index 46a475221f6b8089b9e2177df36467ad7d69fcdd..c39c8a0fb12b7d429a6497f8e1b38224a30762d7 100644 (file)
@@ -324,6 +324,16 @@ func Test_edit_11_indentexpr()
   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
 
index 85fa43da3dfdb938ed1773d20a71c4d18c7f850f..d35b7c807be6b0085ae1231df05b48755568bdfc 100644 (file)
@@ -1382,4 +1382,30 @@ func Test_fold_jump()
   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
index 5e5de415b4a6d29911a42ceef1a5eb35e88edf18..1b13c42cd988eda21d50c5eabe064776e0f1e045 100644 (file)
@@ -217,4 +217,30 @@ func Test_gf_includeexpr()
   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
index 133298db3ae16120a1f94302043d58a4b4415e13..90552843d1cf9239fcb3f6ba66007f4a9bd21e1d 100644 (file)
@@ -258,6 +258,15 @@ func Test_set_balloonexpr()
   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
index e390bd5cc8e4e2304ff6c57eecbf8cbc0a7577e2..be83728b4f950c532952792d106d813de9089903 100644 (file)
@@ -125,6 +125,14 @@ func Test_printexpr()
   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
index 57ea6d3ecce9d642e95830083ca725440282696e..6458a1bed4853d8d971917e87397a21e3e3298df 100644 (file)
@@ -253,6 +253,45 @@ func Test_normal_formatexpr_returns_nonzero()
   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
index 260182bdf74b0ae19f68cceaf94595e7a46f4e49..1ada85606a6435d83012430eff8e9b3bd28f9da6 100644 (file)
@@ -749,6 +749,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3900,
 /**/
     3899,
 /**/