mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -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:
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_letwrong = N_("E734: Wrong variable type for %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
|
||||
static char *e_float_as_string = N_("E806: using Float as a String");
|
||||
#endif
|
||||
@@ -212,7 +213,8 @@ static struct vimvar
|
||||
static dictitem_T vimvars_var; /* variable used for v: */
|
||||
#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_one(char_u *arg);
|
||||
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_script_vars(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 void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, 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, int is_const, 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 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 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 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 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.vval.v_string = (char_u *)"";
|
||||
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
|
||||
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);
|
||||
err = did_emsg;
|
||||
did_emsg |= save_emsg;
|
||||
@@ -601,7 +604,8 @@ var_redir_stop(void)
|
||||
redir_endp = get_lval(redir_varname, NULL, redir_lval,
|
||||
FALSE, FALSE, 0, FNE_CHECK_START);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1337,6 +1341,24 @@ heredoc_get(exarg_T *eap, char_u *cmd)
|
||||
*/
|
||||
void
|
||||
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 *expr = NULL;
|
||||
@@ -1396,7 +1418,7 @@ ex_let(exarg_T *eap)
|
||||
op[0] = '=';
|
||||
op[1] = NUL;
|
||||
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||
op);
|
||||
is_const, op);
|
||||
clear_tv(&rettv);
|
||||
}
|
||||
}
|
||||
@@ -1429,7 +1451,7 @@ ex_let(exarg_T *eap)
|
||||
else if (i != FAIL)
|
||||
{
|
||||
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||
op);
|
||||
is_const, op);
|
||||
clear_tv(&rettv);
|
||||
}
|
||||
}
|
||||
@@ -1447,9 +1469,10 @@ ex_let(exarg_T *eap)
|
||||
ex_let_vars(
|
||||
char_u *arg_start,
|
||||
typval_T *tv,
|
||||
int copy, /* copy values from "tv", don't move */
|
||||
int semicolon, /* from skip_var_list() */
|
||||
int var_count, /* from skip_var_list() */
|
||||
int copy, // copy values from "tv", don't move
|
||||
int semicolon, // from skip_var_list()
|
||||
int var_count, // from skip_var_list()
|
||||
int is_const, // lock variables for const
|
||||
char_u *nextchars)
|
||||
{
|
||||
char_u *arg = arg_start;
|
||||
@@ -1463,7 +1486,7 @@ ex_let_vars(
|
||||
/*
|
||||
* ":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 OK;
|
||||
}
|
||||
@@ -1493,7 +1516,8 @@ ex_let_vars(
|
||||
while (*arg != ']')
|
||||
{
|
||||
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;
|
||||
if (arg == NULL)
|
||||
return FAIL;
|
||||
@@ -1517,8 +1541,8 @@ ex_let_vars(
|
||||
ltv.vval.v_list = l;
|
||||
l->lv_refcount = 1;
|
||||
|
||||
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE,
|
||||
(char_u *)"]", nextchars);
|
||||
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, is_const,
|
||||
(char_u *)"]", nextchars);
|
||||
clear_tv(<v);
|
||||
if (arg == NULL)
|
||||
return FAIL;
|
||||
@@ -1805,11 +1829,12 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first)
|
||||
*/
|
||||
static char_u *
|
||||
ex_let_one(
|
||||
char_u *arg, /* points to variable name */
|
||||
typval_T *tv, /* value to assign to variable */
|
||||
int copy, /* copy value from "tv" */
|
||||
char_u *endchars, /* valid chars after variable name or NULL */
|
||||
char_u *op) /* "+", "-", "." or NULL*/
|
||||
char_u *arg, // points to variable name
|
||||
typval_T *tv, // value to assign to variable
|
||||
int copy, // copy value from "tv"
|
||||
int is_const, // lock variable for const
|
||||
char_u *endchars, // valid chars after variable name or NULL
|
||||
char_u *op) // "+", "-", "." or NULL
|
||||
{
|
||||
int c1;
|
||||
char_u *name;
|
||||
@@ -1824,6 +1849,11 @@ ex_let_one(
|
||||
*/
|
||||
if (*arg == '$')
|
||||
{
|
||||
if (is_const)
|
||||
{
|
||||
emsg(_("E996: Cannot lock an environment variable"));
|
||||
return NULL;
|
||||
}
|
||||
/* Find the end of the name. */
|
||||
++arg;
|
||||
name = arg;
|
||||
@@ -1879,6 +1909,11 @@ ex_let_one(
|
||||
*/
|
||||
else if (*arg == '&')
|
||||
{
|
||||
if (is_const)
|
||||
{
|
||||
emsg(_("E996: Cannot lock an option"));
|
||||
return NULL;
|
||||
}
|
||||
/* Find the end of the name. */
|
||||
p = find_option_end(&arg, &opt_flags);
|
||||
if (p == NULL || (endchars != NULL
|
||||
@@ -1943,6 +1978,11 @@ ex_let_one(
|
||||
*/
|
||||
else if (*arg == '@')
|
||||
{
|
||||
if (is_const)
|
||||
{
|
||||
emsg(_("E996: Cannot lock a register"));
|
||||
return NULL;
|
||||
}
|
||||
++arg;
|
||||
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
|
||||
semsg(_(e_letwrong), op);
|
||||
@@ -1988,7 +2028,7 @@ ex_let_one(
|
||||
emsg(_(e_letunexp));
|
||||
else
|
||||
{
|
||||
set_var_lval(&lv, p, tv, copy, op);
|
||||
set_var_lval(&lv, p, tv, copy, is_const, op);
|
||||
arg_end = p;
|
||||
}
|
||||
}
|
||||
@@ -2430,6 +2470,7 @@ set_var_lval(
|
||||
char_u *endp,
|
||||
typval_T *rettv,
|
||||
int copy,
|
||||
int is_const, // Disallow to modify existing variable for :const
|
||||
char_u *op)
|
||||
{
|
||||
int cc;
|
||||
@@ -2495,6 +2536,13 @@ set_var_lval(
|
||||
{
|
||||
typval_T tv;
|
||||
|
||||
if (is_const)
|
||||
{
|
||||
emsg(_(e_cannot_mod));
|
||||
*endp = cc;
|
||||
return;
|
||||
}
|
||||
|
||||
// handle +=, -=, *=, /=, %= and .=
|
||||
di = NULL;
|
||||
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
|
||||
@@ -2509,7 +2557,7 @@ set_var_lval(
|
||||
}
|
||||
}
|
||||
else
|
||||
set_var(lp->ll_name, rettv, copy);
|
||||
set_var_const(lp->ll_name, rettv, copy, is_const);
|
||||
*endp = cc;
|
||||
}
|
||||
else if (var_check_lock(lp->ll_newkey == NULL
|
||||
@@ -2521,6 +2569,12 @@ set_var_lval(
|
||||
listitem_T *ll_li = lp->ll_li;
|
||||
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
|
||||
*/
|
||||
@@ -2574,6 +2628,11 @@ set_var_lval(
|
||||
/*
|
||||
* 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 (op != NULL && *op != '=')
|
||||
@@ -2860,8 +2919,8 @@ next_for_item(void *fi_void, char_u *arg)
|
||||
tv.v_lock = VAR_FIXED;
|
||||
tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi);
|
||||
++fi->fi_bi;
|
||||
return ex_let_vars(arg, &tv, TRUE,
|
||||
fi->fi_semicolon, fi->fi_varcount, NULL) == OK;
|
||||
return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon,
|
||||
fi->fi_varcount, FALSE, NULL) == OK;
|
||||
}
|
||||
|
||||
item = fi->fi_lw.lw_item;
|
||||
@@ -2870,8 +2929,8 @@ next_for_item(void *fi_void, char_u *arg)
|
||||
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);
|
||||
result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon,
|
||||
fi->fi_varcount, FALSE, NULL) == OK);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -8051,7 +8110,22 @@ list_one_var_a(
|
||||
set_var(
|
||||
char_u *name,
|
||||
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;
|
||||
char_u *varname;
|
||||
@@ -8075,6 +8149,12 @@ set_var(
|
||||
|
||||
if (v != NULL)
|
||||
{
|
||||
if (is_const)
|
||||
{
|
||||
emsg(_(e_cannot_mod));
|
||||
return;
|
||||
}
|
||||
|
||||
/* existing variable, need to clear the value */
|
||||
if (var_check_ro(v->di_flags, name, FALSE)
|
||||
|| var_check_lock(v->di_tv.v_lock, name, FALSE))
|
||||
@@ -8152,6 +8232,8 @@ set_var(
|
||||
return;
|
||||
}
|
||||
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)
|
||||
@@ -8162,6 +8244,9 @@ set_var(
|
||||
v->di_tv.v_lock = 0;
|
||||
init_tv(tv);
|
||||
}
|
||||
|
||||
if (is_const)
|
||||
v->di_tv.v_lock |= VAR_LOCKED;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user