Open-Source Wikis

/

Neovim

/

Systems

/

API and msgpack-rpc

neovim/neovim

API and msgpack-rpc

Purpose

Neovim exposes its functionality as a public API: a flat namespace of nvim_* functions defined in C, callable in-process from Lua and Vimscript and out-of-process over msgpack-rpc by any UI, plugin host, or remote client. This subsystem covers both the API surface (src/nvim/api/) and the RPC transport (src/nvim/msgpack_rpc/).

Directory layout

src/nvim/api/
├── vim.c (2,577 lines)         The catch-all (nvim_eval, nvim_command, nvim_input, ...)
├── buffer.c (1,430)            nvim_buf_*
├── window.c                    nvim_win_*
├── win_config.c (1,530)        nvim_open_win and friends
├── tabpage.c                   nvim_tabpage_*
├── ui.c (1,039)                nvim_ui_attach, nvim_ui_*
├── ui_events.in.h              UI event prototype list
├── command.c (1,341)           nvim_create_user_command, nvim_buf_create_user_command, ...
├── extmark.c (1,374)           nvim_buf_set_extmark and friends
├── autocmd.c (878)             nvim_create_autocmd, nvim_create_augroup, ...
├── options.c                   nvim_get_option_value, nvim_set_option_value
├── vimscript.c                 nvim_eval, nvim_call_function, nvim_call_dict_function
├── deprecated.c (32k bytes)    Old API kept as warning-level shims
├── events.c                    nvim_exec_autocmds
├── private/                    Internal helpers + generated dispatch
└── keysets_defs.h              Generated typed dict descriptors

src/nvim/msgpack_rpc/
├── channel.c (~21k bytes)      Channels: stdio, sockets, jobs
├── channel.h, channel_defs.h
├── server.c                    nvim_listen / nvim_serverstart
├── server.h
├── packer.c                    msgpack writer
├── packer.h, packer_defs.h
└── unpacker.c                  msgpack reader (~19k bytes)

Key abstractions

Type File Description
Object api/private/defs.h The variant value used everywhere across the API boundary.
Error api/private/defs.h Carries failure reason and message. Out-parameter on every API function.
Channel msgpack_rpc/channel_defs.h A connection — id, kind (stdio/socket/job), readers, writers, RPC state.
MsgpackPacker/Unpacker msgpack_rpc/packer.c/unpacker.c Stream codec.
String, Buffer, Window, Tabpage api/private/defs.h Distinct integer-handle types.
Array, Dict, LuaRef api/private/defs.h Compound types crossing the boundary.
Dispatcher (generated) api/private/dispatch.c (gen) Strings → C function pointers + arg coercion.

API contract

Every nvim_* function:

  1. Lives in src/nvim/api/<area>.c.
  2. Has a doc comment with @param / @return annotations parsed by src/gen/cdoc_parser.lua.
  3. Takes parameters as API types only: Boolean, Integer, Float, String, Buffer, Window, Tabpage, Object, Array/ArrayOf(...), Dict/DictOf(...), LuaRef.
  4. Returns one of the same types (or void).
  5. Optionally takes an Error *err out-parameter (most do; only "fast" trivia don't).
  6. May be annotated with // api-fast if reentrant and breakcheck-free.

The dispatcher table, the Lua wrappers, and the docs are generated. You don't write any of them by hand.

How it works

sequenceDiagram
    participant Client as RPC client (UI/plugin)
    participant Ch as Channel (msgpack_rpc)
    participant Disp as Dispatcher (gen)
    participant API as api/<area>.c
    participant Editor as Editor core
    Client->>Ch: msgpack request: [0, msgid, "nvim_buf_set_lines", [args]]
    Ch->>Ch: unpacker decodes to Array of Objects
    Ch->>Disp: lookup "nvim_buf_set_lines" → fn ptr + arg coercion
    Disp->>API: nvim_buf_set_lines(buf, start, end, lines, &err)
    API->>Editor: ml_replace, change_lines, ...
    Editor->>API: ok / failure
    API->>Disp: Object (or Error)
    Disp->>Ch: msgpack response: [1, msgid, err, result]
    Ch->>Client: bytes on the wire

For in-process callers (Lua, Vimscript, internal C), the dispatcher is bypassed; the Lua wrapper or the typval-bridge calls the C function directly with already-converted arguments.

Object and Error

Object is a tagged union — the API counterpart to Vimscript's typval_T. It carries the actual data plus a tag. The conversion functions are:

  • typval ↔ Object: src/nvim/eval/typval.c.
  • Lua ↔ Object: src/nvim/lua/converter.c.
  • msgpack ↔ Object: src/nvim/msgpack_rpc/packer.c and unpacker.c.

Error is set by API code via api_set_error(err, kErrorType, "format", ...). The dispatcher checks ERROR_SET(err) after every API call and either returns the error to the caller (msgpack-rpc) or converts it to a Lua exception (Lua callers) or to an :emsg-style message (Vimscript callers).

Channels

A channel is an RPC peer. Channels are created by:

  • --embed, --listen, --server flags (stdin or socket).
  • nvim_serverstart() / nvim_listen() for additional listeners.
  • chanopen() / nvim_chan_send() from Lua/Vimscript.
  • jobstart({rpc = true}) — spawn a child as an RPC peer.

Each channel has a MsgpackUnpacker reading from its RStream and a MsgpackPacker writing to its WStream. Channels demultiplex notifications (one-way) from requests (request/response) and route to the dispatcher.

channel.c#receive_msgpack is the inflow point — it pulls bytes off the stream, hands them to the unpacker, and once a complete message is available, dispatches.

UI events

UI events are a special class of notification: the editor sends redraw notifications carrying a list of UI events to every attached UI. src/nvim/api/ui.c is where the attach handshake and event marshalling live. UI events are defined in src/nvim/api/ui_events.in.h (a header that is not compiled directly — see below).

src/gen/gen_api_ui_events.lua parses ui_events.in.h and generates:

  • A C function per event (ui_call_grid_line, ui_call_mode_change, ...) that all attached UIs see.
  • Metadata listed in nvim_get_api_info()'s ui_events table.

UIs that want a new event must:

  1. Add the prototype to ui_events.in.h.
  2. Implement the handler in tui.c (for the TUI) and ship a remote-UI version.
  3. Bump NVIM_API_LEVEL.

API levels and stability

Every API function carries a "since" version (the NVIM_API_LEVEL it was introduced in). UIs and clients negotiate which features are available at attach time via the metadata blob. Deprecated functions live in src/nvim/api/deprecated.c (32 KB) and emit a one-time warning when called; they are removed only at a major version bump.

msgpack format

A request is [0, msgid, method, args]. A response is [1, msgid, err, result]. A notification is [2, method, args]. err is null on success or [code, message] on failure. The serializer is in src/nvim/msgpack_rpc/packer.c; the deserializer in unpacker.c. The msgpack library used is the vendored src/mpack/.

The packer streams output without buffering whole responses, so a 1 GB nvim_buf_get_text doesn't allocate a 1 GB intermediate.

Integration points

  • Lua stdlib — every public Lua function is just a vim.api.nvim_* call (or a thin wrapper). Browse runtime/lua/vim/api/ for examples.
  • Vimscriptnvim_* is callable as a built-in (e.g., :call nvim_buf_set_lines(0, 0, -1, false, ['hi'])).
  • TUI — uses the same RPC layer. The TUI is just a UI client.
  • Decoration providersnvim_set_decoration_provider registers a LuaRef; the renderer invokes it.
  • vim.system — implemented in Lua but its child-process supervisor uses the same RPC infrastructure when rpc = true.

Entry points for modification

  • Add a new public function.
    1. Write nvim_my_thing(...) in src/nvim/api/<area>.c with a doc comment.
    2. Run make. The dispatcher and Lua wrapper are regenerated.
    3. Run make doc. runtime/doc/api.txt updates.
    4. Add a test under test/functional/api/.
  • Add a new UI event. Edit src/nvim/api/ui_events.in.h. Bump NVIM_API_LEVEL. Update the TUI handler. Document in runtime/doc/api-ui-events.txt.
  • Deprecate a function. Move its implementation to src/nvim/api/deprecated.c, keep the same name and signature, and call api_deprecate("...") at the top.

Key source files

File Purpose
src/nvim/api/vim.c The grab-bag (nvim_eval, nvim_command, nvim_input, ...)
src/nvim/api/buffer.c Buffer API
src/nvim/api/window.c, win_config.c Window API + floats
src/nvim/api/extmark.c Extmark / namespace API
src/nvim/api/autocmd.c Autocmd API
src/nvim/api/command.c User command API
src/nvim/api/ui.c, ui_events.in.h UI attach and event prototypes
src/nvim/api/private/dispatch.c (generated) Dispatcher table
src/nvim/api/deprecated.c Old shims, kept for compat
src/nvim/msgpack_rpc/channel.c Channels
src/nvim/msgpack_rpc/packer.c, unpacker.c msgpack codec
src/nvim/msgpack_rpc/server.c Listen/accept
src/gen/gen_api_dispatch.lua Generator

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

API and msgpack-rpc – Neovim wiki | Factory