nvim-nio/README.md

246 lines
6.3 KiB
Markdown
Raw Permalink Normal View History

2023-12-20 17:58:17 +01:00
# nvim-nio
2023-12-20 16:07:38 +01:00
A library for asynchronous IO in Neovim, inspired by the asyncio library in Python. The library focuses on providing
both common asynchronous primitives and asynchronous APIs for Neovim's core.
2023-12-20 17:35:29 +01:00
- [Motivation](#motivation)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
2024-02-09 22:23:00 +01:00
- [`nio.control`](#niocontrol): Primitives for flow control in async functions
- [`nio.lsp`](#niolsp): A fully typed and documented async LSP client library, generated from the LSP specification.
- [`nio.file`](#niofile): Open and operate on files asynchronously
- [`nio.process`](#nioprocess): Run and control subprocesses asynchronously
- [`nio.uv`](#niouv): Async versions of `vim.loop` functions
- [`nio.ui`](#nioui): Async versions of vim.ui functions
- [`nio.tests`](#niotests): Async versions of plenary.nvim's test functions
- [Third Party Integration](#third-party-integration)
2024-03-18 18:12:19 +01:00
- [Used By](#used-by)
2023-12-20 17:35:29 +01:00
2023-12-20 16:07:38 +01:00
## Motivation
Work has been ongoing around async libraries in Neovim for years, with a lot of discussion around a [Neovim core
2024-02-09 22:23:00 +01:00
implementation](https://github.com/neovim/neovim/issues/19624). Much of the motivation behind this library can be seen
2023-12-20 16:07:38 +01:00
in that discussion.
nvim-nio aims to provide a simple interface to Lua coroutines that doesn't feel like it gets in the way of your actual
logic. You won't even know you're using them. An example of this is error handling. With other libraries, a custom
`pcall` or some other custom handling must be used to catch errors. With nvim-nio, Lua's built-in `pcall` works exactly
as you'd expect.
nvim-nio is focused on providing a great developer experience. The API is well documented with examples and full type
annotations, which can all be used by the Lua LSP. It's recommended to use
[neodev.nvim](https://github.com/folke/neodev.nvim) to get LSP support.
![image](https://github.com/nvim-lua/plenary.nvim/assets/24252670/0dda462c-0b5c-4300-8e65-b7218e3d2c1e)
Credit to the async library in [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) and
[async.nvim](https://github.com/lewis6991/async.nvim) for inspiring nvim-nio and its implementation.
If Neovim core integrates an async library, nvim-nio will aim to maintain compatibility with it if possible.
## Installation
Install with your favourite package manager
[lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
{ "nvim-neotest/nvim-nio" }
```
[dein](https://github.com/Shougo/dein.vim):
```vim
call dein#add("nvim-neotest/nvim-nio")
```
[vim-plug](https://github.com/junegunn/vim-plug)
```vim
Plug 'nvim-neotest/nvim-nio'
```
[packer.nvim](https://github.com/wbthomason/packer.nvim)
```lua
use { "nvim-neotest/nvim-nio" }
```
## Configuration
There are no configuration options currently available.
## Usage
nvim-nio is based on the concept of tasks. These tasks represent a series of asynchronous actions that run in a single
context. Under the hood, each task is running on a separate lua coroutine.
Tasks are created by providing an async function to `nio.run`. All async
functions must be called from a task.
```lua
local nio = require("nio")
local task = nio.run(function()
nio.sleep(10)
print("Hello world")
end)
```
For simple use cases tasks won't be too important but they support features such as cancelling and retrieving stack traces.
nvim-nio comes with built-in modules to help with writing async code. See `:help nvim-nio` for extensive documentation.
2024-02-09 22:23:00 +01:00
### `nio.control`
Primitives for flow control in async functions
2023-12-20 16:07:38 +01:00
```lua
local event = nio.control.event()
2024-02-19 09:46:05 +01:00
local worker = nio.run(function()
2023-12-20 16:07:38 +01:00
nio.sleep(1000)
event.set()
end)
local listeners = {
2024-02-19 09:46:05 +01:00
nio.run(function()
2023-12-20 16:07:38 +01:00
event.wait()
print("First listener notified")
end),
2024-02-19 09:46:05 +01:00
nio.run(function()
2023-12-20 16:07:38 +01:00
event.wait()
print("Second listener notified")
end),
}
```
2024-02-09 22:23:00 +01:00
### `nio.lsp`
A fully typed and documented async LSP client library, generated from the LSP specification.
2023-12-20 16:07:38 +01:00
```lua
local client = nio.lsp.get_clients({ name = "lua_ls" })[1]
local err, response = client.request.textDocument_semanticTokens_full({
textDocument = { uri = vim.uri_from_bufnr(0) },
})
assert(not err, err)
for _, token in pairs(response.data) do
print(token)
end
```
2024-02-09 22:23:00 +01:00
### `nio.file`
Open and operate on files asynchronously
```lua
local file = nio.file.open("test.txt", "w+")
file.write("Hello, World!\n")
local content = file.read(nil, 0)
print(content)
```
### `nio.process`
Run and control subprocesses asynchronously
```lua
local first = nio.process.run({
cmd = "printf", args = { "hello" }
})
local second = nio.process.run({
cmd = "cat", stdin = first.stdout
})
local output = second.stdout.read()
print(output)
```
### `nio.uv`
Async versions of `vim.loop` functions
2023-12-20 16:07:38 +01:00
```lua
local file_path = "README.md"
local open_err, file_fd = nio.uv.fs_open(file_path, "r", 438)
assert(not open_err, open_err)
local stat_err, stat = nio.uv.fs_fstat(file_fd)
assert(not stat_err, stat_err)
local read_err, data = nio.uv.fs_read(file_fd, stat.size, 0)
assert(not read_err, read_err)
local close_err = nio.uv.fs_close(file_fd)
assert(not close_err, close_err)
print(data)
```
2024-02-09 22:23:00 +01:00
### `nio.ui`
Async versions of vim.ui functions
2023-12-20 16:07:38 +01:00
```lua
local value = nio.ui.input({ prompt = "Enter something: " })
print(("You entered: %s"):format(value))
```
2024-02-09 22:23:00 +01:00
### `nio.tests`
Async versions of plenary.nvim's test functions
2023-12-20 16:07:38 +01:00
```lua
nio.tests.it("notifies listeners", function()
local event = nio.control.event()
local notified = 0
for _ = 1, 10 do
nio.run(function()
event.wait()
notified = notified + 1
end)
end
event.set()
nio.sleep(10)
assert.equals(10, notified)
end)
```
2024-02-09 22:23:00 +01:00
### Third Party Integration
2023-12-20 16:07:38 +01:00
It is also easy to wrap callback style functions to make them asynchronous using `nio.wrap`, which allows easily
integrating third-party APIs with nvim-nio.
```lua
local nio = require("nio")
local sleep = nio.wrap(function(ms, cb)
vim.defer_fn(cb, ms)
end, 2)
nio.run(function()
sleep(10)
print("Slept for 10ms")
end)
```
2024-03-18 18:12:19 +01:00
## Used By
Here are some of the plugins using nvim-nio:
- [neotest](https://github.com/nvim-neotest/neotest)
- [nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)
- [rest.nvim](https://github.com/rest-nvim/rest.nvim)
- [rocks.nvim](https://github.com/nvim-neorocks/rocks.nvim)
- [pathlib.nvim](https://github.com/pysan3/pathlib.nvim)
Please open an issue to add any missing entries!