neovim/runtime/doc/msgpack_rpc.txt
Michael Reed e0f66137d1 docs: Misc. improvements to job_control/msgpack
- Rewrote a few sentences for clarity/brevity
- Various spelling/grammar fixes
- Mention exact time before SIGKILL (mentioned in /src/nvim/os/job.c)
- Reflowed all changed paragraphs accordingly
- Standardize indentation level
- Remove trailing whitespace

- Job control example:
  - Don't buffer output (echo -n); just print a new line for every
    update.
  - Use single quotes around jobsend() arguments to allow for proper
    interpretation of newline characters.
  - Sleep 1 second between updates instead of 2; 10 seconds is plenty of
    time for such a simple example.
2015-01-11 16:50:24 -05:00

248 lines
10 KiB
Plaintext

*msgpack_rpc.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
The Msgpack-RPC Interface to Nvim *msgpack-rpc*
1. Introduction |msgpack-rpc-intro|
2. API |msgpack-rpc-api|
3. Connecting |msgpack-rpc-connecting|
4. Clients |msgpack-rpc-clients|
5. Types |msgpack-rpc-types|
6. Wrapping methods |msgpack-rpc-wrap-methods|
7. Vimscript functions |msgpack-rpc-vim-functions|
==============================================================================
1. Introduction *msgpack-rpc-intro*
The primary means of controlling a running Nvim instance is through
MessagePack-RPC, a messaging protocol that uses the MessagePack serialization
format: https://github.com/msgpack/msgpack/blob/7498cf3/spec.md.
From now on, we'll be referring to the protocol as msgpack-rpc.
At this point, only plugins use msgpack-rpc, but eventually even user
interaction will be achieved through the protocol, since user interfaces will
be separate programs that control a headless Nvim instance.
This is what can be achieved by connecting to the msgpack-rpc interface:
- Call any Nvim API function
- Listen for Nvim events
- Receive remote calls from Nvim
Nvim's msgpack-rpc interface can be seen as a more powerful version of Vim's
`clientserver` feature.
==============================================================================
2. API *msgpack-rpc-api*
The Nvim C API is automatically exposed to the msgpack-rpc interface by the
build system, which parses headers at src/nvim/api from the project root. A
dispatch function is generated, which matches msgpack-rpc method names with
non-static API functions, converting/validating arguments and return values
back to msgpack.
Client libraries will normally provide wrappers that hide msgpack-rpc details
from programmers, which can be automatically generated by reading bundled API
metadata from a compiled nvim instance.
There are two ways to obtain API metadata:
1. By connecting to a running nvim instance and calling `vim_get_api_info`
via msgpack-rpc. This is the preferred way for clients written in
dynamically-typed languages, which can define functions at runtime.
2. Through the `--api-info` command-line option, which makes nvim dump a
msgpack blob containing metadata to stdout and exit. This is preferred
when writing clients for statically-typed languages, which require a
separate compilation step.
Here's a simple way to get human-readable description of the API (requires
python and the `pyyaml`/`msgpack-python` pip packages):
>
nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))' > api.yaml
==============================================================================
3. Connecting *msgpack-rpc-connecting*
There are four ways to open msgpack-rpc streams to nvim:
1. Through Nvim's stdin/stdout when started with the `--embed` option. This is
how other programs can embed nvim.
2. Through the stdin/stdout of a program spawned by the |rpcstart()| function.
3. Through the socket automatically created with each instance. To find out
the socket location (which is random by default) from a running nvim
instance, one can inspect the |$NVIM_LISTEN_ADDRESS| environment variable:
>
:echo $NVIM_LISTEN_ADDRESS
<
4. Through a TCP/IP socket. To make nvim listen on a TCP/IP socket, set the
|$NVIM_LISTEN_ADDRESS| environment variable in a shell before starting:
>
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 fully-featured
Nvim client (which we'll see below). Here's a ruby script that will print the
string 'hello world!' on 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(:vim_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!"')
<
==============================================================================
4. Implementing new clients *msgpack-rpc-clients*
Nvim is still in alpha, so there's no in-depth documentation explaining how to
properly implement a client library yet. The python client (the pip package
"neovim") will always be up-to-date with the latest API changes, so its source
code is the best documentation currently available. There are some guidelines
however:
- Separate the transport layer from the rest of the library. See
|msgpack-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 to receive 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).
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
==============================================================================
5. Types *msgpack-rpc-types*
Nvim's C API uses custom types for all functions (some are just typedefs
around C99 standard types). 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 type mapping:
Nil -> msgpack nil
Boolean -> msgpack boolean
Integer (signed 64-bit integer) -> msgpack integer
Float (IEEE 754 double precision) -> msgpack float
String -> msgpack binary
Array -> msgpack array
Dictionary -> msgpack map
Special Nvim types that use msgpack EXT:
Buffer -> enum value kObjectTypeBuffer
Window -> enum value kObjectTypeWindow
Tabpage -> enum value kObjectTypeTabpage
The most reliable way of determining the type codes for the special nvim types
is at runtime by inspecting the `types` key of metadata dictionary returned by
`vim_get_api_info` method. Here's an example json representation of the
`types` object:
>
"types": {
"Buffer": {
"id": 0
},
"Window": {
"id": 1
},
"Tabpage": {
"id": 2
}
}
<
Even for statically compiled clients, it's a good practice to avoid hardcoding
the type codes, because a client may build for a Nvim version and connect to
another that may have different type codes.
==============================================================================
6. Wrapping methods *msgpack-rpc-wrap-methods*
As mentioned before, clients should provide an API that hides msgpack-rpc
details from programmers, and the API metadata object contains information
that makes this task easier:
- The "functions" key contains a list of metadata objects for individual
functions.
- Each function metadata object has type 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.
- Methods that operate instances of Nvim's types are prefixed with the type
name in lower case, e.g. `buffer_get_line` represents the `get_line` method
of a Buffer instance.
- Global methods are prefixed with `vim`, e.g. `vim_list_buffers`.
So, for an object-oriented language, a client library would have the classes
that represent Nvim's types, and the methods of each class could be defined
by inspecting the method name prefix. There could also be a singleton Vim
class with methods mapped to functions prefixed with `vim_`
==============================================================================
7. Vimscript functions *msgpack-rpc-vim-functions*
Four functions related to msgpack-rpc are available in vimscript:
1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process with
its standard handles connected to Nvim. The difference is that it's not
possible to process raw data to/from the process's stdin/stdout/stderr.
This is because the job's stdin and stdout are used as a single msgpack
channel that is processed directly by Nvim.
2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by
|rpcstart()|.
3. |rpcrequest()|: Sends a msgpack-rpc request to the process.
4. |rpcnotify()|: Sends a msgpack-rpc notification to the process.
The last two functions may also be used with channels created from
connections to |$NVIM_LISTEN_ADDRESS|.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: