mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.0.1239: cannot use a lambda for the skip argument to searchpair()
Problem: Cannot use a lambda for the skip argument to searchpair(). Solution: Evaluate a partial, funcref and lambda. (LemonBoy, closes #1454, closes #2265)
This commit is contained in:
@@ -6784,6 +6784,7 @@ searchpair({start}, {middle}, {end} [, {flags} [, {skip}
|
|||||||
When {skip} is omitted or empty, every match is accepted.
|
When {skip} is omitted or empty, every match is accepted.
|
||||||
When evaluating {skip} causes an error the search is aborted
|
When evaluating {skip} causes an error the search is aborted
|
||||||
and -1 returned.
|
and -1 returned.
|
||||||
|
{skip} can be a string, a lambda, a funcref or a partial.
|
||||||
|
|
||||||
For {stopline} and {timeout} see |search()|.
|
For {stopline} and {timeout} see |search()|.
|
||||||
|
|
||||||
|
99
src/eval.c
99
src/eval.c
@@ -696,6 +696,70 @@ eval_to_bool(
|
|||||||
return (int)retval;
|
return (int)retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||||
|
{
|
||||||
|
char_u *s;
|
||||||
|
int dummy;
|
||||||
|
char_u buf[NUMBUFLEN];
|
||||||
|
|
||||||
|
if (expr->v_type == VAR_FUNC)
|
||||||
|
{
|
||||||
|
s = expr->vval.v_string;
|
||||||
|
if (s == NULL || *s == NUL)
|
||||||
|
return FAIL;
|
||||||
|
if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
|
||||||
|
0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
else if (expr->v_type == VAR_PARTIAL)
|
||||||
|
{
|
||||||
|
partial_T *partial = expr->vval.v_partial;
|
||||||
|
|
||||||
|
s = partial_name(partial);
|
||||||
|
if (s == NULL || *s == NUL)
|
||||||
|
return FAIL;
|
||||||
|
if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
|
||||||
|
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s = get_tv_string_buf_chk(expr, buf);
|
||||||
|
if (s == NULL)
|
||||||
|
return FAIL;
|
||||||
|
s = skipwhite(s);
|
||||||
|
if (eval1(&s, rettv, TRUE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
if (*s != NUL) /* check for trailing chars after expr */
|
||||||
|
{
|
||||||
|
EMSG2(_(e_invexpr2), s);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like eval_to_bool() but using a typval_T instead of a string.
|
||||||
|
* Works for string, funcref and partial.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
eval_expr_to_bool(typval_T *expr, int *error)
|
||||||
|
{
|
||||||
|
typval_T rettv;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
|
||||||
|
{
|
||||||
|
*error = TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
res = (get_tv_number_chk(&rettv, error) != 0);
|
||||||
|
clear_tv(&rettv);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Top level evaluation function, returning a string. If "skip" is TRUE,
|
* Top level evaluation function, returning a string. If "skip" is TRUE,
|
||||||
* only parsing to "nextcmd" is done, without reporting errors. Return
|
* only parsing to "nextcmd" is done, without reporting errors. Return
|
||||||
@@ -9971,44 +10035,13 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
|
|||||||
{
|
{
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
char_u buf[NUMBUFLEN];
|
|
||||||
char_u *s;
|
|
||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
int dummy;
|
|
||||||
|
|
||||||
copy_tv(tv, &vimvars[VV_VAL].vv_tv);
|
copy_tv(tv, &vimvars[VV_VAL].vv_tv);
|
||||||
argv[0] = vimvars[VV_KEY].vv_tv;
|
argv[0] = vimvars[VV_KEY].vv_tv;
|
||||||
argv[1] = vimvars[VV_VAL].vv_tv;
|
argv[1] = vimvars[VV_VAL].vv_tv;
|
||||||
if (expr->v_type == VAR_FUNC)
|
if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
|
||||||
{
|
goto theend;
|
||||||
s = expr->vval.v_string;
|
|
||||||
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
|
||||||
0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL)
|
|
||||||
goto theend;
|
|
||||||
}
|
|
||||||
else if (expr->v_type == VAR_PARTIAL)
|
|
||||||
{
|
|
||||||
partial_T *partial = expr->vval.v_partial;
|
|
||||||
|
|
||||||
s = partial_name(partial);
|
|
||||||
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
|
||||||
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
|
|
||||||
goto theend;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s = get_tv_string_buf_chk(expr, buf);
|
|
||||||
if (s == NULL)
|
|
||||||
goto theend;
|
|
||||||
s = skipwhite(s);
|
|
||||||
if (eval1(&s, &rettv, TRUE) == FAIL)
|
|
||||||
goto theend;
|
|
||||||
if (*s != NUL) /* check for trailing chars after expr */
|
|
||||||
{
|
|
||||||
EMSG2(_(e_invexpr2), s);
|
|
||||||
goto theend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
/* map(): replace the list item value */
|
/* map(): replace the list item value */
|
||||||
|
@@ -9531,13 +9531,12 @@ f_searchdecl(typval_T *argvars, typval_T *rettv)
|
|||||||
searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
||||||
{
|
{
|
||||||
char_u *spat, *mpat, *epat;
|
char_u *spat, *mpat, *epat;
|
||||||
char_u *skip;
|
typval_T *skip;
|
||||||
int save_p_ws = p_ws;
|
int save_p_ws = p_ws;
|
||||||
int dir;
|
int dir;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
char_u nbuf1[NUMBUFLEN];
|
char_u nbuf1[NUMBUFLEN];
|
||||||
char_u nbuf2[NUMBUFLEN];
|
char_u nbuf2[NUMBUFLEN];
|
||||||
char_u nbuf3[NUMBUFLEN];
|
|
||||||
int retval = 0; /* default: FAIL */
|
int retval = 0; /* default: FAIL */
|
||||||
long lnum_stop = 0;
|
long lnum_stop = 0;
|
||||||
long time_limit = 0;
|
long time_limit = 0;
|
||||||
@@ -9571,10 +9570,16 @@ searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
|||||||
/* Optional fifth argument: skip expression */
|
/* Optional fifth argument: skip expression */
|
||||||
if (argvars[3].v_type == VAR_UNKNOWN
|
if (argvars[3].v_type == VAR_UNKNOWN
|
||||||
|| argvars[4].v_type == VAR_UNKNOWN)
|
|| argvars[4].v_type == VAR_UNKNOWN)
|
||||||
skip = (char_u *)"";
|
skip = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
|
skip = &argvars[4];
|
||||||
|
if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
|
||||||
|
&& skip->v_type != VAR_STRING)
|
||||||
|
{
|
||||||
|
/* Type error */
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
if (argvars[5].v_type != VAR_UNKNOWN)
|
if (argvars[5].v_type != VAR_UNKNOWN)
|
||||||
{
|
{
|
||||||
lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
|
lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
|
||||||
@@ -9590,8 +9595,6 @@ searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skip == NULL)
|
|
||||||
goto theend; /* type error */
|
|
||||||
|
|
||||||
retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
|
retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
|
||||||
match_pos, lnum_stop, time_limit);
|
match_pos, lnum_stop, time_limit);
|
||||||
@@ -9645,7 +9648,7 @@ do_searchpair(
|
|||||||
char_u *mpat, /* middle pattern */
|
char_u *mpat, /* middle pattern */
|
||||||
char_u *epat, /* end pattern */
|
char_u *epat, /* end pattern */
|
||||||
int dir, /* BACKWARD or FORWARD */
|
int dir, /* BACKWARD or FORWARD */
|
||||||
char_u *skip, /* skip expression */
|
typval_T *skip, /* skip expression */
|
||||||
int flags, /* SP_SETPCMARK and other SP_ values */
|
int flags, /* SP_SETPCMARK and other SP_ values */
|
||||||
pos_T *match_pos,
|
pos_T *match_pos,
|
||||||
linenr_T lnum_stop, /* stop at this line if not zero */
|
linenr_T lnum_stop, /* stop at this line if not zero */
|
||||||
@@ -9662,6 +9665,7 @@ do_searchpair(
|
|||||||
int n;
|
int n;
|
||||||
int r;
|
int r;
|
||||||
int nest = 1;
|
int nest = 1;
|
||||||
|
int use_skip = FALSE;
|
||||||
int err;
|
int err;
|
||||||
int options = SEARCH_KEEP;
|
int options = SEARCH_KEEP;
|
||||||
proftime_T tm;
|
proftime_T tm;
|
||||||
@@ -9690,6 +9694,14 @@ do_searchpair(
|
|||||||
if (flags & SP_START)
|
if (flags & SP_START)
|
||||||
options |= SEARCH_START;
|
options |= SEARCH_START;
|
||||||
|
|
||||||
|
if (skip != NULL)
|
||||||
|
{
|
||||||
|
/* Empty string means to not use the skip expression. */
|
||||||
|
if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
|
||||||
|
use_skip = skip->vval.v_string != NULL
|
||||||
|
&& *skip->vval.v_string != NUL;
|
||||||
|
}
|
||||||
|
|
||||||
save_cursor = curwin->w_cursor;
|
save_cursor = curwin->w_cursor;
|
||||||
pos = curwin->w_cursor;
|
pos = curwin->w_cursor;
|
||||||
CLEAR_POS(&firstpos);
|
CLEAR_POS(&firstpos);
|
||||||
@@ -9721,11 +9733,12 @@ do_searchpair(
|
|||||||
options &= ~SEARCH_START;
|
options &= ~SEARCH_START;
|
||||||
|
|
||||||
/* If the skip pattern matches, ignore this match. */
|
/* If the skip pattern matches, ignore this match. */
|
||||||
if (*skip != NUL)
|
if (use_skip)
|
||||||
{
|
{
|
||||||
save_pos = curwin->w_cursor;
|
save_pos = curwin->w_cursor;
|
||||||
curwin->w_cursor = pos;
|
curwin->w_cursor = pos;
|
||||||
r = eval_to_bool(skip, &err, NULL, FALSE);
|
err = FALSE;
|
||||||
|
r = eval_expr_to_bool(skip, &err);
|
||||||
curwin->w_cursor = save_pos;
|
curwin->w_cursor = save_pos;
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
@@ -10,6 +10,7 @@ int eval_printexpr(char_u *fname, char_u *args);
|
|||||||
void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
|
void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
|
||||||
void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
|
void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
|
||||||
int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip);
|
int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip);
|
||||||
|
int eval_expr_to_bool(typval_T *expr, int *error);
|
||||||
char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip);
|
char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip);
|
||||||
int skip_expr(char_u **pp);
|
int skip_expr(char_u **pp);
|
||||||
char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
|
char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
|
||||||
@@ -47,7 +48,7 @@ int garbage_collect(int testing);
|
|||||||
int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack);
|
int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack);
|
||||||
int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack);
|
int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack);
|
||||||
int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack);
|
int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack);
|
||||||
char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int dict_val);
|
char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int composite_val);
|
||||||
char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
|
char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
|
||||||
char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
|
char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
|
||||||
char_u *string_quote(char_u *str, int function);
|
char_u *string_quote(char_u *str, int function);
|
||||||
|
@@ -8,7 +8,7 @@ buf_T *buflist_find_by_name(char_u *name, int curtab_only);
|
|||||||
void execute_redir_str(char_u *value, int value_len);
|
void execute_redir_str(char_u *value, int value_len);
|
||||||
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
||||||
float_T vim_round(float_T f);
|
float_T vim_round(float_T f);
|
||||||
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
|
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
|
||||||
char_u *get_callback(typval_T *arg, partial_T **pp);
|
char_u *get_callback(typval_T *arg, partial_T **pp);
|
||||||
void free_callback(char_u *callback, partial_T *partial);
|
void free_callback(char_u *callback, partial_T *partial);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@@ -4015,7 +4015,7 @@ again:
|
|||||||
{
|
{
|
||||||
if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
|
if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
|
||||||
(char_u *)"",
|
(char_u *)"",
|
||||||
(char_u *)"</[^>]*>", BACKWARD, (char_u *)"", 0,
|
(char_u *)"</[^>]*>", BACKWARD, NULL, 0,
|
||||||
NULL, (linenr_T)0, 0L) <= 0)
|
NULL, (linenr_T)0, 0L) <= 0)
|
||||||
{
|
{
|
||||||
curwin->w_cursor = old_pos;
|
curwin->w_cursor = old_pos;
|
||||||
@@ -4049,7 +4049,7 @@ again:
|
|||||||
sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
|
sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
|
||||||
sprintf((char *)epat, "</%.*s>\\c", len, p);
|
sprintf((char *)epat, "</%.*s>\\c", len, p);
|
||||||
|
|
||||||
r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"",
|
r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
|
||||||
0, NULL, (linenr_T)0, 0L);
|
0, NULL, (linenr_T)0, 0L);
|
||||||
|
|
||||||
vim_free(spat);
|
vim_free(spat);
|
||||||
|
@@ -296,6 +296,25 @@ func Test_searchpair()
|
|||||||
q!
|
q!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_searchpair_skip()
|
||||||
|
func Zero()
|
||||||
|
return 0
|
||||||
|
endfunc
|
||||||
|
func Partial(x)
|
||||||
|
return a:x
|
||||||
|
endfunc
|
||||||
|
new
|
||||||
|
call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
|
||||||
|
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
|
||||||
|
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
|
||||||
|
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
|
||||||
|
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
|
||||||
|
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
|
||||||
|
" invalid argument
|
||||||
|
3 | call assert_equal(0, searchpair('{', '', '}', 'bWn', 0))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_searchc()
|
func Test_searchc()
|
||||||
" These commands used to cause memory overflow in searchc().
|
" These commands used to cause memory overflow in searchc().
|
||||||
new
|
new
|
||||||
|
@@ -761,6 +761,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 */
|
||||||
|
/**/
|
||||||
|
1239,
|
||||||
/**/
|
/**/
|
||||||
1238,
|
1238,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user