aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.c43
-rw-r--r--src/nvim/lua/executor.c112
-rw-r--r--src/nvim/lua/vim.lua40
3 files changed, 152 insertions, 43 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 0f7008e150..5abdc33709 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -177,42 +177,47 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
return vim_to_object(&di->di_tv);
}
-/// Set a value in a scope dict. Objects are recursively expanded into their
-/// vimscript equivalents.
-///
-/// @param dict The vimscript dict
-/// @param key The key
-/// @param value The new value
-/// @param del Delete key in place of setting it. Argument `value` is ignored in
-/// this case.
-/// @param retval If true the old value will be converted and returned.
-/// @param[out] err Details of an error that may have occurred
-/// @return The old value if `retval` is true and the key was present, else NIL
-Object dict_set_var(dict_T *dict, String key, Object value, bool del,
- bool retval, Error *err)
+dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
{
- Object rv = OBJECT_INIT;
dictitem_T *di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di != NULL) {
if (di->di_flags & DI_FLAGS_RO) {
api_set_error(err, kErrorTypeException, "Key is read-only: %s", key.data);
- return rv;
} else if (di->di_flags & DI_FLAGS_LOCK) {
api_set_error(err, kErrorTypeException, "Key is locked: %s", key.data);
- return rv;
} else if (del && (di->di_flags & DI_FLAGS_FIX)) {
api_set_error(err, kErrorTypeException, "Key is fixed: %s", key.data);
- return rv;
}
} else if (dict->dv_lock) {
api_set_error(err, kErrorTypeException, "Dictionary is locked");
- return rv;
} else if (key.size == 0) {
api_set_error(err, kErrorTypeValidation, "Key name is empty");
- return rv;
} else if (key.size > INT_MAX) {
api_set_error(err, kErrorTypeValidation, "Key name is too long");
+ }
+
+ return di;
+}
+
+/// Set a value in a scope dict. Objects are recursively expanded into their
+/// vimscript equivalents.
+///
+/// @param dict The vimscript dict
+/// @param key The key
+/// @param value The new value
+/// @param del Delete key in place of setting it. Argument `value` is ignored in
+/// this case.
+/// @param retval If true the old value will be converted and returned.
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value if `retval` is true and the key was present, else NIL
+Object dict_set_var(dict_T *dict, String key, Object value, bool del,
+ bool retval, Error *err)
+{
+ Object rv = OBJECT_INIT;
+ dictitem_T *di = dict_check_writable(dict, key, del, err);
+
+ if (ERROR_SET(err)) {
return rv;
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index f99a2dd0fe..0a52cc16cb 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -471,6 +471,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_wait);
lua_setfield(lstate, -2, "wait");
+ // _getvar
+ lua_pushcfunction(lstate, &nlua_getvar);
+ lua_setfield(lstate, -2, "_getvar");
+
+ // _setvar
+ lua_pushcfunction(lstate, &nlua_setvar);
+ lua_setfield(lstate, -2, "_setvar");
+
+
// vim.loop
luv_set_loop(lstate, &main_loop.uv);
luv_set_callback(lstate, nlua_luv_cfpcall);
@@ -870,6 +879,109 @@ check_err:
return request ? 1 : 0;
}
+static dict_T *nlua_get_var_scope(lua_State *lstate) {
+ const char *scope = luaL_checkstring(lstate, 1);
+ handle_T handle = (handle_T)luaL_checkinteger(lstate, 2);
+ dict_T *dict = NULL;
+ Error err = ERROR_INIT;
+ if (strequal(scope, "g")) {
+ dict = &globvardict;
+ } else if (strequal(scope, "v")) {
+ dict = &vimvardict;
+ } else if (strequal(scope, "b")) {
+ buf_T *buf = find_buffer_by_handle(handle, &err);
+ if (buf) {
+ dict = buf->b_vars;
+ }
+ } else if (strequal(scope, "w")) {
+ win_T *win = find_window_by_handle(handle, &err);
+ if (win) {
+ dict = win->w_vars;
+ }
+ } else if (strequal(scope, "t")) {
+ tabpage_T *tabpage = find_tab_by_handle(handle, &err);
+ if (tabpage) {
+ dict = tabpage->tp_vars;
+ }
+ } else {
+ luaL_error(lstate, "invalid scope", err.msg);
+ return NULL;
+ }
+
+ if (ERROR_SET(&err)) {
+ luaL_error(lstate, "FAIL: %s", err.msg);
+ return NULL;
+ }
+ return dict;
+}
+
+
+static int nlua_getvar(lua_State *lstate)
+{
+ // non-local return if not found
+ dict_T *dict = nlua_get_var_scope(lstate);
+ size_t len;
+ const char *name = luaL_checklstring(lstate, 3, &len);
+
+ dictitem_T *di = tv_dict_find(dict, name, (ptrdiff_t)len);
+ if (di == NULL) {
+ return 0; // nil
+ }
+ nlua_push_typval(lstate, &di->di_tv, false);
+ return 1;
+}
+
+static int nlua_setvar(lua_State *lstate)
+{
+ // non-local return if not found
+ dict_T *dict = nlua_get_var_scope(lstate);
+ String key;
+ key.data = (char *)luaL_checklstring(lstate, 3, &key.size);
+
+ bool del = (lua_gettop(lstate) < 4) || lua_isnil(lstate, 4);
+
+ Error err = ERROR_INIT;
+ dictitem_T *di = dict_check_writable(dict, key, del, &err);
+ if (ERROR_SET(&err)) {
+ return 0;
+ }
+
+ if (del) {
+ // Delete the key
+ if (di == NULL) {
+ // Doesn't exist, nothing to do
+ return 0;
+ } else {
+ // Delete the entry
+ tv_dict_item_remove(dict, di);
+ }
+ } else {
+ // Update the key
+ typval_T tv;
+
+ // Convert the lua value to a vimscript type in the temporary variable
+ lua_pushvalue(lstate, 4);
+ if (!nlua_pop_typval(lstate, &tv)) {
+ return luaL_error(lstate, "Couldn't convert lua value");
+ }
+
+ if (di == NULL) {
+ // Need to create an entry
+ di = tv_dict_item_alloc_len(key.data, key.size);
+ tv_dict_add(dict, di);
+ } else {
+ // Clear the old value
+ tv_clear(&di->di_tv);
+ }
+
+ // Update the value
+ tv_copy(&tv, &di->di_tv);
+ // Clear the temporary variable
+ tv_clear(&tv);
+ }
+ return 0;
+}
+
static int nlua_nil_tostring(lua_State *lstate)
{
lua_pushstring(lstate, "vim.NIL");
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index a678432dda..bc0770da31 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -341,32 +341,24 @@ do
end
return setmetatable({}, mt)
end
- local function pcall_ret(status, ...)
- if status then return ... end
- end
- local function nil_wrap(fn)
- return function(...)
- return pcall_ret(pcall(fn, ...))
+ local function make_dict_accessor(scope)
+ validate {
+ scope = {scope, 's'};
+ }
+ local mt = {}
+ function mt:__newindex(k, v)
+ return vim._setvar(scope, 0, k, v)
end
+ function mt:__index(k)
+ return vim._getvar(scope, 0, k)
+ end
+ return setmetatable({}, mt)
end
-
- vim.b = make_meta_accessor(
- nil_wrap(function(v) return a.nvim_buf_get_var(0, v) end),
- function(v, k) return a.nvim_buf_set_var(0, v, k) end,
- function(v) return a.nvim_buf_del_var(0, v) end
- )
- vim.w = make_meta_accessor(
- nil_wrap(function(v) return a.nvim_win_get_var(0, v) end),
- function(v, k) return a.nvim_win_set_var(0, v, k) end,
- function(v) return a.nvim_win_del_var(0, v) end
- )
- vim.t = make_meta_accessor(
- nil_wrap(function(v) return a.nvim_tabpage_get_var(0, v) end),
- function(v, k) return a.nvim_tabpage_set_var(0, v, k) end,
- function(v) return a.nvim_tabpage_del_var(0, v) end
- )
- vim.g = make_meta_accessor(nil_wrap(a.nvim_get_var), a.nvim_set_var, a.nvim_del_var)
- vim.v = make_meta_accessor(nil_wrap(a.nvim_get_vvar), a.nvim_set_vvar)
+ vim.g = make_dict_accessor('g')
+ vim.v = make_dict_accessor('v')
+ vim.b = make_dict_accessor('b')
+ vim.w = make_dict_accessor('w')
+ vim.t = make_dict_accessor('t')
vim.o = make_meta_accessor(a.nvim_get_option, a.nvim_set_option)
local function getenv(k)