From 8c140be31f0d203b63e7052e698fdfe253e0b5d4 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 27 Jan 2022 12:46:56 +0100 Subject: feat(ts): expose minimum language version to lua (#17186) --- src/nvim/lua/executor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index cfdbe7b344..5c4d7e3c91 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "luv/luv.h" #include "nvim/api/private/defs.h" @@ -1267,6 +1268,12 @@ int tslua_get_language_version(lua_State *L) return 1; } +int tslua_get_minimum_language_version(lua_State *L) +{ + lua_pushnumber(L, TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION); + return 1; +} + static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { tslua_init(lstate); @@ -1288,6 +1295,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_get_language_version); lua_setfield(lstate, -2, "_ts_get_language_version"); + + lua_pushcfunction(lstate, tslua_get_minimum_language_version); + lua_setfield(lstate, -2, "_ts_get_minimum_language_version"); } int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char_u ***results) -- cgit From 2793fcae0ac2aef14c8f22636d579c68a97c0851 Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Fri, 28 Jan 2022 22:54:03 +0100 Subject: vim-patch:8.2.4241: some type casts are redundant Problem: Some type casts are redundant. Solution: Remove the type casts. (closes vim/vim#9643) https://github.com/vim/vim/commit/420fabcd4ffeaf79082a6e43db91e1d363f88f27 This is not a literal port but an equivalent one. --- src/nvim/lua/executor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5c4d7e3c91..cbfb8364f6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -682,7 +682,7 @@ int nlua_call(lua_State *lstate) typval_T vim_args[MAX_FUNC_ARGS + 1]; int i = 0; // also used for freeing the variables for (; i < nargs; i++) { - lua_pushvalue(lstate, (int)i+2); + lua_pushvalue(lstate, i+2); if (!nlua_pop_typval(lstate, &vim_args[i])) { api_set_error(&err, kErrorTypeException, "error converting argument %d", i+1); @@ -747,7 +747,7 @@ static int nlua_rpc(lua_State *lstate, bool request) Array args = ARRAY_DICT_INIT; for (int i = 0; i < nargs; i++) { - lua_pushvalue(lstate, (int)i+3); + lua_pushvalue(lstate, i+3); ADD(args, nlua_pop_Object(lstate, false, &err)); if (ERROR_SET(&err)) { api_free_array(args); -- cgit From adad10284d8e0e7d15189181a061b6b665663467 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 26 Jan 2022 10:23:59 +0000 Subject: refactor(lua): call loadfile internally .. instead of luaL_loadfile allows files to be cached --- src/nvim/lua/executor.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index cbfb8364f6..029e7eb660 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1241,6 +1241,9 @@ void ex_luafile(exarg_T *const eap) /// execute lua code from a file. /// +/// Note: we call the lua global loadfile as opposed to calling luaL_loadfile +/// in case loadfile has been overridden in the users environment. +/// /// @param path path of the file /// /// @return true if everything ok, false if there was an error (echoed) @@ -1249,11 +1252,30 @@ bool nlua_exec_file(const char *path) { lua_State *const lstate = global_lstate; - if (luaL_loadfile(lstate, path)) { + lua_getglobal(lstate, "loadfile"); + lua_pushstring(lstate, path); + + if (nlua_pcall(lstate, 1, 2)) { + nlua_error(lstate, _("E5111: Error calling lua: %.*s")); + return false; + } + + // loadstring() returns either: + // 1. nil, error + // 2. chunk, nil + + if (lua_isnil(lstate, -2)) { + // 1 nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); + assert(lua_isnil(lstate, -1)); + lua_pop(lstate, 1); return false; } + // 2 + assert(lua_isnil(lstate, -1)); + lua_pop(lstate, 1); + if (nlua_pcall(lstate, 0, 0)) { nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); return false; -- cgit From 81bffbd147cd24580ac92fa9d9d85121151ca01f Mon Sep 17 00:00:00 2001 From: Oliver Marriott Date: Sat, 19 Feb 2022 22:56:50 +1100 Subject: feat: call __tostring on lua errors if possible before reporting to user --- src/nvim/lua/executor.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 029e7eb660..a61273084c 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -78,7 +78,22 @@ static void nlua_error(lua_State *const lstate, const char *const msg) FUNC_ATTR_NONNULL_ALL { size_t len; - const char *const str = lua_tolstring(lstate, -1, &len); + const char *str = NULL; + + if (luaL_getmetafield(lstate, -1, "__tostring")) { + if (lua_isfunction(lstate, -1) && luaL_callmeta(lstate, -2, "__tostring")) { + // call __tostring, convert the result and pop result. + str = lua_tolstring(lstate, -1, &len); + lua_pop(lstate, 1); + } + // pop __tostring. + lua_pop(lstate, 1); + } + + if (!str) { + // defer to lua default conversion, this will render tables as [NULL]. + str = lua_tolstring(lstate, -1, &len); + } msg_ext_set_kind("lua_error"); semsg_multiline(msg, (int)len, str); -- cgit From b87867e69e94d9784468a126f21c721446f080de Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 11 Sep 2021 11:48:58 +0900 Subject: feat(lua): add proper support of luv threads --- src/nvim/lua/executor.c | 460 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 380 insertions(+), 80 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 029e7eb660..38f21a933e 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -45,11 +45,22 @@ static int in_fast_callback = 0; // Initialized in nlua_init(). static lua_State *global_lstate = NULL; +static uv_thread_t main_thread; + typedef struct { Error err; String lua_err_str; } LuaError; +typedef struct { + LuaRef nil_ref; + LuaRef empty_dict_ref; + int ref_count; +#if __has_feature(address_sanitizer) + PMap(handle_T) ref_markers; +#endif +} nlua_ref_state_t; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/executor.c.generated.h" # include "lua/vim_module.generated.h" @@ -65,11 +76,16 @@ typedef struct { } #if __has_feature(address_sanitizer) -static PMap(handle_T) nlua_ref_markers = MAP_INIT; static bool nlua_track_refs = false; # define NLUA_TRACK_REFS #endif +typedef enum luv_err_type { + kCallback, + kThread, + kThreadCallback, +} luv_err_t; + /// Convert lua error into a Vim error message /// /// @param lstate Lua interpreter state. @@ -122,8 +138,21 @@ static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL static void nlua_luv_error_event(void **argv) { char *error = (char *)argv[0]; + luv_err_t type = (luv_err_t)(intptr_t)argv[1]; msg_ext_set_kind("lua_error"); - semsg_multiline("Error executing luv callback:\n%s", error); + switch (type) { + case kCallback: + semsg_multiline("Error executing luv callback:\n%s", error); + break; + case kThread: + semsg_multiline("Error in luv thread:\n%s", error); + break; + case kThreadCallback: + semsg_multiline("Error in luv callback, thread:\n%s", error); + break; + default: + break; + } xfree(error); } @@ -148,7 +177,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags const char *error = lua_tostring(lstate, -1); multiqueue_put(main_loop.events, nlua_luv_error_event, - 1, xstrdup(error)); + 2, xstrdup(error), (intptr_t)kCallback); lua_pop(lstate, 1); // error message retval = -status; } else { // LUA_OK @@ -162,6 +191,106 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags return retval; } +static int nlua_luv_thread_cb_cfpcall(lua_State *lstate, int nargs, int nresult, + int flags) +{ + return nlua_luv_thread_common_cfpcall(lstate, nargs, nresult, flags, true); +} + +static int nlua_luv_thread_cfpcall(lua_State *lstate, int nargs, int nresult, + int flags) + FUNC_ATTR_NONNULL_ALL +{ + return nlua_luv_thread_common_cfpcall(lstate, nargs, nresult, flags, false); +} + +static int nlua_luv_thread_cfcpcall(lua_State *lstate, lua_CFunction func, + void *ud, int flags) + FUNC_ATTR_NONNULL_ARG(1, 2) +{ + lua_pushcfunction(lstate, func); + lua_pushlightuserdata(lstate, ud); + int retval = nlua_luv_thread_cfpcall(lstate, 1, 0, flags); + return retval; +} + +static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nresult, + int flags, bool is_callback) + FUNC_ATTR_NONNULL_ALL +{ + int retval; + + int top = lua_gettop(lstate); + int status = lua_pcall(lstate, nargs, nresult, 0); + if (status) { + if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { + // Terminate this thread, as the main thread may be able to continue + // execution. + mch_errmsg(e_outofmem); + mch_errmsg("\n"); + lua_close(lstate); +#ifdef WIN32 + ExitThread(0); +#else + pthread_exit(0); +#endif + } + const char *error = lua_tostring(lstate, -1); + + loop_schedule_deferred(&main_loop, + event_create(nlua_luv_error_event, 2, + xstrdup(error), + is_callback + ? (intptr_t)kThreadCallback + : (intptr_t)kThread)); + lua_pop(lstate, 1); // error message + retval = -status; + } else { // LUA_OK + if (nresult == LUA_MULTRET) { + nresult = lua_gettop(lstate) - top + nargs + 1; + } + retval = nresult; + } + + return retval; +} + +static int nlua_thr_api_nvim__get_runtime(lua_State *lstate) +{ + if (lua_gettop(lstate) != 3) { + return luaL_error(lstate, "Expected 3 arguments"); + } + + luaL_checktype(lstate, -1, LUA_TTABLE); + lua_getfield(lstate, -1, "is_lua"); + if (!lua_isboolean(lstate, -1)) { + return luaL_error(lstate, "is_lua is not a boolean"); + } + bool is_lua = lua_toboolean(lstate, -1); + lua_pop(lstate, 2); + + luaL_checktype(lstate, -1, LUA_TBOOLEAN); + bool all = lua_toboolean(lstate, -1); + lua_pop(lstate, 1); + + Error err = ERROR_INIT; + const Array pat = nlua_pop_Array(lstate, &err); + if (ERROR_SET(&err)) { + luaL_where(lstate, 1); + lua_pushstring(lstate, err.msg); + api_clear_error(&err); + lua_concat(lstate, 2); + return lua_error(lstate); + } + + ArrayOf(String) ret = runtime_get_named_thread(is_lua, pat, all); + nlua_push_Array(lstate, ret, true); + api_free_array(ret); + api_free_array(pat); + + return 1; +} + static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; @@ -302,6 +431,157 @@ static int nlua_wait(lua_State *lstate) return 2; } +static nlua_ref_state_t *nlua_new_ref_state(lua_State *lstate, bool is_thread) + FUNC_ATTR_NONNULL_ALL +{ + nlua_ref_state_t *ref_state = lua_newuserdata(lstate, sizeof(*ref_state)); + memset(ref_state, 0, sizeof(*ref_state)); + ref_state->nil_ref = LUA_NOREF; + ref_state->empty_dict_ref = LUA_NOREF; + return ref_state; +} + +static nlua_ref_state_t *nlua_get_ref_state(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + lua_getfield(lstate, LUA_REGISTRYINDEX, "nlua.ref_state"); + nlua_ref_state_t *ref_state = lua_touserdata(lstate, -1); + lua_pop(lstate, 1); + + return ref_state; +} + +LuaRef nlua_get_nil_ref(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + return ref_state->nil_ref; +} + +LuaRef nlua_get_empty_dict_ref(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + return ref_state->empty_dict_ref; +} + +static int nlua_get_ref_count(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + return ref_state->ref_count; +} + +int nlua_get_global_ref_count(void) +{ + lua_State *const lstate = global_lstate; + return nlua_get_ref_count(lstate); +} + +static void nlua_common_vim_init(lua_State *lstate, bool is_thread) + FUNC_ATTR_NONNULL_ARG(1) +{ + nlua_ref_state_t *ref_state = nlua_new_ref_state(lstate, is_thread); + lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.ref_state"); + + // vim.is_thread + lua_pushboolean(lstate, is_thread); + lua_setfield(lstate, LUA_REGISTRYINDEX, "nvim.thread"); + lua_pushcfunction(lstate, &nlua_is_thread); + lua_setfield(lstate, -2, "is_thread"); + + // vim.NIL + lua_newuserdata(lstate, 0); + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, &nlua_nil_tostring); + lua_setfield(lstate, -2, "__tostring"); + lua_setmetatable(lstate, -2); + ref_state->nil_ref = nlua_ref(lstate, -1); + lua_pushvalue(lstate, -1); + lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.NIL"); + lua_setfield(lstate, -2, "NIL"); + + // vim._empty_dict_mt + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, &nlua_empty_dict_tostring); + lua_setfield(lstate, -2, "__tostring"); + ref_state->empty_dict_ref = nlua_ref(lstate, -1); + lua_pushvalue(lstate, -1); + lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict"); + lua_setfield(lstate, -2, "_empty_dict_mt"); + + // vim.loop + if (is_thread) { + luv_set_callback(lstate, nlua_luv_thread_cb_cfpcall); + luv_set_thread(lstate, nlua_luv_thread_cfpcall); + luv_set_cthread(lstate, nlua_luv_thread_cfcpcall); + } else { + luv_set_loop(lstate, &main_loop.uv); + luv_set_callback(lstate, nlua_luv_cfpcall); + } + luaopen_luv(lstate); + lua_pushvalue(lstate, -1); + lua_setfield(lstate, -3, "loop"); + + // package.loaded.luv = vim.loop + // otherwise luv will be reinitialized when require'luv' + lua_getglobal(lstate, "package"); + lua_getfield(lstate, -1, "loaded"); + lua_pushvalue(lstate, -3); + lua_setfield(lstate, -2, "luv"); + lua_pop(lstate, 3); +} + +static void nlua_common_package_init(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + { + const char *code = (char *)&shared_module[0]; + if (luaL_loadbuffer(lstate, code, sizeof(shared_module) - 1, "@vim/shared.lua") + || nlua_pcall(lstate, 0, 0)) { + nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n")); + return; + } + } + + { + const char *code = (char *)&lua_load_package_module[0]; + if (luaL_loadbuffer(lstate, code, sizeof(lua_load_package_module) - 1, "@vim/_load_package.lua") + || lua_pcall(lstate, 0, 0, 0)) { + nlua_error(lstate, _("E5106: Error while creating _load_package module: %.*s")); + return; + } + } + + { + lua_getglobal(lstate, "package"); // [package] + lua_getfield(lstate, -1, "loaded"); // [package, loaded] + + const char *code = (char *)&inspect_module[0]; + if (luaL_loadbuffer(lstate, code, sizeof(inspect_module) - 1, "@vim/inspect.lua") + || nlua_pcall(lstate, 0, 1)) { + nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s\n")); + return; + } + + // [package, loaded, inspect] + lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded] + } + + { + const char *code = (char *)&lua_F_module[0]; + if (luaL_loadbuffer(lstate, code, sizeof(lua_F_module) - 1, "@vim/F.lua") + || nlua_pcall(lstate, 0, 1)) { + nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s\n")); + return; + } + // [package, loaded, module] + lua_setfield(lstate, -2, "vim.F"); // [package, loaded] + + lua_pop(lstate, 2); // [] + } +} + /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -362,80 +642,22 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_wait); lua_setfield(lstate, -2, "wait"); - // vim.NIL - lua_newuserdata(lstate, 0); - lua_createtable(lstate, 0, 0); - lua_pushcfunction(lstate, &nlua_nil_tostring); - lua_setfield(lstate, -2, "__tostring"); - lua_setmetatable(lstate, -2); - nlua_nil_ref = nlua_ref(lstate, -1); - lua_pushvalue(lstate, -1); - lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.NIL"); - lua_setfield(lstate, -2, "NIL"); - - // vim._empty_dict_mt - lua_createtable(lstate, 0, 0); - lua_pushcfunction(lstate, &nlua_empty_dict_tostring); - lua_setfield(lstate, -2, "__tostring"); - nlua_empty_dict_ref = nlua_ref(lstate, -1); - lua_pushvalue(lstate, -1); - lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict"); - lua_setfield(lstate, -2, "_empty_dict_mt"); + nlua_common_vim_init(lstate, false); // internal vim._treesitter... API nlua_add_treesitter(lstate); - // vim.loop - luv_set_loop(lstate, &main_loop.uv); - luv_set_callback(lstate, nlua_luv_cfpcall); - luaopen_luv(lstate); - lua_pushvalue(lstate, -1); - lua_setfield(lstate, -3, "loop"); - - // package.loaded.luv = vim.loop - // otherwise luv will be reinitialized when require'luv' - lua_getglobal(lstate, "package"); - lua_getfield(lstate, -1, "loaded"); - lua_pushvalue(lstate, -3); - lua_setfield(lstate, -2, "luv"); - lua_pop(lstate, 3); - - nlua_state_add_stdlib(lstate); + nlua_state_add_stdlib(lstate, false); lua_setglobal(lstate, "vim"); - { - const char *code = (char *)&shared_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(shared_module) - 1, "@vim/shared.lua") - || nlua_pcall(lstate, 0, 0)) { - nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n")); - return 1; - } - } + nlua_common_package_init(lstate); { lua_getglobal(lstate, "package"); // [package] lua_getfield(lstate, -1, "loaded"); // [package, loaded] - const char *code = (char *)&inspect_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(inspect_module) - 1, "@vim/inspect.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s\n")); - return 1; - } - // [package, loaded, inspect] - lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded] - - code = (char *)&lua_F_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_F_module) - 1, "@vim/F.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s\n")); - return 1; - } - // [package, loaded, module] - lua_setfield(lstate, -2, "vim.F"); // [package, loaded] - - code = (char *)&lua_filetype_module[0]; + char *code = (char *)&lua_filetype_module[0]; if (luaL_loadbuffer(lstate, code, sizeof(lua_filetype_module) - 1, "@vim/filetype.lua") || nlua_pcall(lstate, 0, 1)) { nlua_error(lstate, _("E5106: Error while creating vim.filetype module: %.*s")); @@ -495,9 +717,60 @@ void nlua_init(void) luaL_openlibs(lstate); nlua_state_init(lstate); + luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem); + global_lstate = lstate; + + main_thread = uv_thread_self(); } +static lua_State *nlua_thread_acquire_vm(void) +{ + // If it is called from the main thread, it will attempt to rebuild the cache. + const uv_thread_t self = uv_thread_self(); + if (uv_thread_equal(&main_thread, &self)) { + runtime_search_path_validate(); + } + + lua_State *lstate = luaL_newstate(); + + // Add in the lua standard libraries + luaL_openlibs(lstate); + + // print + lua_pushcfunction(lstate, &nlua_print); + lua_setglobal(lstate, "print"); + + lua_pushinteger(lstate, 0); + lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.refcount"); + + // vim + lua_newtable(lstate); + + nlua_common_vim_init(lstate, true); + + nlua_state_add_stdlib(lstate, true); + + lua_setglobal(lstate, "vim"); + + nlua_common_package_init(lstate); + + lua_getglobal(lstate, "vim"); + lua_getglobal(lstate, "package"); + lua_getfield(lstate, -1, "loaded"); + lua_getfield(lstate, -1, "vim.inspect"); + lua_setfield(lstate, -4, "inspect"); + lua_pop(lstate, 3); + + lua_getglobal(lstate, "vim"); + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); + lua_setfield(lstate, -2, "nvim__get_runtime"); + lua_setfield(lstate, -2, "api"); + lua_pop(lstate, 1); + + return lstate; +} void nlua_free_all_mem(void) { @@ -505,26 +778,30 @@ void nlua_free_all_mem(void) return; } lua_State *lstate = global_lstate; + nlua_common_free_all_mem(lstate); +} - nlua_unref(lstate, nlua_nil_ref); - nlua_unref(lstate, nlua_empty_dict_ref); +static void nlua_common_free_all_mem(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + nlua_unref(lstate, nlua_get_nil_ref(lstate)); + nlua_unref(lstate, nlua_get_empty_dict_ref(lstate)); #ifdef NLUA_TRACK_REFS - if (nlua_refcount) { - fprintf(stderr, "%d lua references were leaked!", nlua_refcount); + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + if (ref_state->ref_count) { + fprintf(stderr, "%d lua references were leaked!", ref_state->ref_count); } if (nlua_track_refs) { // in case there are leaked luarefs, leak the associated memory // to get LeakSanitizer stacktraces on exit - pmap_destroy(handle_T)(&nlua_ref_markers); + pmap_destroy(handle_T)(&ref_state->ref_markers); } #endif - nlua_refcount = 0; lua_close(lstate); } - static void nlua_print_event(void **argv) { char *str = argv[0]; @@ -602,9 +879,18 @@ static int nlua_print(lua_State *const lstate) #undef PRINT_ERROR ga_append(&msg_ga, NUL); - if (in_fast_callback) { + lua_getfield(lstate, LUA_REGISTRYINDEX, "nvim.thread"); + bool is_thread = lua_toboolean(lstate, -1); + lua_pop(lstate, 1); + + if (is_thread) { + loop_schedule_deferred(&main_loop, + event_create(nlua_print_event, 2, + msg_ga.ga_data, + (intptr_t)msg_ga.ga_len)); + } else if (in_fast_callback) { multiqueue_put(main_loop.events, nlua_print_event, - 2, msg_ga.ga_data, msg_ga.ga_len); + 2, msg_ga.ga_data, (intptr_t)msg_ga.ga_len); } else { nlua_print_event((void *[]){ msg_ga.ga_data, (void *)(intptr_t)msg_ga.ga_len }); @@ -613,10 +899,12 @@ static int nlua_print(lua_State *const lstate) nlua_print_error: ga_clear(&msg_ga); + char *buff = xmalloc(IOSIZE); const char *fmt = _("E5114: Error while converting print argument #%i: %.*s"); - size_t len = (size_t)vim_snprintf((char *)IObuff, IOSIZE, fmt, curargidx, + size_t len = (size_t)vim_snprintf(buff, IOSIZE, fmt, curargidx, (int)errmsg_len, errmsg); - lua_pushlstring(lstate, (char *)IObuff, len); + lua_pushlstring(lstate, buff, len); + xfree(buff); return lua_error(lstate); } @@ -806,16 +1094,19 @@ static int nlua_getenv(lua_State *lstate) /// add the value to the registry +/// The current implementation does not support calls from threads. LuaRef nlua_ref(lua_State *lstate, int index) { + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + lua_pushvalue(lstate, index); LuaRef ref = luaL_ref(lstate, LUA_REGISTRYINDEX); if (ref > 0) { - nlua_refcount++; + ref_state->ref_count++; #ifdef NLUA_TRACK_REFS if (nlua_track_refs) { // dummy allocation to make LeakSanitizer track our luarefs - pmap_put(handle_T)(&nlua_ref_markers, ref, xmalloc(3)); + pmap_put(handle_T)(&ref_state->ref_markers, ref, xmalloc(3)); } #endif } @@ -825,12 +1116,14 @@ LuaRef nlua_ref(lua_State *lstate, int index) /// remove the value from the registry void nlua_unref(lua_State *lstate, LuaRef ref) { + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + if (ref > 0) { - nlua_refcount--; + ref_state->ref_count--; #ifdef NLUA_TRACK_REFS // NB: don't remove entry from map to track double-unref if (nlua_track_refs) { - xfree(pmap_get(handle_T)(&nlua_ref_markers, ref)); + xfree(pmap_get(handle_T)(&ref_state->ref_markers, ref)); } #endif luaL_unref(lstate, LUA_REGISTRYINDEX, ref); @@ -1391,6 +1684,13 @@ cleanup: return ret; } +static int nlua_is_thread(lua_State *lstate) +{ + lua_getfield(lstate, LUA_REGISTRYINDEX, "nvim.thread"); + + return 1; +} + // Required functions for lua c functions as VimL callbacks int nlua_CFunction_func_call(int argcount, typval_T *argvars, typval_T *rettv, void *state) -- cgit From acf38245d8961125f02d4c4168053e0d83dbc6df Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 25 Dec 2021 14:38:26 +0100 Subject: refactor(lua): use references directly on main thread --- src/nvim/lua/executor.c | 64 ++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 35 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 38f21a933e..d207f48435 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -52,15 +52,6 @@ typedef struct { String lua_err_str; } LuaError; -typedef struct { - LuaRef nil_ref; - LuaRef empty_dict_ref; - int ref_count; -#if __has_feature(address_sanitizer) - PMap(handle_T) ref_markers; -#endif -} nlua_ref_state_t; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/executor.c.generated.h" # include "lua/vim_module.generated.h" @@ -296,7 +287,7 @@ static void nlua_schedule_event(void **argv) LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; lua_State *const lstate = global_lstate; nlua_pushref(lstate, cb); - nlua_unref(lstate, cb); + nlua_unref_global(lstate, cb); if (nlua_pcall(lstate, 0, 0)) { nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s")); } @@ -313,7 +304,7 @@ static int nlua_schedule(lua_State *const lstate) return lua_error(lstate); } - LuaRef cb = nlua_ref(lstate, 1); + LuaRef cb = nlua_ref_global(lstate, 1); multiqueue_put(main_loop.events, nlua_schedule_event, 1, (void *)(ptrdiff_t)cb); @@ -438,6 +429,9 @@ static nlua_ref_state_t *nlua_new_ref_state(lua_State *lstate, bool is_thread) memset(ref_state, 0, sizeof(*ref_state)); ref_state->nil_ref = LUA_NOREF; ref_state->empty_dict_ref = LUA_NOREF; + if (!is_thread) { + nlua_global_refs = ref_state; + } return ref_state; } @@ -465,17 +459,9 @@ LuaRef nlua_get_empty_dict_ref(lua_State *lstate) return ref_state->empty_dict_ref; } -static int nlua_get_ref_count(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); - return ref_state->ref_count; -} - int nlua_get_global_ref_count(void) { - lua_State *const lstate = global_lstate; - return nlua_get_ref_count(lstate); + return nlua_global_refs->ref_count; } static void nlua_common_vim_init(lua_State *lstate, bool is_thread) @@ -496,7 +482,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_pushcfunction(lstate, &nlua_nil_tostring); lua_setfield(lstate, -2, "__tostring"); lua_setmetatable(lstate, -2); - ref_state->nil_ref = nlua_ref(lstate, -1); + ref_state->nil_ref = nlua_ref(lstate, ref_state, -1); lua_pushvalue(lstate, -1); lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.NIL"); lua_setfield(lstate, -2, "NIL"); @@ -505,7 +491,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_createtable(lstate, 0, 0); lua_pushcfunction(lstate, &nlua_empty_dict_tostring); lua_setfield(lstate, -2, "__tostring"); - ref_state->empty_dict_ref = nlua_ref(lstate, -1); + ref_state->empty_dict_ref = nlua_ref(lstate, ref_state, -1); lua_pushvalue(lstate, -1); lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict"); lua_setfield(lstate, -2, "_empty_dict_mt"); @@ -784,11 +770,11 @@ void nlua_free_all_mem(void) static void nlua_common_free_all_mem(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { - nlua_unref(lstate, nlua_get_nil_ref(lstate)); - nlua_unref(lstate, nlua_get_empty_dict_ref(lstate)); + nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + nlua_unref(lstate, ref_state, ref_state->nil_ref); + nlua_unref(lstate, ref_state, ref_state->empty_dict_ref); #ifdef NLUA_TRACK_REFS - nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); if (ref_state->ref_count) { fprintf(stderr, "%d lua references were leaked!", ref_state->ref_count); } @@ -1095,10 +1081,8 @@ static int nlua_getenv(lua_State *lstate) /// add the value to the registry /// The current implementation does not support calls from threads. -LuaRef nlua_ref(lua_State *lstate, int index) +LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index) { - nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); - lua_pushvalue(lstate, index); LuaRef ref = luaL_ref(lstate, LUA_REGISTRYINDEX); if (ref > 0) { @@ -1113,11 +1097,15 @@ LuaRef nlua_ref(lua_State *lstate, int index) return ref; } -/// remove the value from the registry -void nlua_unref(lua_State *lstate, LuaRef ref) + +LuaRef nlua_ref_global(lua_State *lstate, int index) { - nlua_ref_state_t *ref_state = nlua_get_ref_state(lstate); + return nlua_ref(lstate, nlua_global_refs, index); +} +/// remove the value from the registry +void nlua_unref(lua_State *lstate, nlua_ref_state_t *ref_state, LuaRef ref) +{ if (ref > 0) { ref_state->ref_count--; #ifdef NLUA_TRACK_REFS @@ -1130,9 +1118,15 @@ void nlua_unref(lua_State *lstate, LuaRef ref) } } +void nlua_unref_global(lua_State *lstate, LuaRef ref) +{ + nlua_unref(lstate, nlua_global_refs, ref); +} + + void api_free_luaref(LuaRef ref) { - nlua_unref(global_lstate, ref); + nlua_unref_global(global_lstate, ref); } /// push a value referenced in the registry @@ -1154,7 +1148,7 @@ LuaRef api_new_luaref(LuaRef original_ref) lua_State *const lstate = global_lstate; nlua_pushref(lstate, original_ref); - LuaRef new_ref = nlua_ref(lstate, -1); + LuaRef new_ref = nlua_ref_global(lstate, -1); lua_pop(lstate, 1); return new_ref; } @@ -1707,7 +1701,7 @@ void nlua_CFunction_func_free(void *state) lua_State *const lstate = global_lstate; LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - nlua_unref(lstate, funcstate->lua_callable.func_ref); + nlua_unref_global(lstate, funcstate->lua_callable.func_ref); xfree(funcstate); } @@ -1757,7 +1751,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) lua_pop(lstate, 2); // [table] LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = nlua_ref(lstate, -1); + state->lua_callable.func_ref = nlua_ref_global(lstate, -1); char_u *name = register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, state); -- cgit From 1b5767aa3480c0cdc43f7a4b78f36a14e85a182f Mon Sep 17 00:00:00 2001 From: Javier Lopez Date: Sun, 27 Feb 2022 14:35:06 -0500 Subject: feat(lua): add to user commands callback (#17522) Works similar to ex . It only splits the arguments if the command has more than one posible argument. In cases were the command can only have 1 argument opts.fargs = { opts.args } --- src/nvim/lua/executor.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d207f48435..3c1676581c 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1814,8 +1814,31 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) lua_pushinteger(lstate, eap->line2); lua_setfield(lstate, -2, "line2"); + lua_newtable(lstate); // f-args table lua_pushstring(lstate, (const char *)eap->arg); - lua_setfield(lstate, -2, "args"); + lua_pushvalue(lstate, -1); // Reference for potential use on f-args + lua_setfield(lstate, -4, "args"); + + // Split args by unescaped whitespace || (nargs dependent) + if (cmd->uc_argt & EX_NOSPC) { + // Commands where nargs = 1 or "?" fargs is the same as args + lua_rawseti(lstate, -2, 1); + } else { + // Commands with more than one possible argument we split + lua_pop(lstate, 1); // Pop the reference of opts.args + int length = (int)STRLEN(eap->arg); + int start = 0; + int end = 0; + int i = 1; + bool res = true; + while (res) { + res = uc_split_args_iter(eap->arg, i, &start, &end, length); + lua_pushlstring(lstate, (const char *)eap->arg + start, (size_t)(end - start + 1)); + lua_rawseti(lstate, -2, i); + i++; + } + } + lua_setfield(lstate, -2, "fargs"); lua_pushstring(lstate, (const char *)&eap->regname); lua_setfield(lstate, -2, "reg"); -- cgit From 991e472881bf29805982b402c1a010cde051ded3 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 28 May 2021 15:45:34 -0400 Subject: feat(lua): add api and lua autocmds --- src/nvim/lua/executor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 3c1676581c..18abf04ff6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1350,6 +1350,16 @@ Object nlua_exec(const String str, const Array args, Error *err) return nlua_pop_Object(lstate, false, err); } +bool nlua_ref_is_function(LuaRef ref) +{ + lua_State *const lstate = global_lstate; + nlua_pushref(lstate, ref); + bool is_function = (lua_type(lstate, -1) == LUA_TFUNCTION); + lua_pop(lstate, 1); + + return is_function; +} + /// call a LuaRef as a function (or table with __call metamethod) /// /// @param ref the reference to call (not consumed) -- cgit From ebfe083337701534887ac3ea3d8e7ad47f7a206a Mon Sep 17 00:00:00 2001 From: shadmansaleh <13149513+shadmansaleh@users.noreply.github.com> Date: Sat, 8 Jan 2022 00:39:44 +0600 Subject: feat(lua): show proper verbose output for lua configuration `:verbose` didn't work properly with lua configs (For example: options or keymaps are set from lua, just say that they were set from lua, doesn't say where they were set at. This fixes that issue. Now `:verbose` will provide filename and line no when option/keymap is set from lua. Changes: - compiles lua/vim/keymap.lua as vim/keymap.lua - When souring a lua file current_sctx.sc_sid is set to SID_LUA - Moved finding scripts SID out of `do_source()` to `get_current_script_id()`. So it can be reused for lua files. - Added new function `nlua_get_sctx` that extracts current lua scripts name and line no with debug library. And creates a sctx for it. NOTE: This function ignores C functions and blacklist which currently contains only vim/_meta.lua so vim.o/opt wrappers aren't targeted. - Added function `nlua_set_sctx` that changes provided sctx to current lua scripts sctx if a lua file is being executed. - Added tests in tests/functional/lua/verbose_spec.lua - add primary support for additional types (:autocmd, :function, :syntax) to lua verbose Note: These can't yet be directly set from lua but once that's possible :verbose should work for them hopefully :D - add :verbose support for nvim_exec & nvim_command within lua Currently auto commands/commands/functions ... can only be defined by nvim_exec/nvim_command this adds support for them. Means if those Are defined within lua with vim.cmd/nvim_exec :verbose will show their location . Though note it'll show the line no on which nvim_exec call was made. --- src/nvim/lua/executor.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 18abf04ff6..3e9786eb1e 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -16,6 +16,7 @@ #include "nvim/change.h" #include "nvim/cursor.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/typval.h" #include "nvim/event/loop.h" #include "nvim/event/time.h" #include "nvim/ex_cmds2.h" @@ -652,6 +653,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL // [package, loaded, module] lua_setfield(lstate, -2, "vim.filetype"); // [package, loaded] + code = (char *)&lua_keymap_module[0]; + if (luaL_loadbuffer(lstate, code, sizeof(lua_keymap_module) - 1, "@vim/keymap.lua") + || nlua_pcall(lstate, 0, 1)) { + nlua_error(lstate, _("E5106: Error while creating vim.keymap module: %.*s")); + return 1; + } + // [package, loaded, module] + lua_setfield(lstate, -2, "vim.keymap"); // [package, loaded] + lua_pop(lstate, 2); // [] } @@ -1808,6 +1818,69 @@ void nlua_execute_on_key(int c) #endif } +// Checks if str is in blacklist array +static bool is_in_ignorelist(const char *str, char *ignorelist[], int ignorelist_size) +{ + for (int i = 0; i < ignorelist_size; i++) { + if (strncmp(ignorelist[i], str, strlen(ignorelist[i])) == 0) { + return true; + } + } + return false; +} +// Get sctx of current file being sourced if doesn't exist generate it +static sctx_T *nlua_get_sourcing_sctx(void) +{ + lua_State *const lstate = global_lstate; + sctx_T *retval = (sctx_T *)xmalloc(sizeof(sctx_T)); + retval->sc_seq = -1; + retval->sc_sid = SID_LUA; + retval->sc_lnum = -1; + lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug)); + + // Files where internal wrappers are defined so we can ignore them + // like vim.o/opt etc are defined in _meta.lua + char *ignorelist[] = { + "vim/_meta.lua", + "vim/keymap.lua", + }; + int blacklist_size = sizeof(ignorelist) / sizeof(ignorelist[0]); + + for (int level = 1; true; level++) { + if (lua_getstack(lstate, level, info) != 1) { + goto cleanup; + } + if (lua_getinfo(lstate, "nSl", info) == 0) { + goto cleanup; + } + + if (info->what[0] == 'C' || info->source[0] != '@' + || is_in_ignorelist(info->source+1, ignorelist, blacklist_size)) { + continue; + } + break; + } + char *source_path = fix_fname(info->source + 1); + get_current_script_id((char_u *)source_path, retval); + xfree(source_path); + retval->sc_lnum = info->currentline; + +cleanup: + xfree(info); + return retval; +} + +// Sets the editor "script context" during Lua execution. Used by :verbose. +// @param[out] current +void nlua_set_sctx(sctx_T *current) +{ + if (p_verbose > 0 && current->sc_sid == SID_LUA) { + sctx_T *lua_sctx = nlua_get_sourcing_sctx(); + *current = *lua_sctx; + xfree(lua_sctx); + } +} + void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) { lua_State *const lstate = global_lstate; -- cgit From 7b6ee3ef0a2d64657c8ca25f440e010c6dc75408 Mon Sep 17 00:00:00 2001 From: shadmansaleh <13149513+shadmansaleh@users.noreply.github.com> Date: Thu, 17 Feb 2022 12:53:17 +0600 Subject: fix: anonymous sid not working --- src/nvim/lua/executor.c | 53 ++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 3e9786eb1e..7c62ba2283 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1818,24 +1818,14 @@ void nlua_execute_on_key(int c) #endif } -// Checks if str is in blacklist array -static bool is_in_ignorelist(const char *str, char *ignorelist[], int ignorelist_size) +// Sets the editor "script context" during Lua execution. Used by :verbose. +// @param[out] current +void nlua_set_sctx(sctx_T *current) { - for (int i = 0; i < ignorelist_size; i++) { - if (strncmp(ignorelist[i], str, strlen(ignorelist[i])) == 0) { - return true; - } + if (p_verbose <= 0 || current->sc_sid != SID_LUA) { + return; } - return false; -} -// Get sctx of current file being sourced if doesn't exist generate it -static sctx_T *nlua_get_sourcing_sctx(void) -{ lua_State *const lstate = global_lstate; - sctx_T *retval = (sctx_T *)xmalloc(sizeof(sctx_T)); - retval->sc_seq = -1; - retval->sc_sid = SID_LUA; - retval->sc_lnum = -1; lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug)); // Files where internal wrappers are defined so we can ignore them @@ -1844,7 +1834,7 @@ static sctx_T *nlua_get_sourcing_sctx(void) "vim/_meta.lua", "vim/keymap.lua", }; - int blacklist_size = sizeof(ignorelist) / sizeof(ignorelist[0]); + int ignorelist_size = sizeof(ignorelist) / sizeof(ignorelist[0]); for (int level = 1; true; level++) { if (lua_getstack(lstate, level, info) != 1) { @@ -1854,31 +1844,30 @@ static sctx_T *nlua_get_sourcing_sctx(void) goto cleanup; } - if (info->what[0] == 'C' || info->source[0] != '@' - || is_in_ignorelist(info->source+1, ignorelist, blacklist_size)) { + bool is_ignored = false; + if (info->what[0] == 'C' || info->source[0] != '@') { + is_ignored = true; + } else { + for (int i = 0; i < ignorelist_size; i++) { + if (strncmp(ignorelist[i], info->source+1, strlen(ignorelist[i])) == 0) { + is_ignored = true; + break; + } + } + } + if (is_ignored) { continue; } break; } char *source_path = fix_fname(info->source + 1); - get_current_script_id((char_u *)source_path, retval); + get_current_script_id((char_u *)source_path, current); xfree(source_path); - retval->sc_lnum = info->currentline; + current->sc_lnum = info->currentline; + current->sc_seq = -1; cleanup: xfree(info); - return retval; -} - -// Sets the editor "script context" during Lua execution. Used by :verbose. -// @param[out] current -void nlua_set_sctx(sctx_T *current) -{ - if (p_verbose > 0 && current->sc_sid == SID_LUA) { - sctx_T *lua_sctx = nlua_get_sourcing_sctx(); - *current = *lua_sctx; - xfree(lua_sctx); - } } void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) -- cgit From 0f613482b389ad259dd53d893907b024a115352e Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 28 May 2021 15:45:34 -0400 Subject: feat(lua): add missing changes to autocmds lost in the rebase Note: some of these changes are breaking, like change of API signatures --- src/nvim/lua/executor.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 18abf04ff6..07071d4e1e 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1354,6 +1354,9 @@ bool nlua_ref_is_function(LuaRef ref) { lua_State *const lstate = global_lstate; nlua_pushref(lstate, ref); + + // TODO(tjdevries): This should probably check for callable tables as well. + // We should put some work maybe into simplifying how all of that works bool is_function = (lua_type(lstate, -1) == LUA_TFUNCTION); lua_pop(lstate, 1); -- cgit From f9faba88fdc46b2dd1a979a37ba61b000830ff3a Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 1 Mar 2022 14:27:19 +0100 Subject: refactor(lua): reorganize builtin modules, phase 1 --- src/nvim/lua/executor.c | 175 +++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 100 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 7ac80f01f0..e233e0e6d0 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -53,6 +53,12 @@ typedef struct { String lua_err_str; } LuaError; +typedef struct { + char *name; + const uint8_t *data; + size_t size; +} ModuleDef; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/executor.c.generated.h" # include "lua/vim_module.generated.h" @@ -519,60 +525,70 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_pop(lstate, 3); } -static void nlua_common_package_init(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL +static void nlua_preload_modules(lua_State *lstate) { - { - const char *code = (char *)&shared_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(shared_module) - 1, "@vim/shared.lua") - || nlua_pcall(lstate, 0, 0)) { - nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n")); - return; - } - } + lua_getglobal(lstate, "package"); // [package] + lua_getfield(lstate, -1, "preload"); // [package, preload] + for (size_t i = 0; i < ARRAY_SIZE(builtin_modules); i++) { + ModuleDef def = builtin_modules[i]; + lua_pushinteger(lstate, (long)i); // [package, preload, i] + lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure] + lua_setfield(lstate, -2, def.name); // [package, preload] - { - const char *code = (char *)&lua_load_package_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_load_package_module) - 1, "@vim/_load_package.lua") - || lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5106: Error while creating _load_package module: %.*s")); - return; + if (nlua_disable_preload && strequal(def.name, "vim")) { + break; } } - { - lua_getglobal(lstate, "package"); // [package] - lua_getfield(lstate, -1, "loaded"); // [package, loaded] + lua_pop(lstate, 2); // [] +} - const char *code = (char *)&inspect_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(inspect_module) - 1, "@vim/inspect.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s\n")); - return; - } +static int nlua_module_preloader(lua_State *lstate) +{ + size_t i = (size_t)lua_tointeger(lstate, lua_upvalueindex(1)); + ModuleDef def = builtin_modules[i]; + char name[256]; + name[0] = '@'; + size_t off = xstrlcpy(name+1, def.name, (sizeof name) - 2); + strchrsub(name+1, '.', '/'); + xstrlcpy(name+1+off, ".lua", (sizeof name)-2-off); - // [package, loaded, inspect] - lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded] + if (luaL_loadbuffer(lstate, (const char *)def.data, def.size - 1, name)) { + return lua_error(lstate); } - { - const char *code = (char *)&lua_F_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_F_module) - 1, "@vim/F.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s\n")); - return; - } - // [package, loaded, module] - lua_setfield(lstate, -2, "vim.F"); // [package, loaded] + lua_call(lstate, 0, 1); // propagates error to caller + return 1; +} - lua_pop(lstate, 2); // [] +static bool nlua_common_package_init(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + nlua_preload_modules(lstate); + + lua_getglobal(lstate, "require"); + lua_pushstring(lstate, "vim._load_package"); + if (nlua_pcall(lstate, 1, 0)) { + nlua_error(lstate, _("E5106: Error while creating _load_package module: %.*s\n")); + return false; + } + + // TODO(bfredl): ideally all initialization should be done as a single require + // call. + lua_getglobal(lstate, "require"); + lua_pushstring(lstate, "vim.shared"); + if (nlua_pcall(lstate, 1, 0)) { + nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n")); + return false; } + + return true; } /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. -static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL +static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { // print lua_pushcfunction(lstate, &nlua_print); @@ -638,59 +654,18 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setglobal(lstate, "vim"); - nlua_common_package_init(lstate); - - { - lua_getglobal(lstate, "package"); // [package] - lua_getfield(lstate, -1, "loaded"); // [package, loaded] - - char *code = (char *)&lua_filetype_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_filetype_module) - 1, "@vim/filetype.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating vim.filetype module: %.*s")); - return 1; - } - // [package, loaded, module] - lua_setfield(lstate, -2, "vim.filetype"); // [package, loaded] - - code = (char *)&lua_keymap_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_keymap_module) - 1, "@vim/keymap.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating vim.keymap module: %.*s")); - return 1; - } - // [package, loaded, module] - lua_setfield(lstate, -2, "vim.keymap"); // [package, loaded] - - lua_pop(lstate, 2); // [] - } - - { - const char *code = (char *)&vim_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(vim_module) - 1, "@vim.lua") - || nlua_pcall(lstate, 0, 0)) { - nlua_error(lstate, _("E5106: Error while creating vim module: %.*s\n")); - return 1; - } + if (!nlua_common_package_init(lstate)) { + return false; } - { - lua_getglobal(lstate, "package"); // [package] - lua_getfield(lstate, -1, "loaded"); // [package, loaded] - - const char *code = (char *)&lua_meta_module[0]; - if (luaL_loadbuffer(lstate, code, sizeof(lua_meta_module) - 1, "@vim/_meta.lua") - || nlua_pcall(lstate, 0, 1)) { - nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s\n")); - return 1; - } - // [package, loaded, module] - lua_setfield(lstate, -2, "vim._meta"); // [package, loaded] - - lua_pop(lstate, 2); // [] + lua_getglobal(lstate, "require"); + lua_pushstring(lstate, "vim"); + if (nlua_pcall(lstate, 1, 0)) { + nlua_error(lstate, _("E5106: Error while creating vim module: %.*s\n")); + return false; } - return 0; + return true; } /// Initialize global lua interpreter @@ -707,11 +682,14 @@ void nlua_init(void) lua_State *lstate = luaL_newstate(); if (lstate == NULL) { - emsg(_("E970: Failed to initialize lua interpreter")); - preserve_exit(); + mch_errmsg(_("E970: Failed to initialize lua interpreter\n")); + os_exit(1); } luaL_openlibs(lstate); - nlua_state_init(lstate); + if (!nlua_state_init(lstate)) { + mch_errmsg(_("E970: Failed to initialize builtin lua modules\n")); + os_exit(1); + } luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem); @@ -747,23 +725,20 @@ static lua_State *nlua_thread_acquire_vm(void) nlua_state_add_stdlib(lstate, true); + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); + lua_setfield(lstate, -2, "nvim__get_runtime"); + lua_setfield(lstate, -2, "api"); + lua_setglobal(lstate, "vim"); nlua_common_package_init(lstate); - lua_getglobal(lstate, "vim"); lua_getglobal(lstate, "package"); lua_getfield(lstate, -1, "loaded"); - lua_getfield(lstate, -1, "vim.inspect"); - lua_setfield(lstate, -4, "inspect"); - lua_pop(lstate, 3); - lua_getglobal(lstate, "vim"); - lua_createtable(lstate, 0, 0); - lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); - lua_setfield(lstate, -2, "nvim__get_runtime"); - lua_setfield(lstate, -2, "api"); - lua_pop(lstate, 1); + lua_setfield(lstate, -2, "vim"); + lua_pop(lstate, 2); return lstate; } -- cgit From 186a559818f7a709dbdd4590fe7440ebd619a208 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 4 Mar 2022 16:18:58 +0100 Subject: refactor(lua): move only runtime lua file in src/ to runtime/lua reorganize so that initialization is done in lua --- src/nvim/lua/executor.c | 56 ++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index e233e0e6d0..29a3c515c2 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -525,24 +525,6 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_pop(lstate, 3); } -static void nlua_preload_modules(lua_State *lstate) -{ - lua_getglobal(lstate, "package"); // [package] - lua_getfield(lstate, -1, "preload"); // [package, preload] - for (size_t i = 0; i < ARRAY_SIZE(builtin_modules); i++) { - ModuleDef def = builtin_modules[i]; - lua_pushinteger(lstate, (long)i); // [package, preload, i] - lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure] - lua_setfield(lstate, -2, def.name); // [package, preload] - - if (nlua_disable_preload && strequal(def.name, "vim")) { - break; - } - } - - lua_pop(lstate, 2); // [] -} - static int nlua_module_preloader(lua_State *lstate) { size_t i = (size_t)lua_tointeger(lstate, lua_upvalueindex(1)); @@ -561,24 +543,29 @@ static int nlua_module_preloader(lua_State *lstate) return 1; } -static bool nlua_common_package_init(lua_State *lstate) +static bool nlua_init_packages(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { - nlua_preload_modules(lstate); + // put builtin packages in preload + lua_getglobal(lstate, "package"); // [package] + lua_getfield(lstate, -1, "preload"); // [package, preload] + for (size_t i = 0; i < ARRAY_SIZE(builtin_modules); i++) { + ModuleDef def = builtin_modules[i]; + lua_pushinteger(lstate, (long)i); // [package, preload, i] + lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure] + lua_setfield(lstate, -2, def.name); // [package, preload] - lua_getglobal(lstate, "require"); - lua_pushstring(lstate, "vim._load_package"); - if (nlua_pcall(lstate, 1, 0)) { - nlua_error(lstate, _("E5106: Error while creating _load_package module: %.*s\n")); - return false; + if (nlua_disable_preload && strequal(def.name, "vim.inspect")) { + break; + } } - // TODO(bfredl): ideally all initialization should be done as a single require - // call. + lua_pop(lstate, 2); // [] + lua_getglobal(lstate, "require"); - lua_pushstring(lstate, "vim.shared"); + lua_pushstring(lstate, "vim._init_packages"); if (nlua_pcall(lstate, 1, 0)) { - nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n")); + nlua_error(lstate, _("E5106: Error while loading packages: %.*s\n")); return false; } @@ -654,14 +641,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setglobal(lstate, "vim"); - if (!nlua_common_package_init(lstate)) { - return false; - } - - lua_getglobal(lstate, "require"); - lua_pushstring(lstate, "vim"); - if (nlua_pcall(lstate, 1, 0)) { - nlua_error(lstate, _("E5106: Error while creating vim module: %.*s\n")); + if (!nlua_init_packages(lstate)) { return false; } @@ -732,7 +712,7 @@ static lua_State *nlua_thread_acquire_vm(void) lua_setglobal(lstate, "vim"); - nlua_common_package_init(lstate); + nlua_init_packages(lstate); lua_getglobal(lstate, "package"); lua_getfield(lstate, -1, "loaded"); -- cgit From 147908336ec2e2051dd752e38964d0c36aea1b54 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 7 Mar 2022 11:01:13 +0100 Subject: fix(lua): don't use nlua_error when exiting early Screen state is not initialized yet. Print directly to stderr instead. --- src/nvim/lua/executor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 29a3c515c2..6aaff100ca 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -565,7 +565,8 @@ static bool nlua_init_packages(lua_State *lstate) lua_getglobal(lstate, "require"); lua_pushstring(lstate, "vim._init_packages"); if (nlua_pcall(lstate, 1, 0)) { - nlua_error(lstate, _("E5106: Error while loading packages: %.*s\n")); + mch_errmsg(lua_tostring(lstate, -1)); + mch_errmsg("\n"); return false; } -- cgit From 7e3bdc75e44b9139d8afaea4381b53ae78b15746 Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Wed, 9 Mar 2022 21:19:37 +0100 Subject: refactor(uncrustify): format all c files --- src/nvim/lua/executor.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 6aaff100ca..054f6c9483 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -15,8 +15,8 @@ #include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/cursor.h" -#include "nvim/eval/userfunc.h" #include "nvim/eval/typval.h" +#include "nvim/eval/userfunc.h" #include "nvim/event/loop.h" #include "nvim/event/time.h" #include "nvim/ex_cmds2.h" @@ -139,17 +139,17 @@ static void nlua_luv_error_event(void **argv) luv_err_t type = (luv_err_t)(intptr_t)argv[1]; msg_ext_set_kind("lua_error"); switch (type) { - case kCallback: - semsg_multiline("Error executing luv callback:\n%s", error); - break; - case kThread: - semsg_multiline("Error in luv thread:\n%s", error); - break; - case kThreadCallback: - semsg_multiline("Error in luv callback, thread:\n%s", error); - break; - default: - break; + case kCallback: + semsg_multiline("Error executing luv callback:\n%s", error); + break; + case kThread: + semsg_multiline("Error in luv thread:\n%s", error); + break; + case kThreadCallback: + semsg_multiline("Error in luv callback, thread:\n%s", error); + break; + default: + break; } xfree(error); } @@ -189,21 +189,18 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags return retval; } -static int nlua_luv_thread_cb_cfpcall(lua_State *lstate, int nargs, int nresult, - int flags) +static int nlua_luv_thread_cb_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) { return nlua_luv_thread_common_cfpcall(lstate, nargs, nresult, flags, true); } -static int nlua_luv_thread_cfpcall(lua_State *lstate, int nargs, int nresult, - int flags) +static int nlua_luv_thread_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) FUNC_ATTR_NONNULL_ALL { return nlua_luv_thread_common_cfpcall(lstate, nargs, nresult, flags, false); } -static int nlua_luv_thread_cfcpcall(lua_State *lstate, lua_CFunction func, - void *ud, int flags) +static int nlua_luv_thread_cfcpcall(lua_State *lstate, lua_CFunction func, void *ud, int flags) FUNC_ATTR_NONNULL_ARG(1, 2) { lua_pushcfunction(lstate, func); @@ -212,8 +209,8 @@ static int nlua_luv_thread_cfcpcall(lua_State *lstate, lua_CFunction func, return retval; } -static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nresult, - int flags, bool is_callback) +static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nresult, int flags, + bool is_callback) FUNC_ATTR_NONNULL_ALL { int retval; @@ -228,9 +225,9 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres mch_errmsg("\n"); lua_close(lstate); #ifdef WIN32 - ExitThread(0); + ExitThread(0); #else - pthread_exit(0); + pthread_exit(0); #endif } const char *error = lua_tostring(lstate, -1); @@ -565,9 +562,9 @@ static bool nlua_init_packages(lua_State *lstate) lua_getglobal(lstate, "require"); lua_pushstring(lstate, "vim._init_packages"); if (nlua_pcall(lstate, 1, 0)) { - mch_errmsg(lua_tostring(lstate, -1)); - mch_errmsg("\n"); - return false; + mch_errmsg(lua_tostring(lstate, -1)); + mch_errmsg("\n"); + return false; } return true; -- cgit From e463eb81465978b5de77e207af9ee1b416ca0053 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 13 Apr 2022 08:04:56 -0600 Subject: fix(api): correctly pass f-args for nvim_create_user_command (#18098) Skip runs of whitespace and do not include `\` characters when followed by another `\` or whitespace. This matches the behavior of when used with `:command`. --- src/nvim/lua/executor.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 21625854fb..81396f1715 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1869,17 +1869,21 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) } else { // Commands with more than one possible argument we split lua_pop(lstate, 1); // Pop the reference of opts.args - int length = (int)STRLEN(eap->arg); - int start = 0; - int end = 0; + size_t length = STRLEN(eap->arg); + size_t end = 0; + size_t len = 0; int i = 1; - bool res = true; - while (res) { - res = uc_split_args_iter(eap->arg, i, &start, &end, length); - lua_pushlstring(lstate, (const char *)eap->arg + start, (size_t)(end - start + 1)); - lua_rawseti(lstate, -2, i); - i++; + char *buf = xcalloc(length, sizeof(char)); + bool done = false; + while (!done) { + done = uc_split_args_iter(eap->arg, length, &end, buf, &len); + if (len > 0) { + lua_pushlstring(lstate, buf, len); + lua_rawseti(lstate, -2, i); + i++; + } } + xfree(buf); } lua_setfield(lstate, -2, "fargs"); -- cgit From eef8de4df0247157e57f306062b1b86e01a41454 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Fri, 29 Apr 2022 13:53:42 +0200 Subject: refactor(uncrustify): change rules to better align with the style guide Add space around arithmetic operators '+' and '-'. Remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. Remove space between '((' or '))' of control statements. Add space between ')' and '{' of control statements. Remove space between function name and '(' on function declaration. Collapse empty blocks between '{' and '}'. Remove newline at the end of the file. Remove newline between 'enum' and '{'. Remove newline between '}' and ')' in a function invocation. Remove newline between '}' and 'while' of 'do' statement. --- src/nvim/lua/executor.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 81396f1715..2c4d527fdf 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -332,8 +332,7 @@ static int nlua_schedule(lua_State *const lstate) // Dummy timer callback. Used by f_wait(). static void dummy_timer_due_cb(TimeWatcher *tw, void *data) -{ -} +{} // Dummy timer close callback. Used by f_wait(). static void dummy_timer_close_cb(TimeWatcher *tw, void *data) @@ -543,9 +542,9 @@ static int nlua_module_preloader(lua_State *lstate) ModuleDef def = builtin_modules[i]; char name[256]; name[0] = '@'; - size_t off = xstrlcpy(name+1, def.name, (sizeof name) - 2); - strchrsub(name+1, '.', '/'); - xstrlcpy(name+1+off, ".lua", (sizeof name)-2-off); + size_t off = xstrlcpy(name + 1, def.name, (sizeof name) - 2); + strchrsub(name + 1, '.', '/'); + xstrlcpy(name + 1 + off, ".lua", (sizeof name) - 2 - off); if (luaL_loadbuffer(lstate, (const char *)def.data, def.size - 1, name)) { return lua_error(lstate); @@ -769,7 +768,7 @@ static void nlua_common_free_all_mem(lua_State *lstate) static void nlua_print_event(void **argv) { char *str = argv[0]; - const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL + const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL for (size_t i = 0; i < len;) { if (got_int) { @@ -926,7 +925,7 @@ int nlua_call(lua_State *lstate) return luaL_error(lstate, e_luv_api_disabled, "vimL function"); } - int nargs = lua_gettop(lstate)-1; + int nargs = lua_gettop(lstate) - 1; if (nargs > MAX_FUNC_ARGS) { return luaL_error(lstate, "Function called with too many arguments"); } @@ -934,10 +933,10 @@ int nlua_call(lua_State *lstate) typval_T vim_args[MAX_FUNC_ARGS + 1]; int i = 0; // also used for freeing the variables for (; i < nargs; i++) { - lua_pushvalue(lstate, i+2); + lua_pushvalue(lstate, i + 2); if (!nlua_pop_typval(lstate, &vim_args[i])) { api_set_error(&err, kErrorTypeException, - "error converting argument %d", i+1); + "error converting argument %d", i + 1); goto free_vim_args; } } @@ -994,12 +993,12 @@ static int nlua_rpc(lua_State *lstate, bool request) size_t name_len; uint64_t chan_id = (uint64_t)luaL_checkinteger(lstate, 1); const char *name = luaL_checklstring(lstate, 2, &name_len); - int nargs = lua_gettop(lstate)-2; + int nargs = lua_gettop(lstate) - 2; Error err = ERROR_INIT; Array args = ARRAY_DICT_INIT; for (int i = 0; i < nargs; i++) { - lua_pushvalue(lstate, i+3); + lua_pushvalue(lstate, i + 3); ADD(args, nlua_pop_Object(lstate, false, &err)); if (ERROR_SET(&err)) { api_free_array(args); @@ -1415,7 +1414,7 @@ void ex_lua(exarg_T *const eap) // lua nlua_typval_exec doesn't expect null terminated string so len // needs to end before null byte. char *code_buf = xmallocz(len); - vim_snprintf(code_buf, len+1, "vim.pretty_print(%s)", code+1); + vim_snprintf(code_buf, len + 1, "vim.pretty_print(%s)", code + 1); xfree(code); code = code_buf; } @@ -1820,7 +1819,7 @@ void nlua_set_sctx(sctx_T *current) is_ignored = true; } else { for (int i = 0; i < ignorelist_size; i++) { - if (strncmp(ignorelist[i], info->source+1, strlen(ignorelist[i])) == 0) { + if (strncmp(ignorelist[i], info->source + 1, strlen(ignorelist[i])) == 0) { is_ignored = true; break; } @@ -1912,4 +1911,3 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) nlua_error(lstate, _("Error executing Lua callback: %.*s")); } } - -- cgit From 13520aae163bfc243fc050cf16b89082c0896eaf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 3 May 2022 09:29:55 +0800 Subject: fix(coverity): use xstrndup() instead of vim_strsave() (#18363) --- src/nvim/lua/executor.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 2c4d527fdf..9cdc299ea7 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1647,9 +1647,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char_u ***resul goto cleanup_array; } - GA_APPEND(char_u *, - &result_array, - vim_strsave((char_u *)v.data.string.data)); + GA_APPEND(char_u *, &result_array, (char_u *)string_to_cstr(v.data.string)); } xp->xp_pattern += prefix_len; -- cgit From 5576d30e89153c817fb1a8d23c30cfc0432bc7c6 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Tue, 3 May 2022 11:06:27 +0200 Subject: refactor: replace char_u variables and functions with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9cdc299ea7..1777ba0a76 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1873,7 +1873,7 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) char *buf = xcalloc(length, sizeof(char)); bool done = false; while (!done) { - done = uc_split_args_iter(eap->arg, length, &end, buf, &len); + done = uc_split_args_iter((char_u *)eap->arg, length, &end, buf, &len); if (len > 0) { lua_pushlstring(lstate, buf, len); lua_rawseti(lstate, -2, i); -- cgit From 9a671e6a24243a5ff2879599d91ab5aec8b4e77d Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Wed, 4 May 2022 18:27:22 +0200 Subject: refactor: replace char_u variables and functions with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/executor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1777ba0a76..b61488b667 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -881,7 +881,7 @@ static int nlua_debug(lua_State *lstate) { .v_lock = VAR_FIXED, .v_type = VAR_STRING, - .vval.v_string = (char_u *)"lua_debug> ", + .vval.v_string = "lua_debug> ", }, { .v_type = VAR_UNKNOWN, @@ -1195,8 +1195,8 @@ void nlua_call_user_expand_func(expand_T *xp, typval_T *ret_tv) lua_State *const lstate = global_lstate; nlua_pushref(lstate, xp->xp_luaref); - lua_pushstring(lstate, (char *)xp->xp_pattern); - lua_pushstring(lstate, (char *)xp->xp_line); + lua_pushstring(lstate, xp->xp_pattern); + lua_pushstring(lstate, xp->xp_line); lua_pushinteger(lstate, xp->xp_col); if (nlua_pcall(lstate, 3, 1)) { @@ -1495,7 +1495,7 @@ void ex_luado(exarg_T *const eap) new_line_transformed[i] = '\n'; } } - ml_replace(l, (char_u *)new_line_transformed, false); + ml_replace(l, new_line_transformed, false); inserted_bytes(l, 0, (int)old_line_len, (int)new_line_len); } lua_pop(lstate, 1); -- cgit From e31b32a293f6ba8708499a176234f8be1df6a145 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Thu, 5 May 2022 13:36:14 +0200 Subject: refactor: replace char_u variables and functions with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/executor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index b61488b667..1da868c137 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -956,7 +956,7 @@ int nlua_call(lua_State *lstate) funcexe.evaluate = true; // call_func() retval is deceptive, ignore it. Instead we set `msg_list` // (TRY_WRAP) to capture abort-causing non-exception errors. - (void)call_func(name, (int)name_len, &rettv, nargs, vim_args, &funcexe); + (void)call_func((char *)name, (int)name_len, &rettv, nargs, vim_args, &funcexe); if (!try_end(&err)) { nlua_push_typval(lstate, &rettv, false); } @@ -1873,7 +1873,7 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) char *buf = xcalloc(length, sizeof(char)); bool done = false; while (!done) { - done = uc_split_args_iter((char_u *)eap->arg, length, &end, buf, &len); + done = uc_split_args_iter(eap->arg, length, &end, buf, &len); if (len > 0) { lua_pushlstring(lstate, buf, len); lua_rawseti(lstate, -2, i); -- cgit From dfcc58466505f7fb5f62d636a67facaeea143285 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sun, 8 May 2022 17:39:45 +0600 Subject: feat(api): add `nvim_cmd` Adds the API function `nvim_cmd` which allows executing an Ex-command through a Dictionary which can have the same values as the return value of `nvim_parse_cmd()`. This makes it much easier to do things like passing arguments with a space to commands that otherwise may not allow it, or to make commands interpret certain characters literally when they otherwise would not. --- src/nvim/lua/executor.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1da868c137..7d08481a7b 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1863,8 +1863,8 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) if (cmd->uc_argt & EX_NOSPC) { // Commands where nargs = 1 or "?" fargs is the same as args lua_rawseti(lstate, -2, 1); - } else { - // Commands with more than one possible argument we split + } else if (eap->args == NULL) { + // For commands with more than one possible argument, split if argument list isn't available. lua_pop(lstate, 1); // Pop the reference of opts.args size_t length = STRLEN(eap->arg); size_t end = 0; @@ -1881,6 +1881,13 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) } } xfree(buf); + } else { + // If argument list is available, just use it. + lua_pop(lstate, 1); + for (size_t i = 0; i < eap->argc; i++) { + lua_pushlstring(lstate, eap->args[i], eap->arglens[i]); + lua_rawseti(lstate, -2, (int)i + 1); + } } lua_setfield(lstate, -2, "fargs"); -- cgit From 85aae12a6dea48621ea2d24a946b3e7b86f9014d Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Sun, 8 May 2022 14:43:16 +0200 Subject: refactor: replace char_u variables and functions with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/executor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1da868c137..29ed40af03 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -920,7 +920,7 @@ int nlua_call(lua_State *lstate) { Error err = ERROR_INIT; size_t name_len; - const char_u *name = (const char_u *)luaL_checklstring(lstate, 1, &name_len); + const char *name = luaL_checklstring(lstate, 1, &name_len); if (!nlua_is_deferred_safe()) { return luaL_error(lstate, e_luv_api_disabled, "vimL function"); } @@ -1249,7 +1249,7 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) char_u *line = NULL; ga_init(&ga, (int)sizeof(char_u *), 10); - while ((line = fgetline(0, cookie, 0, false)) != NULL) { + while ((line = (char_u *)fgetline(0, cookie, 0, false)) != NULL) { GA_APPEND(char_u *, &ga, line); } char *code = ga_concat_strings_sep(&ga, "\n"); -- cgit From 5c41165c8e89356bdb7d1b5835d1f79725b62d2c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 29 Apr 2022 17:26:57 +0100 Subject: feat(lua): allow some viml functions to run in fast This change adds the necessary plumbing to annotate functions in funcs.c as being allowed in run in luv fast events. --- src/nvim/lua/executor.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9758cee0a5..c2d76e3ce8 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -916,12 +916,22 @@ int nlua_in_fast_event(lua_State *lstate) return 1; } +static bool viml_func_is_fast(const char *name) +{ + const EvalFuncDef *const fdef = find_internal_func((const char *)name); + if (fdef) { + return fdef->fast; + } + // Not a vimL function + return false; +} + int nlua_call(lua_State *lstate) { Error err = ERROR_INIT; size_t name_len; const char *name = luaL_checklstring(lstate, 1, &name_len); - if (!nlua_is_deferred_safe()) { + if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) { return luaL_error(lstate, e_luv_api_disabled, "vimL function"); } -- cgit From 9fec6dc9a25b5cf9c9a444ac2bd0728e8af3229e Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 25 May 2022 20:31:14 +0200 Subject: refactor(uncrustify): set maximum number of consecutive newlines to 2 (#18695) --- src/nvim/lua/executor.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9758cee0a5..f63f1ee52f 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -135,7 +135,6 @@ static int nlua_pcall(lua_State *lstate, int nargs, int nresults) return status; } - /// Gets the version of the current Nvim build. /// /// @param lstate Lua interpreter state. @@ -147,7 +146,6 @@ static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } - static void nlua_luv_error_event(void **argv) { char *error = (char *)argv[0]; @@ -1041,7 +1039,6 @@ static int nlua_empty_dict_tostring(lua_State *lstate) return 1; } - #ifdef WIN32 /// os.getenv: override os.getenv to maintain coherency. #9681 /// @@ -1055,7 +1052,6 @@ static int nlua_getenv(lua_State *lstate) } #endif - /// add the value to the registry /// The current implementation does not support calls from threads. LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index) @@ -1074,7 +1070,6 @@ LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index) return ref; } - LuaRef nlua_ref_global(lua_State *lstate, int index) { return nlua_ref(lstate, nlua_global_refs, index); @@ -1100,7 +1095,6 @@ void nlua_unref_global(lua_State *lstate, LuaRef ref) nlua_unref(lstate, nlua_global_refs, ref); } - void api_free_luaref(LuaRef ref) { nlua_unref_global(global_lstate, ref); @@ -1112,7 +1106,6 @@ void nlua_pushref(lua_State *lstate, LuaRef ref) lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref); } - /// Gets a new reference to an object stored at original_ref /// /// NOTE: It does not copy the value, it creates a new ref to the lua object. @@ -1130,7 +1123,6 @@ LuaRef api_new_luaref(LuaRef original_ref) return new_ref; } - /// Evaluate lua string /// /// Used for luaeval(). @@ -1744,7 +1736,6 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) char_u *name = register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, state); - lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); -- cgit From 9988d2f214963b3cac70026d6ad4bb058837afd9 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sun, 29 May 2022 10:42:00 +0600 Subject: feat(nvim_create_user_command): pass structured modifiers to commands Adds an `smods` key to `nvim_create_user_command` Lua command callbacks, which has command modifiers but in a structured format. This removes the need to manually parse command modifiers. It also reduces friction in using `nvim_cmd` inside a Lua command callback. --- src/nvim/lua/executor.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 0009420281..a826dd07d3 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -40,6 +40,7 @@ #include "nvim/undo.h" #include "nvim/version.h" #include "nvim/vim.h" +#include "nvim/window.h" static int in_fast_callback = 0; @@ -1913,6 +1914,61 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) lua_pushstring(lstate, buf); lua_setfield(lstate, -2, "mods"); + lua_newtable(lstate); // smods table + + lua_pushinteger(lstate, cmdmod.tab); + lua_setfield(lstate, -2, "tab"); + lua_pushinteger(lstate, p_verbose); + lua_setfield(lstate, -2, "verbose"); + + if (cmdmod.split & WSP_ABOVE) { + lua_pushstring(lstate, "aboveleft"); + } else if (cmdmod.split & WSP_BELOW) { + lua_pushstring(lstate, "belowright"); + } else if (cmdmod.split & WSP_TOP) { + lua_pushstring(lstate, "topleft"); + } else if (cmdmod.split & WSP_BOT) { + lua_pushstring(lstate, "botright"); + } else { + lua_pushstring(lstate, ""); + } + lua_setfield(lstate, -2, "split"); + + lua_pushboolean(lstate, cmdmod.split & WSP_VERT); + lua_setfield(lstate, -2, "vertical"); + lua_pushboolean(lstate, msg_silent != 0); + lua_setfield(lstate, -2, "silent"); + lua_pushboolean(lstate, emsg_silent != 0); + lua_setfield(lstate, -2, "emsg_silent"); + lua_pushboolean(lstate, eap->did_sandbox); + lua_setfield(lstate, -2, "sandbox"); + lua_pushboolean(lstate, cmdmod.save_ei != NULL); + lua_setfield(lstate, -2, "noautocmd"); + + typedef struct { + bool *set; + char *name; + } mod_entry_T; + static mod_entry_T mod_entries[] = { + { &cmdmod.browse, "browse" }, + { &cmdmod.confirm, "confirm" }, + { &cmdmod.hide, "hide" }, + { &cmdmod.keepalt, "keepalt" }, + { &cmdmod.keepjumps, "keepjumps" }, + { &cmdmod.keepmarks, "keepmarks" }, + { &cmdmod.keeppatterns, "keeppatterns" }, + { &cmdmod.lockmarks, "lockmarks" }, + { &cmdmod.noswapfile, "noswapfile" } + }; + + // The modifiers that are simple flags + for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) { + lua_pushboolean(lstate, *mod_entries[i].set); + lua_setfield(lstate, -2, mod_entries[i].name); + } + + lua_setfield(lstate, -2, "smods"); + if (nlua_pcall(lstate, 1, 0)) { nlua_error(lstate, _("Error executing Lua callback: %.*s")); } -- cgit From 46536f53e82967dcac8d030ee3394cdb156f9603 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 20 Apr 2022 17:02:18 +0600 Subject: feat: add preview functionality to user commands Adds a Lua-only `preview` flag to user commands which allows the command to be incrementally previewed like `:substitute` when 'inccommand' is set. --- src/nvim/lua/executor.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a826dd07d3..deff2347e0 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1840,11 +1840,12 @@ cleanup: xfree(info); } -void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) +/// @param preview Invoke the callback as a |:command-preview| handler. +int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) { lua_State *const lstate = global_lstate; - nlua_pushref(lstate, cmd->uc_luaref); + nlua_pushref(lstate, preview ? cmd->uc_preview_luaref : cmd->uc_luaref); lua_newtable(lstate); lua_pushboolean(lstate, eap->forceit == 1); @@ -1969,7 +1970,31 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) lua_setfield(lstate, -2, "smods"); - if (nlua_pcall(lstate, 1, 0)) { + if (preview) { + lua_pushinteger(lstate, cmdpreview_get_ns()); + + handle_T cmdpreview_bufnr = cmdpreview_get_bufnr(); + if (cmdpreview_bufnr != 0) { + lua_pushinteger(lstate, cmdpreview_bufnr); + } else { + lua_pushnil(lstate); + } + } + + if (nlua_pcall(lstate, preview ? 3 : 1, preview ? 1 : 0)) { nlua_error(lstate, _("Error executing Lua callback: %.*s")); + return 0; } + + int retv = 0; + + if (preview) { + if (lua_isnumber(lstate, -1) && (retv = (int)lua_tointeger(lstate, -1)) >= 0 && retv <= 2) { + lua_pop(lstate, 1); + } else { + retv = 0; + } + } + + return retv; } -- cgit From c84bd9e21fb1e5c55c9c5370b07271a6ae96f19c Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 8 Jun 2022 09:06:36 +0600 Subject: fix(nvim_create_user_command): make `smods` work with `nvim_cmd` Closes #18876. --- src/nvim/lua/executor.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index deff2347e0..3ba4d0d70c 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1919,7 +1919,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushinteger(lstate, cmdmod.tab); lua_setfield(lstate, -2, "tab"); - lua_pushinteger(lstate, p_verbose); + + lua_pushinteger(lstate, eap->verbose_save != -1 ? p_verbose : -1); lua_setfield(lstate, -2, "verbose"); if (cmdmod.split & WSP_ABOVE) { @@ -1937,9 +1938,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushboolean(lstate, cmdmod.split & WSP_VERT); lua_setfield(lstate, -2, "vertical"); - lua_pushboolean(lstate, msg_silent != 0); + lua_pushboolean(lstate, eap->save_msg_silent != -1 ? (msg_silent != 0) : 0); lua_setfield(lstate, -2, "silent"); - lua_pushboolean(lstate, emsg_silent != 0); + lua_pushboolean(lstate, eap->did_esilent); lua_setfield(lstate, -2, "emsg_silent"); lua_pushboolean(lstate, eap->did_sandbox); lua_setfield(lstate, -2, "sandbox"); -- cgit From 11e0fea8bafaf7693531177c4ebaf733738241f1 Mon Sep 17 00:00:00 2001 From: resolritter <17429390+resolritter@users.noreply.github.com> Date: Thu, 9 Jun 2022 12:02:32 -0300 Subject: fix: correct nlua_wait error message #18867 the message is wrapped in `if (timeout < 0)`, which means 0 is a valid value --- src/nvim/lua/executor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 3ba4d0d70c..bd06123d5f 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -357,7 +357,7 @@ static int nlua_wait(lua_State *lstate) { intptr_t timeout = luaL_checkinteger(lstate, 1); if (timeout < 0) { - return luaL_error(lstate, "timeout must be > 0"); + return luaL_error(lstate, "timeout must be >= 0"); } int lua_top = lua_gettop(lstate); @@ -384,7 +384,7 @@ static int nlua_wait(lua_State *lstate) if (lua_top >= 3 && !lua_isnil(lstate, 3)) { interval = luaL_checkinteger(lstate, 3); if (interval < 0) { - return luaL_error(lstate, "interval must be > 0"); + return luaL_error(lstate, "interval must be >= 0"); } } -- cgit From 3f5c647de97a424d8a06e85b912ed46cc3ca8298 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 2 Jun 2022 09:18:13 +0200 Subject: perf(memory): use an arena for RPC decoding drawback: tracing memory errors with ASAN is less accurate for arena allocated memory. Therefore, to start with it is being used for Object types around serialization/deserialization exclusively. This is going to have a large impact especially when TUI is refactored as a co-prosess as all UI events will be serialized and deserialized by nvim itself. --- src/nvim/lua/executor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index bd06123d5f..215aae9430 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1016,10 +1016,11 @@ static int nlua_rpc(lua_State *lstate, bool request) } if (request) { - Object result = rpc_send_call(chan_id, name, args, &err); + ArenaMem res_mem = NULL; + Object result = rpc_send_call(chan_id, name, args, &res_mem, &err); if (!ERROR_SET(&err)) { nlua_push_Object(lstate, result, false); - api_free_object(result); + arena_mem_free(res_mem, NULL); } } else { if (!rpc_send_event(chan_id, name, args)) { -- cgit From da41ca299f52d4e08a34344359c250a3058fd3c6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Jun 2022 17:13:46 +0800 Subject: vim-patch:8.2.1897: command modifiers are saved and set inconsistently Problem: Command modifiers are saved and set inconsistently. Solution: Separate parsing and applying command modifiers. Save values in cmdmod_T. https://github.com/vim/vim/commit/5661ed6c833e05467cab33cb9b1c535e7e5cc570 Cherry-pick: :0verbose fix from patch 8.2.4741 --- src/nvim/lua/executor.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index bd06123d5f..ac68c02d8b 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1920,7 +1920,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushinteger(lstate, cmdmod.tab); lua_setfield(lstate, -2, "tab"); - lua_pushinteger(lstate, eap->verbose_save != -1 ? p_verbose : -1); + lua_pushinteger(lstate, (cmdmod.cmod_verbose != 0 + ? cmdmod.cmod_verbose < 0 ? 0 : cmdmod.cmod_verbose + : -1)); lua_setfield(lstate, -2, "verbose"); if (cmdmod.split & WSP_ABOVE) { @@ -1938,13 +1940,13 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushboolean(lstate, cmdmod.split & WSP_VERT); lua_setfield(lstate, -2, "vertical"); - lua_pushboolean(lstate, eap->save_msg_silent != -1 ? (msg_silent != 0) : 0); + lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT); lua_setfield(lstate, -2, "silent"); - lua_pushboolean(lstate, eap->did_esilent); + lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT); lua_setfield(lstate, -2, "emsg_silent"); - lua_pushboolean(lstate, eap->did_sandbox); + lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SANDBOX); lua_setfield(lstate, -2, "sandbox"); - lua_pushboolean(lstate, cmdmod.save_ei != NULL); + lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_NOAUTOCMD); lua_setfield(lstate, -2, "noautocmd"); typedef struct { -- cgit From 6130b4a84b41b71f4c0c58093a29585c6c67ff16 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Jun 2022 20:20:34 +0800 Subject: vim-patch:8.2.1898: command modifier parsing always uses global cmdmod Problem: Command modifier parsing always uses global cmdmod. Solution: Pass in cmdmod_T to use. Rename struct fields consistently. https://github.com/vim/vim/commit/e10044015841711b989f9a898d427bcc1fdb4c32 --- src/nvim/lua/executor.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index ac68c02d8b..5bc06bf3fe 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1917,7 +1917,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_newtable(lstate); // smods table - lua_pushinteger(lstate, cmdmod.tab); + lua_pushinteger(lstate, cmdmod.cmod_tab); lua_setfield(lstate, -2, "tab"); lua_pushinteger(lstate, (cmdmod.cmod_verbose != 0 @@ -1925,20 +1925,20 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) : -1)); lua_setfield(lstate, -2, "verbose"); - if (cmdmod.split & WSP_ABOVE) { + if (cmdmod.cmod_split & WSP_ABOVE) { lua_pushstring(lstate, "aboveleft"); - } else if (cmdmod.split & WSP_BELOW) { + } else if (cmdmod.cmod_split & WSP_BELOW) { lua_pushstring(lstate, "belowright"); - } else if (cmdmod.split & WSP_TOP) { + } else if (cmdmod.cmod_split & WSP_TOP) { lua_pushstring(lstate, "topleft"); - } else if (cmdmod.split & WSP_BOT) { + } else if (cmdmod.cmod_split & WSP_BOT) { lua_pushstring(lstate, "botright"); } else { lua_pushstring(lstate, ""); } lua_setfield(lstate, -2, "split"); - lua_pushboolean(lstate, cmdmod.split & WSP_VERT); + lua_pushboolean(lstate, cmdmod.cmod_split & WSP_VERT); lua_setfield(lstate, -2, "vertical"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT); lua_setfield(lstate, -2, "silent"); @@ -1950,24 +1950,24 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_setfield(lstate, -2, "noautocmd"); typedef struct { - bool *set; + int flag; char *name; } mod_entry_T; static mod_entry_T mod_entries[] = { - { &cmdmod.browse, "browse" }, - { &cmdmod.confirm, "confirm" }, - { &cmdmod.hide, "hide" }, - { &cmdmod.keepalt, "keepalt" }, - { &cmdmod.keepjumps, "keepjumps" }, - { &cmdmod.keepmarks, "keepmarks" }, - { &cmdmod.keeppatterns, "keeppatterns" }, - { &cmdmod.lockmarks, "lockmarks" }, - { &cmdmod.noswapfile, "noswapfile" } + { CMOD_BROWSE, "browse" }, + { CMOD_CONFIRM, "confirm" }, + { CMOD_HIDE, "hide" }, + { CMOD_KEEPALT, "keepalt" }, + { CMOD_KEEPJUMPS, "keepjumps" }, + { CMOD_KEEPMARKS, "keepmarks" }, + { CMOD_KEEPPATTERNS, "keeppatterns" }, + { CMOD_LOCKMARKS, "lockmarks" }, + { CMOD_NOSWAPFILE, "noswapfile" } }; // The modifiers that are simple flags for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) { - lua_pushboolean(lstate, *mod_entries[i].set); + lua_pushboolean(lstate, cmdmod.cmod_flags & mod_entries[i].flag); lua_setfield(lstate, -2, mod_entries[i].name); } -- cgit From 0a0cda95286bf62fbce2776a0c0081cea39a88a8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 14 Jun 2022 20:46:18 +0800 Subject: vim-patch:8.2.5088: value of cmod_verbose is a bit complicated to use Problem: Value of cmod_verbose is a bit complicated to use. Solution: Use zero for not set, value + 1 when set. (closes vim/vim#10564) https://github.com/vim/vim/commit/cd7496382efc9e6748326c6cda7f01003fa07063 Omit has_cmdmod(): only used for Vim9 script --- src/nvim/lua/executor.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5bc06bf3fe..b0054be613 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1920,9 +1920,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushinteger(lstate, cmdmod.cmod_tab); lua_setfield(lstate, -2, "tab"); - lua_pushinteger(lstate, (cmdmod.cmod_verbose != 0 - ? cmdmod.cmod_verbose < 0 ? 0 : cmdmod.cmod_verbose - : -1)); + lua_pushinteger(lstate, cmdmod.cmod_verbose - 1); lua_setfield(lstate, -2, "verbose"); if (cmdmod.cmod_split & WSP_ABOVE) { -- cgit From 179faa3edd6120a483b55aadf0a367fbf07b25fd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 16 Jun 2022 18:51:36 +0800 Subject: fix(lua): clear got_int when calling vim.on_key() callback (#18979) --- src/nvim/lua/executor.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 30ae274607..164542f4ab 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1775,10 +1775,13 @@ void nlua_execute_on_key(int c) // [ vim, vim._on_key, buf ] lua_pushlstring(lstate, (const char *)buf, buf_len); + int save_got_int = got_int; + got_int = false; // avoid interrupts when the key typed is Ctrl-C if (nlua_pcall(lstate, 1, 0)) { nlua_error(lstate, _("Error executing vim.on_key Lua callback: %.*s")); } + got_int |= save_got_int; // [ vim ] lua_pop(lstate, 1); -- cgit From f93eb169f6e1d72646556153fc0d01b3c843498a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 2 Jul 2022 19:32:27 +0800 Subject: vim-patch:8.2.1900: Vim9: command modifiers do not work Problem: Vim9: command modifiers do not work. Solution: Make most command modifiers work. https://github.com/vim/vim/commit/02194d2bd54eacd0b7b9a017a3fe1702ecb80971 --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 164542f4ab..87244ed03c 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1915,7 +1915,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) // every possible modifier (with room to spare). If the list of possible // modifiers grows this may need to be updated. char buf[200] = { 0 }; - (void)uc_mods(buf); + (void)uc_mods(buf, &cmdmod, false); lua_pushstring(lstate, buf); lua_setfield(lstate, -2, "mods"); -- cgit From 7a907c3314f939a3d2983ac07edc5c9672957352 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 2 Jul 2022 19:35:11 +0800 Subject: feat(api): add `unsilent` to command APIs --- src/nvim/lua/executor.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 87244ed03c..0406ba2199 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1946,6 +1946,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_setfield(lstate, -2, "silent"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT); lua_setfield(lstate, -2, "emsg_silent"); + lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_UNSILENT); + lua_setfield(lstate, -2, "unsilent"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SANDBOX); lua_setfield(lstate, -2, "sandbox"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_NOAUTOCMD); -- cgit From 2c739431e8e5a2aacc39ef429401f5e4427d027a Mon Sep 17 00:00:00 2001 From: ii14 Date: Thu, 7 Jul 2022 14:40:07 +0200 Subject: feat(lua): measure require in --startuptime --- src/nvim/lua/executor.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 0406ba2199..ad03ebd1ed 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -36,6 +36,7 @@ #include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/os.h" +#include "nvim/profile.h" #include "nvim/screen.h" #include "nvim/undo.h" #include "nvim/version.h" @@ -47,6 +48,8 @@ static int in_fast_callback = 0; // Initialized in nlua_init(). static lua_State *global_lstate = NULL; +static LuaRef require_ref = LUA_REFNIL; + static uv_thread_t main_thread; typedef struct { @@ -645,6 +648,16 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL nlua_common_vim_init(lstate, false); + // patch require() (only for --startuptime) + if (time_fd != NULL) { + lua_getglobal(lstate, "require"); + // Must do this after nlua_common_vim_init where nlua_global_refs is initialized. + require_ref = nlua_ref_global(lstate, -1); + lua_pop(lstate, 1); + lua_pushcfunction(lstate, &nlua_require); + lua_setglobal(lstate, "require"); + } + // internal vim._treesitter... API nlua_add_treesitter(lstate); @@ -740,6 +753,7 @@ void nlua_free_all_mem(void) return; } lua_State *lstate = global_lstate; + nlua_unref_global(lstate, require_ref); nlua_common_free_all_mem(lstate); } @@ -870,6 +884,62 @@ nlua_print_error: return lua_error(lstate); } +/// require() for --startuptime +/// +/// @param lstate Lua interpreter state. +static int nlua_require(lua_State *const lstate) + FUNC_ATTR_NONNULL_ALL +{ + const char *name = luaL_checkstring(lstate, 1); + lua_settop(lstate, 1); + // [ name ] + + // try cached module from package.loaded first + lua_getfield(lstate, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(lstate, 2, name); + // [ name package.loaded module ] + if (lua_toboolean(lstate, -1)) { + return 1; + } + lua_pop(lstate, 2); + // [ name ] + + // push original require below the module name + nlua_pushref(lstate, require_ref); + lua_insert(lstate, 1); + // [ require name ] + + if (time_fd == NULL) { + // after log file was closed, try to restore + // global require to the original function... + lua_getglobal(lstate, "require"); + // ...only if it's still referencing this wrapper, + // to not overwrite it in case someone happened to + // patch it in the meantime... + if (lua_iscfunction(lstate, -1) && lua_tocfunction(lstate, -1) == nlua_require) { + lua_pushvalue(lstate, 1); + lua_setglobal(lstate, "require"); + } + lua_pop(lstate, 1); + + // ...and then call require directly. + lua_call(lstate, 1, 1); + return 1; + } + + proftime_T rel_time; + proftime_T start_time; + time_push(&rel_time, &start_time); + int status = lua_pcall(lstate, 1, 1, 0); + if (status == 0) { + vim_snprintf((char *)IObuff, IOSIZE, "require('%s')", name); + time_msg((char *)IObuff, &start_time); + } + time_pop(rel_time); + + return status == 0 ? 1 : lua_error(lstate); +} + /// debug.debug: interaction with user while debugging. /// /// @param lstate Lua interpreter state. -- cgit