patch 9.1.0831: 'findexpr' can't be used as lambad or Funcref
Problem: 'findexpr' can't be used for lambads
(Justin Keyes)
Solution: Replace the findexpr option with the findfunc option
(Yegappan Lakshmanan)
related: #15905
closes: #15976
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index d60e344..380bd23 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6924,58 +6924,71 @@
}
#if defined(FEAT_EVAL) || defined(PROTO)
-/*
- * 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 *pat, int cmdcomplete)
+
+// callback function for 'findfunc'
+static callback_T ffu_cb;
+
+ static callback_T *
+get_findfunc_callback(void)
{
+ return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb;
+}
+
+ static list_T *
+call_findfunc(char_u *pat, int cmdcomplete)
+{
+ typval_T args[3];
+ callback_T *cb;
+ typval_T rettv;
+ int retval;
sctx_T saved_sctx = current_sctx;
- char_u *findexpr;
- char_u *arg;
- typval_T tv;
- list_T *retlist = NULL;
+ sctx_T *ctx;
- findexpr = get_findexpr();
+ // Call 'findfunc' to obtain the list of file names.
+ args[0].v_type = VAR_STRING;
+ args[0].vval.v_string = pat;
+ args[1].v_type = VAR_BOOL;
+ args[1].vval.v_number = cmdcomplete;
+ args[2].v_type = VAR_UNKNOWN;
- set_vim_var_string(VV_FNAME, pat, -1);
- set_vim_var_nr(VV_CMDCOMPLETE, cmdcomplete ? VVAL_TRUE : VVAL_FALSE);
- current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
-
- arg = skipwhite(findexpr);
-
+ // Lock the text to prevent weird things from happening. Also disallow
+ // switching to another window, it should not be needed and may end up in
+ // Insert mode in another buffer.
++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());
- else
- emsg(_(e_invalid_return_type_from_findexpr));
- clear_tv(&tv);
- }
- --textlock;
- clear_evalarg(&EVALARG_EVALUATE, NULL);
+ ctx = get_option_sctx("findfunc");
+ if (ctx != NULL)
+ current_sctx = *ctx;
- set_vim_var_string(VV_FNAME, NULL, 0);
- set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
+ cb = get_findfunc_callback();
+ retval = call_callback(cb, -1, &rettv, 2, args);
+
current_sctx = saved_sctx;
+ --textlock;
+
+ list_T *retlist = NULL;
+
+ if (retval == OK)
+ {
+ if (rettv.v_type == VAR_LIST)
+ retlist = list_copy(rettv.vval.v_list, FALSE, FALSE, get_copyID());
+ else
+ emsg(_(e_invalid_return_type_from_findfunc));
+
+ clear_tv(&rettv);
+ }
+
return retlist;
}
/*
- * Find file names matching "pat" using 'findexpr' and return it in "files".
+ * Find file names matching "pat" using 'findfunc' 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(char_u *pat, char_u ***files, int *numMatches)
+expand_findfunc(char_u *pat, char_u ***files, int *numMatches)
{
list_T *l;
int len;
@@ -6983,7 +6996,7 @@
*numMatches = 0;
*files = NULL;
- l = eval_findexpr(pat, TRUE);
+ l = call_findfunc(pat, VVAL_TRUE);
if (l == NULL)
return FAIL;
@@ -7015,11 +7028,11 @@
}
/*
- * Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
+ * Use 'findfunc' 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)
+findfunc_find_file(char_u *findarg, int findarg_len, int count)
{
list_T *fname_list;
char_u *ret_fname = NULL;
@@ -7029,7 +7042,7 @@
cc = findarg[findarg_len];
findarg[findarg_len] = NUL;
- fname_list = eval_findexpr(findarg, FALSE);
+ fname_list = call_findfunc(findarg, VVAL_FALSE);
fname_count = list_len(fname_list);
if (fname_count == 0)
@@ -7053,6 +7066,62 @@
return ret_fname;
}
+
+/*
+ * Process the 'findfunc' option value.
+ * Returns NULL on success and an error message on failure.
+ */
+ char *
+did_set_findfunc(optset_T *args UNUSED)
+{
+ int retval;
+
+ if (*curbuf->b_p_ffu != NUL)
+ {
+ // buffer-local option set
+ retval = option_set_callback_func(curbuf->b_p_ffu, &curbuf->b_ffu_cb);
+ }
+ else
+ {
+ // global option set
+ retval = option_set_callback_func(p_ffu, &ffu_cb);
+ }
+
+ if (retval == FAIL)
+ return e_invalid_argument;
+
+ // If the option value starts with <SID> or s:, then replace that with
+ // the script identifier.
+ char_u **varp = (char_u **)args->os_varp;
+ char_u *name = get_scriptlocal_funcname(*varp);
+ if (name != NULL)
+ {
+ free_string_option(*varp);
+ *varp = name;
+ }
+
+ return NULL;
+}
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_findfunc_option(void)
+{
+ free_callback(&ffu_cb);
+}
+# endif
+
+/*
+ * Mark the global 'findfunc' callback with "copyID" so that it is not
+ * garbage collected.
+ */
+ int
+set_ref_in_findfunc(int copyID UNUSED)
+{
+ int abort = FALSE;
+ abort = set_ref_in_callback(&ffu_cb, copyID);
+ return abort;
+}
#endif
/*
@@ -7105,10 +7174,10 @@
char_u *file_to_find = NULL;
char *search_ctx = NULL;
- if (*get_findexpr() != NUL)
+ if (*get_findfunc() != NUL)
{
#ifdef FEAT_EVAL
- fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
+ fname = findfunc_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}
@@ -7389,10 +7458,10 @@
char_u *file_to_find = NULL;
char *search_ctx = NULL;
- if (*get_findexpr() != NUL)
+ if (*get_findfunc() != NUL)
{
#ifdef FEAT_EVAL
- fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
+ fname = findfunc_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}