nvim-nio

repository·master·Indexed 19 days ago

https://github.com/nvim-neotest/nvim-nio

An asynchronous IO library for Neovim inspired by Python's asyncio. It provides async primitives and APIs for LSP, file systems, processes, and UI, utilizing Lua coroutines for tasks and maintaining compatibility with Lua's native error handling via pcall.

Tokens
1.6K
Snippets
10
Records
10
Agent score
15%

What's inside nvim-nio

  1. How tasks and nio.run work

    master

    In nvim-nio, asynchronous actions are organized into tasks. A task represents a series of async actions running in a single context, backed by a Lua coroutine.

    To execute asynchronous code, you must wrap it in an async function and pass it to nio.run. All async functions must be called from within a task.

    One key advantage of nvim-nio is that it integrates with Lua's built-in pcall, allowing standard error handling to work as expected without custom wrappers.

    local nio = require("nio")
    
    local task = nio.run(function()
      nio.sleep(10)
      print("Hello world")
    end)
  2. Install nvim-nio

    master

    Install nvim-nio using your preferred Neovim package manager.

    -- lazy.nvim
    { "nvim-neotest/nvim-nio" }
    
    -- packer.nvim
    use { "nvim-neotest/nvim-nio" }
    " dein
    call dein#add("nvim-neotest/nvim-nio")
    
    " vim-plug
    Plug 'nvim-neotest/nvim-nio'
  3. Use nio.control for flow control

    master

    The nio.control module provides primitives for managing execution flow in async functions. For example, you can use nio.control.event() to create an event that multiple tasks can wait for.

    local event = nio.control.event()
    
    local worker = nio.run(function()
      nio.sleep(1000)
      event.set()
    end)
    
    local listeners = {
      nio.run(function()
        event.wait()
        print("First listener notified")
      end),
      nio.run(function()
        event.wait()
        print("Second listener notified")
      end),
    }
  4. Use nio.uv for async Libuv functions

    master

    The nio.uv module provides async versions of vim.loop (Libuv) functions, such as file system operations.

    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)
    
    print(data)
  5. Use nio.lsp for async LSP client requests

    master

    The nio.lsp module provides a fully typed, async LSP client library generated from the LSP specification. You can retrieve clients using nio.lsp.get_clients({ name = "..." }) and call LSP methods directly as async functions.

    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
  6. Use nio.tests for async testing

    master

    The nio.tests module provides async versions of plenary.nvim's test functions, allowing you to write asynchronous test cases using nio.tests.it.

    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)
  7. Wrap callback-style functions with nio.wrap

    master

    You can integrate third-party APIs that use callbacks into nvim-nio by using nio.wrap. This converts a callback-based function into an asynchronous function that can be awaited within a task.

    local nio = require("nio")
    
    -- Wrap a function that takes (ms, callback)
    local sleep = nio.wrap(function(ms, cb)
      vim.defer_fn(cb, ms)
    end, 2)
    
    nio.run(function()
      sleep(10)
      print("Slept for 10ms")
    end)
  8. Use nio.process for async subprocesses

    master

    The nio.process module allows you to run and control subprocesses asynchronously. You can pipe the output of one process into the input of another by passing the stdout property of a process object.

    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)