local uv = vim.uv or vim.loop local M = {} local function create_async_handle(callback) local async async = uv.new_async(vim.schedule_wrap(function(ret) callback(unpack(vim.mpack.decode(ret))) async:close() end)) return async end ---@param callback fun(...) Function to call when the thread returns ---@param fn fun(...) Function to run in a thread ---@param ... any Arguments to pass to the function M.run_in_thread = function(callback, fn, ...) M.wrap_threaded(fn)(..., callback) end ---@param fn fun(...: any): any Function to run in a thread ---@return fun(...: any): any Async function that accepts the same arguments except the last argument is a callback function with the return values as parameters ---@example --- local function sleep_greeter(name) --- vim.loop.sleep(1000) --- return "Hello " .. name --- end --- local async_sleep_greeter = wrap_threaded(sleep_greeter) --- async_sleep_greeter("John", function(greeting) --- print(greeting) --- end) M.wrap_threaded = function(fn) local str_fun = string.dump(fn) return function(...) local callback = select(-1, ...) local args = { ... } -- Remove the callback from args args[select("#", ...)] = nil local handle = create_async_handle(callback) uv.new_thread(function(fn_str, async, args_str) local thread_args = vim.mpack.decode(args_str) local ret = { loadstring(fn_str)(unpack(thread_args)) } async:send(vim.mpack.encode(ret)) end, str_fun, handle, vim.mpack.encode(args)) end end return M