From 81e1dbca99c1485ab28ecb2c46d8d71a61bdb35d Mon Sep 17 00:00:00 2001 From: Andrey Popp <8mayday@gmail.com> Date: Thu, 24 Jan 2019 19:52:05 +0300 Subject: lua: add vim.schedule(cb) This executes Lua callback on main loop's event queue so that nvim API is safe to call. --- src/nvim/lua/executor.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index fa8a67ff39..1c1d51a10a 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -36,6 +36,12 @@ typedef struct { String lua_err_str; } LuaError; +/// We use this to store Lua callbacks +typedef struct { + // TODO: store more info for debugging, traceback? + int cb; +} nlua_ctx; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/vim_module.generated.h" # include "lua/executor.c.generated.h" @@ -108,6 +114,36 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } +static void nlua_schedule_cb(void **argv) +{ + nlua_ctx *ctx = argv[0]; + lua_State *const lstate = nlua_enter(); + lua_rawgeti(lstate, LUA_REGISTRYINDEX, ctx->cb); + luaL_unref(lstate, LUA_REGISTRYINDEX, ctx->cb); + lua_pcall(lstate, 0, 0, 0); + free(ctx); +} + +/// Schedule Lua callback on main loop's event queue +/// +/// This is used to make sure nvim API is called at the right moment. +/// +/// @param lstate Lua interpreter state. +/// @param[in] msg Message base, must contain one `%s`. +static int nlua_schedule(lua_State *const lstate) + FUNC_ATTR_NONNULL_ALL +{ + // TODO: report error using nlua_error instead + luaL_checktype(lstate, 1, LUA_TFUNCTION); + + nlua_ctx* ctx = (nlua_ctx*)malloc(sizeof(nlua_ctx)); + lua_pushvalue(lstate, 1); + ctx->cb = luaL_ref(lstate, LUA_REGISTRYINDEX); + + multiqueue_put(main_loop.events, nlua_schedule_cb, 1, ctx); + return 0; +} + /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -143,6 +179,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL // stricmp lua_pushcfunction(lstate, &nlua_stricmp); lua_setfield(lstate, -2, "stricmp"); + // schedule + lua_pushcfunction(lstate, &nlua_schedule); + lua_setfield(lstate, -2, "schedule"); lua_setglobal(lstate, "vim"); return 0; -- cgit From b684bd05b513b57b4d67ea2f95f7713c0b18daab Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 4 Jun 2019 19:32:43 +0200 Subject: lua: docs and tests for vim.schedule --- src/nvim/lua/executor.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'src/nvim/lua/executor.c') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1c1d51a10a..df08a9dd87 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -36,12 +36,6 @@ typedef struct { String lua_err_str; } LuaError; -/// We use this to store Lua callbacks -typedef struct { - // TODO: store more info for debugging, traceback? - int cb; -} nlua_ctx; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/vim_module.generated.h" # include "lua/executor.c.generated.h" @@ -114,33 +108,32 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } -static void nlua_schedule_cb(void **argv) +static void nlua_schedule_event(void **argv) { - nlua_ctx *ctx = argv[0]; + LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; lua_State *const lstate = nlua_enter(); - lua_rawgeti(lstate, LUA_REGISTRYINDEX, ctx->cb); - luaL_unref(lstate, LUA_REGISTRYINDEX, ctx->cb); - lua_pcall(lstate, 0, 0, 0); - free(ctx); + nlua_pushref(lstate, cb); + nlua_unref(lstate, cb); + if (lua_pcall(lstate, 0, 0, 0)) { + nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s")); + } } /// Schedule Lua callback on main loop's event queue /// -/// This is used to make sure nvim API is called at the right moment. -/// /// @param lstate Lua interpreter state. -/// @param[in] msg Message base, must contain one `%s`. static int nlua_schedule(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { - // TODO: report error using nlua_error instead - luaL_checktype(lstate, 1, LUA_TFUNCTION); + if (lua_type(lstate, 1) != LUA_TFUNCTION) { + lua_pushliteral(lstate, "vim.schedule: expected function"); + return lua_error(lstate); + } - nlua_ctx* ctx = (nlua_ctx*)malloc(sizeof(nlua_ctx)); - lua_pushvalue(lstate, 1); - ctx->cb = luaL_ref(lstate, LUA_REGISTRYINDEX); + LuaRef cb = nlua_ref(lstate, 1); - multiqueue_put(main_loop.events, nlua_schedule_cb, 1, ctx); + multiqueue_put(main_loop.events, nlua_schedule_event, + 1, (void *)(ptrdiff_t)cb); return 0; } -- cgit