Nvim :help pages, generated
from source
using the tree-sitter-vimdoc parser.
vim.async lets Lua code wait for timers, callbacks, and other tasks without
blocking Nvim's event loop. Async work runs inside tasks, which can pause at
checkpoints and manage child tasks created while they are running.local async = vim.async for brevity.local async = vim.async
async.run(function()
vim.notify('waiting...')
async.sleep(1000)
vim.notify('done')
end)err, value:local async = vim.async
async.run(function()
local err, stat = async.await(2, fs_stat, 'notes.txt')
if err then
error(err, 0)
end
print(('notes.txt is %d bytes'):format(stat.size))
end)vim.async saves the Lua stack and returns control
to the event loop. Other callbacks can run while the task is paused. Nothing
interrupts synchronous Lua code in the middle of a stack frame.vim.async.await(...)
vim.async.pawait(...)
vim.async.checkpoint()
vim.async closes that operation before reporting the
cancellation.await(task) returns the task result or raises the
task failure. vim.async.pawait() is the async counterpart to pcall() for
recoverable awaited-operation failures; it returns ok, ... instead of
failing the current task for that awaited operation. It does not suppress
cancellation or a failure already pending on the current task.vim.async.semaphore(permits) creates a
vim.async.Semaphore that limits how many tasks can hold a permit for a
section at once.{close} (fun(self, callback?: fun()))
{is_closing}? (fun(self): boolean)
acquire() suspends the current task until another
task releases one.with() method, which
automatically acquires and releases the semaphore around a function call.
This is useful for limiting sections that start external work and then
await it, such as file reads, requests, or subprocesses.local async = vim.async
async.run(function()
local limit = async.semaphore(4)
local tasks = {}
for _, path in ipairs(paths) do
table.insert(tasks, async.run(function()
return limit:with(function()
return read_file(path)
end)
end))
end
local next_task = async.iter(tasks)
while true do
local task = next_task()
if task == nil then
break
end
async.await(task)
end
end){name}? (string) Name of the task
{on_complete} (fun(self: vim.async.Task, callback: fun(err?: any, ...: R...)): fun())
See Task:on_complete().
{traceback} (fun(self: vim.async.Task, msg: string?, level: integer?): string)
See Task:traceback().
local async = vim.async
async.run(function()
local err, stat = async.await(2, vim.uv.fs_stat, 'notes.txt')
if err then
error(err, 0)
end
print(stat.size)
end)local async = vim.async
async.run(function()
local lines = async.await(function(done)
return start_read_lines('notes.txt', done)
end)
render(lines)
end){...} (any) see overloads
async fun(func: (fun(callback: fun(...: R...)): vim.async.Closable?)): R...
async fun(argc: integer, func: (fun(...: T..., callback: fun(...: R...)): vim.async.Closable?), ...: T...): R...
async fun(task: vim.async.Task<R>): R...
R...)local ok, err = pcall(cleanup_sensitive_work)
cleanup_resources()
vim.async.checkpoint()
if not ok then
error(err, 0)
endwhile not vim.async.is_closing() do
poll_once()
vim.async.sleep(1000)
endboolean)local async = vim.async
async.run(function()
local tasks = {
async.run(function() return 'cache', read_cache() end):detach(),
async.run(function() return 'disk', read_file() end):detach(),
}
for task in async.iter(tasks) do
local ok, source, text = async.pawait(task)
if ok then
for _, other in ipairs(tasks) do
if other ~= task then
other:close()
end
end
print(('loaded from %s'):format(source))
return text
end
end
end)for loop. The iterator may need to suspend while waiting for the
next completed task, and PUC Lua 5.1 cannot yield from a generic-for
iterator call.local next_task = async.iter(tasks)
while true do
local task = next_task()
if task == nil then
break
end
async.await(task)
end{tasks} (vim.async.Task<R>[]) A list of tasks to wait for and
iterate over.
async fun(): vim.async.Task<R>?) iterator that yields each
completed task.pcall(). Accepts the same forms as
vim.async.await(), but returns a leading ok boolean for
awaited-operation failures.local async = vim.async
async.run(function()
local ok, text_or_err = async.pawait(async.run(read_file, 'notes.txt'))
if not ok then
text_or_err = ''
end
show_buffer(text_or_err)
end){...} (any) see overloads
async fun(func: (fun(callback: fun(...: R...)): vim.async.Closable?)): boolean, R...
async fun(argc: integer, func: (fun(...: T..., callback: fun(...: R...)): vim.async.Closable?), ...: T...): boolean, R...
async fun(task: vim.async.Task<R>): boolean, R...
boolean) ok
(R...) ... result or error
(_overload) true
(R...)
(_overload) false
(any)local async = vim.async
async.run(function()
local child = async.run(function()
return read_file('notes.txt')
end)
local text = async.await(child)
show_buffer(text)
end)local task = vim.async.run(function()
vim.async.sleep(100)
return 'done'
end)
print(task:wait()){func} (async fun(...: T...): R...)
{...} (T...) Arguments to pass to the function
fun(name: string, func: async fun(...: T...), ...: T...): vim.async.Task<R...>
vim.async.Task<R...>)1 and
return immediately. If it is 0, wait until Semaphore:release() is
called.1 and can wake a task waiting in
Semaphore:acquire().{fn} (async fun(): R...) Function to execute within the semaphore's
context.
R...) Result(s) of the executed function.sleep() returns
to its caller through the runtime's schedule hook.vim.async.run(function()
vim.async.sleep(100)
vim.notify('resumed later')
end){duration} (integer) ms
"closed".{callback} (fun()?)
boolean)vim.async.run(function()
while true do
refresh_index()
vim.async.sleep(1000)
end
end):detach()vim.async.Task<R>){callback}) Task:on_complete(){callback} (fun(err?: any, ...: R...))
fun()) unsubscribepcall(task.wait, task, timeout).local ok, result_or_err = task:pwait(1000)
if not ok then
vim.notify(tostring(result_or_err), vim.log.levels.ERROR)
end{timeout} (integer?)
boolean)
(R...)vim.async.Task<R>) self"running": task is currently executing Lua code
"normal": task is active but another coroutine is running
"awaiting": task is suspended at a checkpoint or waiting for children
"completed": task and all attached children have completed
"running"|"awaiting"|"normal"|"completed"){msg}, {level}) Task:traceback(){msg} (string?)
{level} (integer?)
string) traceback"timeout". With no timeout, waits indefinitely.local result = task:wait(10) -- wait for 10ms or raise "timeout"
local result = task:wait() -- wait indefinitely{timeout} (integer?)
R...)"timeout" after the target task finishes cancellation cleanup.local async = vim.async
async.run(function()
local task = async.run(read_file, 'notes.txt')
local text = async.timeout(5000, task)
show_buffer(text)
end){duration} (integer) Timeout duration in milliseconds
{task} (vim.async.Task<R>)
R...)argc. If func returns a
closable handle, it is closed when the awaiting task is cancelled.local async = vim.async
local fs_stat = async.wrap(2, vim.uv.fs_stat)
async.run(function()
local err, stat = fs_stat(vim.api.nvim_buf_get_name(0))
if not err and stat then
print(stat.size)
end
end){argc} (integer)
{func} (fun(...: T..., callback: fun(...: R...)): vim.async.Closable?)
async fun(...: T...): R...)