0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.2.0149: maintaining a Vim9 branch separately is more work

Problem:    Maintaining a Vim9 branch separately is more work.
Solution:   Merge the Vim9 script changes.
This commit is contained in:
Bram Moolenaar
2020-01-26 15:56:19 +01:00
parent 1d9215b9aa
commit 8a7d6542b3
65 changed files with 11777 additions and 1327 deletions

View File

@@ -15,8 +15,6 @@
#if defined(FEAT_EVAL) || defined(PROTO)
static char *e_letunexp = N_("E18: Unexpected characters in :let");
static dictitem_T globvars_var; // variable used for g:
static dict_T globvardict; // Dictionary with g: variables
#define globvarht globvardict.dv_hashtab
@@ -41,6 +39,8 @@ static hashtab_T compat_hashtab;
#define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}
typedef struct vimvar vimvar_T;
static struct vimvar
{
char *vv_name; // name of variable, without v:
@@ -163,17 +163,14 @@ static dict_T vimvardict; // Dictionary with v: variables
// for VIM_VERSION_ defines
#include "version.h"
#define SCRIPT_SV(id) (SCRIPT_ITEM(id).sn_vars)
#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
static void ex_let_const(exarg_T *eap, int is_const);
static char_u *skip_var_one(char_u *arg);
static char_u *skip_var_one(char_u *arg, int include_type);
static void list_glob_vars(int *first);
static void list_buf_vars(int *first);
static void list_win_vars(int *first);
static void list_tab_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, int is_const, char_u *endchars, char_u *op);
static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags, char_u *endchars, 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);
static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
@@ -544,7 +541,7 @@ list_script_vars(int *first)
* indentation in the 'cmd' line) is stripped.
* Returns a List with {lines} or NULL.
*/
static list_T *
list_T *
heredoc_get(exarg_T *eap, char_u *cmd)
{
char_u *theline;
@@ -669,6 +666,7 @@ heredoc_get(exarg_T *eap, char_u *cmd)
* ":let var .= expr" assignment command.
* ":let var ..= expr" assignment command.
* ":let [var1, var2] = expr" unpack list.
* ":let var =<< ..." heredoc
*/
void
ex_let(exarg_T *eap)
@@ -701,8 +699,13 @@ ex_let_const(exarg_T *eap, int is_const)
char_u *argend;
int first = TRUE;
int concat;
int flags = is_const ? LET_IS_CONST : 0;
argend = skip_var_list(arg, &var_count, &semicolon);
// detect Vim9 assignment without ":let" or ":const"
if (eap->arg == eap->cmd)
flags |= LET_NO_COMMAND;
argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
if (argend == NULL)
return;
if (argend > arg && argend[-1] == '.') // for var.='str'
@@ -749,7 +752,7 @@ ex_let_const(exarg_T *eap, int is_const)
op[0] = '=';
op[1] = NUL;
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
is_const, op);
flags, op);
}
clear_tv(&rettv);
}
@@ -783,7 +786,7 @@ ex_let_const(exarg_T *eap, int is_const)
else if (i != FAIL)
{
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
is_const, op);
flags, op);
clear_tv(&rettv);
}
}
@@ -804,7 +807,7 @@ ex_let_vars(
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
int flags, // LET_IS_CONST and/or LET_NO_COMMAND
char_u *op)
{
char_u *arg = arg_start;
@@ -816,7 +819,7 @@ ex_let_vars(
if (*arg != '[')
{
// ":let var = expr" or ":for var in list"
if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL)
if (ex_let_one(arg, tv, copy, flags, op, op) == NULL)
return FAIL;
return OK;
}
@@ -844,8 +847,7 @@ ex_let_vars(
while (*arg != ']')
{
arg = skipwhite(arg + 1);
arg = ex_let_one(arg, &item->li_tv, TRUE, is_const,
(char_u *)",;]", op);
arg = ex_let_one(arg, &item->li_tv, TRUE, flags, (char_u *)",;]", op);
item = item->li_next;
if (arg == NULL)
return FAIL;
@@ -869,7 +871,7 @@ ex_let_vars(
ltv.vval.v_list = l;
l->lv_refcount = 1;
arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE, is_const,
arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE, flags,
(char_u *)"]", op);
clear_tv(&ltv);
if (arg == NULL)
@@ -896,6 +898,7 @@ ex_let_vars(
char_u *
skip_var_list(
char_u *arg,
int include_type,
int *var_count,
int *semicolon)
{
@@ -908,7 +911,7 @@ skip_var_list(
for (;;)
{
p = skipwhite(p + 1); // skip whites after '[', ';' or ','
s = skip_var_one(p);
s = skip_var_one(p, TRUE);
if (s == p)
{
semsg(_(e_invarg2), p);
@@ -937,20 +940,29 @@ skip_var_list(
return p + 1;
}
else
return skip_var_one(arg);
return skip_var_one(arg, include_type);
}
/*
* Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
* l[idx].
* In Vim9 script also skip over ": type" if "include_type" is TRUE.
*/
static char_u *
skip_var_one(char_u *arg)
skip_var_one(char_u *arg, int include_type)
{
char_u *end;
if (*arg == '@' && arg[1] != NUL)
return arg + 2;
return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
if (include_type && current_sctx.sc_version == SCRIPT_VERSION_VIM9
&& *end == ':')
{
end = skip_type(skipwhite(end + 1));
}
return end;
}
/*
@@ -1141,7 +1153,7 @@ ex_let_one(
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
int flags, // LET_IS_CONST and/or LET_NO_COMMAND
char_u *endchars, // valid chars after variable name or NULL
char_u *op) // "+", "-", "." or NULL
{
@@ -1156,7 +1168,7 @@ ex_let_one(
// ":let $VAR = expr": Set environment variable.
if (*arg == '$')
{
if (is_const)
if (flags & LET_IS_CONST)
{
emsg(_("E996: Cannot lock an environment variable"));
return NULL;
@@ -1214,9 +1226,9 @@ ex_let_one(
// ":let &g:option = expr": Set global option value.
else if (*arg == '&')
{
if (is_const)
if (flags & LET_IS_CONST)
{
emsg(_("E996: Cannot lock an option"));
emsg(_(e_const_option));
return NULL;
}
// Find the end of the name.
@@ -1281,7 +1293,7 @@ ex_let_one(
// ":let @r = expr": Set register contents.
else if (*arg == '@')
{
if (is_const)
if (flags & LET_IS_CONST)
{
emsg(_("E996: Cannot lock a register"));
return NULL;
@@ -1317,6 +1329,7 @@ ex_let_one(
}
// ":let var = expr": Set internal variable.
// ":let var: type = expr": Set internal variable with type.
// ":let {expr} = expr": Idem, name made with curly braces
else if (eval_isnamec1(*arg) || *arg == '{')
{
@@ -1325,11 +1338,12 @@ ex_let_one(
p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START);
if (p != NULL && lv.ll_name != NULL)
{
if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL)
if (endchars != NULL && vim_strchr(endchars,
*skipwhite(lv.ll_name_end)) == NULL)
emsg(_(e_letunexp));
else
{
set_var_lval(&lv, p, tv, copy, is_const, op);
set_var_lval(&lv, p, tv, copy, flags, op);
arg_end = p;
}
}
@@ -1657,12 +1671,13 @@ item_lock(typval_T *tv, int deep, int lock)
switch (tv->v_type)
{
case VAR_UNKNOWN:
case VAR_VOID:
case VAR_NUMBER:
case VAR_BOOL:
case VAR_STRING:
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_FLOAT:
case VAR_BOOL:
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
@@ -1900,6 +1915,22 @@ get_vimvar_dict(void)
return &vimvardict;
}
/*
* Returns the index of a v:variable. Negative if not found.
*/
int
find_vim_var(char_u *name)
{
dictitem_T *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
struct vimvar *vv;
if (di == NULL)
return -1;
vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
return (int)(vv - vimvars);
}
/*
* Set type of v: variable to "type".
*/
@@ -1919,6 +1950,12 @@ set_vim_var_nr(int idx, varnumber_T val)
vimvars[idx].vv_nr = val;
}
char *
get_vim_var_name(int idx)
{
return vimvars[idx].vv_name;
}
/*
* Get typval_T v: variable value.
*/
@@ -2245,6 +2282,20 @@ get_var_tv(
*dip = v;
}
if (tv == NULL && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
imported_T *import = find_imported(name, NULL);
// imported variable from another script
if (import != NULL)
{
scriptitem_T *si = &SCRIPT_ITEM(import->imp_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ import->imp_var_vals_idx;
tv = sv->sv_tv;
}
}
if (tv == NULL)
{
if (rettv != NULL && verbose)
@@ -2365,6 +2416,58 @@ find_var_in_ht(
return HI2DI(hi);
}
/*
* Get the script-local hashtab. NULL if not in a script context.
*/
hashtab_T *
get_script_local_ht(void)
{
scid_T sid = current_sctx.sc_sid;
if (sid > 0 && sid <= script_items.ga_len)
return &SCRIPT_VARS(sid);
return NULL;
}
/*
* Look for "name[len]" in script-local variables.
* Return -1 when not found.
*/
int
lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
{
hashtab_T *ht = get_script_local_ht();
char_u buffer[30];
char_u *p;
int res;
hashitem_T *hi;
if (ht == NULL)
return -1;
if (len < sizeof(buffer) - 1)
{
vim_strncpy(buffer, name, len);
p = buffer;
}
else
{
p = vim_strnsave(name, (int)len);
if (p == NULL)
return -1;
}
hi = hash_find(ht, p);
res = HASHITEM_EMPTY(hi) ? -1 : 1;
// if not script-local, then perhaps imported
if (res == -1 && find_imported(p, NULL) != NULL)
res = 1;
if (p != buffer)
vim_free(p);
return res;
}
/*
* Find the hashtab used for a variable name.
* Return NULL if the name is not valid.
@@ -2395,9 +2498,18 @@ find_var_ht(char_u *name, char_u **varname)
}
ht = get_funccal_local_ht();
if (ht == NULL)
return &globvarht; // global variable
return ht; // local variable
if (ht != NULL)
return ht; // local variable
// in Vim9 script items at the script level are script-local
if (current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
ht = get_script_local_ht();
if (ht != NULL)
return ht;
}
return &globvarht; // global variable
}
*varname = name + 2;
if (*name == 'g') // global variable
@@ -2414,14 +2526,19 @@ find_var_ht(char_u *name, char_u **varname)
return &curtab->tp_vars->dv_hashtab;
if (*name == 'v') // v: variable
return &vimvarht;
if (*name == 'a') // a: function argument
return get_funccal_args_ht();
if (*name == 'l') // l: local function variable
return get_funccal_local_ht();
if (*name == 's' // script variable
&& current_sctx.sc_sid > 0
&& current_sctx.sc_sid <= script_items.ga_len)
return &SCRIPT_VARS(current_sctx.sc_sid);
if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
{
if (*name == 'a') // a: function argument
return get_funccal_args_ht();
if (*name == 'l') // l: local function variable
return get_funccal_local_ht();
}
if (*name == 's') // script variable
{
ht = get_script_local_ht();
if (ht != NULL)
return ht;
}
return NULL;
}
@@ -2617,7 +2734,7 @@ set_var(
typval_T *tv,
int copy) // make copy of value in "tv"
{
set_var_const(name, tv, copy, FALSE);
set_var_const(name, NULL, tv, copy, 0);
}
/*
@@ -2628,13 +2745,15 @@ set_var(
void
set_var_const(
char_u *name,
type_T *type,
typval_T *tv,
int copy, // make copy of value in "tv"
int is_const) // disallow to modify existing variable
int flags) // LET_IS_CONST and/or LET_NO_COMMAND
{
dictitem_T *v;
dictitem_T *di;
char_u *varname;
hashtab_T *ht;
int is_script_local;
ht = find_var_ht(name, &varname);
if (ht == NULL || *varname == NUL)
@@ -2642,75 +2761,92 @@ set_var_const(
semsg(_(e_illvar), name);
return;
}
v = find_var_in_ht(ht, 0, varname, TRUE);
is_script_local = ht == get_script_local_ht();
di = find_var_in_ht(ht, 0, varname, TRUE);
// Search in parent scope which is possible to reference from lambda
if (v == NULL)
v = find_var_in_scoped_ht(name, TRUE);
if (di == NULL)
di = find_var_in_scoped_ht(name, TRUE);
if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
&& var_check_func_name(name, v == NULL))
&& var_check_func_name(name, di == NULL))
return;
if (v != NULL)
if (di != NULL)
{
if (is_const)
if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
{
emsg(_(e_cannot_mod));
return;
if (flags & LET_IS_CONST)
{
emsg(_(e_cannot_mod));
return;
}
if (var_check_ro(di->di_flags, name, FALSE)
|| var_check_lock(di->di_tv.v_lock, name, FALSE))
return;
if ((flags & LET_NO_COMMAND) == 0
&& is_script_local
&& current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
semsg(_("E1041: Redefining script item %s"), name);
return;
}
}
else
// can only redefine once
di->di_flags &= ~DI_FLAGS_RELOAD;
// 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))
return;
// Handle setting internal v: variables separately where needed to
// Handle setting internal di: variables separately where needed to
// prevent changing the type.
if (ht == &vimvarht)
{
if (v->di_tv.v_type == VAR_STRING)
if (di->di_tv.v_type == VAR_STRING)
{
VIM_CLEAR(v->di_tv.vval.v_string);
VIM_CLEAR(di->di_tv.vval.v_string);
if (copy || tv->v_type != VAR_STRING)
{
char_u *val = tv_get_string(tv);
// Careful: when assigning to v:errmsg and tv_get_string()
// causes an error message the variable will alrady be set.
if (v->di_tv.vval.v_string == NULL)
v->di_tv.vval.v_string = vim_strsave(val);
if (di->di_tv.vval.v_string == NULL)
di->di_tv.vval.v_string = vim_strsave(val);
}
else
{
// Take over the string to avoid an extra alloc/free.
v->di_tv.vval.v_string = tv->vval.v_string;
di->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
return;
}
else if (v->di_tv.v_type == VAR_NUMBER)
else if (di->di_tv.v_type == VAR_NUMBER)
{
v->di_tv.vval.v_number = tv_get_number(tv);
di->di_tv.vval.v_number = tv_get_number(tv);
if (STRCMP(varname, "searchforward") == 0)
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
#ifdef FEAT_SEARCH_EXTRA
else if (STRCMP(varname, "hlsearch") == 0)
{
no_hlsearch = !v->di_tv.vval.v_number;
no_hlsearch = !di->di_tv.vval.v_number;
redraw_all_later(SOME_VALID);
}
#endif
return;
}
else if (v->di_tv.v_type != tv->v_type)
else if (di->di_tv.v_type != tv->v_type)
{
semsg(_("E963: setting %s to value with wrong type"), name);
return;
}
}
clear_tv(&v->di_tv);
clear_tv(&di->di_tv);
}
else // add a new variable
{
@@ -2725,31 +2861,53 @@ set_var_const(
if (!valid_varname(varname))
return;
v = alloc(sizeof(dictitem_T) + STRLEN(varname));
if (v == NULL)
di = alloc(sizeof(dictitem_T) + STRLEN(varname));
if (di == NULL)
return;
STRCPY(v->di_key, varname);
if (hash_add(ht, DI2HIKEY(v)) == FAIL)
STRCPY(di->di_key, varname);
if (hash_add(ht, DI2HIKEY(di)) == FAIL)
{
vim_free(v);
vim_free(di);
return;
}
v->di_flags = DI_FLAGS_ALLOC;
if (is_const)
v->di_flags |= DI_FLAGS_LOCK;
di->di_flags = DI_FLAGS_ALLOC;
if (flags & LET_IS_CONST)
di->di_flags |= DI_FLAGS_LOCK;
if (is_script_local && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid);
// Store a pointer to the typval_T, so that it can be found by
// index instead of using a hastab lookup.
if (ga_grow(&si->sn_var_vals, 1) == OK)
{
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ si->sn_var_vals.ga_len;
sv->sv_name = di->di_key;
sv->sv_tv = &di->di_tv;
sv->sv_type = type == NULL ? &t_any : type;
sv->sv_const = (flags & LET_IS_CONST);
sv->sv_export = is_export;
++si->sn_var_vals.ga_len;
// let ex_export() know the export worked.
is_export = FALSE;
}
}
}
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
copy_tv(tv, &v->di_tv);
copy_tv(tv, &di->di_tv);
else
{
v->di_tv = *tv;
v->di_tv.v_lock = 0;
di->di_tv = *tv;
di->di_tv.v_lock = 0;
init_tv(tv);
}
if (is_const)
v->di_tv.v_lock |= VAR_LOCKED;
if (flags & LET_IS_CONST)
di->di_tv.v_lock |= VAR_LOCKED;
}
/*
@@ -3130,9 +3288,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, FALSE, (char_u *)".");
set_var_lval(redir_lval, redir_endp, &tv, TRUE, 0, (char_u *)".");
else
set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
set_var_lval(redir_lval, redir_endp, &tv, TRUE, 0, (char_u *)"=");
clear_lval(redir_lval);
err = did_emsg;
did_emsg |= save_emsg;
@@ -3205,7 +3363,7 @@ 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, FALSE,
set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
(char_u *)".");
clear_lval(redir_lval);
}