bookmarks.nvim/lua/bookmarks/async.lua

86 lines
1.7 KiB
Lua

local co = coroutine
local async_thread = {
threads = {},
}
local function threadtostring(x)
if jit then
return string.format("%p", x)
else
return tostring(x):match "thread: (.*)"
end
end
function async_thread.running()
local thread = co.running()
local id = threadtostring(thread)
return async_thread.threads[id]
end
function async_thread.create(fn)
local thread = co.create(fn)
local id = threadtostring(thread)
async_thread.threads[id] = true
return thread
end
function async_thread.finished(x)
if co.status(x) == "dead" then
local id = threadtostring(x)
async_thread.threads[id] = nil
return true
end
return false
end
local function execute(async_fn, ...)
local thread = async_thread.create(async_fn)
local function step(...)
local ret = { co.resume(thread, ...) }
local stat, err_or_fn, nargs = unpack(ret)
if not stat then
error(string.format("The coroutine failed with this message: %s\n%s", err_or_fn, debug.traceback(thread)))
end
if async_thread.finished(thread) then
return
end
assert(type(err_or_fn) == "function", "type error :: expected func")
local ret_fn = err_or_fn
local args = { select(4, unpack(ret)) }
args[nargs] = step
ret_fn(unpack(args, 1, nargs))
end
step(...)
end
local M = {}
function M.wrap(func, argc)
return function(...)
if not async_thread.running() then
return func(...)
end
return co.yield(func, argc, ...)
end
end
function M.void(func)
return function(...)
if async_thread.running() then
return func(...)
end
execute(func, ...)
end
end
M.scheduler = M.wrap(vim.schedule, 1)
return M