0
0
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:
Bram Moolenaar 2019-06-15 15:45:06 +02:00
parent dfa97f2aed
commit 9937a05543
8 changed files with 397 additions and 53 deletions

View File

@ -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).

View File

@ -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,7 +1541,7 @@ 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), &ltv, FALSE, arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE, is_const,
(char_u *)"]", nextchars); (char_u *)"]", nextchars);
clear_tv(&ltv); clear_tv(&ltv);
if (arg == NULL) if (arg == NULL)
@ -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;
} }
/* /*

View File

@ -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;

View File

@ -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),

View File

@ -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);

View File

@ -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
View 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

View File

@ -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,
/**/ /**/