From 813476bf7291dfaf9fc0ef77c9f53a07258a3801 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Tue, 30 Aug 2022 23:13:52 +0100 Subject: fix(exceptions): restore `did_throw` (#20000) `!did_throw` doesn't exactly imply `!current_exception`, as `did_throw = false` is sometimes used to defer exception handling for later (without forgetting the exception). E.g: uncaught exception handling in `do_cmdline()` may be deferred to a different call (e.g: when `try_level > 0`). In #7881, `current_exception = NULL` in `do_cmdline()` is used as an analogue of `did_throw = false`, but also causes the pending exception to be lost, which also leaks as `discard_exception()` wasn't used. It may be possible to fix this by saving/restoring `current_exception`, but handling all of `did_throw`'s edge cases seems messier. Maybe not worth diverging over. This fix also uncovers a `man_spec.lua` bug on Windows: exceptions are thrown due to Windows missing `man`, but they're lost; skip these tests if `man` isn't executable. --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 39585ac182..42aa13cfc1 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1027,7 +1027,7 @@ int nlua_call(lua_State *lstate) // TODO(bfredl): this should be simplified in error handling refactor force_abort = false; suppress_errthrow = false; - current_exception = NULL; + did_throw = false; did_emsg = false; try_start(); -- cgit From f31db30975479cb6b57247f124a65f4362f80bfe Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 30 Jun 2022 13:26:31 +0600 Subject: feat(lua): vim.ui_attach to get ui events from lua Co-authored-by: Famiu Haque --- src/nvim/lua/executor.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 4 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 42aa13cfc1..f144e47c3a 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -7,6 +7,7 @@ #include #include "luv/luv.h" +#include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" @@ -40,6 +41,9 @@ #include "nvim/os/os.h" #include "nvim/profile.h" #include "nvim/runtime.h" +#include "nvim/screen.h" +#include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/usercmd.h" #include "nvim/version.h" @@ -589,6 +593,71 @@ static bool nlua_init_packages(lua_State *lstate) return true; } +/// "vim.ui_attach(ns_id, {ext_foo=true}, cb)" function +static int nlua_ui_attach(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1); + + if (!ns_initialized(ns_id)) { + return luaL_error(lstate, "invalid ns_id"); + } + if (!lua_istable(lstate, 2)) { + return luaL_error(lstate, "ext_widgets must be a table"); + } + if (!lua_isfunction(lstate, 3)) { + return luaL_error(lstate, "callback must be a Lua function"); + } + + bool ext_widgets[kUIGlobalCount] = { false }; + bool tbl_has_true_val = false; + + lua_pushvalue(lstate, 2); + lua_pushnil(lstate); + while (lua_next(lstate, -2)) { + // [dict, key, val] + size_t len; + const char *s = lua_tolstring(lstate, -2, &len); + bool val = lua_toboolean(lstate, -1); + + for (size_t i = 0; i < kUIGlobalCount; i++) { + if (strequal(s, ui_ext_names[i])) { + if (val) { + tbl_has_true_val = true; + } + ext_widgets[i] = val; + goto ok; + } + } + + return luaL_error(lstate, "Unexpected key: %s", s); +ok: + lua_pop(lstate, 1); + } + + if (!tbl_has_true_val) { + return luaL_error(lstate, "ext_widgets table must contain at least one 'true' value"); + } + + LuaRef ui_event_cb = nlua_ref_global(lstate, 3); + ui_comp_add_cb(ns_id, ui_event_cb, ext_widgets); + return 0; +} + +/// "vim.ui_detach(ns_id)" function +static int nlua_ui_detach(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1); + + if (!ns_initialized(ns_id)) { + return luaL_error(lstate, "invalid ns_id"); + } + + ui_comp_remove_cb(ns_id); + return 0; +} + /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -649,6 +718,14 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_wait); lua_setfield(lstate, -2, "wait"); + // ui_attach + lua_pushcfunction(lstate, &nlua_ui_attach); + lua_setfield(lstate, -2, "ui_attach"); + + // ui_detach + lua_pushcfunction(lstate, &nlua_ui_detach); + lua_setfield(lstate, -2, "ui_detach"); + nlua_common_vim_init(lstate, false); // patch require() (only for --startuptime) @@ -1422,9 +1499,10 @@ bool nlua_ref_is_function(LuaRef ref) /// @param name if non-NULL, sent to callback as first arg /// if NULL, only args are used /// @param retval if true, convert return value to Object -/// if false, discard return value +/// if false, only check if return value is truthy /// @param err Error details, if any (if NULL, errors are echoed) -/// @return Return value of function, if retval was set. Otherwise NIL. +/// @return Return value of function, if retval was set. Otherwise +/// BOOLEAN_OBJ(true) or NIL. Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err) { lua_State *const lstate = global_lstate; @@ -1438,7 +1516,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro nlua_push_Object(lstate, args.items[i], false); } - if (nlua_pcall(lstate, nargs, retval ? 1 : 0)) { + if (nlua_pcall(lstate, nargs, 1)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; @@ -1458,7 +1536,10 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro } return nlua_pop_Object(lstate, false, err); } else { - return NIL; + bool value = lua_toboolean(lstate, -1); + lua_pop(lstate, 1); + + return value ? BOOLEAN_OBJ(true) : NIL; } } -- cgit From 689f5d604e59eba1ddab6f91b458a8163dc6629d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Sep 2022 20:32:59 +0800 Subject: feat(api): add support for :horizontal modifier --- src/nvim/lua/executor.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index f144e47c3a..2315ecd874 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2103,6 +2103,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushboolean(lstate, cmdmod.cmod_split & WSP_VERT); lua_setfield(lstate, -2, "vertical"); + lua_pushboolean(lstate, cmdmod.cmod_split & WSP_HOR); + lua_setfield(lstate, -2, "horizontal"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT); lua_setfield(lstate, -2, "silent"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT); -- cgit From 1ef7720567b08caec0c077605fb2a01a9d6eafbc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Sep 2022 18:46:34 +0800 Subject: fix(api)!: correctly deal with number before :tab Now nvim_parse_cmd and nvim_create_user_command use a "tab" value which is the same as the number passed before :tab modifier instead of the number plus 1, and "tab" value is -1 if :tab modifier is not used. --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 2315ecd874..1013cf76f9 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2082,7 +2082,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_newtable(lstate); // smods table - lua_pushinteger(lstate, cmdmod.cmod_tab); + lua_pushinteger(lstate, cmdmod.cmod_tab - 1); lua_setfield(lstate, -2, "tab"); lua_pushinteger(lstate, cmdmod.cmod_verbose - 1); -- cgit From db9b8b08e74ae8cfb08960eca0a7273538ebcdf1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 6 Sep 2022 22:23:54 +0200 Subject: refactor(typval): change FC_CFUNC abstraction into FC_LUAREF "cfuncs" was only ever used to wrap luarefs. As vim8script is finished and will not be developed further, support for "cfuncs" for other usecases are not planned. This abstraction was immediately broken anyway in order to get luarefs out of userfuncs again. Even if a new kind of userfunc needs to be invented in the future, likely just extending the FC_... flag union directy, instead of invoking unnecessary heap object and c function pointer indirection, will be a more straightforward design pattern. --- src/nvim/lua/executor.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1013cf76f9..857e2111d6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1425,12 +1425,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) /// @param[in] argcount Count of typval arguments /// @param[in] argvars Typval Arguments /// @param[out] rettv The return value from the called function. -int typval_exec_lua_callable(lua_State *lstate, LuaCallable lua_cb, int argcount, typval_T *argvars, - typval_T *rettv) +int typval_exec_lua_callable(LuaRef lua_cb, int argcount, typval_T *argvars, typval_T *rettv) { - LuaRef cb = lua_cb.func_ref; + lua_State *lstate = global_lstate; - nlua_pushref(lstate, cb); + nlua_pushref(lstate, lua_cb); PUSH_ALL_TYPVALS(lstate, argvars, argcount, false); @@ -1833,26 +1832,6 @@ static int nlua_is_thread(lua_State *lstate) 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) -{ - lua_State *const lstate = global_lstate; - LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - - return typval_exec_lua_callable(lstate, funcstate->lua_callable, - argcount, argvars, rettv); -} - -void nlua_CFunction_func_free(void *state) -{ - lua_State *const lstate = global_lstate; - LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - - nlua_unref_global(lstate, funcstate->lua_callable.func_ref); - xfree(funcstate); -} - bool nlua_is_table_from_lua(typval_T *const arg) { if (arg->v_type == VAR_DICT) { @@ -1898,11 +1877,9 @@ 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_global(lstate, -1); + LuaRef func = nlua_ref_global(lstate, -1); - char_u *name = register_cfunc(&nlua_CFunction_func_call, - &nlua_CFunction_func_free, state); + char_u *name = register_luafunc(func); lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); -- cgit From c5322e752e9e568de907f7a1ef733bbfe342140c Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Fri, 26 Aug 2022 23:11:25 +0200 Subject: refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 857e2111d6..78ac051308 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1044,7 +1044,7 @@ static int nlua_debug(lua_State *lstate) if (input.v_type != VAR_STRING || input.vval.v_string == NULL || *input.vval.v_string == NUL - || STRCMP(input.vval.v_string, "cont") == 0) { + || strcmp(input.vval.v_string, "cont") == 0) { tv_clear(&input); return 0; } -- cgit