aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt34
-rw-r--r--runtime/doc/msgpack_rpc.txt245
2 files changed, 278 insertions, 1 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index cdad6a9d7e..51e09596fc 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1934,6 +1934,12 @@ repeat( {expr}, {count}) String repeat {expr} {count} times
resolve( {filename}) String get filename a shortcut points to
reverse( {list}) List reverse {list} in-place
round( {expr}) Float round off {expr}
+rpcnotify({channel}, {event}[, {args}...])
+ Sends a |msgpack-rpc| notification to {channel}
+rpcrequest({channel}, {method}[, {args}...])
+ Sends a |msgpack-rpc| request to {channel}
+rpcstart({prog}[, {argv}]) Spawns {prog} and opens a |msgpack-rpc| channel
+rpcstop({channel}) Closes a |msgpack-rpc| {channel}
screenattr( {row}, {col}) Number attribute at screen position
screenchar( {row}, {col}) Number character at screen position
screencol() Number current cursor column
@@ -5043,6 +5049,32 @@ round({expr}) *round()*
< -5.0
{only available when compiled with the |+float| feature}
+rpcnotify({channel}, {event}[, {args}...]) {Nvim} *rpcnotify()*
+ Sends {event} to {channel} via |msgpack-rpc| and returns
+ immediately. If {channel} is 0, the event is broadcast to all
+ channels. Example: >
+ :au VimLeave call rpcnotify(0, "leaving")
+
+rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()*
+ Sends a request to {channel} to invoke {method} via
+ |msgpack-rpc| and blocks until a response is received.
+ Example: >
+ :let result = rpcrequest(rpc_chan, "func", 1, 2, 3)
+
+rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()*
+ Spawns {prog} as a job(optionally passing the {argv} list),
+ and open a |msgpack-rpc| channel with the spawned process
+ stdin/stdout. Returns the channel id, which is used by
+ |rpcrequest()|, |rpcnotify()| and |rpcstop()|
+ It expects the rpc channel id as argument. Example: >
+ :let rpc_chan = rpcstart('prog', ['arg1', 'arg2'])
+
+rpcstop({channel}) {Nvim} *rpcstop()*
+ Closes a |msgpack-rpc| channel, possibly created via
+ |rpcspawn()| (Though it will also close channels created by
+ connections to |NVIM_LISTEN_ADDRESS|). It accepts the rpc
+ channel id as only argument.
+
screenattr(row, col) *screenattr()*
Like screenchar(), but return the attribute. This is a rather
arbitrary number that can only be used to compare to the
@@ -8874,4 +8906,4 @@ This is not allowed when the textlock is active:
- etc.
- vim:tw=78:ts=8:ft=help:norl:
+ vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt
new file mode 100644
index 0000000000..5e926b7318
--- /dev/null
+++ b/runtime/doc/msgpack_rpc.txt
@@ -0,0 +1,245 @@
+*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*
+
+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, and it will match 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:
+
+- By connecting to a running nvim instance and calling `vim_get_api_metadata`
+ via msgpack-rpc. This is the preferred way for clients written in
+ dynamically-typed languages, which can define functions at runtime.
+- Through the `--api-info` command-line option, which makes nvim to dump a
+ msgpack blob containing the 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
+ how other programs can embed nvim.
+
+2. Through stdin/stdout of a program spawned by the |rpcstart()| function.
+
+3. Through the socket automatically created with every 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
+ like this:
+>
+ :echo $NVIM_LISTEN_ADDRESS
+<
+4. Through a tcp/ip socket. To make nvim listen on a tcp/ip socket, you need
+ to set the NVIM_LISTEN_ADDRESS environment variable before starting, like
+ this:
+>
+ 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 a 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'
+
+ vim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
+ result = vim.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:
+>
+ >>> import neovim; vim = neovim.connect('[address]')
+ >>> vim.command('echo "hello world!"')
+<
+==============================================================================
+4. Implementing new clients *msgpack-rpc-clients*
+
+Nvim is still alpha and there's no in-depth documentation explaining how to
+properly implement a client library. The python client(neovim pip package)
+will be always up-to-date with the latest API changes, so it's source code is
+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 of how a client can connect to nvim).
+- Use a msgpack library that implements the spec version 5, Nvim uses the
+ BIN/EXT types.
+- 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 you are implementing a client
+ for. 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 multi-tasking.
+- 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 since 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(Though you
+ probably want to handle them immediately anyway).
+
+
+Most of the complexity could be handled by a msgpack-rpc library that supports
+server->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_metadata` 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, eg:
+ 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. Eg: `buffer_get_line` represents the `get_line` method
+ of a Buffer instance.
+- Global methods are prefixed with `vim`. Eg: `vim_list_buffers`
+
+So, for a 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 to vimscript:
+
+- |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process with
+ it's standard handles connected to Nvim, the difference is that it's not
+ possible to process raw data to/from the process stdin/stdout/stderr(Since
+ the job's stdin/stdout combo are used as a msgpack channgel that is
+ processed directly by Nvim C code).
+- |rpcstop()|: Same as |jobstop()|, but operates on handles returned by
+ |rpcstart().|
+- |rpcrequest()|: Sends a msgpack-rpc request to the process.
+- |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: