From c8656e44d85502a1733df839b3cb3e8f239c5505 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 9 Jan 2022 09:02:02 +0800 Subject: feat(api, lua): more conversions between LuaRef and Vim Funcref --- src/nvim/lua/converter.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 8a702ddd60..f9a2533d4e 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -617,6 +617,13 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) semsg(_("E1502: Lua failed to grow stack to %i"), initial_size + 4); return false; } + if (tv->v_type == VAR_FUNC) { + ufunc_T *fp = find_func(tv->vval.v_string); + if (fp->uf_cb == nlua_CFunction_func_call) { + nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); + return true; + } + } if (encode_vim_to_lua(lstate, tv, "nlua_push_typval argument") == FAIL) { return false; } -- cgit From 8f241e535fe845814a195bc5811dac4869a26998 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 19 Jan 2022 21:43:06 -0500 Subject: refactor(coverity/345583): assert fp is non-NULL Since we already have a typval, we know the lookup will succeed. --- src/nvim/lua/converter.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index f9a2533d4e..0fbd56ed53 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -619,6 +619,7 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) } if (tv->v_type == VAR_FUNC) { ufunc_T *fp = find_func(tv->vval.v_string); + assert(fp != NULL); if (fp->uf_cb == nlua_CFunction_func_call) { nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); return true; -- cgit 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') 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') 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 92e92f02e7106fcad1597bb8f0edf1e43186a07f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 5 Feb 2022 17:49:48 +0000 Subject: fix(diff): make algorithm work for vim.diff (#17300) Fixes #17207 --- src/nvim/lua/xdiff.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index b2e971f9f3..ea7a700e1e 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -184,11 +184,11 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, if (strequal("myers", v->data.string.data)) { // default } else if (strequal("minimal", v->data.string.data)) { - cfg->flags |= XDF_NEED_MINIMAL; + params->flags |= XDF_NEED_MINIMAL; } else if (strequal("patience", v->data.string.data)) { - cfg->flags |= XDF_PATIENCE_DIFF; + params->flags |= XDF_PATIENCE_DIFF; } else if (strequal("histogram", v->data.string.data)) { - cfg->flags |= XDF_HISTOGRAM_DIFF; + params->flags |= XDF_HISTOGRAM_DIFF; } else { api_set_error(err, kErrorTypeValidation, "not a valid algorithm"); goto exit_1; -- cgit From b518b577ea89439359dc9faea5ec1bf341c50e52 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 5 Feb 2022 18:00:58 +0000 Subject: fix(lua): restore priority of the preloader Neovim currently places its own loader for searching runtime files at the front of `package.loaders`. This prevents any preloaders in `package.preload` from being used. This change fixes that by moving the default package preloader to run before Neovim's loader. For example, LuaJIT provides preloaders for the built-in modules `ffi` and `bit`, so this optimisation will improve the loading of those. --- src/nvim/lua/vim.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 731e7d8d36..f5993c3f55 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -87,7 +87,8 @@ function vim._load_package(name) return nil end -table.insert(package.loaders, 1, vim._load_package) +-- Insert vim._load_package after the preloader at position 2 +table.insert(package.loaders, 2, vim._load_package) -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c -- cgit From f292dd2126f8dacd6446799ac750ab368b852f81 Mon Sep 17 00:00:00 2001 From: shadmansaleh <13149513+shadmansaleh@users.noreply.github.com> Date: Sat, 12 Feb 2022 10:54:25 +0600 Subject: fix: autoload variables not loaded with vim.g & nvim_get_var --- src/nvim/lua/stdlib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 18a579ed0f..55b23cf0c8 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -25,6 +25,7 @@ #include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/globals.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/lua/stdlib.h" @@ -408,6 +409,12 @@ int nlua_getvar(lua_State *lstate) const char *name = luaL_checklstring(lstate, 3, &len); dictitem_T *di = tv_dict_find(dict, name, (ptrdiff_t)len); + if (di == NULL && dict == &globvardict) { // try to autoload script + if (!script_autoload(name, len, false) || aborting()) { + return 0; // nil + } + di = tv_dict_find(dict, name, (ptrdiff_t)len); + } if (di == NULL) { return 0; // nil } -- 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') 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') 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/converter.c | 14 +- src/nvim/lua/executor.c | 460 ++++++++++++++++++++++++++++++++++++++--------- src/nvim/lua/executor.h | 6 +- src/nvim/lua/stdlib.c | 83 ++++----- src/nvim/lua/vim.lua | 47 ----- 5 files changed, 431 insertions(+), 179 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 0fbd56ed53..47bc9ab91c 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -156,7 +156,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) && ret.string_keys_num == 0)) { ret.type = kObjectTypeArray; if (tsize == 0 && lua_getmetatable(lstate, -1)) { - nlua_pushref(lstate, nlua_empty_dict_ref); + nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); if (lua_rawequal(lstate, -2, -1)) { ret.type = kObjectTypeDictionary; } @@ -401,7 +401,7 @@ nlua_pop_typval_table_processing_end: } case LUA_TUSERDATA: { // TODO(bfredl): check mt.__call and convert to function? - nlua_pushref(lstate, nlua_nil_ref); + nlua_pushref(lstate, nlua_get_nil_ref(lstate)); bool is_nil = lua_rawequal(lstate, -2, -1); lua_pop(lstate, 1); if (is_nil) { @@ -445,7 +445,7 @@ static bool typval_conv_special = false; if (typval_conv_special) { \ lua_pushnil(lstate); \ } else { \ - nlua_pushref(lstate, nlua_nil_ref); \ + nlua_pushref(lstate, nlua_get_nil_ref(lstate)); \ } \ } while (0) @@ -495,7 +495,7 @@ static bool typval_conv_special = false; nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ } else { \ lua_createtable(lstate, 0, 0); \ - nlua_pushref(lstate, nlua_empty_dict_ref); \ + nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); \ lua_setmetatable(lstate, -2); \ } \ } while (0) @@ -734,7 +734,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special } else { lua_createtable(lstate, 0, (int)dict.size); if (dict.size == 0 && !special) { - nlua_pushref(lstate, nlua_empty_dict_ref); + nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); lua_setmetatable(lstate, -2); } } @@ -782,7 +782,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special) if (special) { lua_pushnil(lstate); } else { - nlua_pushref(lstate, nlua_nil_ref); + nlua_pushref(lstate, nlua_get_nil_ref(lstate)); } break; case kObjectTypeLuaRef: { @@ -1206,7 +1206,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) break; case LUA_TUSERDATA: { - nlua_pushref(lstate, nlua_nil_ref); + nlua_pushref(lstate, nlua_get_nil_ref(lstate)); bool is_nil = lua_rawequal(lstate, -2, -1); lua_pop(lstate, 1); if (is_nil) { 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) diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index bf78f7ec5e..6fca8e6c09 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -4,6 +4,7 @@ #include #include +#include "nvim/assert.h" #include "nvim/api/private/defs.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" @@ -14,11 +15,6 @@ // Generated by msgpack-gen.lua void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; -EXTERN LuaRef nlua_nil_ref INIT(= LUA_NOREF); -EXTERN LuaRef nlua_empty_dict_ref INIT(= LUA_NOREF); - -EXTERN int nlua_refcount INIT(= 0); - #define set_api_error(s, err) \ do { \ Error *err_ = (err); \ diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 55b23cf0c8..6a2aef6683 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -471,43 +471,49 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL } -void nlua_state_add_stdlib(lua_State *const lstate) +void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { - // stricmp - lua_pushcfunction(lstate, &nlua_stricmp); - lua_setfield(lstate, -2, "stricmp"); - // str_utfindex - lua_pushcfunction(lstate, &nlua_str_utfindex); - lua_setfield(lstate, -2, "str_utfindex"); - // str_byteindex - lua_pushcfunction(lstate, &nlua_str_byteindex); - lua_setfield(lstate, -2, "str_byteindex"); - // str_utf_pos - lua_pushcfunction(lstate, &nlua_str_utf_pos); - lua_setfield(lstate, -2, "str_utf_pos"); - // str_utf_start - lua_pushcfunction(lstate, &nlua_str_utf_start); - lua_setfield(lstate, -2, "str_utf_start"); - // str_utf_end - lua_pushcfunction(lstate, &nlua_str_utf_end); - lua_setfield(lstate, -2, "str_utf_end"); - // regex - lua_pushcfunction(lstate, &nlua_regex); - lua_setfield(lstate, -2, "regex"); - luaL_newmetatable(lstate, "nvim_regex"); - luaL_register(lstate, NULL, regex_meta); - - lua_pushvalue(lstate, -1); // [meta, meta] - lua_setfield(lstate, -2, "__index"); // [meta] - lua_pop(lstate, 1); // don't use metatable now - - // _getvar - lua_pushcfunction(lstate, &nlua_getvar); - lua_setfield(lstate, -2, "_getvar"); - - // _setvar - lua_pushcfunction(lstate, &nlua_setvar); - lua_setfield(lstate, -2, "_setvar"); + if (!is_thread) { + // stricmp + lua_pushcfunction(lstate, &nlua_stricmp); + lua_setfield(lstate, -2, "stricmp"); + // str_utfindex + lua_pushcfunction(lstate, &nlua_str_utfindex); + lua_setfield(lstate, -2, "str_utfindex"); + // str_byteindex + lua_pushcfunction(lstate, &nlua_str_byteindex); + lua_setfield(lstate, -2, "str_byteindex"); + // str_utf_pos + lua_pushcfunction(lstate, &nlua_str_utf_pos); + lua_setfield(lstate, -2, "str_utf_pos"); + // str_utf_start + lua_pushcfunction(lstate, &nlua_str_utf_start); + lua_setfield(lstate, -2, "str_utf_start"); + // str_utf_end + lua_pushcfunction(lstate, &nlua_str_utf_end); + lua_setfield(lstate, -2, "str_utf_end"); + // regex + lua_pushcfunction(lstate, &nlua_regex); + lua_setfield(lstate, -2, "regex"); + luaL_newmetatable(lstate, "nvim_regex"); + luaL_register(lstate, NULL, regex_meta); + + lua_pushvalue(lstate, -1); // [meta, meta] + lua_setfield(lstate, -2, "__index"); // [meta] + lua_pop(lstate, 1); // don't use metatable now + + // _getvar + lua_pushcfunction(lstate, &nlua_getvar); + lua_setfield(lstate, -2, "_getvar"); + + // _setvar + lua_pushcfunction(lstate, &nlua_setvar); + lua_setfield(lstate, -2, "_setvar"); + + // vim.spell + luaopen_spell(lstate); + lua_setfield(lstate, -2, "spell"); + } // vim.mpack luaopen_mpack(lstate); @@ -526,10 +532,7 @@ void nlua_state_add_stdlib(lua_State *const lstate) lua_pushcfunction(lstate, &nlua_xdl_diff); lua_setfield(lstate, -2, "diff"); - // vim.spell - luaopen_spell(lstate); - lua_setfield(lstate, -2, "spell"); - + // vim.json lua_cjson_new(lstate); lua_setfield(lstate, -2, "json"); } diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index f5993c3f55..68de4f960c 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -43,53 +43,6 @@ assert(vim.inspect) vim.filetype = package.loaded['vim.filetype'] assert(vim.filetype) -local pathtrails = {} -vim._so_trails = {} -for s in (package.cpath..';'):gmatch('[^;]*;') do - s = s:sub(1, -2) -- Strip trailing semicolon - -- Find out path patterns. pathtrail should contain something like - -- /?.so, \?.dll. This allows not to bother determining what correct - -- suffixes are. - local pathtrail = s:match('[/\\][^/\\]*%?.*$') - if pathtrail and not pathtrails[pathtrail] then - pathtrails[pathtrail] = true - table.insert(vim._so_trails, pathtrail) - end -end - -function vim._load_package(name) - local basename = name:gsub('%.', '/') - local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} - local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true}) - if #found > 0 then - local f, err = loadfile(found[1]) - return f or error(err) - end - - local so_paths = {} - for _,trail in ipairs(vim._so_trails) do - local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash - table.insert(so_paths, path) - end - - found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true}) - if #found > 0 then - -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is - -- a) strip prefix up to and including the first dash, if any - -- b) replace all dots by underscores - -- c) prepend "luaopen_" - -- So "foo-bar.baz" should result in "luaopen_bar_baz" - local dash = name:find("-", 1, true) - local modname = dash and name:sub(dash + 1) or name - local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) - return f or error(err) - end - return nil -end - --- Insert vim._load_package after the preloader at position 2 -table.insert(package.loaders, 2, vim._load_package) - -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c setmetatable(vim, { -- 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/converter.c | 22 ++++++++--------- src/nvim/lua/executor.c | 64 ++++++++++++++++++++++-------------------------- src/nvim/lua/executor.h | 12 +++++++++ 3 files changed, 52 insertions(+), 46 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 47bc9ab91c..2b54e56df1 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -156,7 +156,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) && ret.string_keys_num == 0)) { ret.type = kObjectTypeArray; if (tsize == 0 && lua_getmetatable(lstate, -1)) { - nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); + nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); if (lua_rawequal(lstate, -2, -1)) { ret.type = kObjectTypeDictionary; } @@ -316,7 +316,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) LuaRef table_ref = LUA_NOREF; if (lua_getmetatable(lstate, -1)) { lua_pop(lstate, 1); - table_ref = nlua_ref(lstate, -1); + table_ref = nlua_ref_global(lstate, -1); } const LuaTableProps table_props = nlua_traverse_table(lstate); @@ -389,7 +389,7 @@ nlua_pop_typval_table_processing_end: } case LUA_TFUNCTION: { LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = nlua_ref(lstate, -1); + state->lua_callable.func_ref = nlua_ref_global(lstate, -1); char_u *name = register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, @@ -401,7 +401,7 @@ nlua_pop_typval_table_processing_end: } case LUA_TUSERDATA: { // TODO(bfredl): check mt.__call and convert to function? - nlua_pushref(lstate, nlua_get_nil_ref(lstate)); + nlua_pushref(lstate, nlua_global_refs->nil_ref); bool is_nil = lua_rawequal(lstate, -2, -1); lua_pop(lstate, 1); if (is_nil) { @@ -445,7 +445,7 @@ static bool typval_conv_special = false; if (typval_conv_special) { \ lua_pushnil(lstate); \ } else { \ - nlua_pushref(lstate, nlua_get_nil_ref(lstate)); \ + nlua_pushref(lstate, nlua_global_refs->nil_ref); \ } \ } while (0) @@ -495,7 +495,7 @@ static bool typval_conv_special = false; nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ } else { \ lua_createtable(lstate, 0, 0); \ - nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); \ + nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); \ lua_setmetatable(lstate, -2); \ } \ } while (0) @@ -734,7 +734,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special } else { lua_createtable(lstate, 0, (int)dict.size); if (dict.size == 0 && !special) { - nlua_pushref(lstate, nlua_get_empty_dict_ref(lstate)); + nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); lua_setmetatable(lstate, -2); } } @@ -782,7 +782,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special) if (special) { lua_pushnil(lstate); } else { - nlua_pushref(lstate, nlua_get_nil_ref(lstate)); + nlua_pushref(lstate, nlua_global_refs->nil_ref); } break; case kObjectTypeLuaRef: { @@ -1199,14 +1199,14 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) case LUA_TFUNCTION: if (ref) { - *cur.obj = LUAREF_OBJ(nlua_ref(lstate, -1)); + *cur.obj = LUAREF_OBJ(nlua_ref_global(lstate, -1)); } else { goto type_error; } break; case LUA_TUSERDATA: { - nlua_pushref(lstate, nlua_get_nil_ref(lstate)); + nlua_pushref(lstate, nlua_global_refs->nil_ref); bool is_nil = lua_rawequal(lstate, -2, -1); lua_pop(lstate, 1); if (is_nil) { @@ -1240,7 +1240,7 @@ type_error: LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err) { - LuaRef rv = nlua_ref(lstate, -1); + LuaRef rv = nlua_ref_global(lstate, -1); lua_pop(lstate, 1); return rv; } 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); diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 6fca8e6c09..957c61f2f9 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -15,6 +15,15 @@ // Generated by msgpack-gen.lua void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; +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; + #define set_api_error(s, err) \ do { \ Error *err_ = (err); \ @@ -35,4 +44,7 @@ void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/executor.h.generated.h" #endif + +EXTERN nlua_ref_state_t *nlua_global_refs INIT(= NULL); + #endif // NVIM_LUA_EXECUTOR_H -- cgit From 850b3e19c9fc8d84d960e6932a9ad4f0bcad2a8e Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 26 Feb 2022 11:03:39 +0100 Subject: refactor(lua): cleanup and docs for threads --- src/nvim/lua/stdlib.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 6a2aef6683..c2ce899a74 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -474,6 +474,9 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { + // TODO(bfredl): some of basic string functions should already be + // (or be easy to make) threadsafe + // stricmp lua_pushcfunction(lstate, &nlua_stricmp); lua_setfield(lstate, -2, "stricmp"); -- 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') 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 ++++++++++ src/nvim/lua/executor.h | 8 -------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/nvim/lua') 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) diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 957c61f2f9..47ac51dadb 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -24,14 +24,6 @@ typedef struct { #endif } nlua_ref_state_t; -#define set_api_error(s, err) \ - do { \ - Error *err_ = (err); \ - err_->type = kErrorTypeException; \ - err_->set = true; \ - memcpy(&err_->msg[0], s, sizeof(s)); \ - } while (0) - #define NLUA_CLEAR_REF(x) \ do { \ /* Take the address to avoid double evaluation. #1375 */ \ -- 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 +++++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/lua/vim.lua | 6 ++-- 2 files changed, 76 insertions(+), 3 deletions(-) (limited to 'src/nvim/lua') 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; diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 68de4f960c..c0247ad996 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -43,6 +43,9 @@ assert(vim.inspect) vim.filetype = package.loaded['vim.filetype'] assert(vim.filetype) +vim.keymap = package.loaded['vim.keymap'] +assert(vim.keymap) + -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c setmetatable(vim, { @@ -69,9 +72,6 @@ setmetatable(vim, { elseif key == 'ui' then t.ui = require('vim.ui') return t.ui - elseif key == 'keymap' then - t.keymap = require('vim.keymap') - return t.keymap end end }) -- 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') 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') 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 +++++++++++++++++++++--------------------------- src/nvim/lua/executor.h | 1 + src/nvim/lua/vim.lua | 19 +++--- 3 files changed, 86 insertions(+), 109 deletions(-) (limited to 'src/nvim/lua') 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; } diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 47ac51dadb..d978dc55d3 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -38,5 +38,6 @@ typedef struct { #endif EXTERN nlua_ref_state_t *nlua_global_refs INIT(= NULL); +EXTERN bool nlua_disable_preload INIT(= false); #endif // NVIM_LUA_EXECUTOR_H diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index c0247ad996..f5f293939b 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -36,16 +36,8 @@ local vim = vim assert(vim) - -vim.inspect = package.loaded['vim.inspect'] assert(vim.inspect) -vim.filetype = package.loaded['vim.filetype'] -assert(vim.filetype) - -vim.keymap = package.loaded['vim.keymap'] -assert(vim.keymap) - -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c setmetatable(vim, { @@ -53,6 +45,9 @@ setmetatable(vim, { if key == 'treesitter' then t.treesitter = require('vim.treesitter') return t.treesitter + elseif key == 'filetype' then + t.filetype = require('vim.filetype') + return t.filetype elseif key == 'F' then t.F = require('vim.F') return t.F @@ -69,6 +64,9 @@ setmetatable(vim, { elseif key == 'diagnostic' then t.diagnostic = require('vim.diagnostic') return t.diagnostic + elseif key == 'keymap' then + t.keymap = require('vim.keymap') + return t.keymap elseif key == 'ui' then t.ui = require('vim.ui') return t.ui @@ -662,4 +660,7 @@ function vim.pretty_print(...) return ... end -return module + +require('vim._meta') + +return vim -- 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 ++-- src/nvim/lua/vim.lua | 666 ------------------------------------------------ 2 files changed, 18 insertions(+), 704 deletions(-) delete mode 100644 src/nvim/lua/vim.lua (limited to 'src/nvim/lua') 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"); diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua deleted file mode 100644 index f5f293939b..0000000000 --- a/src/nvim/lua/vim.lua +++ /dev/null @@ -1,666 +0,0 @@ --- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib) --- --- Lua code lives in one of three places: --- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the --- `inspect` and `lpeg` modules. --- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests. --- (This will go away if we migrate to nvim as the test-runner.) --- 3. src/nvim/lua/: Compiled-into Nvim itself. --- --- Guideline: "If in doubt, put it in the runtime". --- --- Most functions should live directly in `vim.`, not in submodules. --- The only "forbidden" names are those claimed by legacy `if_lua`: --- $ vim --- :lua for k,v in pairs(vim) do print(k) end --- buffer --- open --- window --- lastline --- firstline --- type --- line --- eval --- dict --- beep --- list --- command --- --- Reference (#6580): --- - https://github.com/luafun/luafun --- - https://github.com/rxi/lume --- - http://leafo.net/lapis/reference/utilities.html --- - https://github.com/torch/paths --- - https://github.com/bakpakin/Fennel (pretty print, repl) --- - https://github.com/howl-editor/howl/tree/master/lib/howl/util - -local vim = vim -assert(vim) -assert(vim.inspect) - --- These are for loading runtime modules lazily since they aren't available in --- the nvim binary as specified in executor.c -setmetatable(vim, { - __index = function(t, key) - if key == 'treesitter' then - t.treesitter = require('vim.treesitter') - return t.treesitter - elseif key == 'filetype' then - t.filetype = require('vim.filetype') - return t.filetype - elseif key == 'F' then - t.F = require('vim.F') - return t.F - elseif require('vim.uri')[key] ~= nil then - -- Expose all `vim.uri` functions on the `vim` module. - t[key] = require('vim.uri')[key] - return t[key] - elseif key == 'lsp' then - t.lsp = require('vim.lsp') - return t.lsp - elseif key == 'highlight' then - t.highlight = require('vim.highlight') - return t.highlight - elseif key == 'diagnostic' then - t.diagnostic = require('vim.diagnostic') - return t.diagnostic - elseif key == 'keymap' then - t.keymap = require('vim.keymap') - return t.keymap - elseif key == 'ui' then - t.ui = require('vim.ui') - return t.ui - end - end -}) - -vim.log = { - levels = { - TRACE = 0; - DEBUG = 1; - INFO = 2; - WARN = 3; - ERROR = 4; - } -} - --- Internal-only until comments in #8107 are addressed. --- Returns: --- {errcode}, {output} -function vim._system(cmd) - local out = vim.fn.system(cmd) - local err = vim.v.shell_error - return err, out -end - --- Gets process info from the `ps` command. --- Used by nvim_get_proc() as a fallback. -function vim._os_proc_info(pid) - if pid == nil or pid <= 0 or type(pid) ~= 'number' then - error('invalid pid') - end - local cmd = { 'ps', '-p', pid, '-o', 'comm=', } - local err, name = vim._system(cmd) - if 1 == err and vim.trim(name) == '' then - return {} -- Process not found. - elseif 0 ~= err then - error('command failed: '..vim.fn.string(cmd)) - end - local _, ppid = vim._system({ 'ps', '-p', pid, '-o', 'ppid=', }) - -- Remove trailing whitespace. - name = vim.trim(name):gsub('^.*/', '') - ppid = tonumber(ppid) or -1 - return { - name = name, - pid = pid, - ppid = ppid, - } -end - --- Gets process children from the `pgrep` command. --- Used by nvim_get_proc_children() as a fallback. -function vim._os_proc_children(ppid) - if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then - error('invalid ppid') - end - local cmd = { 'pgrep', '-P', ppid, } - local err, rv = vim._system(cmd) - if 1 == err and vim.trim(rv) == '' then - return {} -- Process not found. - elseif 0 ~= err then - error('command failed: '..vim.fn.string(cmd)) - end - local children = {} - for s in rv:gmatch('%S+') do - local i = tonumber(s) - if i ~= nil then - table.insert(children, i) - end - end - return children -end - --- TODO(ZyX-I): Create compatibility layer. - ---- Return a human-readable representation of the given object. ---- ----@see https://github.com/kikito/inspect.lua ----@see https://github.com/mpeterv/vinspect -local function inspect(object, options) -- luacheck: no unused - error(object, options) -- Stub for gen_vimdoc.py -end - -do - local tdots, tick, got_line1 = 0, 0, false - - --- Paste handler, invoked by |nvim_paste()| when a conforming UI - --- (such as the |TUI|) pastes text into the editor. - --- - --- Example: To remove ANSI color codes when pasting: - ---
-  --- vim.paste = (function(overridden)
-  ---   return function(lines, phase)
-  ---     for i,line in ipairs(lines) do
-  ---       -- Scrub ANSI color codes from paste input.
-  ---       lines[i] = line:gsub('\27%[[0-9;mK]+', '')
-  ---     end
-  ---     overridden(lines, phase)
-  ---   end
-  --- end)(vim.paste)
-  --- 
- --- - ---@see |paste| - --- - ---@param lines |readfile()|-style list of lines to paste. |channel-lines| - ---@param phase -1: "non-streaming" paste: the call contains all lines. - --- If paste is "streamed", `phase` indicates the stream state: - --- - 1: starts the paste (exactly once) - --- - 2: continues the paste (zero or more times) - --- - 3: ends the paste (exactly once) - ---@returns false if client should cancel the paste. - function vim.paste(lines, phase) - local call = vim.api.nvim_call_function - local now = vim.loop.now() - local mode = call('mode', {}):sub(1,1) - if phase < 2 then -- Reset flags. - tdots, tick, got_line1 = now, 0, false - elseif mode ~= 'c' then - vim.api.nvim_command('undojoin') - end - if mode == 'c' and not got_line1 then -- cmdline-mode: paste only 1 line. - got_line1 = (#lines > 1) - vim.api.nvim_set_option('paste', true) -- For nvim_input(). - local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ') -- Scrub. - vim.api.nvim_input(line1) - vim.api.nvim_set_option('paste', false) - elseif mode ~= 'c' then - if phase < 2 and mode:find('^[vV\22sS\19]') then - vim.api.nvim_command([[exe "normal! \"]]) - vim.api.nvim_put(lines, 'c', false, true) - elseif phase < 2 and not mode:find('^[iRt]') then - vim.api.nvim_put(lines, 'c', true, true) - -- XXX: Normal-mode: workaround bad cursor-placement after first chunk. - vim.api.nvim_command('normal! a') - elseif phase < 2 and mode == 'R' then - local nchars = 0 - for _, line in ipairs(lines) do - nchars = nchars + line:len() - end - local row, col = unpack(vim.api.nvim_win_get_cursor(0)) - local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1] - local firstline = lines[1] - firstline = bufline:sub(1, col)..firstline - lines[1] = firstline - lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len()) - vim.api.nvim_buf_set_lines(0, row-1, row, false, lines) - else - vim.api.nvim_put(lines, 'c', false, true) - end - end - if phase ~= -1 and (now - tdots >= 100) then - local dots = ('.'):rep(tick % 4) - tdots = now - tick = tick + 1 - -- Use :echo because Lua print('') is a no-op, and we want to clear the - -- message when there are zero dots. - vim.api.nvim_command(('echo "%s"'):format(dots)) - end - if phase == -1 or phase == 3 then - vim.api.nvim_command('redraw'..(tick > 1 and '|echo ""' or '')) - end - return true -- Paste will not continue if not returning `true`. - end -end - ---- Defers callback `cb` until the Nvim API is safe to call. ---- ----@see |lua-loop-callbacks| ----@see |vim.schedule()| ----@see |vim.in_fast_event()| -function vim.schedule_wrap(cb) - return (function (...) - local args = vim.F.pack_len(...) - vim.schedule(function() cb(vim.F.unpack_len(args)) end) - end) -end - ---- ----@private -function vim.empty_dict() - return setmetatable({}, vim._empty_dict_mt) -end - --- vim.fn.{func}(...) -vim.fn = setmetatable({}, { - __index = function(t, key) - local _fn - if vim.api[key] ~= nil then - _fn = function() - error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key)) - end - else - _fn = function(...) - return vim.call(key, ...) - end - end - t[key] = _fn - return _fn - end -}) - -vim.funcref = function(viml_func_name) - return vim.fn[viml_func_name] -end - --- An easier alias for commands. -vim.cmd = function(command) - return vim.api.nvim_exec(command, false) -end - --- These are the vim.env/v/g/o/bo/wo variable magic accessors. -do - local validate = vim.validate - - --@private - local function make_dict_accessor(scope, handle) - validate { - scope = {scope, 's'}; - } - local mt = {} - function mt:__newindex(k, v) - return vim._setvar(scope, handle or 0, k, v) - end - function mt:__index(k) - if handle == nil and type(k) == 'number' then - return make_dict_accessor(scope, k) - end - return vim._getvar(scope, handle or 0, k) - end - return setmetatable({}, mt) - end - - vim.g = make_dict_accessor('g', false) - vim.v = make_dict_accessor('v', false) - vim.b = make_dict_accessor('b') - vim.w = make_dict_accessor('w') - vim.t = make_dict_accessor('t') -end - ---- Get a table of lines with start, end columns for a region marked by two points ---- ----@param bufnr number of buffer ----@param pos1 (line, column) tuple marking beginning of region ----@param pos2 (line, column) tuple marking end of region ----@param regtype type of selection (:help setreg) ----@param inclusive boolean indicating whether the selection is end-inclusive ----@return region lua table of the form {linenr = {startcol,endcol}} -function vim.region(bufnr, pos1, pos2, regtype, inclusive) - if not vim.api.nvim_buf_is_loaded(bufnr) then - vim.fn.bufload(bufnr) - end - - -- check that region falls within current buffer - local buf_line_count = vim.api.nvim_buf_line_count(bufnr) - pos1[1] = math.min(pos1[1], buf_line_count - 1) - pos2[1] = math.min(pos2[1], buf_line_count - 1) - - -- in case of block selection, columns need to be adjusted for non-ASCII characters - -- TODO: handle double-width characters - local bufline - if regtype:byte() == 22 then - bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1] - pos1[2] = vim.str_utfindex(bufline, pos1[2]) - end - - local region = {} - for l = pos1[1], pos2[1] do - local c1, c2 - if regtype:byte() == 22 then -- block selection: take width from regtype - c1 = pos1[2] - c2 = c1 + regtype:sub(2) - -- and adjust for non-ASCII characters - bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1] - if c1 < #bufline then - c1 = vim.str_byteindex(bufline, c1) - end - if c2 < #bufline then - c2 = vim.str_byteindex(bufline, c2) - end - else - c1 = (l == pos1[1]) and (pos1[2]) or 0 - c2 = (l == pos2[1]) and (pos2[2] + (inclusive and 1 or 0)) or -1 - end - table.insert(region, l, {c1, c2}) - end - return region -end - ---- Defers calling `fn` until `timeout` ms passes. ---- ---- Use to do a one-shot timer that calls `fn` ---- Note: The {fn} is |schedule_wrap|ped automatically, so API functions are ---- safe to call. ----@param fn Callback to call once `timeout` expires ----@param timeout Number of milliseconds to wait before calling `fn` ----@return timer luv timer object -function vim.defer_fn(fn, timeout) - vim.validate { fn = { fn, 'c', true}; } - local timer = vim.loop.new_timer() - timer:start(timeout, 0, vim.schedule_wrap(function() - timer:stop() - timer:close() - - fn() - end)) - - return timer -end - - ---- Display a notification to the user. ---- ---- This function can be overridden by plugins to display notifications using a ---- custom provider (such as the system notification provider). By default, ---- writes to |:messages|. ---- ----@param msg string Content of the notification to show to the user. ----@param level number|nil One of the values from |vim.log.levels|. ----@param opts table|nil Optional parameters. Unused by default. -function vim.notify(msg, level, opts) -- luacheck: no unused args - if level == vim.log.levels.ERROR then - vim.api.nvim_err_writeln(msg) - elseif level == vim.log.levels.WARN then - vim.api.nvim_echo({{msg, 'WarningMsg'}}, true, {}) - else - vim.api.nvim_echo({{msg}}, true, {}) - end -end - -do - local notified = {} - - --- Display a notification only one time. - --- - --- Like |vim.notify()|, but subsequent calls with the same message will not - --- display a notification. - --- - ---@param msg string Content of the notification to show to the user. - ---@param level number|nil One of the values from |vim.log.levels|. - ---@param opts table|nil Optional parameters. Unused by default. - function vim.notify_once(msg, level, opts) -- luacheck: no unused args - if not notified[msg] then - vim.notify(msg, level, opts) - notified[msg] = true - end - end -end - ----@private -function vim.register_keystroke_callback() - error('vim.register_keystroke_callback is deprecated, instead use: vim.on_key') -end - -local on_key_cbs = {} - ---- Adds Lua function {fn} with namespace id {ns_id} as a listener to every, ---- yes every, input key. ---- ---- The Nvim command-line option |-w| is related but does not support callbacks ---- and cannot be toggled dynamically. ---- ----@param fn function: Callback function. It should take one string argument. ---- On each key press, Nvim passes the key char to fn(). |i_CTRL-V| ---- If {fn} is nil, it removes the callback for the associated {ns_id} ----@param ns_id number? Namespace ID. If nil or 0, generates and returns a new ---- |nvim_create_namespace()| id. ---- ----@return number Namespace id associated with {fn}. Or count of all callbacks ----if on_key() is called without arguments. ---- ----@note {fn} will be removed if an error occurs while calling. ----@note {fn} will not be cleared by |nvim_buf_clear_namespace()| ----@note {fn} will receive the keys after mappings have been evaluated -function vim.on_key(fn, ns_id) - if fn == nil and ns_id == nil then - return #on_key_cbs - end - - vim.validate { - fn = { fn, 'c', true}, - ns_id = { ns_id, 'n', true } - } - - if ns_id == nil or ns_id == 0 then - ns_id = vim.api.nvim_create_namespace('') - end - - on_key_cbs[ns_id] = fn - return ns_id -end - ---- Executes the on_key callbacks. ----@private -function vim._on_key(char) - local failed_ns_ids = {} - local failed_messages = {} - for k, v in pairs(on_key_cbs) do - local ok, err_msg = pcall(v, char) - if not ok then - vim.on_key(nil, k) - table.insert(failed_ns_ids, k) - table.insert(failed_messages, err_msg) - end - end - - if failed_ns_ids[1] then - error(string.format( - "Error executing 'on_key' with ns_ids '%s'\n Messages: %s", - table.concat(failed_ns_ids, ", "), - table.concat(failed_messages, "\n"))) - end -end - ---- Generate a list of possible completions for the string. ---- String starts with ^ and then has the pattern. ---- ---- 1. Can we get it to just return things in the global namespace with that name prefix ---- 2. Can we get it to return things from global namespace even with `print(` in front. -function vim._expand_pat(pat, env) - env = env or _G - - pat = string.sub(pat, 2, #pat) - - if pat == '' then - local result = vim.tbl_keys(env) - table.sort(result) - return result, 0 - end - - -- TODO: We can handle spaces in [] ONLY. - -- We should probably do that at some point, just for cooler completion. - -- TODO: We can suggest the variable names to go in [] - -- This would be difficult as well. - -- Probably just need to do a smarter match than just `:match` - - -- Get the last part of the pattern - local last_part = pat:match("[%w.:_%[%]'\"]+$") - if not last_part then return {}, 0 end - - local parts, search_index = vim._expand_pat_get_parts(last_part) - - local match_part = string.sub(last_part, search_index, #last_part) - local prefix_match_pat = string.sub(pat, 1, #pat - #match_part) or '' - - local final_env = env - - for _, part in ipairs(parts) do - if type(final_env) ~= 'table' then - return {}, 0 - end - local key - - -- Normally, we just have a string - -- Just attempt to get the string directly from the environment - if type(part) == "string" then - key = part - else - -- However, sometimes you want to use a variable, and complete on it - -- With this, you have the power. - - -- MY_VAR = "api" - -- vim[MY_VAR] - -- -> _G[MY_VAR] -> "api" - local result_key = part[1] - if not result_key then - return {}, 0 - end - - local result = rawget(env, result_key) - - if result == nil then - return {}, 0 - end - - key = result - end - local field = rawget(final_env, key) - if field == nil then - local mt = getmetatable(final_env) - if mt and type(mt.__index) == "table" then - field = rawget(mt.__index, key) - end - end - final_env = field - - if not final_env then - return {}, 0 - end - end - - local keys = {} - ---@private - local function insert_keys(obj) - for k,_ in pairs(obj) do - if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then - table.insert(keys,k) - end - end - end - - if type(final_env) == "table" then - insert_keys(final_env) - end - local mt = getmetatable(final_env) - if mt and type(mt.__index) == "table" then - insert_keys(mt.__index) - end - - table.sort(keys) - - return keys, #prefix_match_pat -end - -vim._expand_pat_get_parts = function(lua_string) - local parts = {} - - local accumulator, search_index = '', 1 - local in_brackets, bracket_end = false, -1 - local string_char = nil - for idx = 1, #lua_string do - local s = lua_string:sub(idx, idx) - - if not in_brackets and (s == "." or s == ":") then - table.insert(parts, accumulator) - accumulator = '' - - search_index = idx + 1 - elseif s == "[" then - in_brackets = true - - table.insert(parts, accumulator) - accumulator = '' - - search_index = idx + 1 - elseif in_brackets then - if idx == bracket_end then - in_brackets = false - search_index = idx + 1 - - if string_char == "VAR" then - table.insert(parts, { accumulator }) - accumulator = '' - - string_char = nil - end - elseif not string_char then - bracket_end = string.find(lua_string, ']', idx, true) - - if s == '"' or s == "'" then - string_char = s - elseif s ~= ' ' then - string_char = "VAR" - accumulator = s - end - elseif string_char then - if string_char ~= s then - accumulator = accumulator .. s - else - table.insert(parts, accumulator) - accumulator = '' - - string_char = nil - end - end - else - accumulator = accumulator .. s - end - end - - parts = vim.tbl_filter(function(val) return #val > 0 end, parts) - - return parts, search_index -end - ----Prints given arguments in human-readable format. ----Example: ----
----  -- Print highlight group Normal and store it's contents in a variable.
----  local hl_normal = vim.pretty_print(vim.api.nvim_get_hl_by_name("Normal", true))
----
----@see |vim.inspect()| ----@return given arguments. -function vim.pretty_print(...) - local objects = {} - for i = 1, select('#', ...) do - local v = select(i, ...) - table.insert(objects, vim.inspect(v)) - end - - print(table.concat(objects, ' ')) - return ... -end - - -require('vim._meta') - -return vim -- 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') 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 05f643f9d235b0db881acf94ce05ad3359ffb058 Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Tue, 8 Mar 2022 19:58:45 +0100 Subject: chore(lgtm): fix "empty block without comment" warnings --- src/nvim/lua/xdiff.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index ea7a700e1e..37855630d1 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -171,6 +171,7 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, goto exit_1; } if (strequal("unified", v->data.string.data)) { + // the default } else if (strequal("indices", v->data.string.data)) { had_result_type_indices = true; } else { -- 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 ++++++++++++++++++++++------------------------- src/nvim/lua/executor.h | 8 ++++---- src/nvim/lua/spell.c | 8 ++++---- src/nvim/lua/stdlib.c | 4 ++-- 4 files changed, 32 insertions(+), 35 deletions(-) (limited to 'src/nvim/lua') 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; diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index d978dc55d3..e96494ec5a 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -4,8 +4,8 @@ #include #include -#include "nvim/assert.h" #include "nvim/api/private/defs.h" +#include "nvim/assert.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" @@ -16,9 +16,9 @@ void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; typedef struct { - LuaRef nil_ref; - LuaRef empty_dict_ref; - int ref_count; + LuaRef nil_ref; + LuaRef empty_dict_ref; + int ref_count; #if __has_feature(address_sanitizer) PMap(handle_T) ref_markers; #endif diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index 3a63f61200..31a2b2d19f 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -1,12 +1,12 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include #include +#include +#include "nvim/lua/spell.h" #include "nvim/spell.h" #include "nvim/vim.h" -#include "nvim/lua/spell.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/spell.c.generated.h" @@ -45,7 +45,7 @@ int nlua_spell_check(lua_State *lstate) size_t pos = 0; int capcol = -1; int no_res = 0; - const char * result; + const char *result; lua_createtable(lstate, 0, 0); @@ -90,7 +90,7 @@ int nlua_spell_check(lua_State *lstate) static const luaL_Reg spell_functions[] = { { "check", nlua_spell_check }, - { NULL , NULL } + { NULL, NULL } }; int luaopen_spell(lua_State *L) diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index c2ce899a74..e94c61b37c 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -28,10 +28,10 @@ #include "nvim/globals.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" +#include "nvim/lua/spell.h" #include "nvim/lua/stdlib.h" #include "nvim/lua/treesitter.h" #include "nvim/lua/xdiff.h" -#include "nvim/lua/spell.h" #include "nvim/macros.h" #include "nvim/map.h" #include "nvim/memline.h" @@ -411,7 +411,7 @@ int nlua_getvar(lua_State *lstate) dictitem_T *di = tv_dict_find(dict, name, (ptrdiff_t)len); if (di == NULL && dict == &globvardict) { // try to autoload script if (!script_autoload(name, len, false) || aborting()) { - return 0; // nil + return 0; // nil } di = tv_dict_find(dict, name, (ptrdiff_t)len); } -- cgit From 4ba12b3dda34472c193c9fa8ffd7d3bd5b6c04d6 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 13 Mar 2022 15:11:17 +0100 Subject: refactor: fix clint warnings (#17682) --- src/nvim/lua/converter.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 2b54e56df1..beea1959e1 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -286,9 +286,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) break; case LUA_TBOOLEAN: cur.tv->v_type = VAR_BOOL; - cur.tv->vval.v_bool = (lua_toboolean(lstate, -1) - ? kBoolVarTrue - : kBoolVarFalse); + cur.tv->vval.v_bool = (lua_toboolean(lstate, -1) ? kBoolVarTrue : kBoolVarFalse); break; case LUA_TSTRING: { size_t len; @@ -551,8 +549,8 @@ static bool typval_conv_special = false; const MPConvStackVal mpval = kv_A(*mpstack, backref - 1); \ if (mpval.type == conv_type) { \ if (conv_type == kMPConvDict \ - ? (void *)mpval.data.d.dict == (void *)(val) \ - : (void *)mpval.data.l.list == (void *)(val)) { \ + ? (void *)mpval.data.d.dict == (void *)(val) \ + : (void *)mpval.data.l.list == (void *)(val)) { \ lua_pushvalue(lstate, \ -((int)((kv_size(*mpstack) - backref + 1) * 2))); \ break; \ @@ -1133,10 +1131,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(lstate, -1, &len); - *cur.obj = STRING_OBJ(((String) { - .data = xmemdupz(s, len), - .size = len, - })); + *cur.obj = STRING_OBJ(((String) { .data = xmemdupz(s, len), .size = len })); break; } case LUA_TNUMBER: { @@ -1154,11 +1149,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) switch (table_props.type) { case kObjectTypeArray: - *cur.obj = ARRAY_OBJ(((Array) { - .items = NULL, - .size = 0, - .capacity = 0, - })); + *cur.obj = ARRAY_OBJ(((Array) { .items = NULL, .size = 0, .capacity = 0 })); if (table_props.maxidx != 0) { cur.obj->data.array.items = xcalloc(table_props.maxidx, @@ -1169,11 +1160,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) } break; case kObjectTypeDictionary: - *cur.obj = DICTIONARY_OBJ(((Dictionary) { - .items = NULL, - .size = 0, - .capacity = 0, - })); + *cur.obj = DICTIONARY_OBJ(((Dictionary) { .items = NULL, .size = 0, .capacity = 0 })); if (table_props.string_keys_num != 0) { cur.obj->data.dictionary.items = xcalloc(table_props.string_keys_num, -- cgit From cac90d2de728181edce7ba38fb9ad588d231651b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 18 Mar 2022 03:21:47 +0800 Subject: feat(api, lua): support converting nested Funcref back to LuaRef (#17749) --- src/nvim/lua/converter.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index beea1959e1..0bb224c729 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -476,7 +476,13 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ - TYPVAL_ENCODE_CONV_NIL(tv); \ + ufunc_T *fp = find_func(fun); \ + assert(fp != NULL); \ + if (fp->uf_cb == nlua_CFunction_func_call) { \ + nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \ + } else { \ + TYPVAL_ENCODE_CONV_NIL(tv); \ + } \ goto typval_encode_stop_converting_one_item; \ } while (0) @@ -615,14 +621,6 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) semsg(_("E1502: Lua failed to grow stack to %i"), initial_size + 4); return false; } - if (tv->v_type == VAR_FUNC) { - ufunc_T *fp = find_func(tv->vval.v_string); - assert(fp != NULL); - if (fp->uf_cb == nlua_CFunction_func_call) { - nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); - return true; - } - } if (encode_vim_to_lua(lstate, tv, "nlua_push_typval argument") == FAIL) { return false; } -- cgit From 77eb6f9dc75ebe00aa835441ad623ba46d7108bb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 20 Mar 2022 08:08:50 +0800 Subject: fix(api, lua): return NIL on failure to find converted function (#17779) --- src/nvim/lua/converter.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 0bb224c729..ef49a03660 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -477,8 +477,7 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ ufunc_T *fp = find_func(fun); \ - assert(fp != NULL); \ - if (fp->uf_cb == nlua_CFunction_func_call) { \ + if (fp != NULL && fp->uf_cb == nlua_CFunction_func_call) { \ nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \ } else { \ TYPVAL_ENCODE_CONV_NIL(tv); \ -- 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') 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/converter.c | 2 +- src/nvim/lua/executor.c | 26 ++++++++++++-------------- src/nvim/lua/stdlib.c | 10 +++++----- src/nvim/lua/treesitter.c | 24 ++++++++++++------------ src/nvim/lua/xdiff.c | 2 +- 5 files changed, 31 insertions(+), 33 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index ef49a03660..daf3a32a98 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -1236,7 +1236,7 @@ LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err) type ret; \ if (lua_type(lstate, -1) != LUA_TNUMBER) { \ api_set_error(err, kErrorTypeValidation, "Expected Lua number"); \ - ret = (type)-1; \ + ret = (type) - 1; \ } else { \ ret = (type)lua_tonumber(lstate, -1); \ } \ 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")); } } - diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index e94c61b37c..52a9a1a84f 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -59,8 +59,8 @@ static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) *prog = rm.regprog; if (match) { - lua_pushinteger(lstate, (lua_Integer)(rm.startp[0]-str)); - lua_pushinteger(lstate, (lua_Integer)(rm.endp[0]-str)); + lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - str)); + lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - str)); return 2; } return 0; @@ -110,7 +110,7 @@ static int regex_match_line(lua_State *lstate) return luaL_error(lstate, "invalid row"); } - char_u *line = ml_get_buf(buf, rownr+1, false); + char_u *line = ml_get_buf(buf, rownr + 1, false); size_t len = STRLEN(line); if (start < 0 || (size_t)start > len) { @@ -126,7 +126,7 @@ static int regex_match_line(lua_State *lstate) line[end] = NUL; } - int nret = regex_match(lstate, prog, line+start); + int nret = regex_match(lstate, prog, line + start); if (end >= 0) { line[end] = save; @@ -208,7 +208,7 @@ static int nlua_str_utf_pos(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL size_t idx = 1; size_t clen; for (size_t i = 0; i < s1_len && s1[i] != NUL; i += clen) { - clen = (size_t)utf_ptr2len_len((const char_u *)(s1)+i, (int)(s1_len-i)); + clen = (size_t)utf_ptr2len_len((const char_u *)(s1) + i, (int)(s1_len - i)); lua_pushinteger(lstate, (long)i + 1); lua_rawseti(lstate, -2, (int)idx); idx++; diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index f4067ad02f..a871cd29ce 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -208,7 +208,7 @@ int tslua_inspect_lang(lua_State *L) size_t nsymbols = (size_t)ts_language_symbol_count(lang); - lua_createtable(L, nsymbols-1, 1); // [retval, symbols] + lua_createtable(L, nsymbols - 1, 1); // [retval, symbols] for (size_t i = 0; i < nsymbols; i++) { TSSymbolType t = ts_language_symbol_type(lang, i); if (t == TSSymbolTypeAuxiliary) { @@ -298,15 +298,15 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position *bytes_read = 0; return ""; } - char_u *line = ml_get_buf(bp, position.row+1, false); + char_u *line = ml_get_buf(bp, position.row + 1, false); size_t len = STRLEN(line); if (position.column > len) { *bytes_read = 0; return ""; } - size_t tocopy = MIN(len-position.column, BUFSIZE); + size_t tocopy = MIN(len - position.column, BUFSIZE); - memcpy(buf, line+position.column, tocopy); + memcpy(buf, line + position.column, tocopy); // Translate embedded \n to NUL memchrsub(buf, '\n', '\0', tocopy); *bytes_read = (uint32_t)tocopy; @@ -334,7 +334,7 @@ static void push_ranges(lua_State *L, const TSRange *ranges, const unsigned int lua_pushinteger(L, ranges[i].end_point.column); lua_rawseti(L, -2, 4); - lua_rawseti(L, -2, i+1); + lua_rawseti(L, -2, i + 1); } } @@ -1037,7 +1037,7 @@ static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx) { for (int i = 0; i < match->capture_count; i++) { push_node(L, match->captures[i].node, nodeidx); - lua_rawseti(L, -2, match->captures[i].index+1); + lua_rawseti(L, -2, match->captures[i].index + 1); } } @@ -1049,7 +1049,7 @@ static int query_next_match(lua_State *L) TSQuery *query = query_check(L, lua_upvalueindex(3)); TSQueryMatch match; if (ts_query_cursor_next_match(cursor, &match)) { - lua_pushinteger(L, match.pattern_index+1); // [index] + lua_pushinteger(L, match.pattern_index + 1); // [index] lua_createtable(L, ts_query_capture_count(query), 2); // [index, match] set_match(L, &match, lua_upvalueindex(2)); return 2; @@ -1082,7 +1082,7 @@ static int query_next_capture(lua_State *L) if (ts_query_cursor_next_capture(cursor, &match, &capture_index)) { TSQueryCapture capture = match.captures[capture_index]; - lua_pushinteger(L, capture.index+1); // [index] + lua_pushinteger(L, capture.index + 1); // [index] push_node(L, capture.node, lua_upvalueindex(2)); // [index, node] // Now check if we need to run the predicates @@ -1094,7 +1094,7 @@ static int query_next_capture(lua_State *L) lua_pushvalue(L, lua_upvalueindex(4)); // [index, node, match] set_match(L, &match, lua_upvalueindex(2)); - lua_pushinteger(L, match.pattern_index+1); + lua_pushinteger(L, match.pattern_index + 1); lua_setfield(L, -2, "pattern"); if (match.capture_count > 1) { @@ -1273,7 +1273,7 @@ static int query_inspect(lua_State *L) &strlen); lua_pushlstring(L, str, strlen); // [retval, patterns, pat, pred, item] } else if (step[k].type == TSQueryPredicateStepTypeCapture) { - lua_pushnumber(L, step[k].value_id+1); // [..., pat, pred, item] + lua_pushnumber(L, step[k].value_id + 1); // [..., pat, pred, item] } else { abort(); } @@ -1281,7 +1281,7 @@ static int query_inspect(lua_State *L) } // last predicate should have ended with TypeDone lua_pop(L, 1); // [retval, patters, pat] - lua_rawseti(L, -2, i+1); // [retval, patterns] + lua_rawseti(L, -2, i + 1); // [retval, patterns] } lua_setfield(L, -2, "patterns"); // [retval] @@ -1291,7 +1291,7 @@ static int query_inspect(lua_State *L) uint32_t strlen; const char *str = ts_query_capture_name_for_id(query, i, &strlen); lua_pushlstring(L, str, strlen); // [retval, captures, capture] - lua_rawseti(L, -2, i+1); + lua_rawseti(L, -2, i + 1); } lua_setfield(L, -2, "captures"); // [retval] diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 37855630d1..71f85385b6 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -74,7 +74,7 @@ static int hunk_locations_cb(long start_a, long count_a, long start_b, long coun lua_pushinteger(lstate, count_b); lua_rawseti(lstate, -2, 4); - lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2)+1); + lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1); return 0; } -- 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') 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 e453b6391e1483286385b925f5799dfc4feebdd8 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Tue, 3 May 2022 19:46:11 +0200 Subject: fix(treesitter): bump match limit up This avoids ignoring too many match results, and avoid highlighting being blank in some files. --- src/nvim/lua/treesitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index a871cd29ce..f36a00d9cd 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -1122,7 +1122,7 @@ static int node_rawquery(lua_State *L) // TODO(clason): API introduced after tree-sitter release 0.19.5 // remove guard when minimum ts version is bumped to 0.19.6+ #ifdef NVIM_TS_HAS_SET_MATCH_LIMIT - ts_query_cursor_set_match_limit(cursor, 32); + ts_query_cursor_set_match_limit(cursor, 64); #endif ts_query_cursor_exec(cursor, query, node); -- cgit From a0f17fd4d8e12caad85f0bdf38e64839d8d41079 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 14 Apr 2022 15:00:15 +0200 Subject: perf(treesitter): use a reuse list for query cursors --- src/nvim/lua/treesitter.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index a871cd29ce..c981be9aec 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -16,6 +16,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/buffer.h" +#include "nvim/lib/kvec.h" #include "nvim/lua/treesitter.h" #include "nvim/memline.h" #include "tree_sitter/api.h" @@ -104,6 +105,7 @@ static struct luaL_Reg treecursor_meta[] = { { NULL, NULL } }; +static kvec_t(TSQueryCursor *) cursors = KV_INITIAL_VALUE; static PMap(cstr_t) langs = MAP_INIT; static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) @@ -1116,9 +1118,13 @@ static int node_rawquery(lua_State *L) return 0; } TSQuery *query = query_check(L, 2); - // TODO(bfredl): these are expensive allegedly, - // use a reuse list later on? - TSQueryCursor *cursor = ts_query_cursor_new(); + + TSQueryCursor *cursor; + if (kv_size(cursors) > 0) { + cursor = kv_pop(cursors); + } else { + cursor = ts_query_cursor_new(); + } // TODO(clason): API introduced after tree-sitter release 0.19.5 // remove guard when minimum ts version is bumped to 0.19.6+ #ifdef NVIM_TS_HAS_SET_MATCH_LIMIT @@ -1161,7 +1167,8 @@ static int node_rawquery(lua_State *L) static int querycursor_gc(lua_State *L) { TSLua_cursor *ud = luaL_checkudata(L, 1, TS_META_QUERYCURSOR); - ts_query_cursor_delete(ud->cursor); + kv_push(cursors, ud->cursor); + ud->cursor = NULL; return 0; } -- 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') 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/converter.c | 2 +- src/nvim/lua/executor.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index daf3a32a98..782fc425fc 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -394,7 +394,7 @@ nlua_pop_typval_table_processing_end: state); cur.tv->v_type = VAR_FUNC; - cur.tv->vval.v_string = vim_strsave(name); + cur.tv->vval.v_string = (char *)vim_strsave(name); break; } case LUA_TUSERDATA: { 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') 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') 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') 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 f0148de7907ec297647816d51c79745be729439e Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Mon, 9 May 2022 11:49:32 +0200 Subject: refactor: replace char_u variables and functions with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/stdlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 52a9a1a84f..79e21e518c 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -295,7 +295,7 @@ int nlua_regex(lua_State *lstate) TRY_WRAP({ try_start(); - prog = vim_regcomp((char_u *)text, RE_AUTO | RE_MAGIC | RE_STRICT); + prog = vim_regcomp((char *)text, RE_AUTO | RE_MAGIC | RE_STRICT); try_end(&err); }); -- 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') 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/converter.c | 4 ---- src/nvim/lua/executor.c | 9 --------- src/nvim/lua/stdlib.c | 2 -- src/nvim/lua/treesitter.c | 5 ----- 4 files changed, 20 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 782fc425fc..4d6e6090b8 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -49,7 +49,6 @@ typedef struct { #define LUA_PUSH_STATIC_STRING(lstate, s) \ lua_pushlstring(lstate, s, sizeof(s) - 1) - static LuaTableProps nlua_traverse_table(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { @@ -674,7 +673,6 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, lua_rawset(lstate, -3); } - /// Convert given String to lua string /// /// Leaves converted string on top of the stack. @@ -808,7 +806,6 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special) } } - /// Convert lua value to string /// /// Always pops one value from the stack. @@ -1297,7 +1294,6 @@ void nlua_init_types(lua_State *const lstate) lua_rawset(lstate, -3); } - void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err) { if (!lua_istable(L, -1)) { 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)); diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 79e21e518c..432cb25adc 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -349,7 +349,6 @@ static dict_T *nlua_get_var_scope(lua_State *lstate) return dict; } - int nlua_setvar(lua_State *lstate) { // non-local return if not found @@ -470,7 +469,6 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } - void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index d3693207ec..6ec9cfd21d 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -529,7 +529,6 @@ static int parser_set_ranges(lua_State *L) size_t tbl_len = lua_objlen(L, 2); TSRange *ranges = xmalloc(sizeof(TSRange) * tbl_len); - // [ parser, ranges ] for (size_t index = 0; index < tbl_len; index++) { lua_rawgeti(L, 2, index + 1); // [ parser, ranges, range ] @@ -558,7 +557,6 @@ static int parser_get_ranges(lua_State *L) return 1; } - // Tree methods /// push tree interface on lua stack. @@ -656,7 +654,6 @@ static bool node_check(lua_State *L, int index, TSNode *res) return false; } - static int node_tostring(lua_State *L) { TSNode node; @@ -1059,7 +1056,6 @@ static int query_next_match(lua_State *L) return 0; } - static int query_next_capture(lua_State *L) { // Upvalues are: @@ -1205,7 +1201,6 @@ int tslua_parse_query(lua_State *L) return 1; } - static const char *query_err_string(TSQueryError err) { switch (err) { -- 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') 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') 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 ff20d40321399fa187bd350f9619cf6418d7eb6e Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 4 Jun 2022 05:56:36 +0200 Subject: docs: fix typos (#18269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: zeertzjq Co-authored-by: Dan Sully Co-authored-by: saher Co-authored-by: Stephan Seitz Co-authored-by: Benedikt Müller Co-authored-by: Andrey Mishchenko Co-authored-by: Famiu Haque Co-authored-by: Oliver Marriott --- src/nvim/lua/treesitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 6ec9cfd21d..b96193d199 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -391,7 +391,7 @@ static int parser_parse(lua_State *L) return luaL_error(L, "An error occurred when parsing."); } - // The new tree will be pushed to the stack, without copy, owwership is now to + // The new tree will be pushed to the stack, without copy, ownership is now to // the lua GC. // Old tree is still owned by the lua GC. uint32_t n_ranges = 0; -- 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') 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') 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 a732c253b71f89702285d5ec6fd7803045f6add9 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Sat, 7 May 2022 12:53:37 +0200 Subject: refactor: change type of linenr_T from long to int32_t The size of long varies depending on architecture, in contrast to the MAXLNUM constant which sets the maximum allowable number of lines to 2^32-1. This discrepancy may lead to hard to detect bugs, for example https://github.com/neovim/neovim/issues/18454. Setting linenr_T to a fix maximum size of 2^32-1 will prevent this type of errors in the future. Also change the variables `amount` and `amount_after` to be linenr_T since they're referring to "the line number difference" between two texts. --- src/nvim/lua/stdlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 432cb25adc..b911eb8b59 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -89,7 +89,7 @@ static int regex_match_line(lua_State *lstate) } long bufnr = luaL_checkinteger(lstate, 2); - long rownr = luaL_checkinteger(lstate, 3); + linenr_T rownr = (linenr_T)luaL_checkinteger(lstate, 3); long start = 0, end = -1; if (narg >= 4) { start = luaL_checkinteger(lstate, 4); -- 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') 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') 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') 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') 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') 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 3b8804571c565a91c9ce729bb487c7ba21b659e0 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Tue, 28 Jun 2022 13:03:09 +0200 Subject: refactor: replace char_u Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/stdlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index b911eb8b59..7afb31d55b 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -55,7 +55,7 @@ static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) regmatch_T rm; rm.regprog = *prog; rm.rm_ic = false; - bool match = vim_regexec(&rm, str, 0); + bool match = vim_regexec(&rm, (char *)str, 0); *prog = rm.regprog; if (match) { @@ -252,7 +252,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL if (offset < 0 || offset > (intptr_t)s1_len) { return luaL_error(lstate, "index out of range"); } - int tail_offset = mb_tail_off((char_u *)s1, (char_u *)s1 + offset - 1); + int tail_offset = mb_tail_off(s1, s1 + offset - 1); lua_pushinteger(lstate, tail_offset); return 1; } -- cgit From 0160ff6aa0e2c60843e908ecd83eb9eaa416db02 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 1 Jul 2022 19:17:15 +0200 Subject: fix(lua): don't leak memory on error --- src/nvim/lua/stdlib.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index b911eb8b59..2a89592edb 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -300,7 +300,9 @@ int nlua_regex(lua_State *lstate) }); if (ERROR_SET(&err)) { - return luaL_error(lstate, "couldn't parse regex: %s", err.msg); + nlua_push_errstr(lstate, "couldn't parse regex: %s", err.msg); + api_clear_error(&err); + return lua_error(lstate); } assert(prog); @@ -338,12 +340,14 @@ static dict_T *nlua_get_var_scope(lua_State *lstate) dict = tabpage->tp_vars; } } else { - luaL_error(lstate, "invalid scope", err.msg); + luaL_error(lstate, "invalid scope"); return NULL; } if (ERROR_SET(&err)) { - luaL_error(lstate, "FAIL: %s", err.msg); + nlua_push_errstr(lstate, "scoped variable: %s", err.msg); + api_clear_error(&err); + lua_error(lstate); return NULL; } return dict; @@ -537,3 +541,14 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) lua_cjson_new(lstate); lua_setfield(lstate, -2, "json"); } + +/// like luaL_error, but allow cleanup +void nlua_push_errstr(lua_State *L, const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); +} -- 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') 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') 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') 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