mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 19:25:11 -07:00
f25797f869
The API level is disconnected from the NVIM version. The API metadata holds the current API level, and the lowest backwards-compatible level supported by this instance. Release 0.1.6 will be the first release reporting the Nvim version and API level. metadata['version'] = { major: 0, minor: 1, patch: 6, prerelease: true, api_level: 1, api_compatible: 0, } The API level may remain unchanged across Neovim releases if the API has not changed. When changing the API the CMake variable NVIM_API_PRERELEASE is set to true, and NVIM_API_CURRENT/NVIM_API_COMPATIBILITY are incremented accordingly. The functional tests check the API table against fixtures of past versions of Neovim. It compares all the functions in the old table with the new one, it does ignore some metadata attributes that do not alter the function signature or were removed since 0.1.5. Currently the only fixture is 0.mpack, generated from Neovim 0.1.5 with nvim --api-info.
418 lines
17 KiB
Plaintext
418 lines
17 KiB
Plaintext
*msgpack_rpc.txt* {Nvim}
|
|
|
|
|
|
NVIM REFERENCE MANUAL by Thiago de Arruda
|
|
|
|
|
|
RPC API for Nvim *RPC* *rpc* *msgpack-rpc*
|
|
|
|
1. Introduction |rpc-intro|
|
|
2. API mapping |rpc-api|
|
|
3. Connecting |rpc-connecting|
|
|
4. Clients |rpc-api-client|
|
|
5. Types |rpc-types|
|
|
6. Remote UIs |rpc-remote-ui|
|
|
|
|
==============================================================================
|
|
1. Introduction *rpc-intro*
|
|
|
|
The primary way to control Nvim programmatically is the RPC API, which speaks
|
|
MessagePack-RPC ("msgpack-rpc"), a messaging protocol that uses the
|
|
MessagePack serialization format:
|
|
https://github.com/msgpack/msgpack/blob/0b8f5ac/spec.md
|
|
|
|
All kinds of Nvim "clients" use the RPC API: user interfaces (GUIs), remote
|
|
plugins, scripts like "nvr" (https://github.com/mhinz/neovim-remote), and even
|
|
`nvim` itself can control other `nvim` instances. By connecting to the RPC API
|
|
programs can:
|
|
|
|
- Call any API function
|
|
- Listen for events
|
|
- Receive remote calls from Nvim
|
|
|
|
The RPC API is like a more powerful version of Vim's `clientserver` feature.
|
|
|
|
==============================================================================
|
|
2. API mapping *rpc-api*
|
|
|
|
The Nvim C |API| is automatically exposed to the RPC API by the build system,
|
|
which parses headers at src/nvim/api/*. A dispatch function is generated which
|
|
matches RPC API method names with public API functions, converting/validating
|
|
arguments and return values back to msgpack.
|
|
|
|
Client libraries (|api-client|s) normally provide wrappers that hide
|
|
msgpack-rpc details from application developers. The wrappers can be
|
|
automatically generated by reading bundled API metadata from a compiled Nvim
|
|
instance.
|
|
|
|
There are three ways to obtain API metadata:
|
|
|
|
1. Connect to a running Nvim instance and call `nvim_get_api_info` via
|
|
msgpack-rpc. This is best for clients written in dynamic languages which
|
|
can define functions at runtime.
|
|
|
|
2. Start Nvim with the |--api-info| option. Useful for clients written in
|
|
statically-compiled languages.
|
|
|
|
3. Use the |api_info()| vimscript function.
|
|
|
|
To get a human-readable list of API functions: >
|
|
:new|put =map(api_info().functions, 'v:val.name')
|
|
<
|
|
To get a formatted dump of the API using python (requires the `pyyaml` and
|
|
`msgpack-python` packages): >
|
|
nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))'
|
|
<
|
|
==============================================================================
|
|
3. Connecting *rpc-connecting*
|
|
|
|
There are several ways to open a msgpack-rpc channel to an Nvim instance:
|
|
|
|
1. Through stdin/stdout when `nvim` is started with `--embed`. This is how
|
|
applications can embed Nvim.
|
|
|
|
2. Through stdin/stdout of some other process spawned by |jobstart()|.
|
|
Set the "rpc" key to |v:true| in the options dict to use the job's stdin
|
|
and stdout as a single msgpack channel that is processed directly by
|
|
Nvim. Then it is not possible to process raw data to or from the
|
|
process's stdin and stdout. stderr can still be used, though.
|
|
|
|
3. Through the socket automatically created with each instance. The socket
|
|
location is stored in |v:servername|.
|
|
|
|
4. Through a TCP/IP socket. To make Nvim listen on a TCP/IP socket, set the
|
|
|$NVIM_LISTEN_ADDRESS| environment variable before starting Nvim: >
|
|
NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim
|
|
<
|
|
Connecting to the socket is the easiest way a programmer can test the API,
|
|
which can be done through any msgpack-rpc client library or full-featured
|
|
|api-client|. Here's a Ruby script that prints 'hello world!' in the current
|
|
Nvim instance:
|
|
>
|
|
#!/usr/bin/env ruby
|
|
# Requires msgpack-rpc: gem install msgpack-rpc
|
|
#
|
|
# To run this script, execute it from a running Nvim instance (notice the
|
|
# trailing '&' which is required since Nvim won't process events while
|
|
# running a blocking command):
|
|
#
|
|
# :!./hello.rb &
|
|
#
|
|
# Or from another shell by setting NVIM_LISTEN_ADDRESS:
|
|
# $ NVIM_LISTEN_ADDRESS=[address] ./hello.rb
|
|
|
|
require 'msgpack/rpc'
|
|
require 'msgpack/rpc/transport/unix'
|
|
|
|
nvim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
|
|
result = nvim.call(:nvim_command, 'echo "hello world!"')
|
|
<
|
|
A better way is to use the Python REPL with the `neovim` package, where API
|
|
functions can be called interactively:
|
|
>
|
|
>>> from neovim import attach
|
|
>>> nvim = attach('socket', path='[address]')
|
|
>>> nvim.command('echo "hello world!"')
|
|
<
|
|
You can also embed an Nvim instance via |jobstart()|, and communicate using
|
|
|rpcrequest()| and |rpcnotify()|:
|
|
>
|
|
let nvim = jobstart(['nvim', '--embed'], {'rpc': v:true})
|
|
echo rpcrequest(nvim, 'nvim_eval', '"Hello " . "world!"')
|
|
call jobstop(nvim)
|
|
<
|
|
==============================================================================
|
|
4. Implementing API clients *rpc-api-client* *api-client*
|
|
|
|
"API clients" wrap the Nvim API to provide idiomatic "SDKs" for their
|
|
respective platforms (see |dev-jargon|). You can build a new API client for
|
|
your favorite platform or programming language.
|
|
|
|
Existing API clients are listed here:
|
|
https://github.com/neovim/neovim/wiki/Related-projects#api-clients
|
|
|
|
The Python client is the reference implementation for API clients. It is
|
|
always up-to-date with the Nvim API, so its source code and test suite are
|
|
authoritative references.
|
|
https://github.com/neovim/python-client
|
|
|
|
API client implementation guidelines ~
|
|
|
|
- Separate the transport layer from the rest of the library. See
|
|
|rpc-connecting| for details on how clients can connect to Nvim.
|
|
- Use a MessagePack library that implements at least version 5 of the
|
|
MessagePack spec, which supports the `bin` and `ext` types used by Nvim.
|
|
- Read API metadata in order to create client-side wrappers for all
|
|
msgpack-rpc methods.
|
|
- Use a single-threaded event loop library/pattern.
|
|
- Use a fiber/coroutine library for the language being used for implementing
|
|
a client. These greatly simplify concurrency and allow the library to
|
|
expose a blocking API on top of a non-blocking event loop without the
|
|
complexity that comes with preemptive multitasking.
|
|
- Don't assume anything about the order that responses to msgpack-rpc
|
|
requests will arrive.
|
|
- Clients should expect msgpack-rpc requests, which need to be handled
|
|
immediately because Nvim is blocked while waiting for the client response.
|
|
- Clients should expect to receive msgpack-rpc notifications, but these
|
|
don't need to be handled immediately because they won't block Nvim
|
|
(although they should probably be handled immediately anyway).
|
|
|
|
Note: Most of the complexity could be handled by a msgpack-rpc library that
|
|
supports server to client requests and notifications, but it's not clear if
|
|
this is part of the msgpack-rpc spec. At least the Ruby msgpack-rpc library
|
|
does not seem to support it:
|
|
https://github.com/msgpack-rpc/msgpack-rpc-ruby/blob/master/lib/msgpack/rpc/transport/tcp.rb#L150-L158
|
|
|
|
API metadata object ~
|
|
|
|
API clients exist to hide msgpack-rpc details. The API metadata object
|
|
contains information that makes this task easier (see also |rpc-types|):
|
|
|
|
- The "api_level" key contais API compatibility information. The "current"
|
|
key holds the API version supported Neovim. The "compatibility" key holds
|
|
the oldest supported API version.
|
|
- The "functions" key contains a list of metadata objects for individual
|
|
functions.
|
|
- Each function metadata object has |rpc-types| information about the return
|
|
value and parameters. These can be used for generating strongly-typed APIs
|
|
in static languages.
|
|
- Container types may be decorated with type/size constraints, e.g.
|
|
ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate
|
|
even more strongly-typed APIs.
|
|
- Functions that are considered to be methods that operate on instances of
|
|
Nvim special types (msgpack EXT) will have the `"method"` attribute set to
|
|
`true`. The reciever type is the type of the first argument. The method
|
|
names are prefixed with `nvim_` plus a shortened type name, e.g.
|
|
`nvim_buf_get_lines` represents the `get_lines` method of a Buffer instance.
|
|
- Global functions have `"method"` set to `false` and are prefixed with just
|
|
`nvim_`, e.g. `nvim_get_buffers`.
|
|
|
|
So for an object-oriented language, an API client contains the classes
|
|
representing Nvim special types, and the methods of each class could be
|
|
defined by stripping the prefix for the type as defined in the `types` metadata
|
|
(this will always be the first two "_"-separated parts of the function name).
|
|
There could also be a singleton Vim class with methods where the `nvim_`
|
|
prefix is stripped off.
|
|
|
|
==============================================================================
|
|
5. Types *rpc-types*
|
|
|
|
The Nvim C API uses custom types for all functions. |api-types|
|
|
For the purpose of mapping to msgpack, the types can be split into two groups:
|
|
|
|
- Basic types that map natively to msgpack (and probably have a default
|
|
representation in msgpack-supported programming languages)
|
|
- Special Nvim types that map to msgpack EXT with custom type codes.
|
|
|
|
Basic types ~
|
|
|
|
Nil -> msgpack nil
|
|
Boolean -> msgpack boolean
|
|
Integer (signed 64-bit integer) -> msgpack integer
|
|
Float (IEEE 754 double precision) -> msgpack float
|
|
String -> msgpack string
|
|
Array -> msgpack array
|
|
Dictionary -> msgpack map
|
|
|
|
Special types (msgpack EXT) ~
|
|
|
|
Buffer -> enum value kObjectTypeBuffer
|
|
Window -> enum value kObjectTypeWindow
|
|
Tabpage -> enum value kObjectTypeTabpage
|
|
|
|
An API method expecting one of these types may be passed an integer instead,
|
|
although they are not interchangeable. For example, a Buffer may be passed as
|
|
an integer, but not a Window or Tabpage.
|
|
|
|
The most reliable way of determining the type codes for the special Nvim types
|
|
is to inspect the `types` key of metadata dictionary returned by the
|
|
`nvim_get_api_info` method at runtime. Here's a sample JSON representation of
|
|
the `types` object:
|
|
>
|
|
"types": {
|
|
"Buffer": {
|
|
"id": 0,
|
|
"prefix": "nvim_buf_"
|
|
},
|
|
"Window": {
|
|
"id": 1,
|
|
"prefix": "nvim_win_"
|
|
},
|
|
"Tabpage": {
|
|
"id": 2,
|
|
"prefix": "nvim_tabpage_"
|
|
}
|
|
}
|
|
<
|
|
Even for statically compiled clients it is good practice to avoid hardcoding
|
|
the type codes, because a client may be built against one Nvim version but
|
|
connect to another with different type codes.
|
|
|
|
==============================================================================
|
|
6. Remote UIs *rpc-remote-ui*
|
|
|
|
Nvim allows Graphical user interfaces to be implemented by separate processes
|
|
communicating with Nvim over the RPC API. Currently the ui model conists of a
|
|
terminal-like grid with one single, monospace font size, with a few elements
|
|
that could be drawn separately from the grid (for the momemnt only the popup
|
|
menu)
|
|
|
|
After connecting to a nvim instance (typically a spawned, embedded instance)
|
|
use the |nvim_ui_attach|(width, height, options) API method to tell nvim that your
|
|
program wants to draw the nvim screen on a grid with "width" times
|
|
"height" cells. "options" should be a dictionary with the following (all
|
|
optional) keys:
|
|
`rgb`: Controls what color format to use.
|
|
Set to true (default) to use 24-bit rgb
|
|
colors.
|
|
Set to false to use terminal color codes (at
|
|
most 256 different colors).
|
|
`popupmenu_external`: Instead of drawing the completion popupmenu on
|
|
the grid, Nvim will send higher-level events to
|
|
the ui and let it draw the popupmenu.
|
|
Defaults to false.
|
|
|
|
Nvim will then send msgpack-rpc notifications, with the method name "redraw"
|
|
and a single argument, an array of screen updates (described below).
|
|
These should be processed in order. Preferably the user should only be able to
|
|
see the screen state after all updates are processed (not any intermediate
|
|
state after processing only a part of the array).
|
|
|
|
Screen updates are arrays. The first element a string describing the kind
|
|
of update.
|
|
|
|
["resize", width, height]
|
|
The grid is resized to `width` and `height` cells.
|
|
|
|
["clear"]
|
|
Clear the screen.
|
|
|
|
["eol_clear"]
|
|
Clear from the cursor position to the end of the current line.
|
|
|
|
["cursor_goto", row, col]
|
|
Move the cursor to position (row, col). Currently, the same cursor is
|
|
used to define the position for text insertion and the visible cursor.
|
|
However, only the last cursor position, after processing the entire
|
|
array in the "redraw" event, is intended to be a visible cursor
|
|
position.
|
|
|
|
["update_fg", color]
|
|
["update_bg", color]
|
|
["update_sp", color]
|
|
Set the default foreground, background and special colors
|
|
respectively.
|
|
|
|
["highlight_set", attrs]
|
|
Set the attributes that the next text put on the screen will have.
|
|
`attrs` is a dict with the keys below. Any absent key is reset
|
|
to its default value. Color defaults are set by the `update_fg` etc
|
|
updates. All boolean keys default to false.
|
|
|
|
`foreground`: foreground color.
|
|
`background`: backround color.
|
|
`special`: color to use for underline and undercurl, when present.
|
|
`reverse`: reverse video. Foreground and background colors are
|
|
switched.
|
|
`italic`: italic text.
|
|
`bold`: bold text.
|
|
`underline`: underlined text. The line has `special` color.
|
|
`undercurl`: undercurled text. The curl has `special` color.
|
|
|
|
["put", text]
|
|
The (utf-8 encoded) string `text` is put at the cursor position
|
|
(and the cursor is advanced), with the highlights as set by the
|
|
last `highlight_set` update.
|
|
|
|
["set_scroll_region", top, bot, left, right]
|
|
Define the scroll region used by `scroll` below.
|
|
|
|
["scroll", count]
|
|
Scroll the text in the scroll region. The diagrams below illustrate
|
|
what will happen, depending on the scroll direction. "=" is used to
|
|
represent the SR(scroll region) boundaries and "-" the moved rectangles.
|
|
Note that dst and src share a common region.
|
|
|
|
If count is bigger than 0, move a rectangle in the SR up, this can
|
|
happen while scrolling down.
|
|
>
|
|
+-------------------------+
|
|
| (clipped above SR) | ^
|
|
|=========================| dst_top |
|
|
| dst (still in SR) | |
|
|
+-------------------------+ src_top |
|
|
| src (moved up) and dst | |
|
|
|-------------------------| dst_bot |
|
|
| src (cleared) | |
|
|
+=========================+ src_bot
|
|
<
|
|
If count is less than zero, move a rectangle in the SR down, this can
|
|
happen while scrolling up.
|
|
>
|
|
+=========================+ src_top
|
|
| src (cleared) | |
|
|
|------------------------ | dst_top |
|
|
| src (moved down) and dst| |
|
|
+-------------------------+ src_bot |
|
|
| dst (still in SR) | |
|
|
|=========================| dst_bot |
|
|
| (clipped below SR) | v
|
|
+-------------------------+
|
|
<
|
|
["set_title", title]
|
|
["set_icon", icon]
|
|
Set the window title, and icon (minimized) window title, respectively.
|
|
In windowing systems not distinguishing between the two, "set_icon"
|
|
can be ignored.
|
|
|
|
["mouse_on"]
|
|
["mouse_off"]
|
|
Tells the client whether mouse support, as determined by |'mouse'|
|
|
option, is considered to be active in the current mode. This is mostly
|
|
useful for a terminal frontend, or other situations where nvim mouse
|
|
would conflict with other usages of the mouse. It is safe for a client
|
|
to ignore this and always send mouse events.
|
|
|
|
["busy_on"]
|
|
["busy_off"]
|
|
Nvim started or stopped being busy, and possibly not responsible to user
|
|
input. This could be indicated to the user by hiding the cursor.
|
|
|
|
["suspend"]
|
|
|:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other
|
|
client where it makes sense) could suspend itself. Other clients can
|
|
safely ignore it.
|
|
|
|
["bell"]
|
|
["visual_bell"]
|
|
Notify the user with an audible or visual bell, respectively.
|
|
|
|
["update_menu"]
|
|
The menu mappings changed.
|
|
|
|
["mode_change", mode]
|
|
The mode changed. Currently sent when "insert", "replace" and "normal"
|
|
modes are entered. A client could for instance change the cursor shape.
|
|
|
|
["popupmenu_show", items, selected, row, col]
|
|
When `popupmenu_external` is set to true, nvim will not draw the
|
|
popupmenu on the grid, instead when the popupmenu is to be displayed
|
|
this update is sent. `items` is an array of the items to show, the
|
|
items are themselves arrays of the form [word, kind, menu, info]
|
|
as defined at |complete-items|, except that `word` is replaced by
|
|
`abbr` if present. `selected` is the initially selected item, either a
|
|
zero-based index into the array of items, or -1 if no item is
|
|
selected. `row` and `col` is the anchor position, where the first
|
|
character of the completed word will be.
|
|
|
|
["popupmenu_select", selected]
|
|
An item in the currently displayed popupmenu is selected. `selected`
|
|
is either a zero-based index into the array of items from the last
|
|
`popupmenu_show` event, or -1 if no item is selected.
|
|
|
|
["popupmenu_hide"]
|
|
The popupmenu is hidden.
|
|
|
|
==============================================================================
|
|
vim:tw=78:ts=8:noet:ft=help:norl:
|