Skip to content

Commit aeb1c97

Browse files
yegappanchrisbra
authored andcommitted
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 <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 626b6ab commit aeb1c97

17 files changed

Lines changed: 418 additions & 25 deletions

runtime/doc/eval.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 9.1. Last change: 2024 Jul 28
1+
*eval.txt* For Vim version 9.1. Last change: 2024 Oct 22
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2223,7 +2223,8 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
22232223

22242224
*v:fname* *fname-variable*
22252225
v:fname When evaluating 'includeexpr': the file name that was
2226-
detected. Empty otherwise.
2226+
detected. When evaluating 'findexpr': the argument passed to
2227+
the |:find| command. Empty otherwise.
22272228

22282229
*v:fname_in* *fname_in-variable*
22292230
v:fname_in The name of the input file. Valid while evaluating:

runtime/doc/options.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,6 +3552,51 @@ A jump table for the options with a short description can be found at |Q_op|.
35523552
eob EndOfBuffer |hl-EndOfBuffer|
35533553
lastline NonText |hl-NonText|
35543554

3555+
*'findexpr'* *'fexpr'*
3556+
'findexpr' 'fexpr' string (default "")
3557+
global or local to buffer |global-local|
3558+
{not available when compiled without the |+eval|
3559+
feature}
3560+
Expression that is evaluated to obtain the filename(s) for the |:find|
3561+
command. When this option is empty, the internal |file-searching|
3562+
mechanism is used.
3563+
3564+
While evaluating the expression, the |v:fname| variable is set to the
3565+
argument of the |:find| command.
3566+
3567+
The expression is evaluated only once per |:find| command invocation.
3568+
The expression can process all the directories specified in 'path'.
3569+
3570+
If a match is found, the expression should return a |List| containing
3571+
one or more file names. If a match is not found, the expression
3572+
should return an empty List.
3573+
3574+
If any errors are encountered during the expression evaluation, an
3575+
empty List is used as the return value.
3576+
3577+
Using a function call without arguments is faster |expr-option-function|
3578+
3579+
It is not allowed to change text or jump to another window while
3580+
evaluating 'findexpr' |textlock|.
3581+
3582+
This option cannot be set from a |modeline| or in the |sandbox|, for
3583+
security reasons.
3584+
3585+
Examples:
3586+
>
3587+
" Use glob()
3588+
func FindExprGlob()
3589+
return glob(v:fname, v:false, v:true)
3590+
endfunc
3591+
set findexpr=FindExprGlob()
3592+
3593+
" Use the 'git ls-files' output
3594+
func FindGitFiles()
3595+
let fnames = systemlist('git ls-files')
3596+
return fnames->filter('v:val =~? v:fname')
3597+
endfunc
3598+
set findexpr=FindGitFiles()
3599+
<
35553600
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
35563601
'fixendofline' 'fixeol' boolean (default on)
35573602
local to buffer

runtime/doc/quickref.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*quickref.txt* For Vim version 9.1. Last change: 2024 Mar 03
1+
*quickref.txt* For Vim version 9.1. Last change: 2024 Oct 22
22

33

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

runtime/doc/tags

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ $quote eval.txt /*$quote*
267267
'fenc' options.txt /*'fenc'*
268268
'fencs' options.txt /*'fencs'*
269269
'fex' options.txt /*'fex'*
270+
'fexpr' options.txt /*'fexpr'*
270271
'ff' options.txt /*'ff'*
271272
'ffs' options.txt /*'ffs'*
272273
'fic' options.txt /*'fic'*
@@ -277,6 +278,7 @@ $quote eval.txt /*$quote*
277278
'fileignorecase' options.txt /*'fileignorecase'*
278279
'filetype' options.txt /*'filetype'*
279280
'fillchars' options.txt /*'fillchars'*
281+
'findexpr' options.txt /*'findexpr'*
280282
'fixendofline' options.txt /*'fixendofline'*
281283
'fixeol' options.txt /*'fixeol'*
282284
'fk' options.txt /*'fk'*

runtime/doc/version9.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*version9.txt* For Vim version 9.1. Last change: 2024 Oct 14
1+
*version9.txt* For Vim version 9.1. Last change: 2024 Oct 22
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41649,6 +41649,8 @@ Options: ~
4164941649

4165041650
'completeitemalign' Order of |complete-items| in Insert mode completion
4165141651
popup
41652+
'findexpr' Vim expression to obtain the results for a |:find|
41653+
command
4165241654
'winfixbuf' Keep buffer focused in a window
4165341655
'tabclose' Which tab page to focus after closing a tab page
4165441656
't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420)

src/buffer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,7 @@ free_buf_options(
24122412
clear_string_option(&buf->b_p_fp);
24132413
#if defined(FEAT_EVAL)
24142414
clear_string_option(&buf->b_p_fex);
2415+
clear_string_option(&buf->b_p_fexpr);
24152416
#endif
24162417
#ifdef FEAT_CRYPT
24172418
# ifdef FEAT_SODIUM

src/ex_docmd.c

Lines changed: 136 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6923,6 +6923,103 @@ ex_wrongmodifier(exarg_T *eap)
69236923
eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd);
69246924
}
69256925

6926+
#ifdef FEAT_EVAL
6927+
/*
6928+
* Evaluate the 'findexpr' expression and return the result. When evaluating
6929+
* the expression, v:fname is set to the ":find" command argument.
6930+
*/
6931+
static list_T *
6932+
eval_findexpr(char_u *ptr, int len)
6933+
{
6934+
sctx_T saved_sctx = current_sctx;
6935+
int use_sandbox = FALSE;
6936+
char_u *findexpr;
6937+
char_u *arg;
6938+
typval_T tv;
6939+
list_T *retlist = NULL;
6940+
6941+
if (*curbuf->b_p_fexpr == NUL)
6942+
{
6943+
use_sandbox = was_set_insecurely((char_u *)"findexpr", OPT_GLOBAL);
6944+
findexpr = p_fexpr;
6945+
}
6946+
else
6947+
{
6948+
use_sandbox = was_set_insecurely((char_u *)"findexpr", OPT_LOCAL);
6949+
findexpr = curbuf->b_p_fexpr;
6950+
}
6951+
6952+
set_vim_var_string(VV_FNAME, ptr, len);
6953+
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
6954+
6955+
arg = skipwhite(findexpr);
6956+
6957+
if (use_sandbox)
6958+
++sandbox;
6959+
++textlock;
6960+
6961+
// Evaluate the expression. If the expression is "FuncName()" call the
6962+
// function directly.
6963+
if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
6964+
retlist = NULL;
6965+
else
6966+
{
6967+
if (tv.v_type == VAR_LIST)
6968+
retlist = list_copy(tv.vval.v_list, TRUE, TRUE, get_copyID());
6969+
clear_tv(&tv);
6970+
}
6971+
if (use_sandbox)
6972+
--sandbox;
6973+
--textlock;
6974+
clear_evalarg(&EVALARG_EVALUATE, NULL);
6975+
6976+
set_vim_var_string(VV_FNAME, NULL, 0);
6977+
current_sctx = saved_sctx;
6978+
6979+
return retlist;
6980+
}
6981+
6982+
/*
6983+
* Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
6984+
* the n'th matching file.
6985+
*/
6986+
static char_u *
6987+
findexpr_find_file(char_u *findarg, int findarg_len, int count)
6988+
{
6989+
list_T *fname_list;
6990+
char_u *ret_fname = NULL;
6991+
char_u cc;
6992+
int fname_count;
6993+
6994+
cc = findarg[findarg_len];
6995+
findarg[findarg_len] = NUL;
6996+
6997+
fname_list = eval_findexpr(findarg, findarg_len);
6998+
fname_count = list_len(fname_list);
6999+
7000+
if (fname_count == 0)
7001+
semsg(_(e_cant_find_file_str_in_path), findarg);
7002+
else
7003+
{
7004+
if (count > fname_count)
7005+
semsg(_(e_no_more_file_str_found_in_path), findarg);
7006+
else
7007+
{
7008+
listitem_T *li = list_find(fname_list, count - 1);
7009+
if (li != NULL && li->li_tv.v_type == VAR_STRING)
7010+
ret_fname = vim_strsave(li->li_tv.vval.v_string);
7011+
}
7012+
}
7013+
7014+
if (fname_list != NULL)
7015+
list_free(fname_list);
7016+
7017+
findarg[findarg_len] = cc;
7018+
7019+
return ret_fname;
7020+
}
7021+
#endif
7022+
69267023
/*
69277024
* :sview [+command] file split window with new file, read-only
69287025
* :split [[+command] file] split window with current or new file
@@ -6972,11 +7069,22 @@ ex_splitview(exarg_T *eap)
69727069
{
69737070
char_u *file_to_find = NULL;
69747071
char *search_ctx = NULL;
6975-
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
6976-
FNAME_MESS, TRUE, curbuf->b_ffname,
6977-
&file_to_find, &search_ctx);
6978-
vim_free(file_to_find);
6979-
vim_findfile_cleanup(search_ctx);
7072+
7073+
if (*get_findexpr() != NUL)
7074+
{
7075+
#ifdef FEAT_EVAL
7076+
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
7077+
eap->addr_count > 0 ? eap->line2 : 1);
7078+
#endif
7079+
}
7080+
else
7081+
{
7082+
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
7083+
FNAME_MESS, TRUE, curbuf->b_ffname,
7084+
&file_to_find, &search_ctx);
7085+
vim_free(file_to_find);
7086+
vim_findfile_cleanup(search_ctx);
7087+
}
69807088
if (fname == NULL)
69817089
goto theend;
69827090
eap->arg = fname;
@@ -7241,27 +7349,37 @@ ex_find(exarg_T *eap)
72417349
if (!check_can_set_curbuf_forceit(eap->forceit))
72427350
return;
72437351

7244-
char_u *fname;
7352+
char_u *fname = NULL;
72457353
int count;
72467354
char_u *file_to_find = NULL;
72477355
char *search_ctx = NULL;
72487356

7249-
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
7250-
TRUE, curbuf->b_ffname, &file_to_find, &search_ctx);
7251-
if (eap->addr_count > 0)
7357+
if (*get_findexpr() != NUL)
7358+
{
7359+
#ifdef FEAT_EVAL
7360+
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
7361+
eap->addr_count > 0 ? eap->line2 : 1);
7362+
#endif
7363+
}
7364+
else
72527365
{
7253-
// Repeat finding the file "count" times. This matters when it appears
7254-
// several times in the path.
7255-
count = eap->line2;
7256-
while (fname != NULL && --count > 0)
7366+
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
7367+
TRUE, curbuf->b_ffname, &file_to_find, &search_ctx);
7368+
if (eap->addr_count > 0)
72577369
{
7258-
vim_free(fname);
7259-
fname = find_file_in_path(NULL, 0, FNAME_MESS,
7260-
FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
7370+
// Repeat finding the file "count" times. This matters when it appears
7371+
// several times in the path.
7372+
count = eap->line2;
7373+
while (fname != NULL && --count > 0)
7374+
{
7375+
vim_free(fname);
7376+
fname = find_file_in_path(NULL, 0, FNAME_MESS,
7377+
FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
7378+
}
72617379
}
7380+
VIM_CLEAR(file_to_find);
7381+
vim_findfile_cleanup(search_ctx);
72627382
}
7263-
VIM_CLEAR(file_to_find);
7264-
vim_findfile_cleanup(search_ctx);
72657383

72667384
if (fname == NULL)
72677385
return;

src/option.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6313,6 +6313,11 @@ unset_global_local_option(char_u *name, void *from)
63136313
case PV_FP:
63146314
clear_string_option(&buf->b_p_fp);
63156315
break;
6316+
# ifdef FEAT_EVAL
6317+
case PV_FEXPR:
6318+
clear_string_option(&buf->b_p_fexpr);
6319+
break;
6320+
# endif
63166321
# ifdef FEAT_QUICKFIX
63176322
case PV_EFM:
63186323
clear_string_option(&buf->b_p_efm);
@@ -6391,6 +6396,9 @@ get_varp_scope(struct vimoption *p, int scope)
63916396
switch ((int)p->indir)
63926397
{
63936398
case PV_FP: return (char_u *)&(curbuf->b_p_fp);
6399+
#ifdef FEAT_EVAL
6400+
case PV_FEXPR: return (char_u *)&(curbuf->b_p_fexpr);
6401+
#endif
63946402
#ifdef FEAT_QUICKFIX
63956403
case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
63966404
case PV_GP: return (char_u *)&(curbuf->b_p_gp);
@@ -6501,6 +6509,10 @@ get_varp(struct vimoption *p)
65016509
#endif
65026510
case PV_FP: return *curbuf->b_p_fp != NUL
65036511
? (char_u *)&(curbuf->b_p_fp) : p->var;
6512+
#ifdef FEAT_EVAL
6513+
case PV_FEXPR: return *curbuf->b_p_fexpr != NUL
6514+
? (char_u *)&curbuf->b_p_fexpr : p->var;
6515+
#endif
65046516
#ifdef FEAT_QUICKFIX
65056517
case PV_EFM: return *curbuf->b_p_efm != NUL
65066518
? (char_u *)&(curbuf->b_p_efm) : p->var;
@@ -6747,6 +6759,21 @@ get_equalprg(void)
67476759
return curbuf->b_p_ep;
67486760
}
67496761

6762+
/*
6763+
* Get the value of 'findexpr', either the buffer-local one or the global one.
6764+
*/
6765+
char_u *
6766+
get_findexpr(void)
6767+
{
6768+
#ifdef FEAT_EVAL
6769+
if (*curbuf->b_p_fexpr == NUL)
6770+
return p_fexpr;
6771+
return curbuf->b_p_fexpr;
6772+
#else
6773+
return (char_u *)"";
6774+
#endif
6775+
}
6776+
67506777
/*
67516778
* Copy options from one window to another.
67526779
* Used when splitting a window.
@@ -7275,6 +7302,10 @@ buf_copy_options(buf_T *buf, int flags)
72757302
buf->b_p_efm = empty_option;
72767303
#endif
72777304
buf->b_p_ep = empty_option;
7305+
#if defined(FEAT_EVAL)
7306+
buf->b_p_fexpr = vim_strsave(p_fexpr);
7307+
COPY_OPT_SCTX(buf, BV_FEXPR);
7308+
#endif
72787309
buf->b_p_kp = empty_option;
72797310
buf->b_p_path = empty_option;
72807311
buf->b_p_tags = empty_option;

src/option.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,9 @@ EXTERN char_u *p_ffs; // 'fileformats'
596596
EXTERN int p_fic; // 'fileignorecase'
597597
EXTERN char_u *p_ft; // 'filetype'
598598
EXTERN char_u *p_fcs; // 'fillchar'
599+
#ifdef FEAT_EVAL
600+
EXTERN char_u *p_fexpr; // 'findexpr'
601+
#endif
599602
EXTERN int p_fixeol; // 'fixendofline'
600603
#ifdef FEAT_FOLDING
601604
EXTERN char_u *p_fcl; // 'foldclose'
@@ -1168,6 +1171,7 @@ enum
11681171
, BV_EP
11691172
, BV_ET
11701173
, BV_FENC
1174+
, BV_FEXPR
11711175
, BV_FP
11721176
#ifdef FEAT_EVAL
11731177
, BV_BEXPR

0 commit comments

Comments
 (0)