patch 9.1.0810: cannot easily adjust the |:find| command
Problem: cannot easily adjust the |:find| command
Solution: Add support for the 'findexpr' option (Yegappan Lakshmanan)
closes: #15901
closes: #15905
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index e2c6967..80ccce8 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 9.1. Last change: 2024 Jul 28
+*eval.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2223,7 +2223,8 @@
*v:fname* *fname-variable*
v:fname When evaluating 'includeexpr': the file name that was
- detected. Empty otherwise.
+ detected. When evaluating 'findexpr': the argument passed to
+ the |:find| command. Empty otherwise.
*v:fname_in* *fname_in-variable*
v:fname_in The name of the input file. Valid while evaluating:
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index bc0e183..5593523 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3552,6 +3552,51 @@
eob EndOfBuffer |hl-EndOfBuffer|
lastline NonText |hl-NonText|
+ *'findexpr'* *'fexpr'*
+'findexpr' 'fexpr' string (default "")
+ global or local to buffer |global-local|
+ {not available when compiled without the |+eval|
+ feature}
+ Expression that is evaluated to obtain the filename(s) for the |:find|
+ command. When this option is empty, the internal |file-searching|
+ mechanism is used.
+
+ While evaluating the expression, the |v:fname| variable is set to the
+ argument of the |:find| command.
+
+ The expression is evaluated only once per |:find| command invocation.
+ The expression can process all the directories specified in 'path'.
+
+ If a match is found, the expression should return a |List| containing
+ one or more file names. If a match is not found, the expression
+ should return an empty List.
+
+ If any errors are encountered during the expression evaluation, an
+ empty List is used as the return value.
+
+ Using a function call without arguments is faster |expr-option-function|
+
+ It is not allowed to change text or jump to another window while
+ evaluating 'findexpr' |textlock|.
+
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+
+ Examples:
+>
+ " Use glob()
+ func FindExprGlob()
+ return glob(v:fname, v:false, v:true)
+ endfunc
+ set findexpr=FindExprGlob()
+
+ " Use the 'git ls-files' output
+ func FindGitFiles()
+ let fnames = systemlist('git ls-files')
+ return fnames->filter('v:val =~? v:fname')
+ endfunc
+ set findexpr=FindGitFiles()
+<
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on)
local to buffer
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 42b5228..0f7453a 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -1,4 +1,4 @@
-*quickref.txt* For Vim version 9.1. Last change: 2024 Mar 03
+*quickref.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -707,6 +707,7 @@
'fileignorecase' 'fic' ignore case when using file names
'filetype' 'ft' type of file, used for autocommands
'fillchars' 'fcs' characters to use for displaying special items
+'findexpr' 'fexpr' expression to evaluate for |:find|
'fixendofline' 'fixeol' make sure last line in file has <EOL>
'fkmap' 'fk' obsolete option for Farsi
'foldclose' 'fcl' close a fold when the cursor leaves it
diff --git a/runtime/doc/tags b/runtime/doc/tags
index f8359ac..7a6e84c 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -267,6 +267,7 @@
'fenc' options.txt /*'fenc'*
'fencs' options.txt /*'fencs'*
'fex' options.txt /*'fex'*
+'fexpr' options.txt /*'fexpr'*
'ff' options.txt /*'ff'*
'ffs' options.txt /*'ffs'*
'fic' options.txt /*'fic'*
@@ -277,6 +278,7 @@
'fileignorecase' options.txt /*'fileignorecase'*
'filetype' options.txt /*'filetype'*
'fillchars' options.txt /*'fillchars'*
+'findexpr' options.txt /*'findexpr'*
'fixendofline' options.txt /*'fixendofline'*
'fixeol' options.txt /*'fixeol'*
'fk' options.txt /*'fk'*
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 400ccd7..af180a2 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.1. Last change: 2024 Oct 14
+*version9.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41649,6 +41649,8 @@
'completeitemalign' Order of |complete-items| in Insert mode completion
popup
+'findexpr' Vim expression to obtain the results for a |:find|
+ command
'winfixbuf' Keep buffer focused in a window
'tabclose' Which tab page to focus after closing a tab page
't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420)
diff --git a/src/buffer.c b/src/buffer.c
index 5359527..f1e1330 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2412,6 +2412,7 @@
clear_string_option(&buf->b_p_fp);
#if defined(FEAT_EVAL)
clear_string_option(&buf->b_p_fex);
+ clear_string_option(&buf->b_p_fexpr);
#endif
#ifdef FEAT_CRYPT
# ifdef FEAT_SODIUM
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 32cd7c5..9447a2d 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6923,6 +6923,103 @@
eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd);
}
+#ifdef FEAT_EVAL
+/*
+ * Evaluate the 'findexpr' expression and return the result. When evaluating
+ * the expression, v:fname is set to the ":find" command argument.
+ */
+ static list_T *
+eval_findexpr(char_u *ptr, int len)
+{
+ sctx_T saved_sctx = current_sctx;
+ int use_sandbox = FALSE;
+ char_u *findexpr;
+ char_u *arg;
+ typval_T tv;
+ list_T *retlist = NULL;
+
+ if (*curbuf->b_p_fexpr == NUL)
+ {
+ use_sandbox = was_set_insecurely((char_u *)"findexpr", OPT_GLOBAL);
+ findexpr = p_fexpr;
+ }
+ else
+ {
+ use_sandbox = was_set_insecurely((char_u *)"findexpr", OPT_LOCAL);
+ findexpr = curbuf->b_p_fexpr;
+ }
+
+ set_vim_var_string(VV_FNAME, ptr, len);
+ current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
+
+ arg = skipwhite(findexpr);
+
+ if (use_sandbox)
+ ++sandbox;
+ ++textlock;
+
+ // Evaluate the expression. If the expression is "FuncName()" call the
+ // function directly.
+ if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
+ retlist = NULL;
+ else
+ {
+ if (tv.v_type == VAR_LIST)
+ retlist = list_copy(tv.vval.v_list, TRUE, TRUE, get_copyID());
+ clear_tv(&tv);
+ }
+ if (use_sandbox)
+ --sandbox;
+ --textlock;
+ clear_evalarg(&EVALARG_EVALUATE, NULL);
+
+ set_vim_var_string(VV_FNAME, NULL, 0);
+ current_sctx = saved_sctx;
+
+ return retlist;
+}
+
+/*
+ * Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
+ * the n'th matching file.
+ */
+ static char_u *
+findexpr_find_file(char_u *findarg, int findarg_len, int count)
+{
+ list_T *fname_list;
+ char_u *ret_fname = NULL;
+ char_u cc;
+ int fname_count;
+
+ cc = findarg[findarg_len];
+ findarg[findarg_len] = NUL;
+
+ fname_list = eval_findexpr(findarg, findarg_len);
+ fname_count = list_len(fname_list);
+
+ if (fname_count == 0)
+ semsg(_(e_cant_find_file_str_in_path), findarg);
+ else
+ {
+ if (count > fname_count)
+ semsg(_(e_no_more_file_str_found_in_path), findarg);
+ else
+ {
+ listitem_T *li = list_find(fname_list, count - 1);
+ if (li != NULL && li->li_tv.v_type == VAR_STRING)
+ ret_fname = vim_strsave(li->li_tv.vval.v_string);
+ }
+ }
+
+ if (fname_list != NULL)
+ list_free(fname_list);
+
+ findarg[findarg_len] = cc;
+
+ return ret_fname;
+}
+#endif
+
/*
* :sview [+command] file split window with new file, read-only
* :split [[+command] file] split window with current or new file
@@ -6972,11 +7069,22 @@
{
char_u *file_to_find = NULL;
char *search_ctx = NULL;
- fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
- FNAME_MESS, TRUE, curbuf->b_ffname,
- &file_to_find, &search_ctx);
- vim_free(file_to_find);
- vim_findfile_cleanup(search_ctx);
+
+ if (*get_findexpr() != NUL)
+ {
+#ifdef FEAT_EVAL
+ fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+#endif
+ }
+ else
+ {
+ fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
+ FNAME_MESS, TRUE, curbuf->b_ffname,
+ &file_to_find, &search_ctx);
+ vim_free(file_to_find);
+ vim_findfile_cleanup(search_ctx);
+ }
if (fname == NULL)
goto theend;
eap->arg = fname;
@@ -7241,27 +7349,37 @@
if (!check_can_set_curbuf_forceit(eap->forceit))
return;
- char_u *fname;
+ char_u *fname = NULL;
int count;
char_u *file_to_find = NULL;
char *search_ctx = NULL;
- fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
- TRUE, curbuf->b_ffname, &file_to_find, &search_ctx);
- if (eap->addr_count > 0)
+ if (*get_findexpr() != NUL)
{
- // Repeat finding the file "count" times. This matters when it appears
- // several times in the path.
- count = eap->line2;
- while (fname != NULL && --count > 0)
- {
- vim_free(fname);
- fname = find_file_in_path(NULL, 0, FNAME_MESS,
- FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
- }
+#ifdef FEAT_EVAL
+ fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+#endif
}
- VIM_CLEAR(file_to_find);
- vim_findfile_cleanup(search_ctx);
+ else
+ {
+ fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
+ TRUE, curbuf->b_ffname, &file_to_find, &search_ctx);
+ if (eap->addr_count > 0)
+ {
+ // Repeat finding the file "count" times. This matters when it appears
+ // several times in the path.
+ count = eap->line2;
+ while (fname != NULL && --count > 0)
+ {
+ vim_free(fname);
+ fname = find_file_in_path(NULL, 0, FNAME_MESS,
+ FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
+ }
+ }
+ VIM_CLEAR(file_to_find);
+ vim_findfile_cleanup(search_ctx);
+ }
if (fname == NULL)
return;
diff --git a/src/option.c b/src/option.c
index 84c469e..e82a79b 100644
--- a/src/option.c
+++ b/src/option.c
@@ -6313,6 +6313,11 @@
case PV_FP:
clear_string_option(&buf->b_p_fp);
break;
+# ifdef FEAT_EVAL
+ case PV_FEXPR:
+ clear_string_option(&buf->b_p_fexpr);
+ break;
+# endif
# ifdef FEAT_QUICKFIX
case PV_EFM:
clear_string_option(&buf->b_p_efm);
@@ -6391,6 +6396,9 @@
switch ((int)p->indir)
{
case PV_FP: return (char_u *)&(curbuf->b_p_fp);
+#ifdef FEAT_EVAL
+ case PV_FEXPR: return (char_u *)&(curbuf->b_p_fexpr);
+#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
case PV_GP: return (char_u *)&(curbuf->b_p_gp);
@@ -6501,6 +6509,10 @@
#endif
case PV_FP: return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var;
+#ifdef FEAT_EVAL
+ case PV_FEXPR: return *curbuf->b_p_fexpr != NUL
+ ? (char_u *)&curbuf->b_p_fexpr : p->var;
+#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return *curbuf->b_p_efm != NUL
? (char_u *)&(curbuf->b_p_efm) : p->var;
@@ -6748,6 +6760,21 @@
}
/*
+ * Get the value of 'findexpr', either the buffer-local one or the global one.
+ */
+ char_u *
+get_findexpr(void)
+{
+#ifdef FEAT_EVAL
+ if (*curbuf->b_p_fexpr == NUL)
+ return p_fexpr;
+ return curbuf->b_p_fexpr;
+#else
+ return (char_u *)"";
+#endif
+}
+
+/*
* Copy options from one window to another.
* Used when splitting a window.
*/
@@ -7275,6 +7302,10 @@
buf->b_p_efm = empty_option;
#endif
buf->b_p_ep = empty_option;
+#if defined(FEAT_EVAL)
+ buf->b_p_fexpr = vim_strsave(p_fexpr);
+ COPY_OPT_SCTX(buf, BV_FEXPR);
+#endif
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
buf->b_p_tags = empty_option;
diff --git a/src/option.h b/src/option.h
index ef39031..641514d 100644
--- a/src/option.h
+++ b/src/option.h
@@ -596,6 +596,9 @@
EXTERN int p_fic; // 'fileignorecase'
EXTERN char_u *p_ft; // 'filetype'
EXTERN char_u *p_fcs; // 'fillchar'
+#ifdef FEAT_EVAL
+EXTERN char_u *p_fexpr; // 'findexpr'
+#endif
EXTERN int p_fixeol; // 'fixendofline'
#ifdef FEAT_FOLDING
EXTERN char_u *p_fcl; // 'foldclose'
@@ -1168,6 +1171,7 @@
, BV_EP
, BV_ET
, BV_FENC
+ , BV_FEXPR
, BV_FP
#ifdef FEAT_EVAL
, BV_BEXPR
diff --git a/src/optiondefs.h b/src/optiondefs.h
index ccc527e..96c30e2 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -74,6 +74,7 @@
#define PV_FP OPT_BOTH(OPT_BUF(BV_FP))
#ifdef FEAT_EVAL
# define PV_FEX OPT_BUF(BV_FEX)
+# define PV_FEXPR OPT_BOTH(OPT_BUF(BV_FEXPR))
#endif
#define PV_FF OPT_BUF(BV_FF)
#define PV_FLP OPT_BUF(BV_FLP)
@@ -958,6 +959,15 @@
{(char_u *)"vert:|,fold:-,eob:~,lastline:@",
(char_u *)0L}
SCTX_INIT},
+ {"findexpr", "fexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE,
+#if defined(FEAT_EVAL)
+ (char_u *)&p_fexpr, PV_FEXPR, did_set_optexpr, NULL,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE, NULL, NULL,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
{"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
(char_u *)&p_fixeol, PV_FIXEOL,
did_set_eof_eol_fixeol_bomb, NULL,
diff --git a/src/optionstr.c b/src/optionstr.c
index c45b3bc..d82b8e1 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -324,6 +324,9 @@
check_string_option(&buf->b_p_efm);
#endif
check_string_option(&buf->b_p_ep);
+#ifdef FEAT_EVAL
+ check_string_option(&buf->b_p_fexpr);
+#endif
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
check_string_option(&buf->b_p_tc);
@@ -3132,8 +3135,8 @@
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
- * 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
- * 'patchexpr', 'printexpr' and 'charconvert'.
+ * 'findexpr', 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr',
+ * 'indentexpr', 'patchexpr', 'printexpr' and 'charconvert'.
*
*/
char *
diff --git a/src/proto/option.pro b/src/proto/option.pro
index db92bf2..fce9199 100644
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -120,6 +120,7 @@
char_u *get_option_fullname(int opt_idx);
opt_did_set_cb_T get_option_did_set_cb(int opt_idx);
char_u *get_equalprg(void);
+char_u *get_findexpr(void);
void win_copy_options(win_T *wp_from, win_T *wp_to);
void after_copy_winopt(win_T *wp);
void copy_winopt(winopt_T *from, winopt_T *to);
diff --git a/src/structs.h b/src/structs.h
index e4a79f5..39e60a4 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3327,6 +3327,9 @@
char_u *b_p_efm; // 'errorformat' local value
#endif
char_u *b_p_ep; // 'equalprg' local value
+#ifdef FEAT_EVAL
+ char_u *b_p_fexpr; // 'findexpr' local value
+#endif
char_u *b_p_path; // 'path' local value
int b_p_ar; // 'autoread' local value
char_u *b_p_tags; // 'tags' local value
diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim
index a5e18b9..f8be713 100644
--- a/src/testdir/test_findfile.vim
+++ b/src/testdir/test_findfile.vim
@@ -1,5 +1,7 @@
" Test findfile() and finddir()
+source check.vim
+
let s:files = [ 'Xfinddir1/foo',
\ 'Xfinddir1/bar',
\ 'Xfinddir1/Xdir2/foo',
@@ -281,4 +283,170 @@
let &path = save_path
endfunc
+" Test for 'findexpr'
+func Test_findexpr()
+ CheckUnix
+ call assert_equal('', &findexpr)
+ call writefile(['aFile'], 'Xfindexpr1.c', 'D')
+ call writefile(['bFile'], 'Xfindexpr2.c', 'D')
+ call writefile(['cFile'], 'Xfindexpr3.c', 'D')
+
+ " basic tests
+ func FindExpr1()
+ let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
+ "return fnames->copy()->filter('v:val =~? v:fname')->join("\n")
+ return fnames->copy()->filter('v:val =~? v:fname')
+ endfunc
+
+ set findexpr=FindExpr1()
+ find Xfindexpr3
+ call assert_match('Xfindexpr3.c', @%)
+ bw!
+ 2find Xfind
+ call assert_match('Xfindexpr2.c', @%)
+ bw!
+ call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path')
+ call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path')
+
+ sfind Xfindexpr2.c
+ call assert_match('Xfindexpr2.c', @%)
+ call assert_equal(2, winnr('$'))
+ %bw!
+ call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path')
+
+ tabfind Xfindexpr3.c
+ call assert_match('Xfindexpr3.c', @%)
+ call assert_equal(2, tabpagenr())
+ %bw!
+ call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path')
+
+ " Buffer-local option
+ set findexpr=['abc']
+ new
+ setlocal findexpr=['def']
+ find xxxx
+ call assert_equal('def', @%)
+ wincmd w
+ find xxxx
+ call assert_equal('abc', @%)
+ aboveleft new
+ call assert_equal("['abc']", &findexpr)
+ wincmd k
+ aboveleft new
+ call assert_equal("['abc']", &findexpr)
+ %bw!
+
+ " Empty list
+ set findexpr=[]
+ call assert_fails('find xxxx', 'E345: Can''t find file "xxxx" in path')
+
+ " Error cases
+
+ " Syntax error in the expression
+ set findexpr=FindExpr1{}
+ call assert_fails('find Xfindexpr1.c', 'E15: Invalid expression')
+
+ " Find expression throws an error
+ func FindExpr2()
+ throw 'find error'
+ endfunc
+ set findexpr=FindExpr2()
+ call assert_fails('find Xfindexpr1.c', 'find error')
+
+ " Try using a null string as the expression
+ set findexpr=test_null_string()
+ call assert_fails('find Xfindexpr1.c', 'E345: Can''t find file "Xfindexpr1.c" in path')
+
+ " Try to create a new window from the find expression
+ func FindExpr3()
+ new
+ return ["foo"]
+ endfunc
+ set findexpr=FindExpr3()
+ call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
+
+ " Try to modify the current buffer from the find expression
+ func FindExpr4()
+ call setline(1, ['abc'])
+ return ["foo"]
+ endfunc
+ set findexpr=FindExpr4()
+ call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
+
+ set findexpr&
+ delfunc! FindExpr1
+ delfunc! FindExpr2
+ delfunc! FindExpr3
+ delfunc! FindExpr4
+endfunc
+
+" Test for using a script-local function for 'findexpr'
+func Test_findexpr_scriptlocal_func()
+ func! s:FindExprScript()
+ let g:FindExprArg = v:fname
+ return ['xxx']
+ endfunc
+
+ set findexpr=s:FindExprScript()
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
+ new | only
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ set findexpr=<SID>FindExprScript()
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
+ new | only
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ let &findexpr = 's:FindExprScript()'
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
+ new | only
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ let &findexpr = '<SID>FindExprScript()'
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
+ new | only
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ set findexpr=
+ setglobal findexpr=s:FindExprScript()
+ setlocal findexpr=
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
+ call assert_equal('', &l:findexpr)
+ new | only
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ new | only
+ set findexpr=
+ setglobal findexpr=
+ setlocal findexpr=s:FindExprScript()
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
+ call assert_equal(expand('<SID>') .. 'FindExprScript()', &l:findexpr)
+ call assert_equal('', &g:findexpr)
+ let g:FindExprArg = ''
+ find abc
+ call assert_equal('abc', g:FindExprArg)
+ bw!
+
+ set findexpr=
+ delfunc s:FindExprScript
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim
index 0a7240b..bb5bc6b 100644
--- a/src/testdir/test_modeline.vim
+++ b/src/testdir/test_modeline.vim
@@ -208,6 +208,7 @@
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
call s:modeline_fails('exrc', 'exrc=Something()', 'E520:')
+ call s:modeline_fails('findexpr', 'findexpr=Something()', 'E520:')
call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:')
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 73e6d85..35b7d48 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -1570,7 +1570,7 @@
" Test for changing options in a sandbox
func Test_opt_sandbox()
- for opt in ['backupdir', 'cdpath', 'exrc']
+ for opt in ['backupdir', 'cdpath', 'exrc', 'findexpr']
call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor
diff --git a/src/version.c b/src/version.c
index f97eb8c..c60a7e9 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 810,
+/**/
809,
/**/
808,