0
0
mirror of https://github.com/vim/vim.git synced 2025-08-26 20:03:41 -04:00

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>
This commit is contained in:
Yegappan Lakshmanan 2024-10-22 23:42:20 +02:00 committed by Christian Brabandt
parent 626b6ab486
commit aeb1c97db5
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
17 changed files with 420 additions and 27 deletions

View File

@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@ -2223,7 +2223,8 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
*v:fname* *fname-variable* *v:fname* *fname-variable*
v:fname When evaluating 'includeexpr': the file name that was 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* *fname_in-variable*
v:fname_in The name of the input file. Valid while evaluating: v:fname_in The name of the input file. Valid while evaluating:

View File

@ -3552,6 +3552,51 @@ A jump table for the options with a short description can be found at |Q_op|.
eob EndOfBuffer |hl-EndOfBuffer| eob EndOfBuffer |hl-EndOfBuffer|
lastline NonText |hl-NonText| 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'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on) 'fixendofline' 'fixeol' boolean (default on)
local to buffer local to buffer

View File

@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@ -707,6 +707,7 @@ Short explanation of each option: *option-list*
'fileignorecase' 'fic' ignore case when using file names 'fileignorecase' 'fic' ignore case when using file names
'filetype' 'ft' type of file, used for autocommands 'filetype' 'ft' type of file, used for autocommands
'fillchars' 'fcs' characters to use for displaying special items '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> 'fixendofline' 'fixeol' make sure last line in file has <EOL>
'fkmap' 'fk' obsolete option for Farsi 'fkmap' 'fk' obsolete option for Farsi
'foldclose' 'fcl' close a fold when the cursor leaves it 'foldclose' 'fcl' close a fold when the cursor leaves it

View File

@ -267,6 +267,7 @@ $quote eval.txt /*$quote*
'fenc' options.txt /*'fenc'* 'fenc' options.txt /*'fenc'*
'fencs' options.txt /*'fencs'* 'fencs' options.txt /*'fencs'*
'fex' options.txt /*'fex'* 'fex' options.txt /*'fex'*
'fexpr' options.txt /*'fexpr'*
'ff' options.txt /*'ff'* 'ff' options.txt /*'ff'*
'ffs' options.txt /*'ffs'* 'ffs' options.txt /*'ffs'*
'fic' options.txt /*'fic'* 'fic' options.txt /*'fic'*
@ -277,6 +278,7 @@ $quote eval.txt /*$quote*
'fileignorecase' options.txt /*'fileignorecase'* 'fileignorecase' options.txt /*'fileignorecase'*
'filetype' options.txt /*'filetype'* 'filetype' options.txt /*'filetype'*
'fillchars' options.txt /*'fillchars'* 'fillchars' options.txt /*'fillchars'*
'findexpr' options.txt /*'findexpr'*
'fixendofline' options.txt /*'fixendofline'* 'fixendofline' options.txt /*'fixendofline'*
'fixeol' options.txt /*'fixeol'* 'fixeol' options.txt /*'fixeol'*
'fk' options.txt /*'fk'* 'fk' options.txt /*'fk'*

View File

@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@ -41649,6 +41649,8 @@ Options: ~
'completeitemalign' Order of |complete-items| in Insert mode completion 'completeitemalign' Order of |complete-items| in Insert mode completion
popup popup
'findexpr' Vim expression to obtain the results for a |:find|
command
'winfixbuf' Keep buffer focused in a window 'winfixbuf' Keep buffer focused in a window
'tabclose' Which tab page to focus after closing a tab page 'tabclose' Which tab page to focus after closing a tab page
't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420) 't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420)

View File

@ -2412,6 +2412,7 @@ free_buf_options(
clear_string_option(&buf->b_p_fp); clear_string_option(&buf->b_p_fp);
#if defined(FEAT_EVAL) #if defined(FEAT_EVAL)
clear_string_option(&buf->b_p_fex); clear_string_option(&buf->b_p_fex);
clear_string_option(&buf->b_p_fexpr);
#endif #endif
#ifdef FEAT_CRYPT #ifdef FEAT_CRYPT
# ifdef FEAT_SODIUM # ifdef FEAT_SODIUM

View File

@ -6923,6 +6923,103 @@ ex_wrongmodifier(exarg_T *eap)
eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd); 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 * :sview [+command] file split window with new file, read-only
* :split [[+command] file] split window with current or new file * :split [[+command] file] split window with current or new file
@ -6972,11 +7069,22 @@ ex_splitview(exarg_T *eap)
{ {
char_u *file_to_find = NULL; char_u *file_to_find = NULL;
char *search_ctx = NULL; char *search_ctx = NULL;
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
FNAME_MESS, TRUE, curbuf->b_ffname, if (*get_findexpr() != NUL)
&file_to_find, &search_ctx); {
vim_free(file_to_find); #ifdef FEAT_EVAL
vim_findfile_cleanup(search_ctx); 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) if (fname == NULL)
goto theend; goto theend;
eap->arg = fname; eap->arg = fname;
@ -7241,27 +7349,37 @@ ex_find(exarg_T *eap)
if (!check_can_set_curbuf_forceit(eap->forceit)) if (!check_can_set_curbuf_forceit(eap->forceit))
return; return;
char_u *fname; char_u *fname = NULL;
int count; int count;
char_u *file_to_find = NULL; char_u *file_to_find = NULL;
char *search_ctx = NULL; char *search_ctx = NULL;
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, if (*get_findexpr() != NUL)
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 #ifdef FEAT_EVAL
// several times in the path. fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
count = eap->line2; eap->addr_count > 0 ? eap->line2 : 1);
while (fname != NULL && --count > 0) #endif
{ }
vim_free(fname); else
fname = find_file_in_path(NULL, 0, FNAME_MESS, {
FALSE, curbuf->b_ffname, &file_to_find, &search_ctx); 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);
} }
VIM_CLEAR(file_to_find);
vim_findfile_cleanup(search_ctx);
if (fname == NULL) if (fname == NULL)
return; return;

View File

@ -6313,6 +6313,11 @@ unset_global_local_option(char_u *name, void *from)
case PV_FP: case PV_FP:
clear_string_option(&buf->b_p_fp); clear_string_option(&buf->b_p_fp);
break; break;
# ifdef FEAT_EVAL
case PV_FEXPR:
clear_string_option(&buf->b_p_fexpr);
break;
# endif
# ifdef FEAT_QUICKFIX # ifdef FEAT_QUICKFIX
case PV_EFM: case PV_EFM:
clear_string_option(&buf->b_p_efm); clear_string_option(&buf->b_p_efm);
@ -6391,6 +6396,9 @@ get_varp_scope(struct vimoption *p, int scope)
switch ((int)p->indir) switch ((int)p->indir)
{ {
case PV_FP: return (char_u *)&(curbuf->b_p_fp); 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 #ifdef FEAT_QUICKFIX
case PV_EFM: return (char_u *)&(curbuf->b_p_efm); case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
case PV_GP: return (char_u *)&(curbuf->b_p_gp); case PV_GP: return (char_u *)&(curbuf->b_p_gp);
@ -6501,6 +6509,10 @@ get_varp(struct vimoption *p)
#endif #endif
case PV_FP: return *curbuf->b_p_fp != NUL case PV_FP: return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var; ? (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 #ifdef FEAT_QUICKFIX
case PV_EFM: return *curbuf->b_p_efm != NUL case PV_EFM: return *curbuf->b_p_efm != NUL
? (char_u *)&(curbuf->b_p_efm) : p->var; ? (char_u *)&(curbuf->b_p_efm) : p->var;
@ -6747,6 +6759,21 @@ get_equalprg(void)
return curbuf->b_p_ep; return curbuf->b_p_ep;
} }
/*
* 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. * Copy options from one window to another.
* Used when splitting a window. * Used when splitting a window.
@ -7275,6 +7302,10 @@ buf_copy_options(buf_T *buf, int flags)
buf->b_p_efm = empty_option; buf->b_p_efm = empty_option;
#endif #endif
buf->b_p_ep = empty_option; 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_kp = empty_option;
buf->b_p_path = empty_option; buf->b_p_path = empty_option;
buf->b_p_tags = empty_option; buf->b_p_tags = empty_option;

View File

@ -596,6 +596,9 @@ EXTERN char_u *p_ffs; // 'fileformats'
EXTERN int p_fic; // 'fileignorecase' EXTERN int p_fic; // 'fileignorecase'
EXTERN char_u *p_ft; // 'filetype' EXTERN char_u *p_ft; // 'filetype'
EXTERN char_u *p_fcs; // 'fillchar' EXTERN char_u *p_fcs; // 'fillchar'
#ifdef FEAT_EVAL
EXTERN char_u *p_fexpr; // 'findexpr'
#endif
EXTERN int p_fixeol; // 'fixendofline' EXTERN int p_fixeol; // 'fixendofline'
#ifdef FEAT_FOLDING #ifdef FEAT_FOLDING
EXTERN char_u *p_fcl; // 'foldclose' EXTERN char_u *p_fcl; // 'foldclose'
@ -1168,6 +1171,7 @@ enum
, BV_EP , BV_EP
, BV_ET , BV_ET
, BV_FENC , BV_FENC
, BV_FEXPR
, BV_FP , BV_FP
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
, BV_BEXPR , BV_BEXPR

View File

@ -74,6 +74,7 @@
#define PV_FP OPT_BOTH(OPT_BUF(BV_FP)) #define PV_FP OPT_BOTH(OPT_BUF(BV_FP))
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
# define PV_FEX OPT_BUF(BV_FEX) # define PV_FEX OPT_BUF(BV_FEX)
# define PV_FEXPR OPT_BOTH(OPT_BUF(BV_FEXPR))
#endif #endif
#define PV_FF OPT_BUF(BV_FF) #define PV_FF OPT_BUF(BV_FF)
#define PV_FLP OPT_BUF(BV_FLP) #define PV_FLP OPT_BUF(BV_FLP)
@ -958,6 +959,15 @@ static struct vimoption options[] =
{(char_u *)"vert:|,fold:-,eob:~,lastline:@", {(char_u *)"vert:|,fold:-,eob:~,lastline:@",
(char_u *)0L} (char_u *)0L}
SCTX_INIT}, 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, {"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
(char_u *)&p_fixeol, PV_FIXEOL, (char_u *)&p_fixeol, PV_FIXEOL,
did_set_eof_eol_fixeol_bomb, NULL, did_set_eof_eol_fixeol_bomb, NULL,

View File

@ -324,6 +324,9 @@ check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_efm); check_string_option(&buf->b_p_efm);
#endif #endif
check_string_option(&buf->b_p_ep); 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_path);
check_string_option(&buf->b_p_tags); check_string_option(&buf->b_p_tags);
check_string_option(&buf->b_p_tc); check_string_option(&buf->b_p_tc);
@ -3132,8 +3135,8 @@ expand_set_nrformats(optexpand_T *args, int *numMatches, char_u ***matches)
#if defined(FEAT_EVAL) || defined(PROTO) #if defined(FEAT_EVAL) || defined(PROTO)
/* /*
* One of the '*expr' options is changed: 'balloonexpr', 'diffexpr', * One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
* 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr', * 'findexpr', 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr',
* 'patchexpr', 'printexpr' and 'charconvert'. * 'indentexpr', 'patchexpr', 'printexpr' and 'charconvert'.
* *
*/ */
char * char *

View File

@ -120,6 +120,7 @@ char_u *get_option_var(int opt_idx);
char_u *get_option_fullname(int opt_idx); char_u *get_option_fullname(int opt_idx);
opt_did_set_cb_T get_option_did_set_cb(int opt_idx); opt_did_set_cb_T get_option_did_set_cb(int opt_idx);
char_u *get_equalprg(void); char_u *get_equalprg(void);
char_u *get_findexpr(void);
void win_copy_options(win_T *wp_from, win_T *wp_to); void win_copy_options(win_T *wp_from, win_T *wp_to);
void after_copy_winopt(win_T *wp); void after_copy_winopt(win_T *wp);
void copy_winopt(winopt_T *from, winopt_T *to); void copy_winopt(winopt_T *from, winopt_T *to);

View File

@ -3327,6 +3327,9 @@ struct file_buffer
char_u *b_p_efm; // 'errorformat' local value char_u *b_p_efm; // 'errorformat' local value
#endif #endif
char_u *b_p_ep; // 'equalprg' local value 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 char_u *b_p_path; // 'path' local value
int b_p_ar; // 'autoread' local value int b_p_ar; // 'autoread' local value
char_u *b_p_tags; // 'tags' local value char_u *b_p_tags; // 'tags' local value

View File

@ -1,5 +1,7 @@
" Test findfile() and finddir() " Test findfile() and finddir()
source check.vim
let s:files = [ 'Xfinddir1/foo', let s:files = [ 'Xfinddir1/foo',
\ 'Xfinddir1/bar', \ 'Xfinddir1/bar',
\ 'Xfinddir1/Xdir2/foo', \ 'Xfinddir1/Xdir2/foo',
@ -281,4 +283,170 @@ func Test_find_non_existing_path()
let &path = save_path let &path = save_path
endfunc 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 " vim: shiftwidth=2 sts=2 expandtab

View File

@ -208,6 +208,7 @@ func Test_modeline_fails_always()
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
call s:modeline_fails('exrc', 'exrc=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('formatprg', 'formatprg=Something()', 'E520:')
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')

View File

@ -1570,7 +1570,7 @@ endfunc
" Test for changing options in a sandbox " Test for changing options in a sandbox
func Test_opt_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 set ' .. opt .. '?', 'E48:')
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:') call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor endfor

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
810,
/**/ /**/
809, 809,
/**/ /**/