mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.1.1539: not easy to define a variable and lock it
Problem: Not easy to define a variable and lock it. Solution: Add ":const".
This commit is contained in:
parent
dfa97f2aed
commit
9937a05543
@ -11598,8 +11598,31 @@ text...
|
|||||||
No error message is given for a non-existing
|
No error message is given for a non-existing
|
||||||
variable, also without !.
|
variable, also without !.
|
||||||
If the system does not support deleting an environment
|
If the system does not support deleting an environment
|
||||||
variable, it is made emtpy.
|
variable, it is made empty.
|
||||||
|
|
||||||
|
*:cons* *:const* *E996*
|
||||||
|
:cons[t] {var-name} = {expr1}
|
||||||
|
:cons[t] [{name1}, {name2}, ...] = {expr1}
|
||||||
|
:cons[t] [{name1}, {name2}, ...] .= {expr1}
|
||||||
|
:cons[t] [{name}, ..., ; {lastname}] = {expr1}
|
||||||
|
:cons[t] {var-name} =<< [trim] {marker}
|
||||||
|
text...
|
||||||
|
text...
|
||||||
|
{marker}
|
||||||
|
Similar to |:let|, but additionally lock the variable
|
||||||
|
after setting the value. This is the same as locking
|
||||||
|
the variable with |:lockvar| just after |:let|, thus: >
|
||||||
|
:const x = 1
|
||||||
|
< is equivalent to: >
|
||||||
|
:let x = 1
|
||||||
|
:lockvar 1 x
|
||||||
|
< This is useful if you want to make sure the variable
|
||||||
|
is not modified.
|
||||||
|
*E995*
|
||||||
|
|:const| does not allow to for changing a variable. >
|
||||||
|
:let x = 1
|
||||||
|
:const x = 2 " Error!
|
||||||
|
<
|
||||||
:lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv*
|
:lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv*
|
||||||
Lock the internal variable {name}. Locking means that
|
Lock the internal variable {name}. Locking means that
|
||||||
it can no longer be changed (until it is unlocked).
|
it can no longer be changed (until it is unlocked).
|
||||||
|
139
src/eval.c
139
src/eval.c
@ -28,6 +28,7 @@ static char *e_missbrac = N_("E111: Missing ']'");
|
|||||||
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
|
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
|
||||||
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
|
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
|
||||||
static char *e_illvar = N_("E461: Illegal variable name: %s");
|
static char *e_illvar = N_("E461: Illegal variable name: %s");
|
||||||
|
static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
static char *e_float_as_string = N_("E806: using Float as a String");
|
static char *e_float_as_string = N_("E806: using Float as a String");
|
||||||
#endif
|
#endif
|
||||||
@ -212,7 +213,8 @@ static struct vimvar
|
|||||||
static dictitem_T vimvars_var; /* variable used for v: */
|
static dictitem_T vimvars_var; /* variable used for v: */
|
||||||
#define vimvarht vimvardict.dv_hashtab
|
#define vimvarht vimvardict.dv_hashtab
|
||||||
|
|
||||||
static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars);
|
static void ex_let_const(exarg_T *eap, int is_const);
|
||||||
|
static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, int is_const, char_u *nextchars);
|
||||||
static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon);
|
static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon);
|
||||||
static char_u *skip_var_one(char_u *arg);
|
static char_u *skip_var_one(char_u *arg);
|
||||||
static void list_glob_vars(int *first);
|
static void list_glob_vars(int *first);
|
||||||
@ -222,8 +224,8 @@ static void list_tab_vars(int *first);
|
|||||||
static void list_vim_vars(int *first);
|
static void list_vim_vars(int *first);
|
||||||
static void list_script_vars(int *first);
|
static void list_script_vars(int *first);
|
||||||
static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
|
static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
|
||||||
static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op);
|
static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int is_const, char_u *endchars, char_u *op);
|
||||||
static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op);
|
static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int is_const, char_u *op);
|
||||||
static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
|
static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
|
||||||
static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep);
|
static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep);
|
||||||
static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
|
static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
|
||||||
@ -248,6 +250,7 @@ static typval_T *alloc_string_tv(char_u *string);
|
|||||||
static void delete_var(hashtab_T *ht, hashitem_T *hi);
|
static void delete_var(hashtab_T *ht, hashitem_T *hi);
|
||||||
static void list_one_var(dictitem_T *v, char *prefix, int *first);
|
static void list_one_var(dictitem_T *v, char *prefix, int *first);
|
||||||
static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
|
static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
|
||||||
|
static void set_var_const(char_u *name, typval_T *tv, int copy, int is_const);
|
||||||
static int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
|
static int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
|
||||||
static char_u *find_option_end(char_u **arg, int *opt_flags);
|
static char_u *find_option_end(char_u **arg, int *opt_flags);
|
||||||
|
|
||||||
@ -526,9 +529,9 @@ var_redir_start(char_u *name, int append)
|
|||||||
tv.v_type = VAR_STRING;
|
tv.v_type = VAR_STRING;
|
||||||
tv.vval.v_string = (char_u *)"";
|
tv.vval.v_string = (char_u *)"";
|
||||||
if (append)
|
if (append)
|
||||||
set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)".");
|
set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)".");
|
||||||
else
|
else
|
||||||
set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"=");
|
set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
|
||||||
clear_lval(redir_lval);
|
clear_lval(redir_lval);
|
||||||
err = did_emsg;
|
err = did_emsg;
|
||||||
did_emsg |= save_emsg;
|
did_emsg |= save_emsg;
|
||||||
@ -601,7 +604,8 @@ var_redir_stop(void)
|
|||||||
redir_endp = get_lval(redir_varname, NULL, redir_lval,
|
redir_endp = get_lval(redir_varname, NULL, redir_lval,
|
||||||
FALSE, FALSE, 0, FNE_CHECK_START);
|
FALSE, FALSE, 0, FNE_CHECK_START);
|
||||||
if (redir_endp != NULL && redir_lval->ll_name != NULL)
|
if (redir_endp != NULL && redir_lval->ll_name != NULL)
|
||||||
set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)".");
|
set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE,
|
||||||
|
(char_u *)".");
|
||||||
clear_lval(redir_lval);
|
clear_lval(redir_lval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1337,6 +1341,24 @@ heredoc_get(exarg_T *eap, char_u *cmd)
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ex_let(exarg_T *eap)
|
ex_let(exarg_T *eap)
|
||||||
|
{
|
||||||
|
ex_let_const(eap, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ":const" list all variable values
|
||||||
|
* ":const var1 var2" list variable values
|
||||||
|
* ":const var = expr" assignment command.
|
||||||
|
* ":const [var1, var2] = expr" unpack list.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_const(exarg_T *eap)
|
||||||
|
{
|
||||||
|
ex_let_const(eap, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ex_let_const(exarg_T *eap, int is_const)
|
||||||
{
|
{
|
||||||
char_u *arg = eap->arg;
|
char_u *arg = eap->arg;
|
||||||
char_u *expr = NULL;
|
char_u *expr = NULL;
|
||||||
@ -1396,7 +1418,7 @@ ex_let(exarg_T *eap)
|
|||||||
op[0] = '=';
|
op[0] = '=';
|
||||||
op[1] = NUL;
|
op[1] = NUL;
|
||||||
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||||
op);
|
is_const, op);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1429,7 +1451,7 @@ ex_let(exarg_T *eap)
|
|||||||
else if (i != FAIL)
|
else if (i != FAIL)
|
||||||
{
|
{
|
||||||
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||||
op);
|
is_const, op);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1447,9 +1469,10 @@ ex_let(exarg_T *eap)
|
|||||||
ex_let_vars(
|
ex_let_vars(
|
||||||
char_u *arg_start,
|
char_u *arg_start,
|
||||||
typval_T *tv,
|
typval_T *tv,
|
||||||
int copy, /* copy values from "tv", don't move */
|
int copy, // copy values from "tv", don't move
|
||||||
int semicolon, /* from skip_var_list() */
|
int semicolon, // from skip_var_list()
|
||||||
int var_count, /* from skip_var_list() */
|
int var_count, // from skip_var_list()
|
||||||
|
int is_const, // lock variables for const
|
||||||
char_u *nextchars)
|
char_u *nextchars)
|
||||||
{
|
{
|
||||||
char_u *arg = arg_start;
|
char_u *arg = arg_start;
|
||||||
@ -1463,7 +1486,7 @@ ex_let_vars(
|
|||||||
/*
|
/*
|
||||||
* ":let var = expr" or ":for var in list"
|
* ":let var = expr" or ":for var in list"
|
||||||
*/
|
*/
|
||||||
if (ex_let_one(arg, tv, copy, nextchars, nextchars) == NULL)
|
if (ex_let_one(arg, tv, copy, is_const, nextchars, nextchars) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -1493,7 +1516,8 @@ ex_let_vars(
|
|||||||
while (*arg != ']')
|
while (*arg != ']')
|
||||||
{
|
{
|
||||||
arg = skipwhite(arg + 1);
|
arg = skipwhite(arg + 1);
|
||||||
arg = ex_let_one(arg, &item->li_tv, TRUE, (char_u *)",;]", nextchars);
|
arg = ex_let_one(arg, &item->li_tv, TRUE, is_const,
|
||||||
|
(char_u *)",;]", nextchars);
|
||||||
item = item->li_next;
|
item = item->li_next;
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -1517,8 +1541,8 @@ ex_let_vars(
|
|||||||
ltv.vval.v_list = l;
|
ltv.vval.v_list = l;
|
||||||
l->lv_refcount = 1;
|
l->lv_refcount = 1;
|
||||||
|
|
||||||
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE,
|
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, is_const,
|
||||||
(char_u *)"]", nextchars);
|
(char_u *)"]", nextchars);
|
||||||
clear_tv(<v);
|
clear_tv(<v);
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -1805,11 +1829,12 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first)
|
|||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
ex_let_one(
|
ex_let_one(
|
||||||
char_u *arg, /* points to variable name */
|
char_u *arg, // points to variable name
|
||||||
typval_T *tv, /* value to assign to variable */
|
typval_T *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 or NULL */
|
int is_const, // lock variable for const
|
||||||
char_u *op) /* "+", "-", "." or NULL*/
|
char_u *endchars, // valid chars after variable name or NULL
|
||||||
|
char_u *op) // "+", "-", "." or NULL
|
||||||
{
|
{
|
||||||
int c1;
|
int c1;
|
||||||
char_u *name;
|
char_u *name;
|
||||||
@ -1824,6 +1849,11 @@ ex_let_one(
|
|||||||
*/
|
*/
|
||||||
if (*arg == '$')
|
if (*arg == '$')
|
||||||
{
|
{
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_("E996: Cannot lock an environment variable"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/* Find the end of the name. */
|
/* Find the end of the name. */
|
||||||
++arg;
|
++arg;
|
||||||
name = arg;
|
name = arg;
|
||||||
@ -1879,6 +1909,11 @@ ex_let_one(
|
|||||||
*/
|
*/
|
||||||
else if (*arg == '&')
|
else if (*arg == '&')
|
||||||
{
|
{
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_("E996: Cannot lock an option"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/* 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 || (endchars != NULL
|
if (p == NULL || (endchars != NULL
|
||||||
@ -1943,6 +1978,11 @@ ex_let_one(
|
|||||||
*/
|
*/
|
||||||
else if (*arg == '@')
|
else if (*arg == '@')
|
||||||
{
|
{
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_("E996: Cannot lock a register"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
++arg;
|
++arg;
|
||||||
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
|
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
|
||||||
semsg(_(e_letwrong), op);
|
semsg(_(e_letwrong), op);
|
||||||
@ -1988,7 +2028,7 @@ ex_let_one(
|
|||||||
emsg(_(e_letunexp));
|
emsg(_(e_letunexp));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set_var_lval(&lv, p, tv, copy, op);
|
set_var_lval(&lv, p, tv, copy, is_const, op);
|
||||||
arg_end = p;
|
arg_end = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2430,6 +2470,7 @@ set_var_lval(
|
|||||||
char_u *endp,
|
char_u *endp,
|
||||||
typval_T *rettv,
|
typval_T *rettv,
|
||||||
int copy,
|
int copy,
|
||||||
|
int is_const, // Disallow to modify existing variable for :const
|
||||||
char_u *op)
|
char_u *op)
|
||||||
{
|
{
|
||||||
int cc;
|
int cc;
|
||||||
@ -2495,6 +2536,13 @@ set_var_lval(
|
|||||||
{
|
{
|
||||||
typval_T tv;
|
typval_T tv;
|
||||||
|
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_(e_cannot_mod));
|
||||||
|
*endp = cc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// handle +=, -=, *=, /=, %= and .=
|
// handle +=, -=, *=, /=, %= and .=
|
||||||
di = NULL;
|
di = NULL;
|
||||||
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
|
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
|
||||||
@ -2509,7 +2557,7 @@ set_var_lval(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
set_var(lp->ll_name, rettv, copy);
|
set_var_const(lp->ll_name, rettv, copy, is_const);
|
||||||
*endp = cc;
|
*endp = cc;
|
||||||
}
|
}
|
||||||
else if (var_check_lock(lp->ll_newkey == NULL
|
else if (var_check_lock(lp->ll_newkey == NULL
|
||||||
@ -2521,6 +2569,12 @@ set_var_lval(
|
|||||||
listitem_T *ll_li = lp->ll_li;
|
listitem_T *ll_li = lp->ll_li;
|
||||||
int ll_n1 = lp->ll_n1;
|
int ll_n1 = lp->ll_n1;
|
||||||
|
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_("E996: Cannot lock a range"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether any of the list items is locked
|
* Check whether any of the list items is locked
|
||||||
*/
|
*/
|
||||||
@ -2574,6 +2628,11 @@ set_var_lval(
|
|||||||
/*
|
/*
|
||||||
* Assign to a List or Dictionary item.
|
* Assign to a List or Dictionary item.
|
||||||
*/
|
*/
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_("E996: Cannot lock a list or dict"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (lp->ll_newkey != NULL)
|
if (lp->ll_newkey != NULL)
|
||||||
{
|
{
|
||||||
if (op != NULL && *op != '=')
|
if (op != NULL && *op != '=')
|
||||||
@ -2860,8 +2919,8 @@ next_for_item(void *fi_void, char_u *arg)
|
|||||||
tv.v_lock = VAR_FIXED;
|
tv.v_lock = VAR_FIXED;
|
||||||
tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi);
|
tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi);
|
||||||
++fi->fi_bi;
|
++fi->fi_bi;
|
||||||
return ex_let_vars(arg, &tv, TRUE,
|
return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon,
|
||||||
fi->fi_semicolon, fi->fi_varcount, NULL) == OK;
|
fi->fi_varcount, FALSE, NULL) == OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
item = fi->fi_lw.lw_item;
|
item = fi->fi_lw.lw_item;
|
||||||
@ -2870,8 +2929,8 @@ next_for_item(void *fi_void, char_u *arg)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
fi->fi_lw.lw_item = item->li_next;
|
fi->fi_lw.lw_item = item->li_next;
|
||||||
result = (ex_let_vars(arg, &item->li_tv, TRUE,
|
result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon,
|
||||||
fi->fi_semicolon, fi->fi_varcount, NULL) == OK);
|
fi->fi_varcount, FALSE, NULL) == OK);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -8051,7 +8110,22 @@ list_one_var_a(
|
|||||||
set_var(
|
set_var(
|
||||||
char_u *name,
|
char_u *name,
|
||||||
typval_T *tv,
|
typval_T *tv,
|
||||||
int copy) /* make copy of value in "tv" */
|
int copy) // make copy of value in "tv"
|
||||||
|
{
|
||||||
|
set_var_const(name, tv, copy, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set variable "name" to value in "tv".
|
||||||
|
* If the variable already exists and "is_const" is FALSE the value is updated.
|
||||||
|
* Otherwise the variable is created.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_var_const(
|
||||||
|
char_u *name,
|
||||||
|
typval_T *tv,
|
||||||
|
int copy, // make copy of value in "tv"
|
||||||
|
int is_const) // disallow to modify existing variable
|
||||||
{
|
{
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
char_u *varname;
|
char_u *varname;
|
||||||
@ -8075,6 +8149,12 @@ set_var(
|
|||||||
|
|
||||||
if (v != NULL)
|
if (v != NULL)
|
||||||
{
|
{
|
||||||
|
if (is_const)
|
||||||
|
{
|
||||||
|
emsg(_(e_cannot_mod));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* existing variable, need to clear the value */
|
/* existing variable, need to clear the value */
|
||||||
if (var_check_ro(v->di_flags, name, FALSE)
|
if (var_check_ro(v->di_flags, name, FALSE)
|
||||||
|| var_check_lock(v->di_tv.v_lock, name, FALSE))
|
|| var_check_lock(v->di_tv.v_lock, name, FALSE))
|
||||||
@ -8152,6 +8232,8 @@ set_var(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
v->di_flags = DI_FLAGS_ALLOC;
|
v->di_flags = DI_FLAGS_ALLOC;
|
||||||
|
if (is_const)
|
||||||
|
v->di_flags |= DI_FLAGS_LOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
|
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
|
||||||
@ -8162,6 +8244,9 @@ set_var(
|
|||||||
v->di_tv.v_lock = 0;
|
v->di_tv.v_lock = 0;
|
||||||
init_tv(tv);
|
init_tv(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_const)
|
||||||
|
v->di_tv.v_lock |= VAR_LOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] =
|
|||||||
/* a */ 0,
|
/* a */ 0,
|
||||||
/* b */ 19,
|
/* b */ 19,
|
||||||
/* c */ 42,
|
/* c */ 42,
|
||||||
/* d */ 107,
|
/* d */ 108,
|
||||||
/* e */ 129,
|
/* e */ 130,
|
||||||
/* f */ 149,
|
/* f */ 150,
|
||||||
/* g */ 165,
|
/* g */ 166,
|
||||||
/* h */ 171,
|
/* h */ 172,
|
||||||
/* i */ 180,
|
/* i */ 181,
|
||||||
/* j */ 198,
|
/* j */ 199,
|
||||||
/* k */ 200,
|
/* k */ 201,
|
||||||
/* l */ 205,
|
/* l */ 206,
|
||||||
/* m */ 267,
|
/* m */ 268,
|
||||||
/* n */ 285,
|
/* n */ 286,
|
||||||
/* o */ 305,
|
/* o */ 306,
|
||||||
/* p */ 317,
|
/* p */ 318,
|
||||||
/* q */ 356,
|
/* q */ 357,
|
||||||
/* r */ 359,
|
/* r */ 360,
|
||||||
/* s */ 379,
|
/* s */ 380,
|
||||||
/* t */ 447,
|
/* t */ 448,
|
||||||
/* u */ 492,
|
/* u */ 493,
|
||||||
/* v */ 503,
|
/* v */ 504,
|
||||||
/* w */ 521,
|
/* w */ 522,
|
||||||
/* x */ 535,
|
/* x */ 536,
|
||||||
/* y */ 545,
|
/* y */ 546,
|
||||||
/* z */ 546
|
/* z */ 547
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -43,7 +43,7 @@ static const unsigned char cmdidxs2[26][26] =
|
|||||||
{ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
|
{ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
|
||||||
/* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 },
|
/* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 },
|
||||||
/* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 },
|
/* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 },
|
||||||
/* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 55, 57, 58, 59, 0, 61, 0, 64, 0, 0, 0 },
|
/* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 },
|
||||||
/* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 },
|
/* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
/* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 },
|
/* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 },
|
||||||
/* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 },
|
/* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 },
|
||||||
@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
|
|||||||
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int command_count = 559;
|
static const int command_count = 560;
|
||||||
|
@ -401,6 +401,9 @@ EX(CMD_continue, "continue", ex_continue,
|
|||||||
EX(CMD_confirm, "confirm", ex_wrongmodifier,
|
EX(CMD_confirm, "confirm", ex_wrongmodifier,
|
||||||
NEEDARG|EXTRA|NOTRLCOM|CMDWIN,
|
NEEDARG|EXTRA|NOTRLCOM|CMDWIN,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
|
EX(CMD_const, "const", ex_const,
|
||||||
|
EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
|
||||||
|
ADDR_NONE),
|
||||||
EX(CMD_copen, "copen", ex_copen,
|
EX(CMD_copen, "copen", ex_copen,
|
||||||
RANGE|COUNT|TRLBAR,
|
RANGE|COUNT|TRLBAR,
|
||||||
ADDR_OTHER),
|
ADDR_OTHER),
|
||||||
|
@ -28,6 +28,7 @@ void *call_func_retstr(char_u *func, int argc, typval_T *argv);
|
|||||||
void *call_func_retlist(char_u *func, int argc, typval_T *argv);
|
void *call_func_retlist(char_u *func, int argc, typval_T *argv);
|
||||||
int eval_foldexpr(char_u *arg, int *cp);
|
int eval_foldexpr(char_u *arg, int *cp);
|
||||||
void ex_let(exarg_T *eap);
|
void ex_let(exarg_T *eap);
|
||||||
|
void ex_const(exarg_T *eap);
|
||||||
void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
|
void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
|
||||||
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);
|
||||||
|
@ -87,6 +87,7 @@ NEW_TESTS = \
|
|||||||
test_comparators \
|
test_comparators \
|
||||||
test_compiler \
|
test_compiler \
|
||||||
test_conceal \
|
test_conceal \
|
||||||
|
test_const \
|
||||||
test_crypt \
|
test_crypt \
|
||||||
test_cscope \
|
test_cscope \
|
||||||
test_cursor_func \
|
test_cursor_func \
|
||||||
@ -312,6 +313,7 @@ NEW_TESTS_RES = \
|
|||||||
test_command_count.res \
|
test_command_count.res \
|
||||||
test_comparators.res \
|
test_comparators.res \
|
||||||
test_conceal.res \
|
test_conceal.res \
|
||||||
|
test_const.res \
|
||||||
test_crypt.res \
|
test_crypt.res \
|
||||||
test_cscope.res \
|
test_cscope.res \
|
||||||
test_curswant.res \
|
test_curswant.res \
|
||||||
|
228
src/testdir/test_const.vim
Normal file
228
src/testdir/test_const.vim
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
" Test for :const
|
||||||
|
|
||||||
|
func s:noop()
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_define_var_with_lock()
|
||||||
|
const i = 1
|
||||||
|
const f = 1.1
|
||||||
|
const s = 'vim'
|
||||||
|
const F = funcref('s:noop')
|
||||||
|
const l = [1, 2, 3]
|
||||||
|
const d = {'foo': 10}
|
||||||
|
if has('channel')
|
||||||
|
const j = test_null_job()
|
||||||
|
const c = test_null_channel()
|
||||||
|
endif
|
||||||
|
const b = v:true
|
||||||
|
const n = v:null
|
||||||
|
const bl = 0zC0FFEE
|
||||||
|
const here =<< trim EOS
|
||||||
|
hello
|
||||||
|
EOS
|
||||||
|
|
||||||
|
call assert_fails('let i = 1', 'E741:')
|
||||||
|
call assert_fails('let f = 1.1', 'E741:')
|
||||||
|
call assert_fails('let s = "vim"', 'E741:')
|
||||||
|
call assert_fails('let F = funcref("s:noop")', 'E741:')
|
||||||
|
call assert_fails('let l = [1, 2, 3]', 'E741:')
|
||||||
|
call assert_fails('let d = {"foo": 10}', 'E741:')
|
||||||
|
if has('channel')
|
||||||
|
call assert_fails('let j = test_null_job()', 'E741:')
|
||||||
|
call assert_fails('let c = test_null_channel()', 'E741:')
|
||||||
|
endif
|
||||||
|
call assert_fails('let b = v:true', 'E741:')
|
||||||
|
call assert_fails('let n = v:null', 'E741:')
|
||||||
|
call assert_fails('let bl = 0zC0FFEE', 'E741:')
|
||||||
|
call assert_fails('let here = "xxx"', 'E741:')
|
||||||
|
|
||||||
|
" Unlet
|
||||||
|
unlet i
|
||||||
|
unlet f
|
||||||
|
unlet s
|
||||||
|
unlet F
|
||||||
|
unlet l
|
||||||
|
unlet d
|
||||||
|
unlet j
|
||||||
|
unlet c
|
||||||
|
unlet b
|
||||||
|
unlet n
|
||||||
|
unlet bl
|
||||||
|
unlet here
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_define_l_var_with_lock()
|
||||||
|
" With l: prefix
|
||||||
|
const l:i = 1
|
||||||
|
const l:f = 1.1
|
||||||
|
const l:s = 'vim'
|
||||||
|
const l:F = funcref('s:noop')
|
||||||
|
const l:l = [1, 2, 3]
|
||||||
|
const l:d = {'foo': 10}
|
||||||
|
if has('channel')
|
||||||
|
const l:j = test_null_job()
|
||||||
|
const l:c = test_null_channel()
|
||||||
|
endif
|
||||||
|
const l:b = v:true
|
||||||
|
const l:n = v:null
|
||||||
|
const l:bl = 0zC0FFEE
|
||||||
|
const l:here =<< trim EOS
|
||||||
|
hello
|
||||||
|
EOS
|
||||||
|
|
||||||
|
call assert_fails('let l:i = 1', 'E741:')
|
||||||
|
call assert_fails('let l:f = 1.1', 'E741:')
|
||||||
|
call assert_fails('let l:s = "vim"', 'E741:')
|
||||||
|
call assert_fails('let l:F = funcref("s:noop")', 'E741:')
|
||||||
|
call assert_fails('let l:l = [1, 2, 3]', 'E741:')
|
||||||
|
call assert_fails('let l:d = {"foo": 10}', 'E741:')
|
||||||
|
if has('channel')
|
||||||
|
call assert_fails('let l:j = test_null_job()', 'E741:')
|
||||||
|
call assert_fails('let l:c = test_null_channel()', 'E741:')
|
||||||
|
endif
|
||||||
|
call assert_fails('let l:b = v:true', 'E741:')
|
||||||
|
call assert_fails('let l:n = v:null', 'E741:')
|
||||||
|
call assert_fails('let l:bl = 0zC0FFEE', 'E741:')
|
||||||
|
call assert_fails('let l:here = "xxx"', 'E741:')
|
||||||
|
|
||||||
|
" Unlet
|
||||||
|
unlet l:i
|
||||||
|
unlet l:f
|
||||||
|
unlet l:s
|
||||||
|
unlet l:F
|
||||||
|
unlet l:l
|
||||||
|
unlet l:d
|
||||||
|
unlet l:j
|
||||||
|
unlet l:c
|
||||||
|
unlet l:b
|
||||||
|
unlet l:n
|
||||||
|
unlet l:bl
|
||||||
|
unlet l:here
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_define_script_var_with_lock()
|
||||||
|
const s:x = 0
|
||||||
|
call assert_fails('let s:x = 1', 'E741:')
|
||||||
|
unlet s:x
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_descructuring_with_lock()
|
||||||
|
const [a, b, c] = [1, 1.1, 'vim']
|
||||||
|
|
||||||
|
call assert_fails('let a = 1', 'E741:')
|
||||||
|
call assert_fails('let b = 1.1', 'E741:')
|
||||||
|
call assert_fails('let c = "vim"', 'E741:')
|
||||||
|
|
||||||
|
const [d; e] = [1, 1.1, 'vim']
|
||||||
|
call assert_fails('let d = 1', 'E741:')
|
||||||
|
call assert_fails('let e = [2.2, "a"]', 'E741:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_cannot_modify_existing_variable()
|
||||||
|
let i = 1
|
||||||
|
let f = 1.1
|
||||||
|
let s = 'vim'
|
||||||
|
let F = funcref('s:noop')
|
||||||
|
let l = [1, 2, 3]
|
||||||
|
let d = {'foo': 10}
|
||||||
|
if has('channel')
|
||||||
|
let j = test_null_job()
|
||||||
|
let c = test_null_channel()
|
||||||
|
endif
|
||||||
|
let b = v:true
|
||||||
|
let n = v:null
|
||||||
|
let bl = 0zC0FFEE
|
||||||
|
|
||||||
|
call assert_fails('const i = 1', 'E995:')
|
||||||
|
call assert_fails('const f = 1.1', 'E995:')
|
||||||
|
call assert_fails('const s = "vim"', 'E995:')
|
||||||
|
call assert_fails('const F = funcref("s:noop")', 'E995:')
|
||||||
|
call assert_fails('const l = [1, 2, 3]', 'E995:')
|
||||||
|
call assert_fails('const d = {"foo": 10}', 'E995:')
|
||||||
|
if has('channel')
|
||||||
|
call assert_fails('const j = test_null_job()', 'E995:')
|
||||||
|
call assert_fails('const c = test_null_channel()', 'E995:')
|
||||||
|
endif
|
||||||
|
call assert_fails('const b = v:true', 'E995:')
|
||||||
|
call assert_fails('const n = v:null', 'E995:')
|
||||||
|
call assert_fails('const bl = 0zC0FFEE', 'E995:')
|
||||||
|
call assert_fails('const [i, f, s] = [1, 1.1, "vim"]', 'E995:')
|
||||||
|
|
||||||
|
const i2 = 1
|
||||||
|
const f2 = 1.1
|
||||||
|
const s2 = 'vim'
|
||||||
|
const F2 = funcref('s:noop')
|
||||||
|
const l2 = [1, 2, 3]
|
||||||
|
const d2 = {'foo': 10}
|
||||||
|
if has('channel')
|
||||||
|
const j2 = test_null_job()
|
||||||
|
const c2 = test_null_channel()
|
||||||
|
endif
|
||||||
|
const b2 = v:true
|
||||||
|
const n2 = v:null
|
||||||
|
const bl2 = 0zC0FFEE
|
||||||
|
|
||||||
|
call assert_fails('const i2 = 1', 'E995:')
|
||||||
|
call assert_fails('const f2 = 1.1', 'E995:')
|
||||||
|
call assert_fails('const s2 = "vim"', 'E995:')
|
||||||
|
call assert_fails('const F2 = funcref("s:noop")', 'E995:')
|
||||||
|
call assert_fails('const l2 = [1, 2, 3]', 'E995:')
|
||||||
|
call assert_fails('const d2 = {"foo": 10}', 'E995:')
|
||||||
|
if has('channel')
|
||||||
|
call assert_fails('const j2 = test_null_job()', 'E995:')
|
||||||
|
call assert_fails('const c2 = test_null_channel()', 'E995:')
|
||||||
|
endif
|
||||||
|
call assert_fails('const b2 = v:true', 'E995:')
|
||||||
|
call assert_fails('const n2 = v:null', 'E995:')
|
||||||
|
call assert_fails('const bl2 = 0zC0FFEE', 'E995:')
|
||||||
|
call assert_fails('const [i2, f2, s2] = [1, 1.1, "vim"]', 'E995:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_const_with_index_access()
|
||||||
|
let l = [1, 2, 3]
|
||||||
|
call assert_fails('const l[0] = 4', 'E996:')
|
||||||
|
call assert_fails('const l[0:1] = [1, 2]', 'E996:')
|
||||||
|
|
||||||
|
let d = {'aaa': 0}
|
||||||
|
call assert_fails("const d['aaa'] = 4", 'E996:')
|
||||||
|
call assert_fails("const d.aaa = 4", 'E996:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_const_with_compound_assign()
|
||||||
|
let i = 0
|
||||||
|
call assert_fails('const i += 4', 'E995:')
|
||||||
|
call assert_fails('const i -= 4', 'E995:')
|
||||||
|
call assert_fails('const i *= 4', 'E995:')
|
||||||
|
call assert_fails('const i /= 4', 'E995:')
|
||||||
|
call assert_fails('const i %= 4', 'E995:')
|
||||||
|
|
||||||
|
let s = 'a'
|
||||||
|
call assert_fails('const s .= "b"', 'E995:')
|
||||||
|
|
||||||
|
let [a, b, c] = [1, 2, 3]
|
||||||
|
call assert_fails('const [a, b, c] += [4, 5, 6]', 'E995:')
|
||||||
|
|
||||||
|
let [d; e] = [1, 2, 3]
|
||||||
|
call assert_fails('const [d; e] += [4, 5, 6]', 'E995:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_const_with_special_variables()
|
||||||
|
call assert_fails('const $FOO = "hello"', 'E996:')
|
||||||
|
call assert_fails('const @a = "hello"', 'E996:')
|
||||||
|
call assert_fails('const &filetype = "vim"', 'E996:')
|
||||||
|
call assert_fails('const &l:filetype = "vim"', 'E996:')
|
||||||
|
call assert_fails('const &g:encoding = "utf-8"', 'E996:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_lock_depth_is_1()
|
||||||
|
const l = [1, 2, 3]
|
||||||
|
const d = {'foo': 10}
|
||||||
|
|
||||||
|
" Modify list
|
||||||
|
call add(l, 4)
|
||||||
|
let l[0] = 42
|
||||||
|
|
||||||
|
" Modify dict
|
||||||
|
let d['bar'] = 'hello'
|
||||||
|
let d.foo = 44
|
||||||
|
endfunc
|
@ -777,6 +777,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 */
|
||||||
|
/**/
|
||||||
|
1539,
|
||||||
/**/
|
/**/
|
||||||
1538,
|
1538,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user