mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.1080: Vim9: no line break allowed in a for loop
Problem: Vim9: no line break allowed in a for loop. Solution: Skip line breaks in for command.
This commit is contained in:
parent
d5053d015a
commit
b7a78f7a67
55
src/eval.c
55
src/eval.c
@ -38,6 +38,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
int fi_semicolon; // TRUE if ending in '; var]'
|
int fi_semicolon; // TRUE if ending in '; var]'
|
||||||
int fi_varcount; // nr of variables in the list
|
int fi_varcount; // nr of variables in the list
|
||||||
|
int fi_break_count; // nr of line breaks encountered
|
||||||
listwatch_T fi_lw; // keep an eye on the item used.
|
listwatch_T fi_lw; // keep an eye on the item used.
|
||||||
list_T *fi_list; // list being used
|
list_T *fi_list; // list being used
|
||||||
int fi_bi; // index of blob
|
int fi_bi; // index of blob
|
||||||
@ -344,6 +345,7 @@ eval_to_string_skip(
|
|||||||
}
|
}
|
||||||
if (skip)
|
if (skip)
|
||||||
--emsg_skip;
|
--emsg_skip;
|
||||||
|
clear_evalarg(&EVALARG_EVALUATE, eap);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -461,6 +463,7 @@ eval_to_string(
|
|||||||
retval = vim_strsave(tv_get_string(&tv));
|
retval = vim_strsave(tv_get_string(&tv));
|
||||||
clear_tv(&tv);
|
clear_tv(&tv);
|
||||||
}
|
}
|
||||||
|
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -528,6 +531,7 @@ eval_expr(char_u *arg, exarg_T *eap)
|
|||||||
tv = ALLOC_ONE(typval_T);
|
tv = ALLOC_ONE(typval_T);
|
||||||
if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL)
|
if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL)
|
||||||
VIM_CLEAR(tv);
|
VIM_CLEAR(tv);
|
||||||
|
clear_evalarg(&EVALARG_EVALUATE, eap);
|
||||||
|
|
||||||
return tv;
|
return tv;
|
||||||
}
|
}
|
||||||
@ -675,6 +679,7 @@ eval_foldexpr(char_u *arg, int *cp)
|
|||||||
if (use_sandbox)
|
if (use_sandbox)
|
||||||
--sandbox;
|
--sandbox;
|
||||||
--textwinlock;
|
--textwinlock;
|
||||||
|
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
||||||
|
|
||||||
return (int)retval;
|
return (int)retval;
|
||||||
}
|
}
|
||||||
@ -1481,16 +1486,14 @@ eval_for_line(
|
|||||||
char_u *arg,
|
char_u *arg,
|
||||||
int *errp,
|
int *errp,
|
||||||
exarg_T *eap,
|
exarg_T *eap,
|
||||||
int skip)
|
evalarg_T *evalarg)
|
||||||
{
|
{
|
||||||
forinfo_T *fi;
|
forinfo_T *fi;
|
||||||
char_u *expr;
|
char_u *expr;
|
||||||
typval_T tv;
|
typval_T tv;
|
||||||
list_T *l;
|
list_T *l;
|
||||||
evalarg_T evalarg;
|
int skip = !(evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
|
|
||||||
CLEAR_FIELD(evalarg);
|
|
||||||
evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
|
|
||||||
*errp = TRUE; // default: there is an error
|
*errp = TRUE; // default: there is an error
|
||||||
|
|
||||||
fi = ALLOC_CLEAR_ONE(forinfo_T);
|
fi = ALLOC_CLEAR_ONE(forinfo_T);
|
||||||
@ -1501,8 +1504,9 @@ eval_for_line(
|
|||||||
if (expr == NULL)
|
if (expr == NULL)
|
||||||
return fi;
|
return fi;
|
||||||
|
|
||||||
expr = skipwhite(expr);
|
expr = skipwhite_and_linebreak(expr, evalarg);
|
||||||
if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2]))
|
if (expr[0] != 'i' || expr[1] != 'n'
|
||||||
|
|| !(expr[2] == NUL || VIM_ISWHITE(expr[2])))
|
||||||
{
|
{
|
||||||
emsg(_(e_missing_in));
|
emsg(_(e_missing_in));
|
||||||
return fi;
|
return fi;
|
||||||
@ -1510,7 +1514,8 @@ eval_for_line(
|
|||||||
|
|
||||||
if (skip)
|
if (skip)
|
||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK)
|
expr = skipwhite_and_linebreak(expr + 2, evalarg);
|
||||||
|
if (eval0(expr, &tv, eap, evalarg) == OK)
|
||||||
{
|
{
|
||||||
*errp = FALSE;
|
*errp = FALSE;
|
||||||
if (!skip)
|
if (!skip)
|
||||||
@ -1558,10 +1563,24 @@ eval_for_line(
|
|||||||
}
|
}
|
||||||
if (skip)
|
if (skip)
|
||||||
--emsg_skip;
|
--emsg_skip;
|
||||||
|
fi->fi_break_count = evalarg->eval_break_count;
|
||||||
|
|
||||||
return fi;
|
return fi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used when looping over a :for line, skip the "in expr" part.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
skip_for_lines(void *fi_void, evalarg_T *evalarg)
|
||||||
|
{
|
||||||
|
forinfo_T *fi = (forinfo_T *)fi_void;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < fi->fi_break_count; ++i)
|
||||||
|
eval_next_line(evalarg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the first item in a ":for" list. Advance to the next.
|
* Use the first item in a ":for" list. Advance to the next.
|
||||||
* Assign the values to the variable (list). "arg" points to the first one.
|
* Assign the values to the variable (list). "arg" points to the first one.
|
||||||
@ -1866,6 +1885,7 @@ eval_next_line(evalarg_T *evalarg)
|
|||||||
char_u *line;
|
char_u *line;
|
||||||
|
|
||||||
line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
|
line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE);
|
||||||
|
++evalarg->eval_break_count;
|
||||||
if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
|
if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK)
|
||||||
{
|
{
|
||||||
// Going to concatenate the lines after parsing.
|
// Going to concatenate the lines after parsing.
|
||||||
@ -1898,14 +1918,19 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
|
|||||||
void
|
void
|
||||||
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
|
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (evalarg != NULL && eap != NULL && evalarg->eval_tofree != NULL)
|
if (evalarg != NULL && evalarg->eval_tofree != NULL)
|
||||||
{
|
{
|
||||||
// We may need to keep the original command line, e.g. for
|
if (eap != NULL)
|
||||||
// ":let" it has the variable names. But we may also need the
|
{
|
||||||
// new one, "nextcmd" points into it. Keep both.
|
// We may need to keep the original command line, e.g. for
|
||||||
vim_free(eap->cmdline_tofree);
|
// ":let" it has the variable names. But we may also need the
|
||||||
eap->cmdline_tofree = *eap->cmdlinep;
|
// new one, "nextcmd" points into it. Keep both.
|
||||||
*eap->cmdlinep = evalarg->eval_tofree;
|
vim_free(eap->cmdline_tofree);
|
||||||
|
eap->cmdline_tofree = *eap->cmdlinep;
|
||||||
|
*eap->cmdlinep = evalarg->eval_tofree;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vim_free(evalarg->eval_tofree);
|
||||||
evalarg->eval_tofree = NULL;
|
evalarg->eval_tofree = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1961,8 +1986,6 @@ eval0(
|
|||||||
if (eap != NULL)
|
if (eap != NULL)
|
||||||
eap->nextcmd = check_nextcmd(p);
|
eap->nextcmd = check_nextcmd(p);
|
||||||
|
|
||||||
clear_evalarg(evalarg, eap);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,10 +899,16 @@ ex_eval(exarg_T *eap)
|
|||||||
|
|
||||||
CLEAR_FIELD(evalarg);
|
CLEAR_FIELD(evalarg);
|
||||||
evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
|
evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
|
||||||
evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL;
|
if (getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||||
|
{
|
||||||
|
evalarg.eval_getline = eap->getline;
|
||||||
|
evalarg.eval_cookie = eap->cookie;
|
||||||
|
}
|
||||||
|
|
||||||
if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
|
if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
|
||||||
clear_tv(&tv);
|
clear_tv(&tv);
|
||||||
|
|
||||||
|
clear_evalarg(&evalarg, eap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1108,7 +1114,16 @@ ex_while(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
void *fi;
|
void *fi;
|
||||||
|
evalarg_T evalarg;
|
||||||
|
|
||||||
|
CLEAR_FIELD(evalarg);
|
||||||
|
evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE;
|
||||||
|
if (getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||||
|
{
|
||||||
|
evalarg.eval_getline = eap->getline;
|
||||||
|
evalarg.eval_cookie = eap->cookie;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":for var in list-expr"
|
* ":for var in list-expr"
|
||||||
@ -1119,11 +1134,14 @@ ex_while(exarg_T *eap)
|
|||||||
// previously evaluated list.
|
// previously evaluated list.
|
||||||
fi = cstack->cs_forinfo[cstack->cs_idx];
|
fi = cstack->cs_forinfo[cstack->cs_idx];
|
||||||
error = FALSE;
|
error = FALSE;
|
||||||
|
|
||||||
|
// the "in expr" is not used, skip over it
|
||||||
|
skip_for_lines(fi, &evalarg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Evaluate the argument and get the info in a structure.
|
// Evaluate the argument and get the info in a structure.
|
||||||
fi = eval_for_line(eap->arg, &error, eap, skip);
|
fi = eval_for_line(eap->arg, &error, eap, &evalarg);
|
||||||
cstack->cs_forinfo[cstack->cs_idx] = fi;
|
cstack->cs_forinfo[cstack->cs_idx] = fi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1138,6 +1156,7 @@ ex_while(exarg_T *eap)
|
|||||||
free_for_info(fi);
|
free_for_info(fi);
|
||||||
cstack->cs_forinfo[cstack->cs_idx] = NULL;
|
cstack->cs_forinfo[cstack->cs_idx] = NULL;
|
||||||
}
|
}
|
||||||
|
clear_evalarg(&evalarg, eap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1885,7 +1885,7 @@ EXTERN listitem_T range_list_item;
|
|||||||
// Passed to an eval() function to enable evaluation.
|
// Passed to an eval() function to enable evaluation.
|
||||||
EXTERN evalarg_T EVALARG_EVALUATE
|
EXTERN evalarg_T EVALARG_EVALUATE
|
||||||
# ifdef DO_INIT
|
# ifdef DO_INIT
|
||||||
= {EVAL_EVALUATE, NULL, NULL, {0, 0, 0, 0, NULL}, NULL}
|
= {EVAL_EVALUATE, 0, NULL, NULL, {0, 0, 0, 0, NULL}, NULL}
|
||||||
# endif
|
# endif
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,8 @@ int eval_foldexpr(char_u *arg, int *cp);
|
|||||||
char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags);
|
char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags);
|
||||||
void clear_lval(lval_T *lp);
|
void clear_lval(lval_T *lp);
|
||||||
void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int flags, char_u *op);
|
void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int flags, char_u *op);
|
||||||
void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, int skip);
|
void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, evalarg_T *evalarg);
|
||||||
|
void skip_for_lines(void *fi_void, evalarg_T *evalarg);
|
||||||
int next_for_item(void *fi_void, char_u *arg);
|
int next_for_item(void *fi_void, char_u *arg);
|
||||||
void free_for_info(void *fi_void);
|
void free_for_info(void *fi_void);
|
||||||
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
|
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
|
||||||
|
@ -1758,11 +1758,12 @@ typedef struct
|
|||||||
// Struct passed through eval() functions.
|
// Struct passed through eval() functions.
|
||||||
// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
|
// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int eval_flags; // EVAL_ flag values below
|
int eval_flags; // EVAL_ flag values below
|
||||||
|
int eval_break_count; // nr of line breaks consumed
|
||||||
|
|
||||||
// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
|
// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
|
||||||
char_u *(*eval_getline)(int, void *, int, int);
|
char_u *(*eval_getline)(int, void *, int, int);
|
||||||
void *eval_cookie; // argument for eval_getline()
|
void *eval_cookie; // argument for eval_getline()
|
||||||
|
|
||||||
// Used to collect lines while parsing them, so that they can be
|
// Used to collect lines while parsing them, so that they can be
|
||||||
// concatenated later. Used when "eval_ga.ga_itemsize" is not zero.
|
// concatenated later. Used when "eval_ga.ga_itemsize" is not zero.
|
||||||
|
@ -160,4 +160,35 @@ def Test_while_linebreak()
|
|||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_for_linebreak()
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
let nr = 0
|
||||||
|
for x
|
||||||
|
in
|
||||||
|
[1, 2, 3, 4]
|
||||||
|
nr = nr + x
|
||||||
|
endfor
|
||||||
|
assert_equal(10, nr)
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
let nr = 0
|
||||||
|
for x
|
||||||
|
in
|
||||||
|
[1, 2,
|
||||||
|
3, 4
|
||||||
|
]
|
||||||
|
nr = nr
|
||||||
|
+
|
||||||
|
x
|
||||||
|
endfor
|
||||||
|
assert_equal(10, nr)
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -3825,6 +3825,7 @@ ex_return(exarg_T *eap)
|
|||||||
|
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
--emsg_skip;
|
--emsg_skip;
|
||||||
|
clear_evalarg(&evalarg, eap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -754,6 +754,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 */
|
||||||
|
/**/
|
||||||
|
1080,
|
||||||
/**/
|
/**/
|
||||||
1079,
|
1079,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user