aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/executor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/lua/executor.c')
-rw-r--r--src/nvim/lua/executor.c81
1 files changed, 80 insertions, 1 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 4e94c10283..df08a9dd87 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -108,6 +108,35 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
+static void nlua_schedule_event(void **argv)
+{
+ LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
+ lua_State *const lstate = nlua_enter();
+ 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
+///
+/// @param lstate Lua interpreter state.
+static int nlua_schedule(lua_State *const lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (lua_type(lstate, 1) != LUA_TFUNCTION) {
+ lua_pushliteral(lstate, "vim.schedule: expected function");
+ return lua_error(lstate);
+ }
+
+ LuaRef cb = nlua_ref(lstate, 1);
+
+ multiqueue_put(main_loop.events, nlua_schedule_event,
+ 1, (void *)(ptrdiff_t)cb);
+ return 0;
+}
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -143,6 +172,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;
@@ -363,6 +395,33 @@ static int nlua_getenv(lua_State *lstate)
}
#endif
+/// add the value to the registry
+LuaRef nlua_ref(lua_State *lstate, int index)
+{
+ lua_pushvalue(lstate, index);
+ return luaL_ref(lstate, LUA_REGISTRYINDEX);
+}
+
+/// remove the value from the registry
+void nlua_unref(lua_State *lstate, LuaRef ref)
+{
+ if (ref > 0) {
+ luaL_unref(lstate, LUA_REGISTRYINDEX, ref);
+ }
+}
+
+void executor_free_luaref(LuaRef ref)
+{
+ lua_State *const lstate = nlua_enter();
+ nlua_unref(lstate, ref);
+}
+
+/// push a value referenced in the regirstry
+void nlua_pushref(lua_State *lstate, LuaRef ref)
+{
+ lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref);
+}
+
/// Evaluate lua string
///
/// Used for luaeval().
@@ -451,9 +510,29 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err)
return NIL;
}
- return nlua_pop_Object(lstate, err);
+ return nlua_pop_Object(lstate, false, err);
}
+Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
+{
+ lua_State *const lstate = nlua_enter();
+ nlua_pushref(lstate, ref);
+ lua_pushstring(lstate, name);
+ for (size_t i = 0; i < args.size; i++) {
+ nlua_push_Object(lstate, args.items[i]);
+ }
+
+ if (lua_pcall(lstate, (int)args.size+1, 1, 0)) {
+ // TODO(bfredl): callbacks:s might not always be msg-safe, for instance
+ // lua callbacks for redraw events. Later on let the caller deal with the
+ // error instead.
+ nlua_error(lstate, _("Error executing lua callback: %.*s"));
+ return NIL;
+ }
+ Error err = ERROR_INIT;
+
+ return nlua_pop_Object(lstate, false, &err);
+}
/// Run lua string
///