From 8ee7c94a92598d46b488b7fe3b1a5cff6b1bf94a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 25 Aug 2019 22:01:35 +0200 Subject: lua: add vim.fn.{func} for direct access to vimL function compared to vim.api.|nvim_call_function|, this fixes some typing issues due to the indirect conversion via the API. float values are preserved as such (fixes #9389) as well as empty dicts/arrays. Ref https://github.com/norcalli/nvim.lua for the call syntax --- src/nvim/lua/converter.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 9665655e74..844232c64a 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -401,6 +401,8 @@ nlua_pop_typval_table_processing_end: return ret; } +static bool typval_conv_special = false; + #define TYPVAL_ENCODE_ALLOW_SPECIALS true #define TYPVAL_ENCODE_CONV_NIL(tv) \ @@ -439,7 +441,13 @@ nlua_pop_typval_table_processing_end: lua_createtable(lstate, 0, 0) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary) + do { \ + if (typval_conv_special) { \ + nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ + } else { \ + lua_createtable(lstate, 0, 0); \ + } \ + } while (0) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ do { \ @@ -548,9 +556,11 @@ nlua_pop_typval_table_processing_end: /// @param[in] tv typval_T to convert. /// /// @return true in case of success, false otherwise. -bool nlua_push_typval(lua_State *lstate, typval_T *const tv) +bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) { + typval_conv_special = special; const int initial_size = lua_gettop(lstate); + if (!lua_checkstack(lstate, initial_size + 2)) { emsgf(_("E1502: Lua failed to grow stack to %i"), initial_size + 4); return false; -- cgit From 474d0bcbf724c7eed740f60391a0ed35d651e1d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 27 Oct 2019 20:49:03 +0100 Subject: lua: vim.rpcrequest, vim.rpcnotify, vim.NIL --- src/nvim/lua/converter.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 844232c64a..44fe60e9c8 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -377,6 +377,19 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) nlua_pop_typval_table_processing_end: break; } + case LUA_TUSERDATA: { + nlua_pushref(lstate, nlua_nil_ref); + bool is_nil = lua_rawequal(lstate, -2, -1); + lua_pop(lstate, 1); + if (is_nil) { + cur.tv->v_type = VAR_SPECIAL; + cur.tv->vval.v_special = kSpecialVarNull; + } else { + EMSG(_("E5101: Cannot convert given lua type")); + ret = false; + } + break; + } default: { EMSG(_("E5101: Cannot convert given lua type")); ret = false; @@ -406,7 +419,13 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_ALLOW_SPECIALS true #define TYPVAL_ENCODE_CONV_NIL(tv) \ - lua_pushnil(lstate) + do { \ + if (typval_conv_special) { \ + lua_pushnil(lstate); \ + } else { \ + nlua_pushref(lstate, nlua_nil_ref); \ + } \ + } while (0) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ lua_pushboolean(lstate, (bool)(num)) @@ -718,7 +737,11 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special) { switch (obj.type) { case kObjectTypeNil: { - lua_pushnil(lstate); + if (special) { + lua_pushnil(lstate); + } else { + nlua_pushref(lstate, nlua_nil_ref); + } break; } case kObjectTypeLuaRef: { @@ -1152,6 +1175,19 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) break; } + case LUA_TUSERDATA: { + nlua_pushref(lstate, nlua_nil_ref); + bool is_nil = lua_rawequal(lstate, -2, -1); + lua_pop(lstate, 1); + if (is_nil) { + *cur.obj = NIL; + } else { + api_set_error(err, kErrorTypeValidation, + "Cannot convert userdata"); + } + break; + } + default: { type_error: api_set_error(err, kErrorTypeValidation, -- cgit From 001e69cd4602e84219fd7cfd8ade62f0cb24097c Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Tue, 26 Nov 2019 07:15:14 -0500 Subject: doc: fix typos close #11459 --- src/nvim/lua/converter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 44fe60e9c8..09d1a68898 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -1225,7 +1225,7 @@ GENERATE_INDEX_FUNCTION(Tabpage) #undef GENERATE_INDEX_FUNCTION -/// Record some auxilary values in vim module +/// Record some auxiliary values in vim module /// /// Assumes that module table is on top of the stack. /// -- cgit From ea4127e9a7a624484f51c21e17f37c766da15da0 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 27 Nov 2019 20:45:41 +0100 Subject: lua: metatable for empty dict value --- src/nvim/lua/converter.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 09d1a68898..fca74b5901 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -156,6 +156,13 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) && other_keys_num == 0 && ret.string_keys_num == 0)) { ret.type = kObjectTypeArray; + if (tsize == 0 && lua_getmetatable(lstate, -1)) { + nlua_pushref(lstate, nlua_empty_dict_ref); + if (lua_rawequal(lstate, -2, -1)) { + ret.type = kObjectTypeDictionary; + } + lua_pop(lstate, 2); + } } else if (ret.string_keys_num == tsize) { ret.type = kObjectTypeDictionary; } else { @@ -465,6 +472,8 @@ static bool typval_conv_special = false; nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ } else { \ lua_createtable(lstate, 0, 0); \ + nlua_pushref(lstate, nlua_empty_dict_ref); \ + lua_setmetatable(lstate, -2); \ } \ } while (0) @@ -695,6 +704,10 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); } else { lua_createtable(lstate, 0, (int)dict.size); + if (dict.size == 0 && !special) { + nlua_pushref(lstate, nlua_empty_dict_ref); + lua_setmetatable(lstate, -2); + } } for (size_t i = 0; i < dict.size; i++) { nlua_push_String(lstate, dict.items[i].key, special); -- cgit From 1805fb469a39d998f9bef0415999aa835d051044 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Tue, 28 Apr 2020 23:21:50 +0800 Subject: vim-patch:8.2.0111: VAR_SPECIAL is also used for booleans Problem: VAR_SPECIAL is also used for booleans. Solution: Add VAR_BOOL for better type checking. https://github.com/vim/vim/commit/9b4a15d5dba354d2e1e02871470bad103f34769a --- src/nvim/lua/converter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index fca74b5901..69114c967d 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -286,10 +286,10 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) break; } case LUA_TBOOLEAN: { - cur.tv->v_type = VAR_SPECIAL; - cur.tv->vval.v_special = (lua_toboolean(lstate, -1) - ? kSpecialVarTrue - : kSpecialVarFalse); + cur.tv->v_type = VAR_BOOL; + cur.tv->vval.v_bool = (lua_toboolean(lstate, -1) + ? kBoolVarTrue + : kBoolVarFalse); break; } case LUA_TSTRING: { -- cgit From 971a191c4d772493535d55524b994fe385fae546 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 19 Jun 2020 00:23:30 -0400 Subject: lua: Add ability to pass lua functions directly to vimL --- src/nvim/lua/converter.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 69114c967d..9fc4ca7e7e 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -19,6 +19,7 @@ #include "nvim/globals.h" #include "nvim/message.h" #include "nvim/eval/typval.h" +#include "nvim/eval/userfunc.h" #include "nvim/ascii.h" #include "nvim/macros.h" @@ -50,6 +51,7 @@ typedef struct { #define LUA_PUSH_STATIC_STRING(lstate, s) \ lua_pushlstring(lstate, s, sizeof(s) - 1) + static LuaTableProps nlua_traverse_table(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { @@ -384,6 +386,20 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) nlua_pop_typval_table_processing_end: break; } + case LUA_TFUNCTION: { + LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); + + state->lua_callable.func_ref = nlua_ref(lstate, -1); + + char_u *name = register_cfunc( + &nlua_CFunction_func_call, + &nlua_CFunction_func_free, + state); + + cur.tv->v_type = VAR_FUNC; + cur.tv->vval.v_string = vim_strsave(name); + break; + } case LUA_TUSERDATA: { nlua_pushref(lstate, nlua_nil_ref); bool is_nil = lua_rawequal(lstate, -2, -1); -- cgit From 6360cf7ce87407bd8a519b9a17f45b2148291904 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Tue, 30 Jun 2020 02:05:06 -0400 Subject: lua: Add ability to pass tables with __call vim-patch:8.2.1054: not so easy to pass a lua function to Vim vim-patch:8.2.1084: Lua: registering function has useless code I think I have also opened up the possibility for people to use these callbacks elsewhere, since I've added a new struct that we should be able to use. Also, this should allow us to determine what the state of a list is in Lua or a dictionary in Lua, since we now can track the luaref as we go. --- src/nvim/lua/converter.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/converter.c') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 9fc4ca7e7e..32e804d213 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -316,6 +316,13 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) break; } case LUA_TTABLE: { + // Only need to track table refs if we have a metatable associated. + LuaRef table_ref = LUA_NOREF; + if (lua_getmetatable(lstate, -1)) { + lua_pop(lstate, 1); + table_ref = nlua_ref(lstate, -1); + } + const LuaTableProps table_props = nlua_traverse_table(lstate); for (size_t i = 0; i < kv_size(stack); i++) { @@ -331,6 +338,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) case kObjectTypeArray: { cur.tv->v_type = VAR_LIST; cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx); + cur.tv->vval.v_list->lua_table_ref = table_ref; tv_list_ref(cur.tv->vval.v_list); if (table_props.maxidx != 0) { cur.container = true; @@ -344,6 +352,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) cur.tv->v_type = VAR_DICT; cur.tv->vval.v_dict = tv_dict_alloc(); cur.tv->vval.v_dict->dv_refcount++; + cur.tv->vval.v_dict->lua_table_ref = table_ref; } else { cur.special = table_props.has_string_with_nul; if (table_props.has_string_with_nul) { @@ -354,11 +363,13 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) S_LEN("_VAL")); assert(val_di != NULL); cur.tv = &val_di->di_tv; + cur.tv->vval.v_list->lua_table_ref = table_ref; assert(cur.tv->v_type == VAR_LIST); } else { cur.tv->v_type = VAR_DICT; cur.tv->vval.v_dict = tv_dict_alloc(); cur.tv->vval.v_dict->dv_refcount++; + cur.tv->vval.v_dict->lua_table_ref = table_ref; } cur.container = true; cur.idx = lua_gettop(lstate); @@ -388,8 +399,8 @@ nlua_pop_typval_table_processing_end: } case LUA_TFUNCTION: { LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = nlua_ref(lstate, -1); + state->lua_callable.table_ref = LUA_NOREF; char_u *name = register_cfunc( &nlua_CFunction_func_call, -- cgit