mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
 | 
						|
 | 
						|
		 NVIM REFERENCE MANUAL    by Thiago de Arruda
 | 
						|
 | 
						|
 | 
						|
RPC API for Nvim				     *RPC* *rpc* *msgpack-rpc*
 | 
						|
 | 
						|
				      Type |gO| to see the table of contents.
 | 
						|
 | 
						|
==============================================================================
 | 
						|
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*
 | 
						|
 | 
						|
See |channel-intro|, for various ways to open a channel. Most of the channel
 | 
						|
opening functions take an `rpc` key in the options dictionary, to enable RPC.
 | 
						|
 | 
						|
Additionally, RPC channels can be opened by other processes connecting to
 | 
						|
TCP/IP sockets or named pipes listened to by nvim.
 | 
						|
 | 
						|
Nvim creates a default RPC socket at |startup|, given by |v:servername|. To
 | 
						|
start with a TCP/IP socket instead, use |--listen| with a TCP-style address: >
 | 
						|
    nvim --listen 127.0.0.1:6666
 | 
						|
Additional sockets and named pipes can be started with |serverstart()|.
 | 
						|
 | 
						|
Note that localhost TCP sockets are generally less secure than named pipes,
 | 
						|
and can lead to vunerabilities like remote code execution.
 | 
						|
 | 
						|
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 "version" key contains the Nvim version, API level, and API
 | 
						|
    backwards-compatibility level.
 | 
						|
  - 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 receiver 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|
 | 
						|
At the RPC layer, types form two groups:
 | 
						|
 | 
						|
  - Basic types that map natively to msgpack (and have a default
 | 
						|
    representation in most 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
 | 
						|
 | 
						|
  Note: in function calls, empty Array is accepted for Dictionary parameter.
 | 
						|
 | 
						|
Special types (msgpack EXT) ~
 | 
						|
 | 
						|
  Buffer                            -> enum value kObjectTypeBuffer
 | 
						|
  Window                            -> enum value kObjectTypeWindow
 | 
						|
  Tabpage                           -> enum value kObjectTypeTabpage
 | 
						|
 | 
						|
API functions expecting one of the special EXT types may be passed an integer
 | 
						|
instead, but not another EXT type. E.g. Buffer may be passed as an integer but
 | 
						|
not as a Window or Tabpage. The EXT object data is the object id encoded as
 | 
						|
a msgpack integer: For buffers this is the |bufnr()| and for windows the
 | 
						|
|window-ID|. For tabpages the id is an internal handle, not the tabpage
 | 
						|
number.
 | 
						|
 | 
						|
To determine the type codes of the special EXT types, inspect the `types` key
 | 
						|
of the |api-metadata| at runtime. Example JSON representation: >
 | 
						|
 | 
						|
  "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.
 | 
						|
 | 
						|
 vim:tw=78:ts=8:ft=help:norl:
 |