diff options
Diffstat (limited to 'src/nvim/lua/executor.c')
-rw-r--r-- | src/nvim/lua/executor.c | 125 |
1 files changed, 98 insertions, 27 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 86da517685..5c665920b5 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -299,45 +299,66 @@ static int nlua_wait(lua_State *lstate) return luaL_error(lstate, "timeout must be > 0"); } - // Check if condition can be called. - bool is_function = (lua_type(lstate, 2) == LUA_TFUNCTION); + int lua_top = lua_gettop(lstate); - // Check if condition is callable table - if (!is_function && luaL_getmetafield(lstate, 2, "__call") != 0) { - is_function = (lua_type(lstate, -1) == LUA_TFUNCTION); - lua_pop(lstate, 1); - } + // Check if condition can be called. + bool is_function = false; + if (lua_top >= 2 && !lua_isnil(lstate, 2)) { + is_function = (lua_type(lstate, 2) == LUA_TFUNCTION); + + // Check if condition is callable table + if (!is_function && luaL_getmetafield(lstate, 2, "__call") != 0) { + is_function = (lua_type(lstate, -1) == LUA_TFUNCTION); + lua_pop(lstate, 1); + } - if (!is_function) { - lua_pushliteral(lstate, "vim.wait: condition must be a function"); - return lua_error(lstate); + if (!is_function) { + lua_pushliteral( + lstate, + "vim.wait: if passed, condition must be a function"); + return lua_error(lstate); + } } intptr_t interval = 200; - if (lua_gettop(lstate) >= 3) { + if (lua_top >= 3 && !lua_isnil(lstate, 3)) { interval = luaL_checkinteger(lstate, 3); if (interval < 0) { return luaL_error(lstate, "interval must be > 0"); } } + bool fast_only = false; + if (lua_top >= 4) { + fast_only = lua_toboolean(lstate, 4); + } + + MultiQueue *loop_events = fast_only || in_fast_callback > 0 + ? main_loop.fast_events : main_loop.events; + TimeWatcher *tw = xmalloc(sizeof(TimeWatcher)); // Start dummy timer. time_watcher_init(&main_loop, tw, NULL); - tw->events = main_loop.events; + tw->events = loop_events; tw->blockable = true; - time_watcher_start(tw, dummy_timer_due_cb, - (uint64_t)interval, (uint64_t)interval); + time_watcher_start( + tw, + dummy_timer_due_cb, + (uint64_t)interval, + (uint64_t)interval); int pcall_status = 0; bool callback_result = false; LOOP_PROCESS_EVENTS_UNTIL( &main_loop, - main_loop.events, + loop_events, (int)timeout, - nlua_wait_condition(lstate, &pcall_status, &callback_result) || got_int); + is_function ? nlua_wait_condition( + lstate, + &pcall_status, + &callback_result) : false || got_int); // Stop dummy timer time_watcher_stop(tw); @@ -845,7 +866,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref) } } -void executor_free_luaref(LuaRef ref) +void api_free_luaref(LuaRef ref) { lua_State *const lstate = nlua_enter(); nlua_unref(lstate, ref); @@ -879,8 +900,8 @@ LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref) /// @param[out] ret_tv Location where result will be saved. /// /// @return Result of the execution. -void executor_eval_lua(const String str, typval_T *const arg, - typval_T *const ret_tv) +void nlua_typval_eval(const String str, typval_T *const arg, + typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { #define EVALHEADER "local _A=select(1,...) return (" @@ -902,8 +923,8 @@ void executor_eval_lua(const String str, typval_T *const arg, } } -void executor_call_lua(const char *str, size_t len, typval_T *const args, - int argcount, typval_T *ret_tv) +void nlua_typval_call(const char *str, size_t len, typval_T *const args, + int argcount, typval_T *ret_tv) FUNC_ATTR_NONNULL_ALL { #define CALLHEADER "return " @@ -1006,14 +1027,14 @@ int typval_exec_lua_callable( /// Execute Lua string /// -/// Used for nvim_exec_lua(). +/// Used for nvim_exec_lua() and internally to execute a lua string. /// /// @param[in] str String to execute. /// @param[in] args array of ... args /// @param[out] err Location where error will be saved. /// /// @return Return value of the execution. -Object executor_exec_lua_api(const String str, const Array args, Error *err) +Object nlua_exec(const String str, const Array args, Error *err) { lua_State *const lstate = nlua_enter(); @@ -1040,17 +1061,30 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err) return nlua_pop_Object(lstate, false, err); } -Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args, - bool retval, Error *err) +/// call a LuaRef as a function (or table with __call metamethod) +/// +/// @param ref the reference to call (not consumed) +/// @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 +/// @param err Error details, if any (if NULL, errors are echoed) +/// @return Return value of function, if retval was set. Otherwise NIL. +Object nlua_call_ref(LuaRef ref, const char *name, Array args, + bool retval, Error *err) { lua_State *const lstate = nlua_enter(); nlua_pushref(lstate, ref); - lua_pushstring(lstate, name); + int nargs = (int)args.size; + if (name != NULL) { + lua_pushstring(lstate, name); + nargs++; + } for (size_t i = 0; i < args.size; i++) { nlua_push_Object(lstate, args.items[i], false); } - if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) { + if (lua_pcall(lstate, nargs, retval ? 1 : 0, 0)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; @@ -1465,3 +1499,40 @@ void nlua_free_typval_dict(dict_T *const d) d->lua_table_ref = LUA_NOREF; } } + +void nlua_execute_log_keystroke(int c) +{ + char_u buf[NUMBUFLEN]; + size_t buf_len = special_to_buf(c, mod_mask, false, buf); + + lua_State *const lstate = nlua_enter(); + +#ifndef NDEBUG + int top = lua_gettop(lstate); +#endif + + // [ vim ] + lua_getglobal(lstate, "vim"); + + // [ vim, vim._log_keystroke ] + lua_getfield(lstate, -1, "_log_keystroke"); + luaL_checktype(lstate, -1, LUA_TFUNCTION); + + // [ vim, vim._log_keystroke, buf ] + lua_pushlstring(lstate, (const char *)buf, buf_len); + + if (lua_pcall(lstate, 1, 0, 0)) { + nlua_error( + lstate, + _("Error executing vim.log_keystroke lua callback: %.*s")); + } + + // [ vim ] + lua_pop(lstate, 1); + +#ifndef NDEBUG + // [ ] + assert(top == lua_gettop(lstate)); +#endif +} + |