aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-10-29 09:01:46 +0800
committerGitHub <noreply@github.com>2024-10-29 09:01:46 +0800
commit0e32c480604d76a319602656f2d8e2722497606e (patch)
treeb18deb6eaae322957f27ae87e134f7c8bb3ee5e9 /src
parent42fa3d080ec170b7927e36ec563efdd526c712d7 (diff)
parent60b3ccd850ca038af6fc0a19cad12578f63d67ec (diff)
downloadrneovim-0e32c480604d76a319602656f2d8e2722497606e.tar.gz
rneovim-0e32c480604d76a319602656f2d8e2722497606e.tar.bz2
rneovim-0e32c480604d76a319602656f2d8e2722497606e.zip
Merge pull request #30979 from zeertzjq/vim-9.1.0810
vim-patch:9.1.{0810,0811,0821}: 'findexpr'
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/cmdexpand.c37
-rw-r--r--src/nvim/cmdexpand_defs.h1
-rw-r--r--src/nvim/errors.h6
-rw-r--r--src/nvim/eval.c7
-rw-r--r--src/nvim/eval.h1
-rw-r--r--src/nvim/ex_docmd.c162
-rw-r--r--src/nvim/file_search.c8
-rw-r--r--src/nvim/option.c15
-rw-r--r--src/nvim/option_vars.h1
-rw-r--r--src/nvim/options.lua59
-rw-r--r--src/nvim/optionstr.c6
-rw-r--r--src/nvim/vvars.lua10
14 files changed, 269 insertions, 46 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 2142b5b298..42cc745fe6 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2049,6 +2049,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
clear_string_option(&buf->b_p_indk);
clear_string_option(&buf->b_p_fp);
clear_string_option(&buf->b_p_fex);
+ clear_string_option(&buf->b_p_fexpr);
clear_string_option(&buf->b_p_kp);
clear_string_option(&buf->b_p_mps);
clear_string_option(&buf->b_p_fo);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 134d69de96..88e8d59faa 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -608,6 +608,7 @@ struct file_buffer {
char *b_p_mp; ///< 'makeprg' local value
char *b_p_efm; ///< 'errorformat' local value
char *b_p_ep; ///< 'equalprg' local value
+ char *b_p_fexpr; ///< 'findexpr' local value
char *b_p_path; ///< 'path' local value
int b_p_ar; ///< 'autoread' local value
char *b_p_tags; ///< 'tags' local value
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 549ed826bc..aeaed536fc 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
+ && xp->xp_context != EXPAND_FINDEXPR
&& xp->xp_context != EXPAND_HELP
&& xp->xp_context != EXPAND_KEYMAP
&& xp->xp_context != EXPAND_LUA
@@ -1228,7 +1229,8 @@ char *addstar(char *fname, size_t len, int context)
// For help tags the translation is done in find_help_tags().
// For a tag pattern starting with "/" no translation is needed.
- if (context == EXPAND_HELP
+ if (context == EXPAND_FINDEXPR
+ || context == EXPAND_HELP
|| context == EXPAND_COLORS
|| context == EXPAND_COMPILER
|| context == EXPAND_OWNSYNTAX
@@ -1827,7 +1829,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
case CMD_sfind:
case CMD_tabfind:
if (xp->xp_context == EXPAND_FILES) {
- xp->xp_context = EXPAND_FILES_IN_PATH;
+ xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR : EXPAND_FILES_IN_PATH;
}
break;
case CMD_cd:
@@ -2497,21 +2499,25 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int *
}
}
- if (xp->xp_context == EXPAND_FILES) {
- flags |= EW_FILE;
- } else if (xp->xp_context == EXPAND_FILES_IN_PATH) {
- flags |= (EW_FILE | EW_PATH);
- } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
- flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
+ int ret = FAIL;
+ if (xp->xp_context == EXPAND_FINDEXPR) {
+ ret = expand_findexpr(pat, matches, numMatches);
} else {
- flags = (flags | EW_DIR) & ~EW_FILE;
- }
- if (options & WILD_ICASE) {
- flags |= EW_ICASE;
+ if (xp->xp_context == EXPAND_FILES) {
+ flags |= EW_FILE;
+ } else if (xp->xp_context == EXPAND_FILES_IN_PATH) {
+ flags |= (EW_FILE | EW_PATH);
+ } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
+ flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
+ } else {
+ flags = (flags | EW_DIR) & ~EW_FILE;
+ }
+ if (options & WILD_ICASE) {
+ flags |= EW_ICASE;
+ }
+ // Expand wildcards, supporting %:h and the like.
+ ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
}
-
- // Expand wildcards, supporting %:h and the like.
- int ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
if (free_pat) {
xfree(pat);
}
@@ -2716,6 +2722,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_FINDEXPR
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options);
}
diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h
index 86725eafd6..ce51f30bec 100644
--- a/src/nvim/cmdexpand_defs.h
+++ b/src/nvim/cmdexpand_defs.h
@@ -107,6 +107,7 @@ enum {
EXPAND_KEYMAP,
EXPAND_DIRS_IN_CDPATH,
EXPAND_SHELLCMDLINE,
+ EXPAND_FINDEXPR,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};
diff --git a/src/nvim/errors.h b/src/nvim/errors.h
index 39095db952..6682a42d61 100644
--- a/src/nvim/errors.h
+++ b/src/nvim/errors.h
@@ -156,6 +156,11 @@ EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called i
EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
+EXTERN const char e_cant_find_directory_str_in_cdpath[] INIT(= N_("E344: Can't find directory \"%s\" in cdpath"));
+EXTERN const char e_cant_find_file_str_in_path[] INIT(= N_("E345: Can't find file \"%s\" in path"));
+EXTERN const char e_no_more_directory_str_found_in_cdpath[] INIT(= N_("E346: No more directory \"%s\" found in cdpath"));
+EXTERN const char e_no_more_file_str_found_in_path[] INIT(= N_("E347: No more file \"%s\" found in path"));
+
EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
@@ -181,6 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")
EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
+EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: 'findexpr' did not return a List type"));
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 93cff80bd4..bf85ed1646 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -270,6 +270,7 @@ static struct vimvar {
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO),
+ VV(VV_CMDCOMPLETE, "cmdcomplete", VAR_BOOL, VV_RO),
// Neovim
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
@@ -460,6 +461,9 @@ void eval_init(void)
set_vim_var_nr(VV_SEARCHFORWARD, 1);
set_vim_var_nr(VV_HLSEARCH, 1);
set_vim_var_nr(VV_COUNT1, 1);
+ set_vim_var_special(VV_EXITING, kSpecialVarNull);
+ set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse);
+
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
@@ -475,7 +479,6 @@ void eval_init(void)
set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
- set_vim_var_special(VV_EXITING, kSpecialVarNull);
set_vim_var_nr(VV_MAXCOL, MAXCOL);
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
@@ -2631,7 +2634,7 @@ static int may_call_simple_func(const char *arg, typval_T *rettv)
/// Handle zero level expression with optimization for a simple function call.
/// Same arguments and return value as eval0().
-static int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
+int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
{
int r = may_call_simple_func(arg, rettv);
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index bb9b00abc7..b5605bb644 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -167,6 +167,7 @@ typedef enum {
VV_COLLATE,
VV_EXITING,
VV_MAXCOL,
+ VV_CMDCOMPLETE,
// Nvim
VV_STDERR,
VV_MSGPACK_TYPES,
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 293aaac036..74ba19b30a 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5165,6 +5165,115 @@ static void ex_wrongmodifier(exarg_T *eap)
eap->errmsg = _(e_invcmd);
}
+/// 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(const char *pat, bool cmdcomplete)
+{
+ const sctx_T saved_sctx = current_sctx;
+
+ char *findexpr = get_findexpr();
+
+ set_vim_var_string(VV_FNAME, pat, -1);
+ set_vim_var_bool(VV_CMDCOMPLETE, cmdcomplete ? kBoolVarTrue : kBoolVarFalse);
+ current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx;
+
+ char *arg = skipwhite(findexpr);
+
+ textlock++;
+
+ // Evaluate the expression. If the expression is "FuncName()" call the
+ // function directly.
+ typval_T tv;
+ list_T *retlist = NULL;
+ if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
+ retlist = NULL;
+ } else {
+ if (tv.v_type == VAR_LIST) {
+ retlist = tv_list_copy(NULL, tv.vval.v_list, true, get_copyID());
+ } else {
+ emsg(_(e_invalid_return_type_from_findexpr));
+ }
+ tv_clear(&tv);
+ }
+ textlock--;
+ clear_evalarg(&EVALARG_EVALUATE, NULL);
+
+ set_vim_var_string(VV_FNAME, NULL, 0);
+ set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse);
+ current_sctx = saved_sctx;
+
+ return retlist;
+}
+
+/// Find file names matching "pat" using 'findexpr' and return it in "files".
+/// Used for expanding the :find, :sfind and :tabfind command argument.
+/// Returns OK on success and FAIL otherwise.
+int expand_findexpr(const char *pat, char ***files, int *numMatches)
+{
+ *numMatches = 0;
+ *files = NULL;
+
+ list_T *l = eval_findexpr(pat, true);
+ if (l == NULL) {
+ return FAIL;
+ }
+
+ int len = tv_list_len(l);
+ if (len == 0) { // empty List
+ return FAIL;
+ }
+
+ *files = xmalloc(sizeof(char *) * (size_t)len);
+
+ // Copy all the List items
+ int idx = 0;
+ TV_LIST_ITER_CONST(l, li, {
+ if (TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) {
+ (*files)[idx] = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string);
+ idx++;
+ }
+ });
+
+ *numMatches = idx;
+ tv_list_free(l);
+
+ return OK;
+}
+
+/// Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
+/// the n'th matching file.
+static char *findexpr_find_file(char *findarg, size_t findarg_len, int count)
+{
+ char *ret_fname = NULL;
+
+ const char cc = findarg[findarg_len];
+ findarg[findarg_len] = NUL;
+
+ list_T *fname_list = eval_findexpr(findarg, false);
+ int fname_count = tv_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 = tv_list_find(fname_list, count - 1);
+ if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) {
+ ret_fname = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string);
+ }
+ }
+ }
+
+ if (fname_list != NULL) {
+ tv_list_free(fname_list);
+ }
+
+ findarg[findarg_len] = cc;
+
+ return ret_fname;
+}
+
/// :sview [+command] file split window with new file, read-only
/// :split [[+command] file] split window with current or new file
/// :vsplit [[+command] file] split window vertically with current or new file
@@ -5196,13 +5305,17 @@ void ex_splitview(exarg_T *eap)
}
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
- char *file_to_find = NULL;
- char *search_ctx = NULL;
- fname = find_file_in_path(eap->arg, strlen(eap->arg),
- FNAME_MESS, true, curbuf->b_ffname,
- &file_to_find, &search_ctx);
- xfree(file_to_find);
- vim_findfile_cleanup(search_ctx);
+ if (*get_findexpr() != NUL) {
+ fname = findexpr_find_file(eap->arg, strlen(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+ } else {
+ char *file_to_find = NULL;
+ char *search_ctx = NULL;
+ fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true,
+ curbuf->b_ffname, &file_to_find, &search_ctx);
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
+ }
if (fname == NULL) {
goto theend;
}
@@ -5398,23 +5511,28 @@ static void ex_find(exarg_T *eap)
return;
}
- char *file_to_find = NULL;
- char *search_ctx = NULL;
- char *fname = find_file_in_path(eap->arg, 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.
- linenr_T count = eap->line2;
- while (fname != NULL && --count > 0) {
- xfree(fname);
- fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname,
- &file_to_find, &search_ctx);
+ char *fname = NULL;
+ if (*get_findexpr() != NUL) {
+ fname = findexpr_find_file(eap->arg, strlen(eap->arg),
+ eap->addr_count > 0 ? eap->line2 : 1);
+ } else {
+ char *file_to_find = NULL;
+ char *search_ctx = NULL;
+ fname = find_file_in_path(eap->arg, 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.
+ linenr_T count = eap->line2;
+ while (fname != NULL && --count > 0) {
+ xfree(fname);
+ fname = find_file_in_path(NULL, 0, FNAME_MESS, false,
+ curbuf->b_ffname, &file_to_find, &search_ctx);
+ }
}
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
}
- xfree(file_to_find);
- vim_findfile_cleanup(search_ctx);
if (fname == NULL) {
return;
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index cdfd281718..aeaf448a05 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1489,15 +1489,15 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch
if (file_name == NULL && (options & FNAME_MESS)) {
if (first == true) {
if (find_what == FINDFILE_DIR) {
- semsg(_("E344: Can't find directory \"%s\" in cdpath"), *file_to_find);
+ semsg(_(e_cant_find_directory_str_in_cdpath), *file_to_find);
} else {
- semsg(_("E345: Can't find file \"%s\" in path"), *file_to_find);
+ semsg(_(e_cant_find_file_str_in_path), *file_to_find);
}
} else {
if (find_what == FINDFILE_DIR) {
- semsg(_("E346: No more directory \"%s\" found in cdpath"), *file_to_find);
+ semsg(_(e_no_more_directory_str_found_in_cdpath), *file_to_find);
} else {
- semsg(_("E347: No more file \"%s\" found in path"), *file_to_find);
+ semsg(_(e_no_more_file_str_found_in_path), *file_to_find);
}
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 7c32c99d0e..65f03ca77f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4530,6 +4530,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
switch ((int)p->indir) {
case PV_FP:
return &(buf->b_p_fp);
+ case PV_FEXPR:
+ return &(buf->b_p_fexpr);
case PV_EFM:
return &(buf->b_p_efm);
case PV_GP:
@@ -4651,6 +4653,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var;
case PV_FP:
return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var;
+ case PV_FEXPR:
+ return *buf->b_p_fexpr != NUL ? &(buf->b_p_fexpr) : p->var;
case PV_EFM:
return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var;
case PV_GP:
@@ -4922,6 +4926,15 @@ char *get_equalprg(void)
return curbuf->b_p_ep;
}
+/// Get the value of 'findexpr', either the buffer-local one or the global one.
+char *get_findexpr(void)
+{
+ if (*curbuf->b_p_fexpr == NUL) {
+ return p_fexpr;
+ }
+ return curbuf->b_p_fexpr;
+}
+
/// Copy options from one window to another.
/// Used when splitting a window.
void win_copy_options(win_T *wp_from, win_T *wp_to)
@@ -5320,6 +5333,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_mp = empty_string_option;
buf->b_p_efm = empty_string_option;
buf->b_p_ep = empty_string_option;
+ buf->b_p_fexpr = xstrdup(p_fexpr);
+ COPY_OPT_SCTX(buf, BV_FEXPR);
buf->b_p_kp = empty_string_option;
buf->b_p_path = empty_string_option;
buf->b_p_tags = empty_string_option;
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
index 5b630117ab..a88b51dae7 100644
--- a/src/nvim/option_vars.h
+++ b/src/nvim/option_vars.h
@@ -451,6 +451,7 @@ EXTERN char *p_ffs; ///< 'fileformats'
EXTERN int p_fic; ///< 'fileignorecase'
EXTERN char *p_ft; ///< 'filetype'
EXTERN char *p_fcs; ///< 'fillchar'
+EXTERN char *p_fexpr; ///< 'findexpr'
EXTERN int p_fixeol; ///< 'fixendofline'
EXTERN char *p_fcl; ///< 'foldclose'
EXTERN OptInt p_fdls; ///< 'foldlevelstart'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index a891d18364..d59958eaf2 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2906,6 +2906,65 @@ return {
varname = 'p_fcs',
},
{
+ abbreviation = 'fexpr',
+ cb = 'did_set_optexpr',
+ defaults = { if_true = '' },
+ desc = [=[
+ 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'.
+
+ The expression may be evaluated for command-line completion as well,
+ in which case the |v:cmdcomplete| variable will be set to |v:true|,
+ otherwise it will be set to |v:false|.
+
+ 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:
+ >vim
+ " Use glob()
+ func FindExprGlob()
+ let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname
+ return glob(pat, 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()
+ <
+ ]=],
+ full_name = 'findexpr',
+ scope = { 'global', 'buffer' },
+ secure = true,
+ short_desc = N_('expression used for :find'),
+ tags = { 'E1514' },
+ type = 'string',
+ varname = 'p_fexpr',
+ },
+ {
abbreviation = 'fixeol',
cb = 'did_set_eof_eol_fixeol_bomb',
defaults = { if_true = true },
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index e07fcf2f0e..c66849800c 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -233,6 +233,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_mp);
check_string_option(&buf->b_p_efm);
check_string_option(&buf->b_p_ep);
+ check_string_option(&buf->b_p_fexpr);
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
check_string_option(&buf->b_p_tfu);
@@ -1885,8 +1886,9 @@ int expand_set_nrformats(optexpand_T *args, int *numMatches, char ***matches)
matches);
}
-/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext',
-/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'.
+/// One of the '*expr' options is changed:, 'diffexpr', 'findexpr',
+/// 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
+/// 'patchexpr' and 'charconvert'.
const char *did_set_optexpr(optset_T *args)
{
char **varp = (char **)args->os_varp;
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index ad139bbbfe..6c6edd4ee2 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -50,6 +50,13 @@ M.vars = {
can be used.
]=],
},
+ cmdcomplete = {
+ type = 'boolean',
+ desc = [=[
+ When evaluating 'findexpr': if 'findexpr' is used for cmdline
+ completion the value is |v:true|, otherwise it is |v:false|.
+ ]=],
+ },
collate = {
type = 'string',
desc = [=[
@@ -284,7 +291,8 @@ M.vars = {
type = 'string',
desc = [=[
When evaluating 'includeexpr': the file name that was
- detected. Empty otherwise.
+ detected. When evaluating 'findexpr': the argument passed to
+ the |:find| command. Empty otherwise.
]=],
},
fname_diff = {