From 96e9041a7886ca56bc0e59d1d76acf6110aa7e6e Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 4 Oct 2025 00:28:30 -0400 Subject: [PATCH] vim-patch:partial:8.1.1939: code for handling v: variables in generic eval file (#35968) Problem: Code for handling v: variables in generic eval file. Solution: Move v: variables to evalvars.c. (Yegappan Lakshmanan, closes vim/vim#4872) https://github.com/vim/vim/commit/e5cdf153bcb348c68011b308c8988cea42d6ddeb Remove direct reference to "vimvars" for following functions: - assert_error() - get_vim_var_nr() - get_vim_var_list() - get_vim_var_dict() - get_vim_var_str() - set_cmdarg() - set_reg_var() - set_vcount() - set_vexception() - set_vthrowpoint() - set_vim_var_bool() - set_vim_var_dict() - set_vim_var_list() - set_vim_var_nr() - set_vim_var_special() - set_vim_var_string() - set_vim_var_type() Reorder functions based on v8.2.4930 for eval_one_expr_in_str() and eval_all_expr_in_str(). Co-authored-by: Bram Moolenaar --- src/nvim/api/events.c | 2 +- src/nvim/api/ui.c | 2 +- src/nvim/api/vim.c | 2 +- src/nvim/buffer.c | 1 - src/nvim/change.c | 2 +- src/nvim/drawline.c | 2 +- src/nvim/drawscreen.c | 2 +- src/nvim/edit.c | 1 + src/nvim/eval.c | 488 +--------------------------------- src/nvim/eval.h | 107 -------- src/nvim/eval/fs.c | 1 + src/nvim/eval/funcs.c | 1 - src/nvim/eval/vars.c | 488 +++++++++++++++++++++++++++++++++- src/nvim/eval/vars.h | 7 + src/nvim/eval_defs.h | 107 ++++++++ src/nvim/ex_cmds.c | 2 +- src/nvim/ex_docmd.c | 2 +- src/nvim/ex_eval.c | 1 + src/nvim/ex_session.c | 1 + src/nvim/file_search.c | 1 + src/nvim/fileio.c | 1 + src/nvim/fold.c | 1 + src/nvim/getchar.c | 1 + src/nvim/indent.c | 1 + src/nvim/insexpand.c | 1 + src/nvim/log.c | 2 +- src/nvim/main.c | 1 + src/nvim/mapping.c | 1 + src/nvim/memline.c | 2 +- src/nvim/message.c | 1 + src/nvim/msgpack_rpc/server.c | 2 +- src/nvim/normal.c | 1 + src/nvim/os/env.c | 1 + src/nvim/os/lang.c | 2 +- src/nvim/os/shell.c | 2 +- src/nvim/os/signal.c | 2 +- src/nvim/profile.c | 2 +- src/nvim/quickfix.c | 1 + src/nvim/runtime.c | 1 + src/nvim/search.c | 2 +- src/nvim/shada.c | 1 + src/nvim/syntax.c | 1 - src/nvim/tag.c | 1 + src/nvim/terminal.c | 1 + src/nvim/testing.c | 1 + src/nvim/textformat.c | 1 + 46 files changed, 647 insertions(+), 607 deletions(-) diff --git a/src/nvim/api/events.c b/src/nvim/api/events.c index 077f04bda3..6290e52ffa 100644 --- a/src/nvim/api/events.c +++ b/src/nvim/api/events.c @@ -18,7 +18,7 @@ #include "nvim/autocmd_defs.h" #include "nvim/channel.h" #include "nvim/channel_defs.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/globals.h" #include "nvim/main.h" #include "nvim/map_defs.h" diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index b56e329847..fe02809f82 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -17,8 +17,8 @@ #include "nvim/autocmd_defs.h" #include "nvim/channel.h" #include "nvim/channel_defs.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 260886dc69..5b7f5420bf 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -31,9 +31,9 @@ #include "nvim/drawline.h" #include "nvim/drawscreen.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fold.h" diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e6288b4dca..74502ae6d3 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -44,7 +44,6 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/change.c b/src/nvim/change.c index bbd6b62e0b..ed0834422e 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -18,7 +18,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/extmark.h" #include "nvim/extmark_defs.h" diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index e345bf11aa..838f603060 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -21,7 +21,7 @@ #include "nvim/diff.h" #include "nvim/drawline.h" #include "nvim/drawscreen.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/fold.h" #include "nvim/fold_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 7ea3f6bbd5..fedd1c1331 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -75,7 +75,7 @@ #include "nvim/digraph.h" #include "nvim/drawline.h" #include "nvim/drawscreen.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_getln.h" #include "nvim/fold.h" #include "nvim/fold_defs.h" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 4f2ff39c6f..12857ad7e6 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -25,6 +25,7 @@ #include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/extmark.h" diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1ba15bff1e..5f14be6f96 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -125,9 +125,6 @@ static hashtab_T compat_hashtab; /// Used for checking if local variables or arguments used in a lambda. bool *eval_lavars_used = NULL; -#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars) -#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) - static int echo_hl_id = 0; // highlight id used for ":echo" /// Info used by a ":for" loop. @@ -290,13 +287,8 @@ static struct vimvar { // shorthand #define vv_type vv_di.di_tv.v_type #define vv_nr vv_di.di_tv.vval.v_number -#define vv_bool vv_di.di_tv.vval.v_bool -#define vv_special vv_di.di_tv.vval.v_special -#define vv_float vv_di.di_tv.vval.v_float #define vv_str vv_di.di_tv.vval.v_string #define vv_list vv_di.di_tv.vval.v_list -#define vv_dict vv_di.di_tv.vval.v_dict -#define vv_blob vv_di.di_tv.vval.v_blob #define vv_partial vv_di.di_tv.vval.v_partial #define vv_tv vv_di.di_tv @@ -305,9 +297,6 @@ static ScopeDictDictItem vimvars_var; static partial_T *vvlua_partial; -/// v: hashtab -#define vimvarht vimvardict.dv_hashtab - /// Enum used by filter(), map(), mapnew() and foreach() typedef enum { FILTERMAP_FILTER, @@ -546,19 +535,6 @@ void eval_clear(void) #endif -/// Set an internal variable to a string value. Creates the variable if it does -/// not already exist. -void set_internal_string_var(const char *name, char *value) // NOLINT(readability-non-const-parameter) - FUNC_ATTR_NONNULL_ARG(1) -{ - typval_T tv = { - .v_type = VAR_STRING, - .vval.v_string = value, - }; - - set_var(name, strlen(name), &tv, true); -} - static lval_T *redir_lval = NULL; static garray_T redir_ga; // Only valid when redir_lval is not NULL. static char *redir_endp = NULL; @@ -1146,25 +1122,6 @@ static typval_T *eval_expr_ext(char *arg, exarg_T *eap, const bool use_simple_fu return tv; } -/// List Vim variables. -void list_vim_vars(int *first) -{ - list_hashtable_vars(&vimvarht, "v:", false, first); -} - -/// List script-local variables, if there is a script. -void list_script_vars(int *first) -{ - if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { - list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first); - } -} - -bool is_vimvarht(const hashtab_T *ht) -{ - return ht == &vimvarht; -} - bool is_compatht(const hashtab_T *ht) { return ht == &compat_hashtab; @@ -1214,8 +1171,7 @@ list_T *eval_spell_expr(char *badword, char *expr) // Set "v:val" to the bad word. prepare_vimvar(VV_VAL, &save_val); - vimvars[VV_VAL].vv_type = VAR_STRING; - vimvars[VV_VAL].vv_str = badword; + set_vim_var_string(VV_VAL, badword, -1); if (p_verbose == 0) { emsg_off++; } @@ -1239,6 +1195,7 @@ list_T *eval_spell_expr(char *badword, char *expr) if (p_verbose == 0) { emsg_off--; } + tv_clear(get_vim_var_tv(VV_VAL)); restore_vimvar(VV_VAL, &save_val); current_sctx = saved_sctx; @@ -4777,9 +4734,7 @@ bool garbage_collect(bool testing) ABORTING(set_ref_in_previous_funccal)(copyID); // script-local variables - for (int i = 1; i <= script_items.ga_len; i++) { - ABORTING(set_ref_in_ht)(&SCRIPT_VARS(i), copyID, NULL); - } + ABORTING(garbage_collect_scriptvars)(copyID); FOR_ALL_BUFFERS(buf) { // buffer-local variables @@ -4878,7 +4833,7 @@ bool garbage_collect(bool testing) ABORTING(set_ref_in_func_args)(copyID); // v: vars - ABORTING(set_ref_in_ht)(&vimvarht, copyID, NULL); + ABORTING(garbage_collect_vimvars)(copyID); ABORTING(set_ref_in_quickfix)(copyID); @@ -5379,18 +5334,6 @@ static int eval_env_var(char **arg, typval_T *rettv, int evaluate) return OK; } -/// Add an assert error to v:errors. -void assert_error(garray_T *gap) -{ - struct vimvar *vp = &vimvars[VV_ERRORS]; - - if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) { - // Make sure v:errors is a list. - set_vim_var_list(VV_ERRORS, tv_list_alloc(1)); - } - tv_list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, (ptrdiff_t)gap->ga_len); -} - /// Implementation of map(), filter(), foreach() for a Dict. Apply "expr" to /// every item in Dict "d" and return the result in "rettv". static void filter_map_dict(dict_T *d, filtermap_T filtermap, const char *func_name, @@ -5726,7 +5669,7 @@ static int filter_map_one(typval_T *tv, typval_T *expr, const filtermap_T filter typval_T argv[3]; int retval = FAIL; - tv_copy(tv, &vimvars[VV_VAL].vv_tv); + tv_copy(tv, get_vim_var_tv(VV_VAL)); newtv->v_type = VAR_UNKNOWN; if (filtermap == FILTERMAP_FOREACH && expr->v_type == VAR_STRING) { @@ -5738,8 +5681,8 @@ static int filter_map_one(typval_T *tv, typval_T *expr, const filtermap_T filter goto theend; } - argv[0] = vimvars[VV_KEY].vv_tv; - argv[1] = vimvars[VV_VAL].vv_tv; + argv[0] = *get_vim_var_tv(VV_KEY); + argv[1] = *get_vim_var_tv(VV_VAL); if (eval_expr_typval(expr, false, argv, 2, newtv) == FAIL) { goto theend; } @@ -5759,7 +5702,7 @@ static int filter_map_one(typval_T *tv, typval_T *expr, const filtermap_T filter } retval = OK; theend: - tv_clear(&vimvars[VV_VAL].vv_tv); + tv_clear(get_vim_var_tv(VV_VAL)); return retval; } @@ -6923,155 +6866,11 @@ bool eval_isdictc(int c) } /// Get typval_T v: variable value. -typval_T *get_vim_var_tv(int idx) +typval_T *get_vim_var_tv(const VimVarIndex idx) { return &vimvars[idx].vv_tv; } -/// Get number v: variable value. -varnumber_T get_vim_var_nr(int idx) FUNC_ATTR_PURE -{ - return vimvars[idx].vv_nr; -} - -/// Get string v: variable value. Uses a static buffer, can only be used once. -/// If the String variable has never been set, return an empty string. -/// Never returns NULL. -char *get_vim_var_str(int idx) - FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET -{ - return (char *)tv_get_string(&vimvars[idx].vv_tv); -} - -/// Get List v: variable value. Caller must take care of reference count when -/// needed. -list_T *get_vim_var_list(int idx) FUNC_ATTR_PURE -{ - return vimvars[idx].vv_list; -} - -/// Get Dictionary v: variable value. Caller must take care of reference count -/// when needed. -dict_T *get_vim_var_dict(int idx) FUNC_ATTR_PURE -{ - return vimvars[idx].vv_dict; -} - -/// Set v:char to character "c". -void set_vim_var_char(int c) -{ - char buf[MB_MAXCHAR + 1]; - - buf[utf_char2bytes(c, buf)] = NUL; - set_vim_var_string(VV_CHAR, buf, -1); -} - -/// Set v:count to "count" and v:count1 to "count1". -/// -/// @param set_prevcount if true, first set v:prevcount from v:count. -void set_vcount(int64_t count, int64_t count1, bool set_prevcount) -{ - if (set_prevcount) { - vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr; - } - vimvars[VV_COUNT].vv_nr = count; - vimvars[VV_COUNT1].vv_nr = count1; -} - -/// Set type of v: variable to the given type. -/// -/// @param[in] idx Index of variable to set. -/// @param[in] type Type to set to. -void set_vim_var_type(const VimVarIndex idx, const VarType type) -{ - vimvars[idx].vv_type = type; -} - -/// Set number v: variable to the given value -/// Note that this does not set the type, use set_vim_var_type() for that. -/// -/// @param[in] idx Index of variable to set. -/// @param[in] val Value to set to. -void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val) -{ - tv_clear(&vimvars[idx].vv_tv); - vimvars[idx].vv_nr = val; -} - -/// Set boolean v: {true, false} to the given value -/// -/// @param[in] idx Index of variable to set. -/// @param[in] val Value to set to. -void set_vim_var_bool(const VimVarIndex idx, const BoolVarValue val) -{ - tv_clear(&vimvars[idx].vv_tv); - vimvars[idx].vv_type = VAR_BOOL; - vimvars[idx].vv_bool = val; -} - -/// Set special v: variable to the given value -/// -/// @param[in] idx Index of variable to set. -/// @param[in] val Value to set to. -void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val) -{ - tv_clear(&vimvars[idx].vv_tv); - vimvars[idx].vv_type = VAR_SPECIAL; - vimvars[idx].vv_special = val; -} - -/// Set string v: variable to the given string -/// -/// @param[in] idx Index of variable to set. -/// @param[in] val Value to set to. Will be copied. -/// @param[in] len Length of that value or -1 in which case strlen() will be -/// used. -void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len) -{ - tv_clear(&vimvars[idx].vv_di.di_tv); - vimvars[idx].vv_type = VAR_STRING; - if (val == NULL) { - vimvars[idx].vv_str = NULL; - } else if (len == -1) { - vimvars[idx].vv_str = xstrdup(val); - } else { - vimvars[idx].vv_str = xstrndup(val, (size_t)len); - } -} - -/// Set list v: variable to the given list -/// -/// @param[in] idx Index of variable to set. -/// @param[in,out] val Value to set to. Reference count will be incremented. -void set_vim_var_list(const VimVarIndex idx, list_T *const val) -{ - tv_clear(&vimvars[idx].vv_di.di_tv); - vimvars[idx].vv_type = VAR_LIST; - vimvars[idx].vv_list = val; - if (val != NULL) { - tv_list_ref(val); - } -} - -/// Set Dictionary v: variable to the given dictionary -/// -/// @param[in] idx Index of variable to set. -/// @param[in,out] val Value to set to. Reference count will be incremented. -/// Also keys of the dictionary will be made read-only. -void set_vim_var_dict(const VimVarIndex idx, dict_T *const val) -{ - tv_clear(&vimvars[idx].vv_di.di_tv); - vimvars[idx].vv_type = VAR_DICT; - vimvars[idx].vv_dict = val; - if (val == NULL) { - return; - } - - val->dv_refcount++; - // Set readonly - tv_dict_set_keys_readonly(val); -} - /// Set v:variable to tv. /// /// @param[in] idx Index of variable to set. @@ -7095,185 +6894,6 @@ void set_argv_var(char **argv, int argc) set_vim_var_list(VV_ARGV, l); } -/// Set v:register if needed. -void set_reg_var(int c) -{ - char regname; - - if (c == 0 || c == ' ') { - regname = '"'; - } else { - regname = (char)c; - } - // Avoid free/alloc when the value is already right. - if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c) { - set_vim_var_string(VV_REG, ®name, 1); - } -} - -/// Get or set v:exception. If "oldval" == NULL, return the current value. -/// Otherwise, restore the value to "oldval" and return NULL. -/// Must always be called in pairs to save and restore v:exception! Does not -/// take care of memory allocations. -char *v_exception(char *oldval) -{ - if (oldval == NULL) { - return vimvars[VV_EXCEPTION].vv_str; - } - - vimvars[VV_EXCEPTION].vv_str = oldval; - return NULL; -} - -/// Get or set v:throwpoint. If "oldval" == NULL, return the current value. -/// Otherwise, restore the value to "oldval" and return NULL. -/// Must always be called in pairs to save and restore v:throwpoint! Does not -/// take care of memory allocations. -char *v_throwpoint(char *oldval) -{ - if (oldval == NULL) { - return vimvars[VV_THROWPOINT].vv_str; - } - - vimvars[VV_THROWPOINT].vv_str = oldval; - return NULL; -} - -/// Set v:cmdarg. -/// If "eap" != NULL, use "eap" to generate the value and return the old value. -/// If "oldarg" != NULL, restore the value to "oldarg" and return NULL. -/// Must always be called in pairs! -char *set_cmdarg(exarg_T *eap, char *oldarg) -{ - char *oldval = vimvars[VV_CMDARG].vv_str; - if (eap == NULL) { - goto error; - } - - size_t len = 0; - if (eap->force_bin == FORCE_BIN) { - len += 6; // " ++bin" - } else if (eap->force_bin == FORCE_NOBIN) { - len += 8; // " ++nobin" - } - - if (eap->read_edit) { - len += 7; // " ++edit" - } - - if (eap->force_ff != 0) { - len += 10; // " ++ff=unix" - } - if (eap->force_enc != 0) { - len += strlen(eap->cmd + eap->force_enc) + 7; - } - if (eap->bad_char != 0) { - len += 7 + 4; // " ++bad=" + "keep" or "drop" - } - if (eap->mkdir_p != 0) { - len += 4; // " ++p" - } - - const size_t newval_len = len + 1; - char *newval = xmalloc(newval_len); - size_t xlen = 0; - int rc = 0; - - if (eap->force_bin == FORCE_BIN) { - rc = snprintf(newval, newval_len, " ++bin"); - } else if (eap->force_bin == FORCE_NOBIN) { - rc = snprintf(newval, newval_len, " ++nobin"); - } else { - *newval = NUL; - } - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - - if (eap->read_edit) { - rc = snprintf(newval + xlen, newval_len - xlen, " ++edit"); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } - - if (eap->force_ff != 0) { - rc = snprintf(newval + xlen, - newval_len - xlen, - " ++ff=%s", - eap->force_ff == 'u' ? "unix" - : eap->force_ff == 'd' ? "dos" : "mac"); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } - if (eap->force_enc != 0) { - rc = snprintf(newval + (xlen), newval_len - xlen, " ++enc=%s", eap->cmd + eap->force_enc); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } - - if (eap->bad_char == BAD_KEEP) { - rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=keep"); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } else if (eap->bad_char == BAD_DROP) { - rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=drop"); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } else if (eap->bad_char != 0) { - rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=%c", eap->bad_char); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } - - if (eap->mkdir_p != 0) { - rc = snprintf(newval + xlen, newval_len - xlen, " ++p"); - if (rc < 0) { - goto error; - } - xlen += (size_t)rc; - } - assert(xlen <= newval_len); - - vimvars[VV_CMDARG].vv_str = newval; - return oldval; - -error: - xfree(oldval); - vimvars[VV_CMDARG].vv_str = oldarg; - return NULL; -} - -/// Check if variable "name[len]" is a local variable or an argument. -/// If so, "*eval_lavars_used" is set to true. -static void check_vars(const char *name, size_t len) -{ - if (eval_lavars_used == NULL) { - return; - } - - const char *varname; - hashtab_T *ht = find_var_ht(name, len, &varname); - - if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht()) { - if (find_var(name, len, NULL, true) != NULL) { - *eval_lavars_used = true; - } - } -} - /// check if special v:lua value for calling lua functions bool is_luafunc(partial_T *partial) FUNC_ATTR_PURE @@ -7513,35 +7133,6 @@ void set_selfdict(typval_T *const rettv, dict_T *const selfdict) make_partial(selfdict, rettv); } -/// Find variable "name" in the list of variables. -/// Careful: "a:0" variables don't have a name. -/// When "htp" is not NULL we are writing to the variable, set "htp" to the -/// hashtab_T used. -/// -/// @return a pointer to it if found, NULL if not found. -dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **htp, - int no_autoload) -{ - const char *varname; - hashtab_T *const ht = find_var_ht(name, name_len, &varname); - if (htp != NULL) { - *htp = ht; - } - if (ht == NULL) { - return NULL; - } - dictitem_T *const ret = find_var_in_ht(ht, *name, - varname, - name_len - (size_t)(varname - name), - no_autoload || htp != NULL); - if (ret != NULL) { - return ret; - } - - // Search in parent scope for lambda - return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL); -} - /// Find variable in hashtab. /// When "varname" is empty returns curwin/curtab/etc vars dictionary. /// @@ -7684,55 +7275,6 @@ end: return *d ? &(*d)->dv_hashtab : NULL; } -/// Find the hashtable used for a variable -/// -/// @param[in] name Variable name, possibly with scope prefix. -/// @param[in] name_len Variable name length. -/// @param[out] varname Will be set to the start of the name without scope -/// prefix. -/// -/// @return Scope hashtab, NULL if name is not valid. -hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **varname) -{ - dict_T *d; - return find_var_ht_dict(name, name_len, varname, &d); -} - -/// Allocate a new hashtab for a sourced script. It will be used while -/// sourcing this script and when executing functions defined in the script. -void new_script_vars(scid_T id) -{ - scriptvar_T *sv = xcalloc(1, sizeof(scriptvar_T)); - init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); - SCRIPT_ITEM(id)->sn_vars = sv; -} - -/// Initialize dictionary "dict" as a scope and set variable "dict_var" to -/// point to it. -void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, ScopeType scope) -{ - hash_init(&dict->dv_hashtab); - dict->dv_lock = VAR_UNLOCKED; - dict->dv_scope = scope; - dict->dv_refcount = DO_NOT_FREE_CNT; - dict->dv_copyID = 0; - dict_var->di_tv.vval.v_dict = dict; - dict_var->di_tv.v_type = VAR_DICT; - dict_var->di_tv.v_lock = VAR_FIXED; - dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; - dict_var->di_key[0] = NUL; - QUEUE_INIT(&dict->watchers); -} - -/// Unreference a dictionary initialized by init_var_dict(). -void unref_var_dict(dict_T *dict) -{ - // Now the dict needs to be freed if no one else is using it, go back to - // normal reference counting. - dict->dv_refcount -= DO_NOT_FREE_CNT - 1; - tv_dict_unref(dict); -} - /// Make a copy of an item /// /// Lists and Dictionaries are also copied. @@ -8071,18 +7613,6 @@ void last_set_msg(sctx_T script_ctx) verbose_leave(); } -// reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal, -// v:option_type, and v:option_command. -void reset_v_option_vars(void) -{ - set_vim_var_string(VV_OPTION_NEW, NULL, -1); - set_vim_var_string(VV_OPTION_OLD, NULL, -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1); - set_vim_var_string(VV_OPTION_COMMAND, NULL, -1); - set_vim_var_string(VV_OPTION_TYPE, NULL, -1); -} - /// Adjust a filename, according to a string of modifiers. /// *fnamep must be NUL terminated when called. When returning, the length is /// determined by *fnamelen. diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 3a91dd23e8..27069e757e 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -74,113 +74,6 @@ typedef enum { VAR_FLAVOUR_SHADA = 4, // all uppercase } var_flavour_T; -/// Defines for Vim variables -typedef enum { - VV_COUNT, - VV_COUNT1, - VV_PREVCOUNT, - VV_ERRMSG, - VV_WARNINGMSG, - VV_STATUSMSG, - VV_SHELL_ERROR, - VV_THIS_SESSION, - VV_VERSION, - VV_LNUM, - VV_TERMREQUEST, - VV_TERMRESPONSE, - VV_FNAME, - VV_LANG, - VV_LC_TIME, - VV_CTYPE, - VV_CC_FROM, - VV_CC_TO, - VV_FNAME_IN, - VV_FNAME_OUT, - VV_FNAME_NEW, - VV_FNAME_DIFF, - VV_CMDARG, - VV_FOLDSTART, - VV_FOLDEND, - VV_FOLDDASHES, - VV_FOLDLEVEL, - VV_PROGNAME, - VV_SEND_SERVER, - VV_DYING, - VV_EXCEPTION, - VV_THROWPOINT, - VV_REG, - VV_CMDBANG, - VV_INSERTMODE, - VV_VAL, - VV_KEY, - VV_PROFILING, - VV_FCS_REASON, - VV_FCS_CHOICE, - VV_BEVAL_BUFNR, - VV_BEVAL_WINNR, - VV_BEVAL_WINID, - VV_BEVAL_LNUM, - VV_BEVAL_COL, - VV_BEVAL_TEXT, - VV_SCROLLSTART, - VV_SWAPNAME, - VV_SWAPCHOICE, - VV_SWAPCOMMAND, - VV_CHAR, - VV_MOUSE_WIN, - VV_MOUSE_WINID, - VV_MOUSE_LNUM, - VV_MOUSE_COL, - VV_OP, - VV_SEARCHFORWARD, - VV_HLSEARCH, - VV_OLDFILES, - VV_WINDOWID, - VV_PROGPATH, - VV_COMPLETED_ITEM, - VV_OPTION_NEW, - VV_OPTION_OLD, - VV_OPTION_OLDLOCAL, - VV_OPTION_OLDGLOBAL, - VV_OPTION_COMMAND, - VV_OPTION_TYPE, - VV_ERRORS, - VV_FALSE, - VV_TRUE, - VV_NULL, - VV_NUMBERMAX, - VV_NUMBERMIN, - VV_NUMBERSIZE, - VV_VIM_DID_ENTER, - VV_TESTING, - VV_TYPE_NUMBER, - VV_TYPE_STRING, - VV_TYPE_FUNC, - VV_TYPE_LIST, - VV_TYPE_DICT, - VV_TYPE_FLOAT, - VV_TYPE_BOOL, - VV_TYPE_BLOB, - VV_EVENT, - VV_VERSIONLONG, - VV_ECHOSPACE, - VV_ARGV, - VV_COLLATE, - VV_EXITING, - VV_MAXCOL, - VV_STACKTRACE, - // Nvim - VV_STDERR, - VV_MSGPACK_TYPES, - VV__NULL_STRING, // String with NULL value. For test purposes only. - VV__NULL_LIST, // List with NULL value. For test purposes only. - VV__NULL_DICT, // Dict with NULL value. For test purposes only. - VV__NULL_BLOB, // Blob with NULL value. For test purposes only. - VV_LUA, - VV_RELNUM, - VV_VIRTNUM, -} VimVarIndex; - /// Array mapping values from MessagePackType to corresponding list pointers extern const list_T *eval_msgpack_type_lists[NUM_MSGPACK_TYPES]; diff --git a/src/nvim/eval/fs.c b/src/nvim/eval/fs.c index 1f51395339..799b84e375 100644 --- a/src/nvim/eval/fs.c +++ b/src/nvim/eval/fs.c @@ -20,6 +20,7 @@ #include "nvim/eval/fs.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/eval/window.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 51737bf383..c805a2ff9e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -36,7 +36,6 @@ #include "nvim/cursor.h" #include "nvim/edit.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/buffer.h" #include "nvim/eval/decode.h" #include "nvim/eval/encode.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 93c234c295..343e8ac6da 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -34,12 +34,14 @@ #include "nvim/globals.h" #include "nvim/hashtab.h" #include "nvim/macros_defs.h" +#include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option.h" #include "nvim/option_defs.h" #include "nvim/os/os.h" #include "nvim/register.h" +#include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/strings.h" #include "nvim/types_defs.h" @@ -63,6 +65,49 @@ static const char e_setting_v_str_to_value_with_wrong_type[] static const char e_missing_end_marker_str[] = N_("E990: Missing end marker '%s'"); static const char e_cannot_use_heredoc_here[] = N_("E991: Cannot use =<< here"); +bool garbage_collect_vimvars(int copyID) +{ + return set_ref_in_ht(&vimvarht, copyID, NULL); +} + +bool garbage_collect_scriptvars(int copyID) +{ + bool abort = false; + + for (int i = 1; i <= script_items.ga_len; i++) { + abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL); + } + + return abort; +} + +/// Set an internal variable to a string value. Creates the variable if it does +/// not already exist. +void set_internal_string_var(const char *name, char *value) // NOLINT(readability-non-const-parameter) + FUNC_ATTR_NONNULL_ARG(1) +{ + typval_T tv = { + .v_type = VAR_STRING, + .vval.v_string = value, + }; + + set_var(name, strlen(name), &tv, true); +} + +/// List Vim variables. +static void list_vim_vars(int *first) +{ + list_hashtable_vars(&vimvarht, "v:", false, first); +} + +/// List script-local variables, if there is a script. +static void list_script_vars(int *first) +{ + if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { + list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first); + } +} + /// Evaluate one Vim expression {expr} in string "p" and append the /// resulting string to "gap". "p" points to the opening "{". /// When "evaluate" is false only skip over the expression. @@ -1290,6 +1335,325 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap return ret; } +/// Get number v: variable value. +varnumber_T get_vim_var_nr(const VimVarIndex idx) FUNC_ATTR_PURE +{ + typval_T *tv = get_vim_var_tv(idx); + return tv->vval.v_number; +} + +/// Get List v: variable value. Caller must take care of reference count when +/// needed. +list_T *get_vim_var_list(const VimVarIndex idx) FUNC_ATTR_PURE +{ + typval_T *tv = get_vim_var_tv(idx); + return tv->vval.v_list; +} + +/// Get Dictionary v: variable value. Caller must take care of reference count +/// when needed. +dict_T *get_vim_var_dict(const VimVarIndex idx) FUNC_ATTR_PURE +{ + typval_T *tv = get_vim_var_tv(idx); + return tv->vval.v_dict; +} + +/// Get string v: variable value. Uses a static buffer, can only be used once. +/// If the String variable has never been set, return an empty string. +/// Never returns NULL. +char *get_vim_var_str(const VimVarIndex idx) + FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET +{ + return (char *)tv_get_string(get_vim_var_tv(idx)); +} + +/// Set type of v: variable to the given type. +/// +/// @param[in] idx Index of variable to set. +/// @param[in] type Type to set to. +void set_vim_var_type(const VimVarIndex idx, const VarType type) +{ + typval_T *tv = get_vim_var_tv(idx); + tv->v_type = type; +} + +/// Set number v: variable to the given value +/// Note that this does not set the type, use set_vim_var_type() for that. +/// +/// @param[in] idx Index of variable to set. +/// @param[in] val Value to set to. +void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->vval.v_number = val; +} + +/// Set boolean v: {true, false} to the given value +/// +/// @param[in] idx Index of variable to set. +/// @param[in] val Value to set to. +void set_vim_var_bool(const VimVarIndex idx, const BoolVarValue val) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->v_type = VAR_BOOL; + tv->vval.v_bool = val; +} + +/// Set special v: variable to the given value +/// +/// @param[in] idx Index of variable to set. +/// @param[in] val Value to set to. +void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->v_type = VAR_SPECIAL; + tv->vval.v_special = val; +} + +/// Set v:char to character "c". +void set_vim_var_char(int c) +{ + char buf[MB_MAXCHAR + 1]; + + buf[utf_char2bytes(c, buf)] = NUL; + set_vim_var_string(VV_CHAR, buf, -1); +} + +/// Set string v: variable to the given string +/// +/// @param[in] idx Index of variable to set. +/// @param[in] val Value to set to. Will be copied. +/// @param[in] len Length of that value or -1 in which case strlen() will be +/// used. +void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->v_type = VAR_STRING; + if (val == NULL) { + tv->vval.v_string = NULL; + } else if (len == -1) { + tv->vval.v_string = xstrdup(val); + } else { + tv->vval.v_string = xstrndup(val, (size_t)len); + } +} + +/// Set list v: variable to the given list +/// +/// @param[in] idx Index of variable to set. +/// @param[in,out] val Value to set to. Reference count will be incremented. +void set_vim_var_list(const VimVarIndex idx, list_T *const val) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->v_type = VAR_LIST; + tv->vval.v_list = val; + if (val != NULL) { + tv_list_ref(val); + } +} + +/// Set Dictionary v: variable to the given dictionary +/// +/// @param[in] idx Index of variable to set. +/// @param[in,out] val Value to set to. Reference count will be incremented. +/// Also keys of the dictionary will be made read-only. +void set_vim_var_dict(const VimVarIndex idx, dict_T *const val) +{ + typval_T *tv = get_vim_var_tv(idx); + tv_clear(tv); + tv->v_type = VAR_DICT; + tv->vval.v_dict = val; + if (val == NULL) { + return; + } + + val->dv_refcount++; + // Set readonly + tv_dict_set_keys_readonly(val); +} + +/// Set v:register if needed. +void set_reg_var(int c) +{ + char regname; + + if (c == 0 || c == ' ') { + regname = '"'; + } else { + regname = (char)c; + } + // Avoid free/alloc when the value is already right. + typval_T *tv = get_vim_var_tv(VV_REG); + if (tv->vval.v_string == NULL || tv->vval.v_string[0] != c) { + set_vim_var_string(VV_REG, ®name, 1); + } +} + +/// Get or set v:exception. If "oldval" == NULL, return the current value. +/// Otherwise, restore the value to "oldval" and return NULL. +/// Must always be called in pairs to save and restore v:exception! Does not +/// take care of memory allocations. +char *v_exception(char *oldval) +{ + typval_T *tv = get_vim_var_tv(VV_EXCEPTION); + if (oldval == NULL) { + return tv->vval.v_string; + } + + tv->vval.v_string = oldval; + return NULL; +} + +/// Set v:cmdarg. +/// If "eap" != NULL, use "eap" to generate the value and return the old value. +/// If "oldarg" != NULL, restore the value to "oldarg" and return NULL. +/// Must always be called in pairs! +char *set_cmdarg(exarg_T *eap, char *oldarg) +{ + typval_T *tv = get_vim_var_tv(VV_CMDARG); + char *oldval = tv->vval.v_string; + if (eap == NULL) { + goto error; + } + + size_t len = 0; + if (eap->force_bin == FORCE_BIN) { + len += 6; // " ++bin" + } else if (eap->force_bin == FORCE_NOBIN) { + len += 8; // " ++nobin" + } + + if (eap->read_edit) { + len += 7; // " ++edit" + } + + if (eap->force_ff != 0) { + len += 10; // " ++ff=unix" + } + if (eap->force_enc != 0) { + len += strlen(eap->cmd + eap->force_enc) + 7; + } + if (eap->bad_char != 0) { + len += 7 + 4; // " ++bad=" + "keep" or "drop" + } + if (eap->mkdir_p != 0) { + len += 4; // " ++p" + } + + const size_t newval_len = len + 1; + char *newval = xmalloc(newval_len); + size_t xlen = 0; + int rc = 0; + + if (eap->force_bin == FORCE_BIN) { + rc = snprintf(newval, newval_len, " ++bin"); + } else if (eap->force_bin == FORCE_NOBIN) { + rc = snprintf(newval, newval_len, " ++nobin"); + } else { + *newval = NUL; + } + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + + if (eap->read_edit) { + rc = snprintf(newval + xlen, newval_len - xlen, " ++edit"); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } + + if (eap->force_ff != 0) { + rc = snprintf(newval + xlen, + newval_len - xlen, + " ++ff=%s", + eap->force_ff == 'u' ? "unix" + : eap->force_ff == 'd' ? "dos" : "mac"); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } + if (eap->force_enc != 0) { + rc = snprintf(newval + (xlen), newval_len - xlen, " ++enc=%s", eap->cmd + eap->force_enc); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } + + if (eap->bad_char == BAD_KEEP) { + rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=keep"); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } else if (eap->bad_char == BAD_DROP) { + rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=drop"); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } else if (eap->bad_char != 0) { + rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=%c", eap->bad_char); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } + + if (eap->mkdir_p != 0) { + rc = snprintf(newval + xlen, newval_len - xlen, " ++p"); + if (rc < 0) { + goto error; + } + xlen += (size_t)rc; + } + assert(xlen <= newval_len); + + tv->vval.v_string = newval; + return oldval; + +error: + xfree(oldval); + tv->vval.v_string = oldarg; + return NULL; +} + +/// Get or set v:throwpoint. If "oldval" == NULL, return the current value. +/// Otherwise, restore the value to "oldval" and return NULL. +/// Must always be called in pairs to save and restore v:throwpoint! Does not +/// take care of memory allocations. +char *v_throwpoint(char *oldval) +{ + typval_T *tv = get_vim_var_tv(VV_THROWPOINT); + if (oldval == NULL) { + return tv->vval.v_string; + } + + tv->vval.v_string = oldval; + return NULL; +} + +/// Set v:count to "count" and v:count1 to "count1". +/// +/// @param set_prevcount if true, first set v:prevcount from v:count. +void set_vcount(int64_t count, int64_t count1, bool set_prevcount) +{ + if (set_prevcount) { + get_vim_var_tv(VV_PREVCOUNT)->vval.v_number = get_vim_var_nr(VV_COUNT); + } + get_vim_var_tv(VV_COUNT)->vval.v_number = count; + get_vim_var_tv(VV_COUNT1)->vval.v_number = count1; +} + /// Get the value of internal variable "name". /// Return OK or FAIL. If OK is returned "rettv" must be cleared. /// @@ -1325,6 +1689,67 @@ int eval_variable(const char *name, int len, typval_T *rettv, dictitem_T **dip, return ret; } +/// Check if variable "name[len]" is a local variable or an argument. +/// If so, "*eval_lavars_used" is set to true. +void check_vars(const char *name, size_t len) +{ + if (eval_lavars_used == NULL) { + return; + } + + const char *varname; + hashtab_T *ht = find_var_ht(name, len, &varname); + + if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht()) { + if (find_var(name, len, NULL, true) != NULL) { + *eval_lavars_used = true; + } + } +} + +/// Find variable "name" in the list of variables. +/// Careful: "a:0" variables don't have a name. +/// When "htp" is not NULL we are writing to the variable, set "htp" to the +/// hashtab_T used. +/// +/// @return a pointer to it if found, NULL if not found. +dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **htp, + int no_autoload) +{ + const char *varname; + hashtab_T *const ht = find_var_ht(name, name_len, &varname); + if (htp != NULL) { + *htp = ht; + } + if (ht == NULL) { + return NULL; + } + dictitem_T *const ret = find_var_in_ht(ht, *name, + varname, + name_len - (size_t)(varname - name), + no_autoload || htp != NULL); + if (ret != NULL) { + return ret; + } + + // Search in parent scope for lambda + return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL); +} + +/// Find the hashtable used for a variable +/// +/// @param[in] name Variable name, possibly with scope prefix. +/// @param[in] name_len Variable name length. +/// @param[out] varname Will be set to the start of the name without scope +/// prefix. +/// +/// @return Scope hashtab, NULL if name is not valid. +hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **varname) +{ + dict_T *d; + return find_var_ht_dict(name, name_len, varname, &d); +} + /// @return the string value of a (global/local) variable or /// NULL when it doesn't exist. /// @@ -1340,6 +1765,41 @@ char *get_var_value(const char *const name) return (char *)tv_get_string(&v->di_tv); } +/// Allocate a new hashtab for a sourced script. It will be used while +/// sourcing this script and when executing functions defined in the script. +void new_script_vars(scid_T id) +{ + scriptvar_T *sv = xcalloc(1, sizeof(scriptvar_T)); + init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); + SCRIPT_ITEM(id)->sn_vars = sv; +} + +/// Initialize dictionary "dict" as a scope and set variable "dict_var" to +/// point to it. +void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, ScopeType scope) +{ + hash_init(&dict->dv_hashtab); + dict->dv_lock = VAR_UNLOCKED; + dict->dv_scope = scope; + dict->dv_refcount = DO_NOT_FREE_CNT; + dict->dv_copyID = 0; + dict_var->di_tv.vval.v_dict = dict; + dict_var->di_tv.v_type = VAR_DICT; + dict_var->di_tv.v_lock = VAR_FIXED; + dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; + dict_var->di_key[0] = NUL; + QUEUE_INIT(&dict->watchers); +} + +/// Unreference a dictionary initialized by init_var_dict(). +void unref_var_dict(dict_T *dict) +{ + // Now the dict needs to be freed if no one else is using it, go back to + // normal reference counting. + dict->dv_refcount -= DO_NOT_FREE_CNT - 1; + tv_dict_unref(dict); +} + /// Clean up a list of internal variables. /// Frees all allocated variables and the value they contain. /// Clears hashtab "ht", does not free it. @@ -1575,7 +2035,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, // Handle setting internal v: variables separately where needed to // prevent changing the type. bool type_error = false; - if (is_vimvarht(ht) + if (ht == &vimvarht && !before_set_vvar(varname, di, tv, copy, watched, &type_error)) { if (type_error) { semsg(_(e_setting_v_str_to_value_with_wrong_type), varname); @@ -1589,7 +2049,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, tv_clear(&di->di_tv); } else { // Add a new variable. // Can't add "v:" or "a:" variable. - if (is_vimvarht(ht) || ht == get_funccal_args_ht()) { + if (ht == &vimvarht || ht == get_funccal_args_ht()) { semsg(_(e_illvar), name); return; } @@ -2053,6 +2513,30 @@ static void setwinvar(typval_T *argvars, int off) } } +// reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal, +// v:option_type, and v:option_command. +void reset_v_option_vars(void) +{ + set_vim_var_string(VV_OPTION_NEW, NULL, -1); + set_vim_var_string(VV_OPTION_OLD, NULL, -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1); + set_vim_var_string(VV_OPTION_COMMAND, NULL, -1); + set_vim_var_string(VV_OPTION_TYPE, NULL, -1); +} + +/// Add an assert error to v:errors. +void assert_error(garray_T *gap) +{ + typval_T *tv = get_vim_var_tv(VV_ERRORS); + + if (tv->v_type != VAR_LIST || tv->vval.v_list == NULL) { + // Make sure v:errors is a list. + set_vim_var_list(VV_ERRORS, tv_list_alloc(1)); + } + tv_list_append_string(get_vim_var_list(VV_ERRORS), gap->ga_data, (ptrdiff_t)gap->ga_len); +} + bool var_exists(const char *var) FUNC_ATTR_NONNULL_ALL { diff --git a/src/nvim/eval/vars.h b/src/nvim/eval/vars.h index a14e4f0f4c..b6959434f6 100644 --- a/src/nvim/eval/vars.h +++ b/src/nvim/eval/vars.h @@ -2,6 +2,7 @@ #include // IWYU pragma: keep +#include "nvim/eval_defs.h" #include "nvim/ex_cmds_defs.h" // IWYU pragma: keep #include "nvim/garray_defs.h" // IWYU pragma: keep #include "nvim/hashtab_defs.h" // IWYU pragma: keep @@ -9,3 +10,9 @@ #include "nvim/types_defs.h" // IWYU pragma: keep #include "eval/vars.h.generated.h" + +#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars) +#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) + +/// v: hashtab +#define vimvarht vimvardict.dv_hashtab diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index 7adea6dfa9..07b01f0c93 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -27,3 +27,110 @@ typedef struct { /// pointer to the last line obtained with getsourceline() char *eval_tofree; } evalarg_T; + +/// Defines for Vim variables +typedef enum { + VV_COUNT, + VV_COUNT1, + VV_PREVCOUNT, + VV_ERRMSG, + VV_WARNINGMSG, + VV_STATUSMSG, + VV_SHELL_ERROR, + VV_THIS_SESSION, + VV_VERSION, + VV_LNUM, + VV_TERMREQUEST, + VV_TERMRESPONSE, + VV_FNAME, + VV_LANG, + VV_LC_TIME, + VV_CTYPE, + VV_CC_FROM, + VV_CC_TO, + VV_FNAME_IN, + VV_FNAME_OUT, + VV_FNAME_NEW, + VV_FNAME_DIFF, + VV_CMDARG, + VV_FOLDSTART, + VV_FOLDEND, + VV_FOLDDASHES, + VV_FOLDLEVEL, + VV_PROGNAME, + VV_SEND_SERVER, + VV_DYING, + VV_EXCEPTION, + VV_THROWPOINT, + VV_REG, + VV_CMDBANG, + VV_INSERTMODE, + VV_VAL, + VV_KEY, + VV_PROFILING, + VV_FCS_REASON, + VV_FCS_CHOICE, + VV_BEVAL_BUFNR, + VV_BEVAL_WINNR, + VV_BEVAL_WINID, + VV_BEVAL_LNUM, + VV_BEVAL_COL, + VV_BEVAL_TEXT, + VV_SCROLLSTART, + VV_SWAPNAME, + VV_SWAPCHOICE, + VV_SWAPCOMMAND, + VV_CHAR, + VV_MOUSE_WIN, + VV_MOUSE_WINID, + VV_MOUSE_LNUM, + VV_MOUSE_COL, + VV_OP, + VV_SEARCHFORWARD, + VV_HLSEARCH, + VV_OLDFILES, + VV_WINDOWID, + VV_PROGPATH, + VV_COMPLETED_ITEM, + VV_OPTION_NEW, + VV_OPTION_OLD, + VV_OPTION_OLDLOCAL, + VV_OPTION_OLDGLOBAL, + VV_OPTION_COMMAND, + VV_OPTION_TYPE, + VV_ERRORS, + VV_FALSE, + VV_TRUE, + VV_NULL, + VV_NUMBERMAX, + VV_NUMBERMIN, + VV_NUMBERSIZE, + VV_VIM_DID_ENTER, + VV_TESTING, + VV_TYPE_NUMBER, + VV_TYPE_STRING, + VV_TYPE_FUNC, + VV_TYPE_LIST, + VV_TYPE_DICT, + VV_TYPE_FLOAT, + VV_TYPE_BOOL, + VV_TYPE_BLOB, + VV_EVENT, + VV_VERSIONLONG, + VV_ECHOSPACE, + VV_ARGV, + VV_COLLATE, + VV_EXITING, + VV_MAXCOL, + VV_STACKTRACE, + // Nvim + VV_STDERR, + VV_MSGPACK_TYPES, + VV__NULL_STRING, // String with NULL value. For test purposes only. + VV__NULL_LIST, // List with NULL value. For test purposes only. + VV__NULL_DICT, // Dict with NULL value. For test purposes only. + VV__NULL_BLOB, // Blob with NULL value. For test purposes only. + VV_LUA, + VV_RELNUM, + VV_VIRTNUM, +} VimVarIndex; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index e28f282dc4..ed19458d61 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -36,9 +36,9 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 97d1fbf575..653b4afdca 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -34,10 +34,10 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 7d03dc9e86..71dd7e6347 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -16,6 +16,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/eval_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index bfee05a1ec..a1b550302a 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -21,6 +21,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 5ec46c5e2a..3facd32c32 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -62,6 +62,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/file_search.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 750f4fc3df..e0688ce5ad 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -29,6 +29,7 @@ #include "nvim/edit.h" #include "nvim/errors.h" #include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" #include "nvim/fileio.h" diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 61a4d67f57..46561079df 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -25,6 +25,7 @@ #include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_session.h" #include "nvim/extmark.h" #include "nvim/extmark_defs.h" diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index dba23f6ac6..77f2a2ce23 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -24,6 +24,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 17c90d78aa..10c7755b3c 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -17,6 +17,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/extmark.h" diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 9917f34ac4..cd79ca0119 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -29,6 +29,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/extmark.h" diff --git a/src/nvim/log.c b/src/nvim/log.c index e254b617e0..d3dd2cb7b6 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -18,7 +18,7 @@ #include "auto/config.h" #include "nvim/ascii_defs.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/memory.h" diff --git a/src/nvim/main.c b/src/nvim/main.c index 8d101f43f7..380e81dd69 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -43,6 +43,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/event/proc.h" diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 07b1970248..f1d6eb9b7a 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -25,6 +25,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_session.h" #include "nvim/fuzzy.h" diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 058fb46ac1..1a3d1f86c8 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -56,8 +56,8 @@ #include "nvim/change.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/fileio.h" #include "nvim/getchar.h" diff --git a/src/nvim/message.c b/src/nvim/message.c index 51f6dcfebb..1125dddd42 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -24,6 +24,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index a6b4a68f9e..54ed66e763 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -6,7 +6,7 @@ #include "nvim/ascii_defs.h" #include "nvim/channel.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/socket.h" #include "nvim/garray.h" diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 4ff46a3c37..1cafc6562a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -31,6 +31,7 @@ #include "nvim/edit.h" #include "nvim/errors.h" #include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 8d4a86537f..6af90b99f0 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -15,6 +15,7 @@ #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" #include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/macros_defs.h" diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c index 12555a19ed..7f859a2c75 100644 --- a/src/nvim/os/lang.c +++ b/src/nvim/os/lang.c @@ -16,7 +16,7 @@ #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/garray.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 22fde313ac..46d2dc99c5 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -11,8 +11,8 @@ #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/libuv_proc.h" #include "nvim/event/loop.h" diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 15297866f2..f0c038d8e1 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -9,7 +9,7 @@ #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" #include "nvim/buffer_defs.h" -#include "nvim/eval.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/signal.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/profile.c b/src/nvim/profile.c index 4d38cbd4c3..e88d818fe0 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -12,9 +12,9 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/fileio.h" #include "nvim/garray.h" diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index d0b9638bf8..14cbd3ccc8 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -24,6 +24,7 @@ #include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.h" #include "nvim/eval/window.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index ef73bf78ed..59f4f9957e 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -26,6 +26,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" diff --git a/src/nvim/search.c b/src/nvim/search.c index fe0bceef62..8f129bfcf4 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -19,9 +19,9 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/shada.c b/src/nvim/shada.c index dd8e08d770..09bbe6d8f3 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -23,6 +23,7 @@ #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 1c2ddd2b11..650577924d 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -16,7 +16,6 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/drawscreen.h" #include "nvim/errors.h" -#include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/tag.c b/src/nvim/tag.c index b8f81c3eff..09567d0960 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -21,6 +21,7 @@ #include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 1116c1b52c..8032eb11f5 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -58,6 +58,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/event/defs.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 3185a5b0ac..f57a7b6b41 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -12,6 +12,7 @@ #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_docmd.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 5a9d028fb0..a0f14e2d9d 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -13,6 +13,7 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_cmds_defs.h" #include "nvim/getchar.h" #include "nvim/globals.h"