aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/diff.txt10
-rw-r--r--runtime/doc/fold.txt10
-rw-r--r--runtime/doc/options.txt15
-rw-r--r--runtime/doc/print.txt5
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/lua/executor.c4
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/optionstr.c54
-rw-r--r--src/nvim/testdir/test_diffmode.vim26
-rw-r--r--src/nvim/testdir/test_edit.vim10
-rw-r--r--src/nvim/testdir/test_fold.vim57
-rw-r--r--src/nvim/testdir/test_gf.vim26
-rw-r--r--src/nvim/testdir/test_hardcopy.vim8
-rw-r--r--src/nvim/testdir/test_normal.vim39
14 files changed, 258 insertions, 12 deletions
diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt
index b5a3891d3f..f38f123393 100644
--- a/runtime/doc/diff.txt
+++ b/runtime/doc/diff.txt
@@ -388,6 +388,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:
@@ -439,4 +444,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:
diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt
index e97a0a6459..fa823608df 100644
--- a/runtime/doc/fold.txt
+++ b/runtime/doc/fold.txt
@@ -116,6 +116,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|). Examples: >
+ 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: >
@@ -521,6 +526,11 @@ The resulting line is truncated to fit in the window, it never wraps.
When there is room after the text, it is filled with the character specified
by 'fillchars'.
+If the 'foldtext' expression starts with s: or |<SID>|, then it is replaced
+with the script ID (|local-function|). Examples: >
+ set foldtext=s:MyFoldText()
+ set foldtext=<SID>SomeFoldText()
+<
Note that backslashes need to be used for characters that the ":set" command
handles differently: Space, backslash and double-quote. |option-backslash|
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 33bade3545..7edc965941 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2738,6 +2738,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.
@@ -3362,6 +3367,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.
@@ -3417,6 +3427,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).
diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt
index e24b6b0347..ef3e47d32c 100644
--- a/runtime/doc/print.txt
+++ b/runtime/doc/print.txt
@@ -155,6 +155,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.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 6d8f4d092c..554771d9c9 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -711,7 +711,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch
set_vim_var_string(VV_FNAME_IN, origfile, -1);
set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
set_vim_var_string(VV_FNAME_OUT, outfile, -1);
- (void)eval_to_bool((char *)p_pex, &err, NULL, false);
+ (void)eval_to_bool(p_pex, &err, NULL, false);
set_vim_var_string(VV_FNAME_IN, NULL, -1);
set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
set_vim_var_string(VV_FNAME_OUT, NULL, -1);
@@ -5511,7 +5511,7 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool retlist
}
/// Get a callback from "arg". It can be a Funcref or a function name.
-bool callback_from_typval(Callback *const callback, typval_T *const arg)
+bool callback_from_typval(Callback *const callback, const typval_T *const arg)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int r = OK;
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 5380559baf..48ab2e3d70 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1845,7 +1845,7 @@ static int nlua_is_thread(lua_State *lstate)
return 1;
}
-bool nlua_is_table_from_lua(typval_T *const arg)
+bool nlua_is_table_from_lua(const typval_T *const arg)
{
if (arg->v_type == VAR_DICT) {
return arg->vval.v_dict->lua_table_ref != LUA_NOREF;
@@ -1856,7 +1856,7 @@ bool nlua_is_table_from_lua(typval_T *const arg)
}
}
-char_u *nlua_register_table_as_callable(typval_T *const arg)
+char_u *nlua_register_table_as_callable(const typval_T *const arg)
{
LuaRef table_ref = LUA_NOREF;
if (arg->v_type == VAR_DICT) {
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 40ce022bea..de07327416 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -622,7 +622,7 @@ EXTERN char *p_opfunc; // 'operatorfunc'
EXTERN char_u *p_para; // 'paragraphs'
EXTERN int p_paste; // 'paste'
EXTERN char *p_pt; // 'pastetoggle'
-EXTERN char_u *p_pex; // 'patchexpr'
+EXTERN char *p_pex; // 'patchexpr'
EXTERN char *p_pm; // 'patchmode'
EXTERN char_u *p_path; // 'path'
EXTERN char_u *p_cdpath; // 'cdpath'
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 61a51532a4..cd87db9aa9 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -17,6 +17,7 @@
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
#include "nvim/ex_getln.h"
#include "nvim/fold.h"
@@ -1341,10 +1342,6 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
newFoldLevel();
}
}
- } else if (varp == &curwin->w_p_fde) { // 'foldexpr'
- if (foldmethodIsExpr(curwin)) {
- foldUpdateAll(curwin);
- }
} else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker'
p = vim_strchr(*varp, ',');
if (p == NULL) {
@@ -1484,6 +1481,55 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
}
}
}
+ } else if (varp == &p_dex
+ || varp == &curwin->w_p_fde
+ || varp == &curwin->w_p_fdt
+ || gvarp == &p_fex
+ || gvarp == &p_inex
+ || gvarp == &p_inde
+ || varp == &p_pex
+ || varp == &p_pexpr) { // '*expr' options
+ char **p_opt = NULL;
+
+ // If the option value starts with <SID> or s:, then replace that with
+ // the script identifier.
+
+ if (varp == &p_dex) { // 'diffexpr'
+ p_opt = &p_dex;
+ }
+ if (varp == &curwin->w_p_fde) { // 'foldexpr'
+ p_opt = &curwin->w_p_fde;
+ }
+ if (varp == &curwin->w_p_fdt) { // 'foldtext'
+ p_opt = &curwin->w_p_fdt;
+ }
+ if (gvarp == &p_fex) { // 'formatexpr'
+ p_opt = &curbuf->b_p_fex;
+ }
+ if (gvarp == &p_inex) { // 'includeexpr'
+ p_opt = &curbuf->b_p_inex;
+ }
+ if (gvarp == &p_inde) { // 'indentexpr'
+ p_opt = &curbuf->b_p_inde;
+ }
+ if (varp == &p_pex) { // 'patchexpr'
+ p_opt = &p_pex;
+ }
+ if (varp == &p_pexpr) { // 'printexpr'
+ p_opt = &p_pexpr;
+ }
+
+ if (p_opt != NULL) {
+ char *name = get_scriptlocal_funcname(*p_opt);
+ if (name != NULL) {
+ free_string_option(*p_opt);
+ *p_opt = name;
+ }
+ }
+
+ if (varp == &curwin->w_p_fde && foldmethodIsExpr(curwin)) {
+ foldUpdateAll(curwin);
+ }
} else if (gvarp == &p_cfu) { // 'completefunc'
if (set_completefunc_option() == FAIL) {
errmsg = e_invarg;
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index d83cd505a6..0049398776 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1,4 +1,5 @@
" Tests for diff mode
+
source shared.vim
source screendump.vim
source check.vim
@@ -681,15 +682,25 @@ 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()
" The patch program on MS-Windows may fail or hang.
- if !executable('patch') || !has('unix')
- return
- endif
+ CheckExecutable patch
+ CheckUnix
new
insert
***************
@@ -1250,10 +1261,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
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 89e597f401..fd54f77ccb 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -330,6 +330,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
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 2215166cd6..d74187537c 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -1273,6 +1273,63 @@ 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
+
+" Test for using a script-local function for 'foldtext'
+func Test_foldtext_scriptlocal_func()
+ func! s:FoldText()
+ let g:FoldTextArgs = [v:foldstart, v:foldend]
+ return foldtext()
+ endfunc
+ new | only
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ set foldmethod=manual
+ set foldtext=s:FoldText()
+ norm! 4Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([4, 8], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ new | only
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ set foldmethod=manual
+ set foldtext=<SID>FoldText()
+ norm! 8Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([8, 12], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ delfunc s:FoldText
+endfunc
+
" Make sure a fold containing a nested fold is split correctly when using
" foldmethod=indent
func Test_fold_split()
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index b2bb189688..e369645328 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -226,6 +226,32 @@ 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
+
" Check that expanding directories can handle more than 255 entries.
func Test_gf_subdirs_wildcard()
let cwd = getcwd()
diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim
index e390bd5cc8..be83728b4f 100644
--- a/src/nvim/testdir/test_hardcopy.vim
+++ b/src/nvim/testdir/test_hardcopy.vim
@@ -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
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 9c5cc51f79..7e8b8c5eef 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -255,6 +255,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