aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/executor.c
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2019-11-06 19:23:24 +0100
committerTJ DeVries <devries.timothyj@gmail.com>2020-05-30 12:01:32 -0400
commit504d6878da8fc128f68396f9ff42d2b1d2ff16b1 (patch)
tree5142b8b1f44493da4b22d2fbb7109bd82589c9cf /src/nvim/lua/executor.c
parent7d8dc4c331fee2527dfe499066035fa7470ad5b3 (diff)
downloadrneovim-504d6878da8fc128f68396f9ff42d2b1d2ff16b1.tar.gz
rneovim-504d6878da8fc128f68396f9ff42d2b1d2ff16b1.tar.bz2
rneovim-504d6878da8fc128f68396f9ff42d2b1d2ff16b1.zip
lua: vim.wait initial outline
Diffstat (limited to 'src/nvim/lua/executor.c')
-rw-r--r--src/nvim/lua/executor.c92
1 files changed, 91 insertions, 1 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 144646fca2..f2075897b4 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -28,6 +28,8 @@
#include "nvim/ascii.h"
#include "nvim/change.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/event/time.h"
+#include "nvim/event/loop.h"
#ifdef WIN32
#include "nvim/os/os.h"
@@ -255,6 +257,91 @@ static struct luaL_Reg regex_meta[] = {
{ NULL, NULL }
};
+// 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)
+{
+ xfree(tw);
+}
+
+static bool nlua_wait_condition(lua_State *lstate, int *status,
+ bool *callback_result)
+{
+ lua_pushvalue(lstate, 2);
+ *status = lua_pcall(lstate, 0, 1, 0);
+ if (*status) {
+ return true; // break on error, but keep error on stack
+ }
+ *callback_result = lua_toboolean(lstate, -1);
+ lua_pop(lstate, 1);
+ return *callback_result; // break if true
+}
+
+/// "vim.wait(timeout, condition[, interval])" function
+static int nlua_wait(lua_State *lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ intptr_t timeout = luaL_checkinteger(lstate, 1);
+ if (timeout < 0) {
+ return luaL_error(lstate, "timeout must be > 0");
+ }
+ if (lua_type(lstate, 2) != LUA_TFUNCTION) {
+ lua_pushliteral(lstate, "vim.wait: condition must be a function");
+ return lua_error(lstate);
+ }
+
+ intptr_t interval = 200;
+ if (lua_gettop(lstate) >= 3) {
+ interval = luaL_checkinteger(lstate, 3);
+ if (interval < 0) {
+ return luaL_error(lstate, "interval must be > 0");
+ }
+ }
+
+ TimeWatcher *tw = xmalloc(sizeof(TimeWatcher));
+
+ // Start dummy timer.
+ time_watcher_init(&main_loop, tw, NULL);
+ tw->events = main_loop.events;
+ tw->blockable = true;
+ 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, (int)timeout,
+ nlua_wait_condition(lstate, &pcall_status,
+ &callback_result)
+ || got_int);
+
+ if (pcall_status) {
+ // TODO: add prefix to error?
+ // handled after stopped time_watcher
+ } else if (got_int) {
+ got_int = false;
+ vgetc();
+ lua_pushinteger(lstate, -2);
+ } else if (callback_result) {
+ lua_pushinteger(lstate, 0);
+ } else {
+ lua_pushinteger(lstate, -1);
+ }
+
+ // Stop dummy timer
+ time_watcher_stop(tw);
+ time_watcher_close(tw, dummy_timer_close_cb);
+
+ if (pcall_status) {
+ return lua_error(lstate);
+ }
+ return 1;
+}
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -305,7 +392,6 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// 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]
@@ -320,6 +406,10 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_rpcnotify);
lua_setfield(lstate, -2, "rpcnotify");
+ // wait
+ lua_pushcfunction(lstate, &nlua_wait);
+ lua_setfield(lstate, -2, "wait");
+
// vim.loop
luv_set_loop(lstate, &main_loop.uv);
luv_set_callback(lstate, nlua_luv_cfpcall);