mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
vim-patch:8.1.1939: code for handling v: variables in generic eval file (#36312)
Problem: Code for handling v: variables in generic eval file.
Solution: Move v: variables to evalvars.c. (Yegappan Lakshmanan,
closes vim/vim#4872)
e5cdf153bc
Cherry-pick get_vim_var_name() from 8.2.0149.
Cherry-pick evalvars.c changes from 8.2.1788.
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/eval/userfunc.h"
|
#include "nvim/eval/userfunc.h"
|
||||||
|
#include "nvim/eval/vars.h"
|
||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
#include "nvim/ex_cmds_defs.h"
|
#include "nvim/ex_cmds_defs.h"
|
||||||
#include "nvim/ex_docmd.h"
|
#include "nvim/ex_docmd.h"
|
||||||
|
|||||||
607
src/nvim/eval.c
607
src/nvim/eval.c
@@ -80,7 +80,6 @@
|
|||||||
#include "nvim/tag.h"
|
#include "nvim/tag.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/version.h"
|
|
||||||
#include "nvim/vim_defs.h"
|
#include "nvim/vim_defs.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
|
||||||
@@ -113,13 +112,6 @@ static const char e_cannot_use_partial_here[]
|
|||||||
|
|
||||||
static char * const namespace_char = "abglstvw";
|
static char * const namespace_char = "abglstvw";
|
||||||
|
|
||||||
/// Variable used for g:
|
|
||||||
static ScopeDictDictItem globvars_var;
|
|
||||||
|
|
||||||
/// Old Vim variables such as "v:version" are also available without the "v:".
|
|
||||||
/// Also in functions. We need a special hashtable for them.
|
|
||||||
static hashtab_T compat_hashtab;
|
|
||||||
|
|
||||||
/// Used for checking if local variables or arguments used in a lambda.
|
/// Used for checking if local variables or arguments used in a lambda.
|
||||||
bool *eval_lavars_used = NULL;
|
bool *eval_lavars_used = NULL;
|
||||||
|
|
||||||
@@ -143,186 +135,11 @@ typedef enum {
|
|||||||
GLV_STOP,
|
GLV_STOP,
|
||||||
} glv_status_T;
|
} glv_status_T;
|
||||||
|
|
||||||
// values for vv_flags:
|
|
||||||
#define VV_COMPAT 1 // compatible, also used without "v:"
|
|
||||||
#define VV_RO 2 // read-only
|
|
||||||
#define VV_RO_SBX 4 // read-only in the sandbox
|
|
||||||
|
|
||||||
#define VV(idx, name, type, flags) \
|
|
||||||
[idx] = { \
|
|
||||||
.vv_name = (name), \
|
|
||||||
.vv_di = { \
|
|
||||||
.di_tv = { .v_type = (type) }, \
|
|
||||||
.di_flags = 0, \
|
|
||||||
.di_key = { 0 }, \
|
|
||||||
}, \
|
|
||||||
.vv_flags = (flags), \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables
|
|
||||||
|
|
||||||
// Array to hold the value of v: variables.
|
|
||||||
// The value is in a dictitem, so that it can also be used in the v: scope.
|
|
||||||
// The reason to use this table anyway is for very quick access to the
|
|
||||||
// variables with the VV_ defines.
|
|
||||||
static struct vimvar {
|
|
||||||
char *vv_name; ///< Name of the variable, without v:.
|
|
||||||
TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di; ///< Value and name for key (max 16 chars).
|
|
||||||
char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
|
|
||||||
} vimvars[] = {
|
|
||||||
// VV_ tails differing from upcased string literals:
|
|
||||||
// VV_CC_FROM "charconvert_from"
|
|
||||||
// VV_CC_TO "charconvert_to"
|
|
||||||
// VV_SEND_SERVER "servername"
|
|
||||||
// VV_REG "register"
|
|
||||||
// VV_OP "operator"
|
|
||||||
VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
|
|
||||||
VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
|
|
||||||
VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
|
|
||||||
VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
|
|
||||||
VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT + VV_RO),
|
|
||||||
VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
|
|
||||||
VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_TERMREQUEST, "termrequest", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_LANG, "lang", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
|
|
||||||
VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
|
|
||||||
VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
|
|
||||||
VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
|
|
||||||
VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_REG, "register", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
|
|
||||||
VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
|
|
||||||
VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
|
|
||||||
VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
|
|
||||||
VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
|
|
||||||
VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_CHAR, "char", VAR_STRING, 0),
|
|
||||||
VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
|
|
||||||
VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
|
|
||||||
VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
|
|
||||||
VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
|
|
||||||
VV(VV_OP, "operator", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
|
|
||||||
VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
|
|
||||||
VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
|
|
||||||
VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
|
|
||||||
VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, 0),
|
|
||||||
VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_OPTION_COMMAND, "option_command", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_ERRORS, "errors", VAR_LIST, 0),
|
|
||||||
VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
|
|
||||||
VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
|
|
||||||
VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
|
|
||||||
VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TESTING, "testing", VAR_NUMBER, 0),
|
|
||||||
VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_EVENT, "event", VAR_DICT, VV_RO),
|
|
||||||
VV(VV_VERSIONLONG, "versionlong", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
|
|
||||||
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
|
|
||||||
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_STACKTRACE, "stacktrace", VAR_LIST, VV_RO),
|
|
||||||
// Neovim
|
|
||||||
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
|
|
||||||
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
|
|
||||||
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
|
|
||||||
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
|
|
||||||
VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
|
|
||||||
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
|
|
||||||
VV(VV_RELNUM, "relnum", VAR_NUMBER, VV_RO),
|
|
||||||
VV(VV_VIRTNUM, "virtnum", VAR_NUMBER, VV_RO),
|
|
||||||
};
|
|
||||||
#undef VV
|
|
||||||
|
|
||||||
// shorthand
|
|
||||||
#define vv_type vv_di.di_tv.v_type
|
|
||||||
#define vv_nr vv_di.di_tv.vval.v_number
|
|
||||||
#define vv_str vv_di.di_tv.vval.v_string
|
|
||||||
#define vv_list vv_di.di_tv.vval.v_list
|
|
||||||
#define vv_partial vv_di.di_tv.vval.v_partial
|
|
||||||
#define vv_tv vv_di.di_tv
|
|
||||||
|
|
||||||
#define vimvarht get_vimvar_dict()->dv_hashtab
|
|
||||||
|
|
||||||
/// Variable used for v:
|
|
||||||
static ScopeDictDictItem vimvars_var;
|
|
||||||
|
|
||||||
static partial_T *vvlua_partial;
|
|
||||||
|
|
||||||
#include "eval.c.generated.h"
|
#include "eval.c.generated.h"
|
||||||
|
|
||||||
static uint64_t last_timer_id = 1;
|
static uint64_t last_timer_id = 1;
|
||||||
static PMap(uint64_t) timers = MAP_INIT;
|
static PMap(uint64_t) timers = MAP_INIT;
|
||||||
|
|
||||||
static const char *const msgpack_type_names[] = {
|
|
||||||
[kMPNil] = "nil",
|
|
||||||
[kMPBoolean] = "boolean",
|
|
||||||
[kMPInteger] = "integer",
|
|
||||||
[kMPFloat] = "float",
|
|
||||||
[kMPString] = "string",
|
|
||||||
[kMPArray] = "array",
|
|
||||||
[kMPMap] = "map",
|
|
||||||
[kMPExt] = "ext",
|
|
||||||
};
|
|
||||||
const list_T *eval_msgpack_type_lists[] = {
|
|
||||||
[kMPNil] = NULL,
|
|
||||||
[kMPBoolean] = NULL,
|
|
||||||
[kMPInteger] = NULL,
|
|
||||||
[kMPFloat] = NULL,
|
|
||||||
[kMPString] = NULL,
|
|
||||||
[kMPArray] = NULL,
|
|
||||||
[kMPMap] = NULL,
|
|
||||||
[kMPExt] = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
dict_T *get_v_event(save_v_event_T *sve)
|
dict_T *get_v_event(save_v_event_T *sve)
|
||||||
{
|
{
|
||||||
dict_T *v_event = get_vim_var_dict(VV_EVENT);
|
dict_T *v_event = get_vim_var_dict(VV_EVENT);
|
||||||
@@ -384,130 +201,11 @@ varnumber_T num_modulus(varnumber_T n1, varnumber_T n2)
|
|||||||
/// Initialize the global and v: variables.
|
/// Initialize the global and v: variables.
|
||||||
void eval_init(void)
|
void eval_init(void)
|
||||||
{
|
{
|
||||||
dict_T *vimvardict = get_vimvar_dict();
|
evalvars_init();
|
||||||
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
|
|
||||||
|
|
||||||
init_var_dict(get_globvar_dict(), &globvars_var, VAR_DEF_SCOPE);
|
|
||||||
init_var_dict(vimvardict, &vimvars_var, VAR_SCOPE);
|
|
||||||
vimvardict->dv_lock = VAR_FIXED;
|
|
||||||
hash_init(&compat_hashtab);
|
|
||||||
func_init();
|
func_init();
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
|
|
||||||
struct vimvar *p = &vimvars[i];
|
|
||||||
assert(strlen(p->vv_name) <= VIMVAR_KEY_LEN);
|
|
||||||
STRCPY(p->vv_di.di_key, p->vv_name);
|
|
||||||
if (p->vv_flags & VV_RO) {
|
|
||||||
p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
|
|
||||||
} else if (p->vv_flags & VV_RO_SBX) {
|
|
||||||
p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
|
|
||||||
} else {
|
|
||||||
p->vv_di.di_flags = DI_FLAGS_FIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to v: scope dict, unless the value is not always available
|
|
||||||
if (p->vv_type != VAR_UNKNOWN) {
|
|
||||||
hash_add(&vimvarht, p->vv_di.di_key);
|
|
||||||
}
|
|
||||||
if (p->vv_flags & VV_COMPAT) {
|
|
||||||
// add to compat scope dict
|
|
||||||
hash_add(&compat_hashtab, p->vv_di.di_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
|
|
||||||
vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
|
|
||||||
|
|
||||||
dict_T *const msgpack_types_dict = tv_dict_alloc();
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
|
|
||||||
list_T *const type_list = tv_list_alloc(0);
|
|
||||||
tv_list_set_lock(type_list, VAR_FIXED);
|
|
||||||
tv_list_ref(type_list);
|
|
||||||
dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
|
|
||||||
di->di_flags |= DI_FLAGS_RO|DI_FLAGS_FIX;
|
|
||||||
di->di_tv = (typval_T) {
|
|
||||||
.v_type = VAR_LIST,
|
|
||||||
.vval = { .v_list = type_list, },
|
|
||||||
};
|
|
||||||
eval_msgpack_type_lists[i] = type_list;
|
|
||||||
if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
|
|
||||||
// There must not be duplicate items in this dictionary by definition.
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
msgpack_types_dict->dv_lock = VAR_FIXED;
|
|
||||||
|
|
||||||
set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
|
|
||||||
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
|
|
||||||
|
|
||||||
set_vim_var_dict(VV_EVENT, tv_dict_alloc_lock(VAR_FIXED));
|
|
||||||
set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
|
|
||||||
set_vim_var_nr(VV_STDERR, CHAN_STDERR);
|
|
||||||
set_vim_var_nr(VV_SEARCHFORWARD, 1);
|
|
||||||
set_vim_var_nr(VV_HLSEARCH, 1);
|
|
||||||
set_vim_var_nr(VV_COUNT1, 1);
|
|
||||||
set_vim_var_special(VV_EXITING, kSpecialVarNull);
|
|
||||||
|
|
||||||
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
|
|
||||||
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
|
|
||||||
set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
|
|
||||||
set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
|
|
||||||
set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
|
|
||||||
set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
|
|
||||||
set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
|
|
||||||
set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
|
|
||||||
|
|
||||||
set_vim_var_bool(VV_FALSE, kBoolVarFalse);
|
|
||||||
set_vim_var_bool(VV_TRUE, kBoolVarTrue);
|
|
||||||
set_vim_var_special(VV_NULL, kSpecialVarNull);
|
|
||||||
set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
|
|
||||||
set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
|
|
||||||
set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
|
|
||||||
set_vim_var_nr(VV_MAXCOL, MAXCOL);
|
|
||||||
|
|
||||||
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
|
||||||
|
|
||||||
vimvars[VV_LUA].vv_type = VAR_PARTIAL;
|
|
||||||
vvlua_partial = xcalloc(1, sizeof(partial_T));
|
|
||||||
vimvars[VV_LUA].vv_partial = vvlua_partial;
|
|
||||||
// this value shouldn't be printed, but if it is, do not crash
|
|
||||||
vvlua_partial->pt_name = xmallocz(0);
|
|
||||||
vvlua_partial->pt_refcount++;
|
|
||||||
|
|
||||||
set_reg_var(0); // default for v:register is not 0 but '"'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE)
|
#if defined(EXITFREE)
|
||||||
static void evalvars_clear(void)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
|
|
||||||
struct vimvar *p = &vimvars[i];
|
|
||||||
if (p->vv_di.di_tv.v_type == VAR_STRING) {
|
|
||||||
XFREE_CLEAR(p->vv_str);
|
|
||||||
} else if (p->vv_di.di_tv.v_type == VAR_LIST) {
|
|
||||||
tv_list_unref(p->vv_list);
|
|
||||||
p->vv_list = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partial_unref(vvlua_partial);
|
|
||||||
vimvars[VV_LUA].vv_partial = vvlua_partial = NULL;
|
|
||||||
|
|
||||||
hash_clear(&vimvarht);
|
|
||||||
hash_init(&vimvarht); // garbage_collect() will access it
|
|
||||||
hash_clear(&compat_hashtab);
|
|
||||||
|
|
||||||
// global variables
|
|
||||||
vars_clear(get_globvar_ht());
|
|
||||||
|
|
||||||
// Script-local variables. Clear all the variables here.
|
|
||||||
// The scriptvar_T is cleared later in free_scriptnames(), because a
|
|
||||||
// variable in one script might hold a reference to the whole scope of
|
|
||||||
// another script.
|
|
||||||
for (int i = 1; i <= script_items.ga_len; i++) {
|
|
||||||
vars_clear(&SCRIPT_VARS(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void eval_clear(void)
|
void eval_clear(void)
|
||||||
{
|
{
|
||||||
evalvars_clear();
|
evalvars_clear();
|
||||||
@@ -921,41 +619,6 @@ typval_T *eval_expr_ext(char *arg, exarg_T *eap, const bool use_simple_function)
|
|||||||
return tv;
|
return tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_compatht(const hashtab_T *ht)
|
|
||||||
{
|
|
||||||
return ht == &compat_hashtab;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepare v: variable "idx" to be used.
|
|
||||||
/// Save the current typeval in "save_tv" and clear it.
|
|
||||||
/// When not used yet add the variable to the v: hashtable.
|
|
||||||
void prepare_vimvar(int idx, typval_T *save_tv)
|
|
||||||
{
|
|
||||||
*save_tv = vimvars[idx].vv_tv;
|
|
||||||
vimvars[idx].vv_str = NULL; // don't free it now
|
|
||||||
if (vimvars[idx].vv_type == VAR_UNKNOWN) {
|
|
||||||
hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Restore v: variable "idx" to typeval "save_tv".
|
|
||||||
/// Note that the v: variable must have been cleared already.
|
|
||||||
/// When no longer defined, remove the variable from the v: hashtable.
|
|
||||||
void restore_vimvar(int idx, typval_T *save_tv)
|
|
||||||
{
|
|
||||||
vimvars[idx].vv_tv = *save_tv;
|
|
||||||
if (vimvars[idx].vv_type != VAR_UNKNOWN) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hashitem_T *hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
|
|
||||||
if (HASHITEM_EMPTY(hi)) {
|
|
||||||
internal_error("restore_vimvar()");
|
|
||||||
} else {
|
|
||||||
hash_remove(&vimvarht, hi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call some Vim script function and return the result in "*rettv".
|
/// Call some Vim script function and return the result in "*rettv".
|
||||||
/// Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
|
/// Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
|
||||||
/// should have type VAR_UNKNOWN.
|
/// should have type VAR_UNKNOWN.
|
||||||
@@ -975,7 +638,7 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett
|
|||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
pt = vvlua_partial;
|
pt = get_vim_var_partial(VV_LUA);
|
||||||
}
|
}
|
||||||
|
|
||||||
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
|
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
|
||||||
@@ -2000,116 +1663,6 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx)
|
|||||||
xp->xp_pattern = arg;
|
xp->xp_pattern = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local string buffer for the next two functions to store a variable name
|
|
||||||
/// with its prefix. Allocated in cat_prefix_varname(), freed later in
|
|
||||||
/// get_user_var_name().
|
|
||||||
|
|
||||||
static char *varnamebuf = NULL;
|
|
||||||
static size_t varnamebuflen = 0;
|
|
||||||
|
|
||||||
/// Function to concatenate a prefix and a variable name.
|
|
||||||
char *cat_prefix_varname(int prefix, const char *name)
|
|
||||||
FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
|
||||||
size_t len = strlen(name) + 3;
|
|
||||||
|
|
||||||
if (len > varnamebuflen) {
|
|
||||||
xfree(varnamebuf);
|
|
||||||
len += 10; // some additional space
|
|
||||||
varnamebuf = xmalloc(len);
|
|
||||||
varnamebuflen = len;
|
|
||||||
}
|
|
||||||
*varnamebuf = (char)prefix;
|
|
||||||
varnamebuf[1] = ':';
|
|
||||||
STRCPY(varnamebuf + 2, name);
|
|
||||||
return varnamebuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function given to ExpandGeneric() to obtain the list of user defined
|
|
||||||
/// (global/buffer/window/built-in) variable names.
|
|
||||||
char *get_user_var_name(expand_T *xp, int idx)
|
|
||||||
{
|
|
||||||
static size_t gdone;
|
|
||||||
static size_t bdone;
|
|
||||||
static size_t wdone;
|
|
||||||
static size_t tdone;
|
|
||||||
static size_t vidx;
|
|
||||||
static hashitem_T *hi;
|
|
||||||
|
|
||||||
if (idx == 0) {
|
|
||||||
gdone = bdone = wdone = vidx = 0;
|
|
||||||
tdone = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global variables
|
|
||||||
hashtab_T *globvarht = get_globvar_ht();
|
|
||||||
if (gdone < globvarht->ht_used) {
|
|
||||||
if (gdone++ == 0) {
|
|
||||||
hi = globvarht->ht_array;
|
|
||||||
} else {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
while (HASHITEM_EMPTY(hi)) {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
if (strncmp("g:", xp->xp_pattern, 2) == 0) {
|
|
||||||
return cat_prefix_varname('g', hi->hi_key);
|
|
||||||
}
|
|
||||||
return hi->hi_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
// b: variables
|
|
||||||
const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
|
|
||||||
if (bdone < ht->ht_used) {
|
|
||||||
if (bdone++ == 0) {
|
|
||||||
hi = ht->ht_array;
|
|
||||||
} else {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
while (HASHITEM_EMPTY(hi)) {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
return cat_prefix_varname('b', hi->hi_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// w: variables
|
|
||||||
ht = &prevwin_curwin()->w_vars->dv_hashtab;
|
|
||||||
if (wdone < ht->ht_used) {
|
|
||||||
if (wdone++ == 0) {
|
|
||||||
hi = ht->ht_array;
|
|
||||||
} else {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
while (HASHITEM_EMPTY(hi)) {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
return cat_prefix_varname('w', hi->hi_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// t: variables
|
|
||||||
ht = &curtab->tp_vars->dv_hashtab;
|
|
||||||
if (tdone < ht->ht_used) {
|
|
||||||
if (tdone++ == 0) {
|
|
||||||
hi = ht->ht_array;
|
|
||||||
} else {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
while (HASHITEM_EMPTY(hi)) {
|
|
||||||
hi++;
|
|
||||||
}
|
|
||||||
return cat_prefix_varname('t', hi->hi_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v: variables
|
|
||||||
if (vidx < ARRAY_SIZE(vimvars)) {
|
|
||||||
return cat_prefix_varname('v', vimvars[vidx++].vv_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
XFREE_CLEAR(varnamebuf);
|
|
||||||
varnamebuflen = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Does not use 'cpo' and always uses 'magic'.
|
/// Does not use 'cpo' and always uses 'magic'.
|
||||||
///
|
///
|
||||||
/// @return true if "pat" matches "text".
|
/// @return true if "pat" matches "text".
|
||||||
@@ -3172,7 +2725,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
|
|||||||
// in handle_subscript() to parse v:lua, so set it here.
|
// in handle_subscript() to parse v:lua, so set it here.
|
||||||
if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) {
|
if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) {
|
||||||
rettv->v_type = VAR_PARTIAL;
|
rettv->v_type = VAR_PARTIAL;
|
||||||
rettv->vval.v_partial = vvlua_partial;
|
rettv->vval.v_partial = get_vim_var_partial(VV_LUA);
|
||||||
rettv->vval.v_partial->pt_refcount++;
|
rettv->vval.v_partial->pt_refcount++;
|
||||||
}
|
}
|
||||||
ret = OK;
|
ret = OK;
|
||||||
@@ -3470,7 +3023,7 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const
|
|||||||
} else if (lua_funcname != NULL) {
|
} else if (lua_funcname != NULL) {
|
||||||
if (evaluate) {
|
if (evaluate) {
|
||||||
rettv->v_type = VAR_PARTIAL;
|
rettv->v_type = VAR_PARTIAL;
|
||||||
rettv->vval.v_partial = vvlua_partial;
|
rettv->vval.v_partial = get_vim_var_partial(VV_LUA);
|
||||||
rettv->vval.v_partial->pt_refcount++;
|
rettv->vval.v_partial->pt_refcount++;
|
||||||
}
|
}
|
||||||
ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, lua_funcname);
|
ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, lua_funcname);
|
||||||
@@ -5322,7 +4875,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co
|
|||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
partial = vvlua_partial;
|
partial = get_vim_var_partial(VV_LUA);
|
||||||
} else {
|
} else {
|
||||||
partial = NULL;
|
partial = NULL;
|
||||||
}
|
}
|
||||||
@@ -6181,12 +5734,6 @@ bool eval_isdictc(int c)
|
|||||||
return ASCII_ISALNUM(c) || c == '_';
|
return ASCII_ISALNUM(c) || c == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get typval_T v: variable value.
|
|
||||||
typval_T *get_vim_var_tv(const VimVarIndex idx)
|
|
||||||
{
|
|
||||||
return &vimvars[idx].vv_tv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the v:argv list.
|
/// Set the v:argv list.
|
||||||
void set_argv_var(char **argv, int argc)
|
void set_argv_var(char **argv, int argc)
|
||||||
{
|
{
|
||||||
@@ -6204,7 +5751,7 @@ void set_argv_var(char **argv, int argc)
|
|||||||
bool is_luafunc(partial_T *partial)
|
bool is_luafunc(partial_T *partial)
|
||||||
FUNC_ATTR_PURE
|
FUNC_ATTR_PURE
|
||||||
{
|
{
|
||||||
return partial == vvlua_partial;
|
return partial == get_vim_var_partial(VV_LUA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check if special v:lua value for calling lua functions
|
/// check if special v:lua value for calling lua functions
|
||||||
@@ -6439,148 +5986,6 @@ void set_selfdict(typval_T *const rettv, dict_T *const selfdict)
|
|||||||
make_partial(selfdict, rettv);
|
make_partial(selfdict, rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find variable in hashtab.
|
|
||||||
/// When "varname" is empty returns curwin/curtab/etc vars dictionary.
|
|
||||||
///
|
|
||||||
/// @param[in] ht Hashtab to find variable in.
|
|
||||||
/// @param[in] htname Hashtab name (first character).
|
|
||||||
/// @param[in] varname Variable name.
|
|
||||||
/// @param[in] varname_len Variable name length.
|
|
||||||
/// @param[in] no_autoload If true then autoload scripts will not be sourced
|
|
||||||
/// if autoload variable was not found.
|
|
||||||
///
|
|
||||||
/// @return pointer to the dictionary item with the found variable or NULL if it
|
|
||||||
/// was not found.
|
|
||||||
dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const varname,
|
|
||||||
const size_t varname_len, int no_autoload)
|
|
||||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
|
||||||
if (varname_len == 0) {
|
|
||||||
// Must be something like "s:", otherwise "ht" would be NULL.
|
|
||||||
switch (htname) {
|
|
||||||
case 's':
|
|
||||||
return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
|
|
||||||
case 'g':
|
|
||||||
return (dictitem_T *)&globvars_var;
|
|
||||||
case 'v':
|
|
||||||
return (dictitem_T *)&vimvars_var;
|
|
||||||
case 'b':
|
|
||||||
return (dictitem_T *)&curbuf->b_bufvar;
|
|
||||||
case 'w':
|
|
||||||
return (dictitem_T *)&curwin->w_winvar;
|
|
||||||
case 't':
|
|
||||||
return (dictitem_T *)&curtab->tp_winvar;
|
|
||||||
case 'l':
|
|
||||||
return get_funccal_local_var();
|
|
||||||
case 'a':
|
|
||||||
return get_funccal_args_var();
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hashitem_T *hi = hash_find_len(ht, varname, varname_len);
|
|
||||||
if (HASHITEM_EMPTY(hi)) {
|
|
||||||
// For global variables we may try auto-loading the script. If it
|
|
||||||
// worked find the variable again. Don't auto-load a script if it was
|
|
||||||
// loaded already, otherwise it would be loaded every time when
|
|
||||||
// checking if a function name is a Funcref variable.
|
|
||||||
if (ht == get_globvar_ht() && !no_autoload) {
|
|
||||||
// Note: script_autoload() may make "hi" invalid. It must either
|
|
||||||
// be obtained again or not used.
|
|
||||||
if (!script_autoload(varname, varname_len, false) || aborting()) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
hi = hash_find_len(ht, varname, varname_len);
|
|
||||||
}
|
|
||||||
if (HASHITEM_EMPTY(hi)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TV_DICT_HI2DI(hi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds the dict (g:, l:, s:, …) and hashtable used for a variable.
|
|
||||||
///
|
|
||||||
/// Assigns SID if s: scope is accessed from Lua or anonymous Vimscript. #15994
|
|
||||||
///
|
|
||||||
/// @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.
|
|
||||||
/// @param[out] d Scope dictionary.
|
|
||||||
///
|
|
||||||
/// @return Scope hashtab, NULL if name is not valid.
|
|
||||||
hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
|
|
||||||
dict_T **d)
|
|
||||||
{
|
|
||||||
funccall_T *funccal = get_funccal();
|
|
||||||
*d = NULL;
|
|
||||||
|
|
||||||
if (name_len == 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (name_len == 1 || name[1] != ':') {
|
|
||||||
// name has implicit scope
|
|
||||||
if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
|
|
||||||
// The name must not start with a colon or #.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*varname = name;
|
|
||||||
|
|
||||||
// "version" is "v:version" in all scopes
|
|
||||||
hashitem_T *hi = hash_find_len(&compat_hashtab, name, name_len);
|
|
||||||
if (!HASHITEM_EMPTY(hi)) {
|
|
||||||
return &compat_hashtab;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (funccal == NULL) { // global variable
|
|
||||||
*d = get_globvar_dict();
|
|
||||||
} else { // l: variable
|
|
||||||
*d = &funccal->fc_l_vars;
|
|
||||||
}
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
*varname = name + 2;
|
|
||||||
if (*name == 'g') { // global variable
|
|
||||||
*d = get_globvar_dict();
|
|
||||||
} else if (name_len > 2
|
|
||||||
&& (memchr(name + 2, ':', name_len - 2) != NULL
|
|
||||||
|| memchr(name + 2, AUTOLOAD_CHAR, name_len - 2) != NULL)) {
|
|
||||||
// There must be no ':' or '#' in the rest of the name if g: was not used
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*name == 'b') { // buffer variable
|
|
||||||
*d = curbuf->b_vars;
|
|
||||||
} else if (*name == 'w') { // window variable
|
|
||||||
*d = curwin->w_vars;
|
|
||||||
} else if (*name == 't') { // tab page variable
|
|
||||||
*d = curtab->tp_vars;
|
|
||||||
} else if (*name == 'v') { // v: variable
|
|
||||||
*d = get_vimvar_dict();
|
|
||||||
} else if (*name == 'a' && funccal != NULL) { // function argument
|
|
||||||
*d = &funccal->fc_l_avars;
|
|
||||||
} else if (*name == 'l' && funccal != NULL) { // local variable
|
|
||||||
*d = &funccal->fc_l_vars;
|
|
||||||
} else if (*name == 's' // script variable
|
|
||||||
&& (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR
|
|
||||||
|| current_sctx.sc_sid == SID_LUA)
|
|
||||||
&& current_sctx.sc_sid <= script_items.ga_len) {
|
|
||||||
// For anonymous scripts without a script item, create one now so script vars can be used
|
|
||||||
// Try to resolve lua filename & linenr so it can be shown in last-set messages.
|
|
||||||
nlua_set_sctx(¤t_sctx);
|
|
||||||
if (current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) {
|
|
||||||
// Create SID if s: scope is accessed from Lua or anon Vimscript. #15994
|
|
||||||
new_script_item(NULL, ¤t_sctx.sc_sid);
|
|
||||||
}
|
|
||||||
*d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
return *d ? &(*d)->dv_hashtab : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make a copy of an item
|
/// Make a copy of an item
|
||||||
///
|
///
|
||||||
/// Lists and Dictionaries are also copied.
|
/// Lists and Dictionaries are also copied.
|
||||||
|
|||||||
@@ -74,9 +74,6 @@ typedef enum {
|
|||||||
VAR_FLAVOUR_SHADA = 4, // all uppercase
|
VAR_FLAVOUR_SHADA = 4, // all uppercase
|
||||||
} var_flavour_T;
|
} var_flavour_T;
|
||||||
|
|
||||||
/// Array mapping values from MessagePackType to corresponding list pointers
|
|
||||||
extern const list_T *eval_msgpack_type_lists[NUM_MSGPACK_TYPES];
|
|
||||||
|
|
||||||
// Struct passed to get_v_event() and restore_v_event().
|
// Struct passed to get_v_event() and restore_v_event().
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool sve_did_save;
|
bool sve_did_save;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "nvim/eval/encode.h"
|
#include "nvim/eval/encode.h"
|
||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
|
#include "nvim/eval/vars.h"
|
||||||
#include "nvim/eval_defs.h"
|
#include "nvim/eval_defs.h"
|
||||||
#include "nvim/garray.h"
|
#include "nvim/garray.h"
|
||||||
#include "nvim/gettext_defs.h"
|
#include "nvim/gettext_defs.h"
|
||||||
|
|||||||
@@ -255,6 +255,7 @@
|
|||||||
#include "nvim/eval/encode.h"
|
#include "nvim/eval/encode.h"
|
||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_encode.h"
|
#include "nvim/eval/typval_encode.h"
|
||||||
|
#include "nvim/eval/vars.h"
|
||||||
#include "nvim/func_attr.h"
|
#include "nvim/func_attr.h"
|
||||||
|
|
||||||
/// Dummy variable used because some macros need lvalue
|
/// Dummy variable used because some macros need lvalue
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "nvim/gettext_defs.h"
|
#include "nvim/gettext_defs.h"
|
||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/hashtab.h"
|
#include "nvim/hashtab.h"
|
||||||
|
#include "nvim/lua/executor.h"
|
||||||
#include "nvim/macros_defs.h"
|
#include "nvim/macros_defs.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
#include "nvim/search.h"
|
#include "nvim/search.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
|
#include "nvim/version.h"
|
||||||
#include "nvim/vim_defs.h"
|
#include "nvim/vim_defs.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
|
||||||
@@ -65,14 +67,313 @@ 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_missing_end_marker_str[] = N_("E990: Missing end marker '%s'");
|
||||||
static const char e_cannot_use_heredoc_here[] = N_("E991: Cannot use =<< here");
|
static const char e_cannot_use_heredoc_here[] = N_("E991: Cannot use =<< here");
|
||||||
|
|
||||||
|
/// Variable used for g:
|
||||||
|
static ScopeDictDictItem globvars_var;
|
||||||
static dict_T globvardict; // Dict with g: variables
|
static dict_T globvardict; // Dict with g: variables
|
||||||
/// g: value
|
/// g: value
|
||||||
#define globvarht globvardict.dv_hashtab
|
#define globvarht globvardict.dv_hashtab
|
||||||
|
|
||||||
|
/// Old Vim variables such as "v:version" are also available without the "v:".
|
||||||
|
/// Also in functions. We need a special hashtable for them.
|
||||||
|
static hashtab_T compat_hashtab;
|
||||||
|
|
||||||
|
// values for vv_flags:
|
||||||
|
#define VV_COMPAT 1 // compatible, also used without "v:"
|
||||||
|
#define VV_RO 2 // read-only
|
||||||
|
#define VV_RO_SBX 4 // read-only in the sandbox
|
||||||
|
|
||||||
|
#define VV(idx, name, type, flags) \
|
||||||
|
[idx] = { \
|
||||||
|
.vv_name = (name), \
|
||||||
|
.vv_di = { \
|
||||||
|
.di_tv = { .v_type = (type) }, \
|
||||||
|
.di_flags = 0, \
|
||||||
|
.di_key = { 0 }, \
|
||||||
|
}, \
|
||||||
|
.vv_flags = (flags), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables
|
||||||
|
|
||||||
|
// Array to hold the value of v: variables.
|
||||||
|
// The value is in a dictitem, so that it can also be used in the v: scope.
|
||||||
|
// The reason to use this table anyway is for very quick access to the
|
||||||
|
// variables with the VV_ defines.
|
||||||
|
static struct vimvar {
|
||||||
|
char *vv_name; ///< Name of the variable, without v:.
|
||||||
|
TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di; ///< Value and name for key (max 16 chars).
|
||||||
|
char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
|
||||||
|
} vimvars[] = {
|
||||||
|
// VV_ tails differing from upcased string literals:
|
||||||
|
// VV_CC_FROM "charconvert_from"
|
||||||
|
// VV_CC_TO "charconvert_to"
|
||||||
|
// VV_SEND_SERVER "servername"
|
||||||
|
// VV_REG "register"
|
||||||
|
// VV_OP "operator"
|
||||||
|
VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
|
||||||
|
VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
|
||||||
|
VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
|
||||||
|
VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
|
||||||
|
VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT + VV_RO),
|
||||||
|
VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
|
||||||
|
VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_TERMREQUEST, "termrequest", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_LANG, "lang", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
|
||||||
|
VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
|
||||||
|
VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
|
||||||
|
VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
|
||||||
|
VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_REG, "register", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
|
||||||
|
VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
|
||||||
|
VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
|
||||||
|
VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
|
||||||
|
VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
|
||||||
|
VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_CHAR, "char", VAR_STRING, 0),
|
||||||
|
VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
|
||||||
|
VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
|
||||||
|
VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
|
||||||
|
VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
|
||||||
|
VV(VV_OP, "operator", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
|
||||||
|
VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
|
||||||
|
VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
|
||||||
|
VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
|
||||||
|
VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, 0),
|
||||||
|
VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_OPTION_COMMAND, "option_command", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_ERRORS, "errors", VAR_LIST, 0),
|
||||||
|
VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
|
||||||
|
VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
|
||||||
|
VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
|
||||||
|
VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TESTING, "testing", VAR_NUMBER, 0),
|
||||||
|
VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_EVENT, "event", VAR_DICT, VV_RO),
|
||||||
|
VV(VV_VERSIONLONG, "versionlong", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
|
||||||
|
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
|
||||||
|
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_STACKTRACE, "stacktrace", VAR_LIST, VV_RO),
|
||||||
|
// Neovim
|
||||||
|
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
|
||||||
|
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
|
||||||
|
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
|
||||||
|
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
|
||||||
|
VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
|
||||||
|
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
|
||||||
|
VV(VV_RELNUM, "relnum", VAR_NUMBER, VV_RO),
|
||||||
|
VV(VV_VIRTNUM, "virtnum", VAR_NUMBER, VV_RO),
|
||||||
|
};
|
||||||
|
#undef VV
|
||||||
|
|
||||||
|
// shorthand
|
||||||
|
#define vv_type vv_di.di_tv.v_type
|
||||||
|
#define vv_str vv_di.di_tv.vval.v_string
|
||||||
|
#define vv_list vv_di.di_tv.vval.v_list
|
||||||
|
#define vv_tv vv_di.di_tv
|
||||||
|
|
||||||
|
/// Variable used for v:
|
||||||
|
static ScopeDictDictItem vimvars_var;
|
||||||
static dict_T vimvardict; // Dict with v: variables
|
static dict_T vimvardict; // Dict with v: variables
|
||||||
/// v: hashtab
|
/// v: hashtab
|
||||||
#define vimvarht vimvardict.dv_hashtab
|
#define vimvarht vimvardict.dv_hashtab
|
||||||
|
|
||||||
|
static const char *const msgpack_type_names[] = {
|
||||||
|
[kMPNil] = "nil",
|
||||||
|
[kMPBoolean] = "boolean",
|
||||||
|
[kMPInteger] = "integer",
|
||||||
|
[kMPFloat] = "float",
|
||||||
|
[kMPString] = "string",
|
||||||
|
[kMPArray] = "array",
|
||||||
|
[kMPMap] = "map",
|
||||||
|
[kMPExt] = "ext",
|
||||||
|
};
|
||||||
|
const list_T *eval_msgpack_type_lists[] = {
|
||||||
|
[kMPNil] = NULL,
|
||||||
|
[kMPBoolean] = NULL,
|
||||||
|
[kMPInteger] = NULL,
|
||||||
|
[kMPFloat] = NULL,
|
||||||
|
[kMPString] = NULL,
|
||||||
|
[kMPArray] = NULL,
|
||||||
|
[kMPMap] = NULL,
|
||||||
|
[kMPExt] = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars)
|
||||||
|
#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
|
||||||
|
|
||||||
|
void evalvars_init(void)
|
||||||
|
{
|
||||||
|
init_var_dict(get_globvar_dict(), &globvars_var, VAR_DEF_SCOPE);
|
||||||
|
init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
|
||||||
|
vimvardict.dv_lock = VAR_FIXED;
|
||||||
|
hash_init(&compat_hashtab);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
|
||||||
|
struct vimvar *p = &vimvars[i];
|
||||||
|
assert(strlen(p->vv_name) <= VIMVAR_KEY_LEN);
|
||||||
|
STRCPY(p->vv_di.di_key, p->vv_name);
|
||||||
|
if (p->vv_flags & VV_RO) {
|
||||||
|
p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
|
||||||
|
} else if (p->vv_flags & VV_RO_SBX) {
|
||||||
|
p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
|
||||||
|
} else {
|
||||||
|
p->vv_di.di_flags = DI_FLAGS_FIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to v: scope dict, unless the value is not always available
|
||||||
|
if (p->vv_type != VAR_UNKNOWN) {
|
||||||
|
hash_add(&vimvarht, p->vv_di.di_key);
|
||||||
|
}
|
||||||
|
if (p->vv_flags & VV_COMPAT) {
|
||||||
|
// add to compat scope dict
|
||||||
|
hash_add(&compat_hashtab, p->vv_di.di_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
|
||||||
|
set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
|
||||||
|
|
||||||
|
dict_T *const msgpack_types_dict = tv_dict_alloc();
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
|
||||||
|
list_T *const type_list = tv_list_alloc(0);
|
||||||
|
tv_list_set_lock(type_list, VAR_FIXED);
|
||||||
|
tv_list_ref(type_list);
|
||||||
|
dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
|
||||||
|
di->di_flags |= DI_FLAGS_RO|DI_FLAGS_FIX;
|
||||||
|
di->di_tv = (typval_T) {
|
||||||
|
.v_type = VAR_LIST,
|
||||||
|
.vval = { .v_list = type_list, },
|
||||||
|
};
|
||||||
|
eval_msgpack_type_lists[i] = type_list;
|
||||||
|
if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
|
||||||
|
// There must not be duplicate items in this dictionary by definition.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msgpack_types_dict->dv_lock = VAR_FIXED;
|
||||||
|
|
||||||
|
set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
|
||||||
|
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
|
||||||
|
|
||||||
|
set_vim_var_dict(VV_EVENT, tv_dict_alloc_lock(VAR_FIXED));
|
||||||
|
set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
|
||||||
|
set_vim_var_nr(VV_STDERR, CHAN_STDERR);
|
||||||
|
set_vim_var_nr(VV_SEARCHFORWARD, 1);
|
||||||
|
set_vim_var_nr(VV_HLSEARCH, 1);
|
||||||
|
set_vim_var_nr(VV_COUNT1, 1);
|
||||||
|
set_vim_var_special(VV_EXITING, kSpecialVarNull);
|
||||||
|
|
||||||
|
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
|
||||||
|
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
|
||||||
|
set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
|
||||||
|
set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
|
||||||
|
set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
|
||||||
|
set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
|
||||||
|
set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
|
||||||
|
set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
|
||||||
|
|
||||||
|
set_vim_var_bool(VV_FALSE, kBoolVarFalse);
|
||||||
|
set_vim_var_bool(VV_TRUE, kBoolVarTrue);
|
||||||
|
set_vim_var_special(VV_NULL, kSpecialVarNull);
|
||||||
|
set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
|
||||||
|
set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
|
||||||
|
set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
|
||||||
|
set_vim_var_nr(VV_MAXCOL, MAXCOL);
|
||||||
|
|
||||||
|
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
||||||
|
|
||||||
|
// vimvars[VV_LUA].vv_type = VAR_PARTIAL;
|
||||||
|
partial_T *vvlua_partial = xcalloc(1, sizeof(partial_T));
|
||||||
|
// this value shouldn't be printed, but if it is, do not crash
|
||||||
|
vvlua_partial->pt_name = xmallocz(0);
|
||||||
|
vvlua_partial->pt_refcount++;
|
||||||
|
set_vim_var_partial(VV_LUA, vvlua_partial);
|
||||||
|
|
||||||
|
set_reg_var(0); // default for v:register is not 0 but '"'
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EXITFREE)
|
||||||
|
void evalvars_clear(void)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
|
||||||
|
struct vimvar *p = &vimvars[i];
|
||||||
|
if (p->vv_di.di_tv.v_type == VAR_STRING) {
|
||||||
|
XFREE_CLEAR(p->vv_str);
|
||||||
|
} else if (p->vv_di.di_tv.v_type == VAR_LIST) {
|
||||||
|
tv_list_unref(p->vv_list);
|
||||||
|
p->vv_list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial_unref(get_vim_var_partial(VV_LUA));
|
||||||
|
set_vim_var_partial(VV_LUA, NULL);
|
||||||
|
hash_clear(&vimvarht);
|
||||||
|
hash_init(&vimvarht); // garbage_collect() will access it
|
||||||
|
hash_clear(&compat_hashtab);
|
||||||
|
|
||||||
|
// global variables
|
||||||
|
vars_clear(get_globvar_ht());
|
||||||
|
|
||||||
|
// Script-local variables. Clear all the variables here.
|
||||||
|
// The scriptvar_T is cleared later in free_scriptnames(), because a
|
||||||
|
// variable in one script might hold a reference to the whole scope of
|
||||||
|
// another script.
|
||||||
|
for (int i = 1; i <= script_items.ga_len; i++) {
|
||||||
|
vars_clear(&SCRIPT_VARS(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int garbage_collect_globvars(int copyID)
|
int garbage_collect_globvars(int copyID)
|
||||||
{
|
{
|
||||||
return set_ref_in_ht(&globvarht, copyID, NULL);
|
return set_ref_in_ht(&globvarht, copyID, NULL);
|
||||||
@@ -254,6 +555,36 @@ int get_spellword(list_T *const list, const char **ret_word)
|
|||||||
return (int)tv_list_find_nr(list, -1, NULL);
|
return (int)tv_list_find_nr(list, -1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prepare v: variable "idx" to be used.
|
||||||
|
/// Save the current typeval in "save_tv" and clear it.
|
||||||
|
/// When not used yet add the variable to the v: hashtable.
|
||||||
|
void prepare_vimvar(int idx, typval_T *save_tv)
|
||||||
|
{
|
||||||
|
*save_tv = vimvars[idx].vv_tv;
|
||||||
|
vimvars[idx].vv_str = NULL; // don't free it now
|
||||||
|
if (vimvars[idx].vv_type == VAR_UNKNOWN) {
|
||||||
|
hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restore v: variable "idx" to typeval "save_tv".
|
||||||
|
/// Note that the v: variable must have been cleared already.
|
||||||
|
/// When no longer defined, remove the variable from the v: hashtable.
|
||||||
|
void restore_vimvar(int idx, typval_T *save_tv)
|
||||||
|
{
|
||||||
|
vimvars[idx].vv_tv = *save_tv;
|
||||||
|
if (vimvars[idx].vv_type != VAR_UNKNOWN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashitem_T *hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
|
||||||
|
if (HASHITEM_EMPTY(hi)) {
|
||||||
|
internal_error("restore_vimvar()");
|
||||||
|
} else {
|
||||||
|
hash_remove(&vimvarht, hi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// List Vim variables.
|
/// List Vim variables.
|
||||||
static void list_vim_vars(int *first)
|
static void list_vim_vars(int *first)
|
||||||
{
|
{
|
||||||
@@ -1378,7 +1709,7 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
|
|||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
if (ht == &globvarht) {
|
if (ht == &globvarht) {
|
||||||
d = &globvardict;
|
d = &globvardict;
|
||||||
} else if (is_compatht(ht)) {
|
} else if (ht == &compat_hashtab) {
|
||||||
d = &vimvardict;
|
d = &vimvardict;
|
||||||
} else {
|
} else {
|
||||||
dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
|
dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
|
||||||
@@ -1533,9 +1864,21 @@ dict_T *get_vimvar_dict(void)
|
|||||||
/// @param[in] val Value to set to. Will be copied.
|
/// @param[in] val Value to set to. Will be copied.
|
||||||
void set_vim_var_tv(const VimVarIndex idx, typval_T *const tv)
|
void set_vim_var_tv(const VimVarIndex idx, typval_T *const tv)
|
||||||
{
|
{
|
||||||
typval_T *vv_tv = get_vim_var_tv(idx);
|
typval_T *tv_out = get_vim_var_tv(idx);
|
||||||
tv_clear(vv_tv);
|
tv_clear(tv_out);
|
||||||
tv_copy(tv, vv_tv);
|
tv_copy(tv, tv_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_vim_var_name(const VimVarIndex idx)
|
||||||
|
FUNC_ATTR_NONNULL_RET
|
||||||
|
{
|
||||||
|
return vimvars[idx].vv_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get typval_T v: variable value.
|
||||||
|
typval_T *get_vim_var_tv(const VimVarIndex idx)
|
||||||
|
{
|
||||||
|
return &vimvars[idx].vv_tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get number v: variable value.
|
/// Get number v: variable value.
|
||||||
@@ -1570,6 +1913,123 @@ char *get_vim_var_str(const VimVarIndex idx)
|
|||||||
return (char *)tv_get_string(get_vim_var_tv(idx));
|
return (char *)tv_get_string(get_vim_var_tv(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get Partial v: variable value. Caller must take care of reference count
|
||||||
|
/// when needed.
|
||||||
|
partial_T *get_vim_var_partial(const VimVarIndex idx) FUNC_ATTR_PURE
|
||||||
|
{
|
||||||
|
typval_T *tv = get_vim_var_tv(idx);
|
||||||
|
return tv->vval.v_partial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Local string buffer for the next two functions to store a variable name
|
||||||
|
/// with its prefix. Allocated in cat_prefix_varname(), freed later in
|
||||||
|
/// get_user_var_name().
|
||||||
|
|
||||||
|
static char *varnamebuf = NULL;
|
||||||
|
static size_t varnamebuflen = 0;
|
||||||
|
|
||||||
|
/// Function to concatenate a prefix and a variable name.
|
||||||
|
char *cat_prefix_varname(int prefix, const char *name)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
size_t len = strlen(name) + 3;
|
||||||
|
|
||||||
|
if (len > varnamebuflen) {
|
||||||
|
xfree(varnamebuf);
|
||||||
|
len += 10; // some additional space
|
||||||
|
varnamebuf = xmalloc(len);
|
||||||
|
varnamebuflen = len;
|
||||||
|
}
|
||||||
|
*varnamebuf = (char)prefix;
|
||||||
|
varnamebuf[1] = ':';
|
||||||
|
STRCPY(varnamebuf + 2, name);
|
||||||
|
return varnamebuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function given to ExpandGeneric() to obtain the list of user defined
|
||||||
|
/// (global/buffer/window/built-in) variable names.
|
||||||
|
char *get_user_var_name(expand_T *xp, int idx)
|
||||||
|
{
|
||||||
|
static size_t gdone;
|
||||||
|
static size_t bdone;
|
||||||
|
static size_t wdone;
|
||||||
|
static size_t tdone;
|
||||||
|
static size_t vidx;
|
||||||
|
static hashitem_T *hi;
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
gdone = bdone = wdone = vidx = 0;
|
||||||
|
tdone = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
if (gdone < globvarht.ht_used) {
|
||||||
|
if (gdone++ == 0) {
|
||||||
|
hi = globvarht.ht_array;
|
||||||
|
} else {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
while (HASHITEM_EMPTY(hi)) {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
if (strncmp("g:", xp->xp_pattern, 2) == 0) {
|
||||||
|
return cat_prefix_varname('g', hi->hi_key);
|
||||||
|
}
|
||||||
|
return hi->hi_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// b: variables
|
||||||
|
const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
|
||||||
|
if (bdone < ht->ht_used) {
|
||||||
|
if (bdone++ == 0) {
|
||||||
|
hi = ht->ht_array;
|
||||||
|
} else {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
while (HASHITEM_EMPTY(hi)) {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
return cat_prefix_varname('b', hi->hi_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// w: variables
|
||||||
|
ht = &prevwin_curwin()->w_vars->dv_hashtab;
|
||||||
|
if (wdone < ht->ht_used) {
|
||||||
|
if (wdone++ == 0) {
|
||||||
|
hi = ht->ht_array;
|
||||||
|
} else {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
while (HASHITEM_EMPTY(hi)) {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
return cat_prefix_varname('w', hi->hi_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// t: variables
|
||||||
|
ht = &curtab->tp_vars->dv_hashtab;
|
||||||
|
if (tdone < ht->ht_used) {
|
||||||
|
if (tdone++ == 0) {
|
||||||
|
hi = ht->ht_array;
|
||||||
|
} else {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
while (HASHITEM_EMPTY(hi)) {
|
||||||
|
hi++;
|
||||||
|
}
|
||||||
|
return cat_prefix_varname('t', hi->hi_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// v: variables
|
||||||
|
if (vidx < ARRAY_SIZE(vimvars)) {
|
||||||
|
return cat_prefix_varname('v', get_vim_var_name((VimVarIndex)vidx++));
|
||||||
|
}
|
||||||
|
|
||||||
|
XFREE_CLEAR(varnamebuf);
|
||||||
|
varnamebuflen = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set type of v: variable to the given type.
|
/// Set type of v: variable to the given type.
|
||||||
///
|
///
|
||||||
/// @param[in] idx Index of variable to set.
|
/// @param[in] idx Index of variable to set.
|
||||||
@@ -1680,6 +2140,17 @@ void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
|
|||||||
tv_dict_set_keys_readonly(val);
|
tv_dict_set_keys_readonly(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set partial 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_partial(const VimVarIndex idx, partial_T *val)
|
||||||
|
{
|
||||||
|
typval_T *tv = get_vim_var_tv(idx);
|
||||||
|
tv->vval.v_partial = val;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set v:register if needed.
|
/// Set v:register if needed.
|
||||||
void set_reg_var(int c)
|
void set_reg_var(int c)
|
||||||
{
|
{
|
||||||
@@ -1939,6 +2410,148 @@ dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **
|
|||||||
return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL);
|
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.
|
||||||
|
///
|
||||||
|
/// @param[in] ht Hashtab to find variable in.
|
||||||
|
/// @param[in] htname Hashtab name (first character).
|
||||||
|
/// @param[in] varname Variable name.
|
||||||
|
/// @param[in] varname_len Variable name length.
|
||||||
|
/// @param[in] no_autoload If true then autoload scripts will not be sourced
|
||||||
|
/// if autoload variable was not found.
|
||||||
|
///
|
||||||
|
/// @return pointer to the dictionary item with the found variable or NULL if it
|
||||||
|
/// was not found.
|
||||||
|
dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const varname,
|
||||||
|
const size_t varname_len, int no_autoload)
|
||||||
|
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
if (varname_len == 0) {
|
||||||
|
// Must be something like "s:", otherwise "ht" would be NULL.
|
||||||
|
switch (htname) {
|
||||||
|
case 's':
|
||||||
|
return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
|
||||||
|
case 'g':
|
||||||
|
return (dictitem_T *)&globvars_var;
|
||||||
|
case 'v':
|
||||||
|
return (dictitem_T *)&vimvars_var;
|
||||||
|
case 'b':
|
||||||
|
return (dictitem_T *)&curbuf->b_bufvar;
|
||||||
|
case 'w':
|
||||||
|
return (dictitem_T *)&curwin->w_winvar;
|
||||||
|
case 't':
|
||||||
|
return (dictitem_T *)&curtab->tp_winvar;
|
||||||
|
case 'l':
|
||||||
|
return get_funccal_local_var();
|
||||||
|
case 'a':
|
||||||
|
return get_funccal_args_var();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashitem_T *hi = hash_find_len(ht, varname, varname_len);
|
||||||
|
if (HASHITEM_EMPTY(hi)) {
|
||||||
|
// For global variables we may try auto-loading the script. If it
|
||||||
|
// worked find the variable again. Don't auto-load a script if it was
|
||||||
|
// loaded already, otherwise it would be loaded every time when
|
||||||
|
// checking if a function name is a Funcref variable.
|
||||||
|
if (ht == get_globvar_ht() && !no_autoload) {
|
||||||
|
// Note: script_autoload() may make "hi" invalid. It must either
|
||||||
|
// be obtained again or not used.
|
||||||
|
if (!script_autoload(varname, varname_len, false) || aborting()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
hi = hash_find_len(ht, varname, varname_len);
|
||||||
|
}
|
||||||
|
if (HASHITEM_EMPTY(hi)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TV_DICT_HI2DI(hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the dict (g:, l:, s:, …) and hashtable used for a variable.
|
||||||
|
///
|
||||||
|
/// Assigns SID if s: scope is accessed from Lua or anonymous Vimscript. #15994
|
||||||
|
///
|
||||||
|
/// @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.
|
||||||
|
/// @param[out] d Scope dictionary.
|
||||||
|
///
|
||||||
|
/// @return Scope hashtab, NULL if name is not valid.
|
||||||
|
static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
|
||||||
|
dict_T **d)
|
||||||
|
{
|
||||||
|
funccall_T *funccal = get_funccal();
|
||||||
|
*d = NULL;
|
||||||
|
|
||||||
|
if (name_len == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (name_len == 1 || name[1] != ':') {
|
||||||
|
// name has implicit scope
|
||||||
|
if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
|
||||||
|
// The name must not start with a colon or #.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*varname = name;
|
||||||
|
|
||||||
|
// "version" is "v:version" in all scopes
|
||||||
|
hashitem_T *hi = hash_find_len(&compat_hashtab, name, name_len);
|
||||||
|
if (!HASHITEM_EMPTY(hi)) {
|
||||||
|
return &compat_hashtab;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (funccal == NULL) { // global variable
|
||||||
|
*d = get_globvar_dict();
|
||||||
|
} else { // l: variable
|
||||||
|
*d = &funccal->fc_l_vars;
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
*varname = name + 2;
|
||||||
|
if (*name == 'g') { // global variable
|
||||||
|
*d = get_globvar_dict();
|
||||||
|
} else if (name_len > 2
|
||||||
|
&& (memchr(name + 2, ':', name_len - 2) != NULL
|
||||||
|
|| memchr(name + 2, AUTOLOAD_CHAR, name_len - 2) != NULL)) {
|
||||||
|
// There must be no ':' or '#' in the rest of the name if g: was not used
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*name == 'b') { // buffer variable
|
||||||
|
*d = curbuf->b_vars;
|
||||||
|
} else if (*name == 'w') { // window variable
|
||||||
|
*d = curwin->w_vars;
|
||||||
|
} else if (*name == 't') { // tab page variable
|
||||||
|
*d = curtab->tp_vars;
|
||||||
|
} else if (*name == 'v') { // v: variable
|
||||||
|
*d = get_vimvar_dict();
|
||||||
|
} else if (*name == 'a' && funccal != NULL) { // function argument
|
||||||
|
*d = &funccal->fc_l_avars;
|
||||||
|
} else if (*name == 'l' && funccal != NULL) { // local variable
|
||||||
|
*d = &funccal->fc_l_vars;
|
||||||
|
} else if (*name == 's' // script variable
|
||||||
|
&& (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR
|
||||||
|
|| current_sctx.sc_sid == SID_LUA)
|
||||||
|
&& current_sctx.sc_sid <= script_items.ga_len) {
|
||||||
|
// For anonymous scripts without a script item, create one now so script vars can be used
|
||||||
|
// Try to resolve lua filename & linenr so it can be shown in last-set messages.
|
||||||
|
nlua_set_sctx(¤t_sctx);
|
||||||
|
if (current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) {
|
||||||
|
// Create SID if s: scope is accessed from Lua or anon Vimscript. #15994
|
||||||
|
new_script_item(NULL, ¤t_sctx.sc_sid);
|
||||||
|
}
|
||||||
|
*d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return *d ? &(*d)->dv_hashtab : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the hashtable used for a variable
|
/// Find the hashtable used for a variable
|
||||||
///
|
///
|
||||||
/// @param[in] name Variable name, possibly with scope prefix.
|
/// @param[in] name Variable name, possibly with scope prefix.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "nvim/option_defs.h" // IWYU pragma: keep
|
#include "nvim/option_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include "eval/vars.h.generated.h"
|
/// Array mapping values from MessagePackType to corresponding list pointers
|
||||||
|
extern const list_T *eval_msgpack_type_lists[NUM_MSGPACK_TYPES];
|
||||||
|
|
||||||
#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars)
|
#include "eval/vars.h.generated.h"
|
||||||
#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user