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:
- Lives in
src/nvim/api/<area>.c. - Has a doc comment with
@param/@returnannotations parsed bysrc/gen/cdoc_parser.lua. - Takes parameters as API types only:
Boolean,Integer,Float,String,Buffer,Window,Tabpage,Object,Array/ArrayOf(...),Dict/DictOf(...),LuaRef. - Returns one of the same types (or
void). - Optionally takes an
Error *errout-parameter (most do; only "fast" trivia don't). - May be annotated with
// api-fastif 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 wireFor 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.candunpacker.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,--serverflags (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()'sui_eventstable.
UIs that want a new event must:
- Add the prototype to
ui_events.in.h. - Implement the handler in
tui.c(for the TUI) and ship a remote-UI version. - 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). Browseruntime/lua/vim/api/for examples. - Vimscript —
nvim_*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 providers —
nvim_set_decoration_providerregisters aLuaRef; the renderer invokes it. vim.system— implemented in Lua but its child-process supervisor uses the same RPC infrastructure whenrpc = true.
Entry points for modification
- Add a new public function.
- Write
nvim_my_thing(...)insrc/nvim/api/<area>.cwith a doc comment. - Run
make. The dispatcher and Lua wrapper are regenerated. - Run
make doc.runtime/doc/api.txtupdates. - Add a test under
test/functional/api/.
- Write
- Add a new UI event. Edit
src/nvim/api/ui_events.in.h. BumpNVIM_API_LEVEL. Update the TUI handler. Document inruntime/doc/api-ui-events.txt. - Deprecate a function. Move its implementation to
src/nvim/api/deprecated.c, keep the same name and signature, and callapi_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.