mirror of
https://github.com/vim/vim.git
synced 2025-08-27 20:13:38 -04:00
updated for version 7.0031
This commit is contained in:
parent
1280586e4b
commit
3d60ec2aaf
@ -1,4 +1,4 @@
|
|||||||
*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 04
|
*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 05
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -30,16 +30,16 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
|
|||||||
*known-bugs*
|
*known-bugs*
|
||||||
-------------------- Known bugs and current work -----------------------
|
-------------------- Known bugs and current work -----------------------
|
||||||
|
|
||||||
When 'insertmode' is set CTRL-I 4isometext<Esc> and then some typing hangs
|
|
||||||
Vim. (Jens Paulus)
|
|
||||||
|
|
||||||
:let completion stops after the first argument.
|
|
||||||
|
|
||||||
List data type:
|
List data type:
|
||||||
|
- When removing items from the condition stack may free cs_fors.
|
||||||
|
- don't copy the list, use a list-watcher to adjust the item pointer when it's
|
||||||
|
deleted.
|
||||||
- "for a in list"
|
- "for a in list"
|
||||||
|
Make copy of the list to avoid trouble when it changes. As one big block?
|
||||||
- "for [a, b] in [[1, 2], [3, 4]]"
|
- "for [a, b] in [[1, 2], [3, 4]]"
|
||||||
|
- support list generator: items are obtained with a function by index.
|
||||||
|
"range(1, 400, 2)" creates one.
|
||||||
- == (same value) and "is" (same list)
|
- == (same value) and "is" (same list)
|
||||||
- store in viminfo: read_viminfo_varlist()
|
|
||||||
- add many functions:
|
- add many functions:
|
||||||
call(func, list) call function
|
call(func, list) call function
|
||||||
keys(list) list of all indexes 0 - (len(list) - 1)
|
keys(list) list of all indexes 0 - (len(list) - 1)
|
||||||
@ -56,6 +56,8 @@ List data type:
|
|||||||
getval(list, idx[, default]) get value at idx or default
|
getval(list, idx[, default]) get value at idx or default
|
||||||
file2lines()
|
file2lines()
|
||||||
file2words()
|
file2words()
|
||||||
|
str2list() parse string to list in several ways: white
|
||||||
|
separated, [] form, etc.
|
||||||
Fix the error numbers E999 in eval.c.
|
Fix the error numbers E999 in eval.c.
|
||||||
|
|
||||||
Function reference: Define a nameless (numbered) function and assign
|
Function reference: Define a nameless (numbered) function and assign
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*version7.txt* For Vim version 7.0aa. Last change: 2005 Jan 04
|
*version7.txt* For Vim version 7.0aa. Last change: 2005 Jan 05
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -645,4 +645,6 @@ Use a Vim command to fix all fileformats to dos before executing the tests.
|
|||||||
When using ":new" and the file fits in the window, lines could still be above
|
When using ":new" and the file fits in the window, lines could still be above
|
||||||
the window. Now remove empty lines instead of keeping the relative position.
|
the window. Now remove empty lines instead of keeping the relative position.
|
||||||
|
|
||||||
|
Cmdline completion didn't work after ":let var1 var<Tab>".
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
vim:tw=78:ts=8:ft=help:norl:
|
||||||
|
486
src/eval.c
486
src/eval.c
@ -82,13 +82,23 @@ struct listitem_S
|
|||||||
typedef struct listitem_S listitem;
|
typedef struct listitem_S listitem;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure to hold the info about a list.
|
* Struct used by those that are using an item in a list.
|
||||||
|
*/
|
||||||
|
typedef struct listwatch_S
|
||||||
|
{
|
||||||
|
listitem *lw_item; /* item being watched */
|
||||||
|
struct listwatch_S *lw_next; /* next watcher */
|
||||||
|
} listwatch;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to hold info about a list.
|
||||||
*/
|
*/
|
||||||
struct listvar_S
|
struct listvar_S
|
||||||
{
|
{
|
||||||
int lv_refcount; /* reference count */
|
int lv_refcount; /* reference count */
|
||||||
listitem *lv_first; /* first item, NULL if none */
|
listitem *lv_first; /* first item, NULL if none */
|
||||||
listitem *lv_last; /* last item, NULL if none */
|
listitem *lv_last; /* last item, NULL if none */
|
||||||
|
listwatch *lv_watch; /* first watcher, NULL if none */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct listvar_S listvar;
|
typedef struct listvar_S listvar;
|
||||||
@ -169,6 +179,18 @@ struct funccall
|
|||||||
int level; /* top nesting level of executed function */
|
int level; /* top nesting level of executed function */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Info used by a ":for" loop.
|
||||||
|
*/
|
||||||
|
typedef struct forinfo_S
|
||||||
|
{
|
||||||
|
int fi_semicolon; /* TRUE if ending in '; var]' */
|
||||||
|
int fi_varcount; /* nr of variables in the list */
|
||||||
|
listwatch fi_lw; /* keep an eye on the item used. */
|
||||||
|
listvar *fi_list; /* list being used */
|
||||||
|
} forinfo;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the name of the executed function.
|
* Return the name of the executed function.
|
||||||
*/
|
*/
|
||||||
@ -504,10 +526,14 @@ static void call_user_func __ARGS((ufunc_T *fp, int argcount, typeval *argvars,
|
|||||||
|
|
||||||
static char_u * make_expanded_name __ARGS((char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end));
|
static char_u * make_expanded_name __ARGS((char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end));
|
||||||
|
|
||||||
|
static int ex_let_vars __ARGS((char_u *arg, typeval *tv, int copy, int semicolon, int var_count, char_u *nextchars));
|
||||||
|
static char_u *skip_var_list __ARGS((char_u *arg, int *var_count, int *semicolon));
|
||||||
|
static char_u *skip_var_one __ARGS((char_u *arg));
|
||||||
static void list_all_vars __ARGS((void));
|
static void list_all_vars __ARGS((void));
|
||||||
static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg));
|
static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg));
|
||||||
static char_u *ex_let_one __ARGS((char_u *arg, typeval *tv, int copy, char_u *endchars));
|
static char_u *ex_let_one __ARGS((char_u *arg, typeval *tv, int copy, char_u *endchars));
|
||||||
static char_u *set_var_idx __ARGS((char_u *name, char_u *ip, typeval *rettv, int copy, char_u *endchars));
|
static char_u *set_var_idx __ARGS((char_u *name, char_u *ip, typeval *rettv, int copy, char_u *endchars));
|
||||||
|
static void list_add_watch __ARGS((listvar *l, listwatch *lw));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set an internal variable to a string value. Creates the variable if it does
|
* Set an internal variable to a string value. Creates the variable if it does
|
||||||
@ -1021,14 +1047,16 @@ ex_let(eap)
|
|||||||
int i;
|
int i;
|
||||||
int var_count = 0;
|
int var_count = 0;
|
||||||
int semicolon = 0;
|
int semicolon = 0;
|
||||||
listvar *l;
|
|
||||||
listitem *item;
|
|
||||||
|
|
||||||
if (*arg != '[')
|
expr = skip_var_list(arg, &var_count, &semicolon);
|
||||||
expr = vim_strchr(find_name_end(arg, NULL, NULL, TRUE), '=');
|
if (expr == NULL)
|
||||||
if (*arg != '[' && expr == NULL)
|
return;
|
||||||
|
expr = vim_strchr(expr, '=');
|
||||||
|
if (expr == NULL)
|
||||||
{
|
{
|
||||||
if (!ends_excmd(*arg))
|
if (*arg == '[')
|
||||||
|
EMSG(_(e_invarg));
|
||||||
|
else if (!ends_excmd(*arg))
|
||||||
/* ":let var1 var2" */
|
/* ":let var1 var2" */
|
||||||
arg = list_arg_vars(eap, arg);
|
arg = list_arg_vars(eap, arg);
|
||||||
else if (!eap->skip)
|
else if (!eap->skip)
|
||||||
@ -1038,54 +1066,11 @@ ex_let(eap)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (*arg == '[')
|
expr = skipwhite(expr + 1);
|
||||||
{
|
|
||||||
/* ":let [a, b] = expr": find the matching ']' to get to the
|
|
||||||
* expression. */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
arg = skipwhite(arg + 1);
|
|
||||||
if (vim_strchr((char_u *)"$@&", *arg) != NULL)
|
|
||||||
++arg;
|
|
||||||
expr = find_name_end(arg, NULL, NULL, TRUE);
|
|
||||||
if (expr == arg)
|
|
||||||
{
|
|
||||||
EMSG2(_(e_invarg2), arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++var_count;
|
|
||||||
|
|
||||||
arg = skipwhite(expr);
|
|
||||||
if (*arg == ']')
|
|
||||||
break;
|
|
||||||
else if (*arg == ';')
|
|
||||||
{
|
|
||||||
if (semicolon == 1)
|
|
||||||
{
|
|
||||||
EMSG(_("Double ; in :let"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
semicolon = 1;
|
|
||||||
}
|
|
||||||
else if (*arg != ',')
|
|
||||||
{
|
|
||||||
EMSG2(_(e_invarg2), arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for '=' after the ']' */
|
|
||||||
expr = skipwhite(arg + 1);
|
|
||||||
if (*expr != '=')
|
|
||||||
{
|
|
||||||
EMSG(_(e_letunexp));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
i = eval0(expr + 1, &rettv, &eap->nextcmd, !eap->skip);
|
i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
{
|
{
|
||||||
if (i != FAIL)
|
if (i != FAIL)
|
||||||
@ -1094,70 +1079,169 @@ ex_let(eap)
|
|||||||
}
|
}
|
||||||
else if (i != FAIL)
|
else if (i != FAIL)
|
||||||
{
|
{
|
||||||
/* Move "arg" back to the variable name(s). */
|
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||||
arg = eap->arg;
|
(char_u *)"=");
|
||||||
|
clear_tv(&rettv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign the typevalue "tv" to the variable or variables at "arg_start".
|
||||||
|
* Handles both "var" with any type and "[var, var; var]" with a list type.
|
||||||
|
* Returns OK or FAIL;
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ex_let_vars(arg_start, tv, copy, semicolon, var_count, nextchars)
|
||||||
|
char_u *arg_start;
|
||||||
|
typeval *tv;
|
||||||
|
int copy; /* copy values from "tv", don't move */
|
||||||
|
int semicolon; /* from skip_var_list() */
|
||||||
|
int var_count; /* from skip_var_list() */
|
||||||
|
char_u *nextchars; /* characters that must follow or NULL */
|
||||||
|
{
|
||||||
|
char_u *arg = arg_start;
|
||||||
|
listvar *l;
|
||||||
|
int i;
|
||||||
|
listitem *item;
|
||||||
|
typeval ltv;
|
||||||
|
|
||||||
if (*arg != '[')
|
if (*arg != '[')
|
||||||
{
|
{
|
||||||
/* ":let var = expr" */
|
/*
|
||||||
(void)ex_let_one(arg, &rettv, FALSE, (char_u *)"=");
|
* ":let var = expr" or ":for var in list"
|
||||||
|
*/
|
||||||
|
if (ex_let_one(arg, tv, copy, nextchars) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
/*
|
||||||
/* ":let [v1, v2] = list" */
|
* ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
|
||||||
l = rettv.vval.v_list;
|
*/
|
||||||
if (rettv.v_type != VAR_LIST || l == NULL)
|
l = tv->vval.v_list;
|
||||||
EMSG(_("E999: List required"));
|
if (tv->v_type != VAR_LIST || l == NULL)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
EMSG(_(e_listreq));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
i = list_len(l);
|
i = list_len(l);
|
||||||
if (semicolon == 0 && var_count < i)
|
if (semicolon == 0 && var_count < i)
|
||||||
EMSG(_("E999: Less targets than List items"));
|
|
||||||
else if (var_count - semicolon > i)
|
|
||||||
EMSG(_("E999: More targets than List items"));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
EMSG(_("E999: Less targets than List items"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (var_count - semicolon > i)
|
||||||
|
{
|
||||||
|
EMSG(_("E999: More targets than List items"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
item = l->lv_first;
|
item = l->lv_first;
|
||||||
while (*arg != ']')
|
while (*arg != ']')
|
||||||
{
|
{
|
||||||
arg = skipwhite(arg + 1);
|
arg = skipwhite(arg + 1);
|
||||||
arg = ex_let_one(arg, &item->li_tv,
|
arg = ex_let_one(arg, &item->li_tv, TRUE, (char_u *)",;]");
|
||||||
TRUE, (char_u *)",;]");
|
|
||||||
item = item->li_next;
|
item = item->li_next;
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
break;
|
return FAIL;
|
||||||
|
|
||||||
arg = skipwhite(arg);
|
arg = skipwhite(arg);
|
||||||
if (*arg == ';')
|
if (*arg == ';')
|
||||||
{
|
{
|
||||||
/* Put the rest of the list (may be empty) in
|
/* Put the rest of the list (may be empty) in the var after ';'.
|
||||||
* the var after ';'. */
|
* Create a new list for this. */
|
||||||
l = list_alloc();
|
l = list_alloc();
|
||||||
if (l == NULL)
|
if (l == NULL)
|
||||||
break;
|
return FAIL;
|
||||||
while (item != NULL)
|
while (item != NULL)
|
||||||
{
|
{
|
||||||
list_append_tv(l, &item->li_tv);
|
list_append_tv(l, &item->li_tv);
|
||||||
item = item->li_next;
|
item = item->li_next;
|
||||||
}
|
}
|
||||||
list_unref(rettv.vval.v_list);
|
|
||||||
rettv.vval.v_list = l;
|
ltv.v_type = VAR_LIST;
|
||||||
|
ltv.vval.v_list = l;
|
||||||
l->lv_refcount = 1;
|
l->lv_refcount = 1;
|
||||||
(void)ex_let_one(skipwhite(arg + 1), &rettv,
|
|
||||||
FALSE, (char_u *)"]");
|
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, (char_u *)"]");
|
||||||
|
clear_tv(<v);
|
||||||
|
if (arg == NULL)
|
||||||
|
return FAIL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (*arg != ',' && *arg != ']')
|
else if (*arg != ',' && *arg != ']')
|
||||||
{
|
{
|
||||||
EMSG2(_(e_intern2), "ex_let()");
|
EMSG2(_(e_intern2), "ex_let_vars()");
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip over assignable variable "var" or list of variables "[var, var]".
|
||||||
|
* Used for ":let varvar = expr" and ":for varvar in expr".
|
||||||
|
* For "[var, var]" increment "*var_count" for each variable.
|
||||||
|
* for "[var, var; var]" set "semicolon".
|
||||||
|
* Return NULL for an error.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
skip_var_list(arg, var_count, semicolon)
|
||||||
|
char_u *arg;
|
||||||
|
int *var_count;
|
||||||
|
int *semicolon;
|
||||||
|
{
|
||||||
|
char_u *p, *s;
|
||||||
|
|
||||||
|
if (*arg == '[')
|
||||||
|
{
|
||||||
|
/* "[var, var]": find the matching ']'. */
|
||||||
|
p = arg;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
p = skipwhite(p + 1); /* skip whites after '[', ';' or ',' */
|
||||||
|
s = skip_var_one(p);
|
||||||
|
if (s == p)
|
||||||
|
{
|
||||||
|
EMSG2(_(e_invarg2), p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
++*var_count;
|
||||||
|
|
||||||
|
p = skipwhite(s);
|
||||||
|
if (*p == ']')
|
||||||
break;
|
break;
|
||||||
|
else if (*p == ';')
|
||||||
|
{
|
||||||
|
if (*semicolon == 1)
|
||||||
|
{
|
||||||
|
EMSG(_("Double ; in list of variables"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*semicolon = 1;
|
||||||
|
}
|
||||||
|
else if (*p != ',')
|
||||||
|
{
|
||||||
|
EMSG2(_(e_invarg2), p);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return p + 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return skip_var_one(arg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
clear_tv(&rettv);
|
static char_u *
|
||||||
}
|
skip_var_one(arg)
|
||||||
}
|
char_u *arg;
|
||||||
|
{
|
||||||
|
if (vim_strchr((char_u *)"$@&", *arg) != NULL)
|
||||||
|
++arg;
|
||||||
|
return find_name_end(arg, NULL, NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1309,7 +1393,7 @@ ex_let_one(arg, tv, copy, endchars)
|
|||||||
char_u *arg; /* points to variable name */
|
char_u *arg; /* points to variable name */
|
||||||
typeval *tv; /* value to assign to variable */
|
typeval *tv; /* value to assign to variable */
|
||||||
int copy; /* copy value from "tv" */
|
int copy; /* copy value from "tv" */
|
||||||
char_u *endchars; /* valid chars after variable name */
|
char_u *endchars; /* valid chars after variable name or NULL */
|
||||||
{
|
{
|
||||||
int c1;
|
int c1;
|
||||||
char_u *name;
|
char_u *name;
|
||||||
@ -1331,7 +1415,8 @@ ex_let_one(arg, tv, copy, endchars)
|
|||||||
EMSG2(_(e_invarg2), name - 1);
|
EMSG2(_(e_invarg2), name - 1);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (vim_strchr(endchars, *skipwhite(arg)) == NULL)
|
if (endchars != NULL
|
||||||
|
&& vim_strchr(endchars, *skipwhite(arg)) == NULL)
|
||||||
EMSG(_(e_letunexp));
|
EMSG(_(e_letunexp));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1360,7 +1445,8 @@ ex_let_one(arg, tv, copy, endchars)
|
|||||||
{
|
{
|
||||||
/* Find the end of the name. */
|
/* Find the end of the name. */
|
||||||
p = find_option_end(&arg, &opt_flags);
|
p = find_option_end(&arg, &opt_flags);
|
||||||
if (p == NULL || vim_strchr(endchars, *skipwhite(p)) == NULL)
|
if (p == NULL || (endchars != NULL
|
||||||
|
&& vim_strchr(endchars, *skipwhite(p)) == NULL))
|
||||||
EMSG(_(e_letunexp));
|
EMSG(_(e_letunexp));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1379,7 +1465,8 @@ ex_let_one(arg, tv, copy, endchars)
|
|||||||
else if (*arg == '@')
|
else if (*arg == '@')
|
||||||
{
|
{
|
||||||
++arg;
|
++arg;
|
||||||
if (vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
|
if (endchars != NULL
|
||||||
|
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
|
||||||
EMSG(_(e_letunexp));
|
EMSG(_(e_letunexp));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1415,7 +1502,8 @@ ex_let_one(arg, tv, copy, endchars)
|
|||||||
}
|
}
|
||||||
else if (*p == '[')
|
else if (*p == '[')
|
||||||
arg_end = set_var_idx(arg, p, tv, copy, endchars);
|
arg_end = set_var_idx(arg, p, tv, copy, endchars);
|
||||||
else if (vim_strchr(endchars, *skipwhite(p)) == NULL)
|
else if (endchars != NULL
|
||||||
|
&& vim_strchr(endchars, *skipwhite(p)) == NULL)
|
||||||
EMSG(_(e_letunexp));
|
EMSG(_(e_letunexp));
|
||||||
else if (STRNCMP(arg, "b:changedtick", 13) == 0
|
else if (STRNCMP(arg, "b:changedtick", 13) == 0
|
||||||
&& !eval_isnamec(arg[13]))
|
&& !eval_isnamec(arg[13]))
|
||||||
@ -1505,7 +1593,7 @@ set_var_idx(name, ip, rettv, copy, endchars)
|
|||||||
|
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
{
|
{
|
||||||
if (vim_strchr(endchars, *p) == NULL)
|
if (endchars != NULL && vim_strchr(endchars, *p) == NULL)
|
||||||
{
|
{
|
||||||
EMSG(_(e_letunexp));
|
EMSG(_(e_letunexp));
|
||||||
p = NULL;
|
p = NULL;
|
||||||
@ -1525,6 +1613,157 @@ set_var_idx(name, ip, rettv, copy, endchars)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a watcher to a list.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
list_add_watch(l, lw)
|
||||||
|
listvar *l;
|
||||||
|
listwatch *lw;
|
||||||
|
{
|
||||||
|
lw->lw_next = l->lv_watch;
|
||||||
|
l->lv_watch = lw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a watches from a list.
|
||||||
|
* No warning when it isn't found...
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
list_rem_watch(l, lwrem)
|
||||||
|
listvar *l;
|
||||||
|
listwatch *lwrem;
|
||||||
|
{
|
||||||
|
listwatch *lw, **lwp;
|
||||||
|
|
||||||
|
lwp = &l->lv_watch;
|
||||||
|
for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
|
||||||
|
{
|
||||||
|
if (lw == lwrem)
|
||||||
|
{
|
||||||
|
*lwp = lw->lw_next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lwp = &lw->lw_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just before removing an item from a list: advance watchers to the next
|
||||||
|
* item.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
list_fix_watch(l, item)
|
||||||
|
listvar *l;
|
||||||
|
listitem *item;
|
||||||
|
{
|
||||||
|
listwatch *lw;
|
||||||
|
|
||||||
|
for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
|
||||||
|
if (lw->lw_item == item)
|
||||||
|
lw->lw_item = item->li_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate the expression used in a ":for var in expr" command.
|
||||||
|
* "arg" points to "var".
|
||||||
|
* Set "*errp" to TRUE for an error, FALSE otherwise;
|
||||||
|
* Return a pointer that holds the info. Null when there is an error.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
eval_for_line(arg, errp, nextcmdp, skip)
|
||||||
|
char_u *arg;
|
||||||
|
int *errp;
|
||||||
|
char_u **nextcmdp;
|
||||||
|
int skip;
|
||||||
|
{
|
||||||
|
forinfo *fi;
|
||||||
|
char_u *expr;
|
||||||
|
typeval tv;
|
||||||
|
listvar *l;
|
||||||
|
|
||||||
|
*errp = TRUE; /* default: there is an error */
|
||||||
|
|
||||||
|
fi = (forinfo *)alloc_clear(sizeof(forinfo));
|
||||||
|
if (fi == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
|
||||||
|
if (expr == NULL)
|
||||||
|
return fi;
|
||||||
|
|
||||||
|
expr = skipwhite(expr);
|
||||||
|
if (expr[0] != 'i' || expr[1] != 'n' || !vim_iswhite(expr[2]))
|
||||||
|
{
|
||||||
|
EMSG(_("E999: Missing \"in\" after :for"));
|
||||||
|
return fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
++emsg_skip;
|
||||||
|
if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK)
|
||||||
|
{
|
||||||
|
*errp = FALSE;
|
||||||
|
if (!skip)
|
||||||
|
{
|
||||||
|
l = tv.vval.v_list;
|
||||||
|
if (tv.v_type != VAR_LIST || l == NULL)
|
||||||
|
EMSG(_(e_listreq));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fi->fi_list = l;
|
||||||
|
list_add_watch(l, &fi->fi_lw);
|
||||||
|
fi->fi_lw.lw_item = l->lv_first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skip)
|
||||||
|
--emsg_skip;
|
||||||
|
|
||||||
|
return fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* Return TRUE when a valid item was found, FALSE when at end of list or
|
||||||
|
* something wrong.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
next_for_item(fi_void, arg)
|
||||||
|
void *fi_void;
|
||||||
|
char_u *arg;
|
||||||
|
{
|
||||||
|
forinfo *fi = (forinfo *)fi_void;
|
||||||
|
int result;
|
||||||
|
listitem *item;
|
||||||
|
|
||||||
|
item = fi->fi_lw.lw_item;
|
||||||
|
if (item == NULL)
|
||||||
|
result = FALSE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fi->fi_lw.lw_item = item->li_next;
|
||||||
|
result = (ex_let_vars(arg, &item->li_tv, TRUE,
|
||||||
|
fi->fi_semicolon, fi->fi_varcount, NULL) == OK);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the structure used to store info used by ":for".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
free_for_info(fi_void)
|
||||||
|
void *fi_void;
|
||||||
|
{
|
||||||
|
forinfo *fi = (forinfo *)fi_void;
|
||||||
|
|
||||||
|
if (fi->fi_list != NULL)
|
||||||
|
list_rem_watch(fi->fi_list, &fi->fi_lw);
|
||||||
|
vim_free(fi);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
|
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1535,9 +1774,26 @@ set_context_for_expression(xp, arg, cmdidx)
|
|||||||
{
|
{
|
||||||
int got_eq = FALSE;
|
int got_eq = FALSE;
|
||||||
int c;
|
int c;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
xp->xp_context = cmdidx == CMD_let ? EXPAND_USER_VARS
|
if (cmdidx == CMD_let)
|
||||||
: cmdidx == CMD_call ? EXPAND_FUNCTIONS
|
{
|
||||||
|
xp->xp_context = EXPAND_USER_VARS;
|
||||||
|
if (vim_strchr(arg, '=') == NULL)
|
||||||
|
{
|
||||||
|
/* ":let var1 var2 ...": find last space. */
|
||||||
|
for (p = arg + STRLEN(arg); p > arg; )
|
||||||
|
{
|
||||||
|
xp->xp_pattern = p;
|
||||||
|
p = mb_ptr_back(arg, p);
|
||||||
|
if (vim_iswhite(*p))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
xp->xp_context = cmdidx == CMD_call ? EXPAND_FUNCTIONS
|
||||||
: EXPAND_EXPRESSION;
|
: EXPAND_EXPRESSION;
|
||||||
while ((xp->xp_pattern = vim_strpbrk(arg,
|
while ((xp->xp_pattern = vim_strpbrk(arg,
|
||||||
(char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL)
|
(char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL)
|
||||||
@ -1601,7 +1857,9 @@ set_context_for_expression(xp, arg, cmdidx)
|
|||||||
xp->xp_context = EXPAND_EXPRESSION;
|
xp->xp_context = EXPAND_EXPRESSION;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
xp->xp_context = EXPAND_NOTHING;
|
/* Doesn't look like something valid, expand as an expression
|
||||||
|
* anyway. */
|
||||||
|
xp->xp_context = EXPAND_EXPRESSION;
|
||||||
arg = xp->xp_pattern;
|
arg = xp->xp_pattern;
|
||||||
if (*arg != NUL)
|
if (*arg != NUL)
|
||||||
while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
|
while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
|
||||||
@ -3303,7 +3561,7 @@ listitem_alloc()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free a list item. Also clears the value;
|
* Free a list item. Also clears the value. Does not notify watchers.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
listitem_free(item)
|
listitem_free(item)
|
||||||
@ -3471,6 +3729,7 @@ list_getrem(l, n)
|
|||||||
item = list_find(l, n);
|
item = list_find(l, n);
|
||||||
if (item != NULL)
|
if (item != NULL)
|
||||||
{
|
{
|
||||||
|
list_fix_watch(l, item); /* notify watchers */
|
||||||
if (item->li_next == NULL)
|
if (item->li_next == NULL)
|
||||||
l->lv_last = item->li_prev;
|
l->lv_last = item->li_prev;
|
||||||
else
|
else
|
||||||
@ -11806,8 +12065,7 @@ read_viminfo_varlist(virp, writing)
|
|||||||
{
|
{
|
||||||
char_u *tab;
|
char_u *tab;
|
||||||
int is_string = FALSE;
|
int is_string = FALSE;
|
||||||
typeval *tvp = NULL;
|
typeval tv;
|
||||||
char_u *val;
|
|
||||||
|
|
||||||
if (!writing && (find_viminfo_parameter('!') != NULL))
|
if (!writing && (find_viminfo_parameter('!') != NULL))
|
||||||
{
|
{
|
||||||
@ -11821,29 +12079,20 @@ read_viminfo_varlist(virp, writing)
|
|||||||
tab = vim_strchr(tab, '\t');
|
tab = vim_strchr(tab, '\t');
|
||||||
if (tab != NULL)
|
if (tab != NULL)
|
||||||
{
|
{
|
||||||
/* create a typeval to hold the value */
|
|
||||||
if (is_string)
|
if (is_string)
|
||||||
{
|
{
|
||||||
val = viminfo_readstring(virp,
|
tv.v_type = VAR_STRING;
|
||||||
|
tv.vval.v_string = viminfo_readstring(virp,
|
||||||
(int)(tab - virp->vir_line + 1), TRUE);
|
(int)(tab - virp->vir_line + 1), TRUE);
|
||||||
if (val != NULL)
|
|
||||||
tvp = alloc_string_tv(val);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tvp = alloc_tv();
|
tv.v_type = VAR_NUMBER;
|
||||||
if (tvp != NULL)
|
tv.vval.v_number = atol((char *)tab + 1);
|
||||||
{
|
|
||||||
tvp->v_type = VAR_NUMBER;
|
|
||||||
tvp->vval.v_number = atol((char *)tab + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* assign the value to the variable */
|
|
||||||
if (tvp != NULL)
|
|
||||||
{
|
|
||||||
set_var(virp->vir_line + 1, tvp, FALSE);
|
|
||||||
free_tv(tvp);
|
|
||||||
}
|
}
|
||||||
|
set_var(virp->vir_line + 1, &tv, FALSE);
|
||||||
|
if (is_string)
|
||||||
|
vim_free(tv.vval.v_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11878,11 +12127,7 @@ write_viminfo_varlist(fp)
|
|||||||
{
|
{
|
||||||
case VAR_STRING: s = "STR"; break;
|
case VAR_STRING: s = "STR"; break;
|
||||||
case VAR_NUMBER: s = "NUM"; break;
|
case VAR_NUMBER: s = "NUM"; break;
|
||||||
case VAR_LIST: s = "LST"; break;
|
default: continue;
|
||||||
case VAR_FUNC: s = "FUN"; break;
|
|
||||||
default:
|
|
||||||
EMSGN(_("E999: Internal error: write_viminfo_varlist(): %ld"), (long)this_var->tv.v_type);
|
|
||||||
s = "ERR";
|
|
||||||
}
|
}
|
||||||
fprintf(fp, "!%s\t%s\t", this_var->v_name, s);
|
fprintf(fp, "!%s\t%s\t", this_var->v_name, s);
|
||||||
viminfo_writestring(fp, tv2string(&this_var->tv, &tofree));
|
viminfo_writestring(fp, tv2string(&this_var->tv, &tofree));
|
||||||
@ -11905,11 +12150,12 @@ store_session_globals(fd)
|
|||||||
for (i = gap->ga_len; --i >= 0; )
|
for (i = gap->ga_len; --i >= 0; )
|
||||||
{
|
{
|
||||||
this_var = &VAR_GAP_ENTRY(i, gap);
|
this_var = &VAR_GAP_ENTRY(i, gap);
|
||||||
if (this_var->v_name != NULL)
|
if (this_var->v_name != NULL
|
||||||
|
&& (this_var->tv.v_type == VAR_NUMBER
|
||||||
|
|| this_var->tv.v_type == VAR_STRING)
|
||||||
|
&& var_flavour(this_var->v_name) == VAR_FLAVOUR_SESSION)
|
||||||
{
|
{
|
||||||
if (var_flavour(this_var->v_name) == VAR_FLAVOUR_SESSION)
|
/* Escape special characters with a backslash. Turn a LF and
|
||||||
{
|
|
||||||
/* Escapse special characters with a backslash. Turn a LF and
|
|
||||||
* CR into \n and \r. */
|
* CR into \n and \r. */
|
||||||
p = vim_strsave_escaped(get_var_string(this_var),
|
p = vim_strsave_escaped(get_var_string(this_var),
|
||||||
(char_u *)"\\\"\n\r");
|
(char_u *)"\\\"\n\r");
|
||||||
@ -11932,8 +12178,6 @@ store_session_globals(fd)
|
|||||||
}
|
}
|
||||||
vim_free(p);
|
vim_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -3258,13 +3258,13 @@ ex_append(eap)
|
|||||||
if (eap->getline == NULL)
|
if (eap->getline == NULL)
|
||||||
theline = getcmdline(
|
theline = getcmdline(
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
eap->cstack->cs_whilelevel > 0 ? -1 :
|
eap->cstack->cs_looplevel > 0 ? -1 :
|
||||||
#endif
|
#endif
|
||||||
NUL, 0L, 0);
|
NUL, 0L, 0);
|
||||||
else
|
else
|
||||||
theline = eap->getline(
|
theline = eap->getline(
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
eap->cstack->cs_whilelevel > 0 ? -1 :
|
eap->cstack->cs_looplevel > 0 ? -1 :
|
||||||
#endif
|
#endif
|
||||||
NUL, eap->cookie, 0);
|
NUL, eap->cookie, 0);
|
||||||
lines_left = Rows - 1;
|
lines_left = Rows - 1;
|
||||||
|
@ -342,6 +342,8 @@ EX(CMD_endif, "endif", ex_endif,
|
|||||||
TRLBAR|SBOXOK|CMDWIN),
|
TRLBAR|SBOXOK|CMDWIN),
|
||||||
EX(CMD_endfunction, "endfunction", ex_endfunction,
|
EX(CMD_endfunction, "endfunction", ex_endfunction,
|
||||||
TRLBAR|CMDWIN),
|
TRLBAR|CMDWIN),
|
||||||
|
EX(CMD_endfor, "endfor", ex_endwhile,
|
||||||
|
TRLBAR|SBOXOK|CMDWIN),
|
||||||
EX(CMD_endtry, "endtry", ex_endtry,
|
EX(CMD_endtry, "endtry", ex_endtry,
|
||||||
TRLBAR|SBOXOK|CMDWIN),
|
TRLBAR|SBOXOK|CMDWIN),
|
||||||
EX(CMD_endwhile, "endwhile", ex_endwhile,
|
EX(CMD_endwhile, "endwhile", ex_endwhile,
|
||||||
@ -382,6 +384,8 @@ EX(CMD_folddoclosed, "folddoclosed", ex_folddo,
|
|||||||
RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM),
|
RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM),
|
||||||
EX(CMD_foldopen, "foldopen", ex_foldopen,
|
EX(CMD_foldopen, "foldopen", ex_foldopen,
|
||||||
RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN),
|
RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN),
|
||||||
|
EX(CMD_for, "for", ex_while,
|
||||||
|
EXTRA|NOTRLCOM|SBOXOK|CMDWIN),
|
||||||
EX(CMD_function, "function", ex_function,
|
EX(CMD_function, "function", ex_function,
|
||||||
EXTRA|BANG|CMDWIN),
|
EXTRA|BANG|CMDWIN),
|
||||||
EX(CMD_global, "global", ex_global,
|
EX(CMD_global, "global", ex_global,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user