nvim_oxi/
toplevel.rs

1use std::error::Error as StdError;
2
3use luajit::{self as lua, ffi::*, macros::cstr};
4use types::Function;
5
6use crate::IntoResult;
7
8/// Binding to [`vim.schedule()`][1].
9///
10/// Schedules a callback to be invoked soon by the main event-loop. Useful to
11/// avoid [`textlock`][2] or other temporary restrictions.
12///
13/// [1]: https://neovim.io/doc/user/lua.html#vim.schedule()
14/// [2]: https://neovim.io/doc/user/eval.html#textlock
15pub fn schedule<F, R>(fun: F)
16where
17    F: FnOnce(()) -> R + 'static,
18    R: IntoResult<()>,
19    R::Error: StdError + 'static,
20{
21    // https://github.com/neovim/neovim/blob/v0.9.0/src/nvim/lua/executor.c#L363
22    //
23    // Unfortunately the `nlua_schedule` C function is not exported, so we have
24    // to call the Lua function instead.
25    unsafe {
26        lua::with_state(move |lstate| {
27            // Put `vim.schedule` on the stack.
28            lua_getglobal(lstate, cstr!("vim"));
29            lua_getfield(lstate, -1, cstr!("schedule"));
30
31            // Store the function in the registry and put a reference to it on
32            // the stack.
33            let fun = Function::from_fn_once(fun);
34            lua_rawgeti(lstate, LUA_REGISTRYINDEX, fun.lua_ref());
35
36            lua_call(lstate, 1, 0);
37
38            // Pop `vim` off the stack and remove the function from the registry.
39            lua_pop(lstate, 1);
40            luaL_unref(lstate, LUA_REGISTRYINDEX, fun.lua_ref());
41        })
42    };
43}