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>
This commit is contained in:
Yegappan Lakshmanan
2024-11-02 18:40:10 +01:00
committed by Christian Brabandt
parent 0b8176dff2
commit a13f3a4f5d
25 changed files with 629 additions and 256 deletions

View File

@ -6924,58 +6924,71 @@ ex_wrongmodifier(exarg_T *eap)
}
#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();
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);
// 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;
// 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;
cb = get_findfunc_callback();
retval = call_callback(cb, -1, &rettv, 2, args);
set_vim_var_string(VV_FNAME, NULL, 0);
set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
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 @@ expand_findexpr(char_u *pat, char_u ***files, int *numMatches)
*numMatches = 0;
*files = NULL;
l = eval_findexpr(pat, TRUE);
l = call_findfunc(pat, VVAL_TRUE);
if (l == NULL)
return FAIL;
@ -7015,11 +7028,11 @@ expand_findexpr(char_u *pat, char_u ***files, int *numMatches)
}
/*
* 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 @@ findexpr_find_file(char_u *findarg, int findarg_len, int count)
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 @@ findexpr_find_file(char_u *findarg, int findarg_len, int count)
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 @@ ex_splitview(exarg_T *eap)
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 @@ ex_find(exarg_T *eap)
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
}