doc: Revise for flow and consistency #2831

In general, attempt to make things more concise.

Reviewed-by: Michael Reed <m.reed@mykolab.com>
This commit is contained in:
alecbrooks 2015-06-22 21:51:15 -05:00 committed by Michael Reed
parent 91fcd33787
commit e8c82372ff
2 changed files with 81 additions and 83 deletions

View File

@ -17,22 +17,22 @@ The Msgpack-RPC Interface to Nvim *msgpack-rpc*
==============================================================================
1. Introduction *msgpack-rpc-intro*
The primary means of controlling a running Nvim instance is through
The primary way to control 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.
From now on, we refer 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.
interaction will happen through it, 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:
By connecting to the msgpack-rpc interface, programs can:
- 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
Nvim's msgpack-rpc interface is like a more powerful version of Vim's
`clientserver` feature.
==============================================================================
@ -45,19 +45,19 @@ 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.
from programmers. The wrappers 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.
1. By connecting to a running Nvim instance and calling `vim_get_api_info`
via msgpack-rpc. This is best 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.
2. By starting Nvim with the `--api-info` command-line option, which makes Nvim
dump a blob of msgpack metadata to standard output and exit. This is best
for clients written in 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):
@ -67,37 +67,37 @@ Python and the `pyyaml`/`msgpack-python` pip packages):
==============================================================================
3. Connecting *msgpack-rpc-connecting*
There are four ways to open msgpack-rpc streams to nvim:
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.
1. Through Nvim's stdin/stdout when it's 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.
*$NVIM_LISTEN_ADDRESS*
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:
3. Through the socket automatically created with each instance. To get the
socket location for a running Nvim instance (which is random by default),
see the |$NVIM_LISTEN_ADDRESS| environment variable:
>
:echo $NVIM_LISTEN_ADDRESS
:echo $NVIM_LISTEN_ADDRESS
<
See also |v:servername|.
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:
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:
>
NVIM_LISTEN_ADDRESS=127.0.0.1:6666 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 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:
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 in the next section). 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
# 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 &
@ -118,7 +118,7 @@ functions can be called interactively:
>>> nvim = attach('socket', path='[address]')
>>> nvim.command('echo "hello world!"')
<
One can also spawn and connect to an embedded nvim instance via |rpcstart()|
One can also spawn and connect to an embedded Nvim instance via |rpcstart()|
>
let vim = rpcstart('nvim', ['--embed'])
echo rpcrequest(vim, 'vim_eval', '"Hello " . "world!"')
@ -134,9 +134,9 @@ 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.
|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.
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.
@ -146,17 +146,17 @@ however:
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 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
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
==============================================================================
@ -189,10 +189,10 @@ 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 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:
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
`vim_get_api_info` method at runtime. Here's an example JSON representation of
the `types` object:
>
"types": {
"Buffer": {
@ -207,8 +207,8 @@ is at runtime by inspecting the `types` key of metadata dictionary returned by
}
<
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.
the type codes, because a client may be built against one Nvim version but connect
to another with different type codes.
==============================================================================
6. Wrapping methods *msgpack-rpc-wrap-methods*
@ -238,13 +238,13 @@ 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:
Four msgpack-rpc functions 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.
possible to process raw data to or from the process's stdin, stdout, or
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()|.

View File

@ -15,12 +15,12 @@ Nvim support for remote plugins *remote-plugin*
1. Introduction *remote-plugin-intro*
Extensibility is a primary goal of Nvim. Any programming language may be used
to extend nvim without changes to nvim itself. This is achieved with remote
to extend Nvim without changes to Nvim itself. This is achieved with remote
plugins, coprocesses that have a direct communication channel (via
|msgpack-rpc|) with the Nvim process.
Even though these plugins are running in separate processes they can call, be
called, and receive events just as if the code was being executed in the main
Even though these plugins run in separate processes they can call, be called,
and receive events just as if the plugin's code were executed in the main
process.
==============================================================================
@ -28,21 +28,20 @@ process.
While plugins can be implemented as arbitrary programs that communicate
directly with the high-level Nvim API and are called via |rpcrequest()| and
|rpcnotify()|, that is not the best approach available. Instead, developers
should first check if a plugin host implementation is available for their
chosen programming language.
|rpcnotify()|, that is not the best approach. Instead, developers should first
check whether a plugin host is available for their chosen programming language.
Plugin hosts are programs that provide a high level environment for plugins,
Plugin hosts are programs that provide a high-level environment for plugins,
taking care of most boilerplate involved in defining commands, autocmds, and
functions that are implemented over |msgpack-rpc| connections. Hosts are
loaded only when one of their registered plugins require it, keeping Nvim's
startup as fast as possible if many plugins/hosts are installed.
startup as fast as possible, even if many plugins/hosts are installed.
==============================================================================
3. Example *remote-plugin-example*
The best way to learn about remote plugins is with an example, so let's see
what a Python plugin looks like. This plugin exports a command, a function and
what a Python plugin looks like. This plugin exports a command, a function, and
an autocmd. The plugin is called 'Limit', and all it does is limit the number
of requests made to it. Here's the plugin source code:
>
@ -81,17 +80,17 @@ of requests made to it. Here's the plugin source code:
self.calls += 1
<
As can be seen, the plugin is implemented using pure Python idioms (classes,
methods, and decorators), the translation between these language-specific
idioms to vimscript occurs while the plugin manifest is being generated (see
below).
As can be seen, the plugin is implemented using idomatic Python (classes,
methods, and decorators). The translation between these language-specific
idioms to Vimscript occurs while the plugin manifest is being generated (see
the next section).
Notice that the exported command and autocmd are defined with the "sync" flag,
which affects how Nvim calls the plugin: with "sync" the |rpcrequest()|
function is used, which will block Nvim until the handler function returns a
value. Without the "sync" flag, the call is made using a fire and forget
approach with |rpcnotify()| (return values or exceptions raised in the handler
function are ignored).
approach with |rpcnotify()|, meaning return values or exceptions raised in the
handler function are ignored.
To test the above plugin, it must be saved in "rplugin/python" in a
'runtimepath' directory (~/.nvim/rplugin/python/limit.py for example). Then,
@ -101,35 +100,34 @@ the remote plugin manifest must be generated with `:UpdateRemotePlugins`.
4. Remote plugin manifest *remote-plugin-manifest*
Just installing remote plugins to "rplugin/{host}" isn't enough for them to be
automatically loaded when required. The `:UpdateRemotePlugins` command must be
executed every time a remote plugin is installed, updated, or deleted.
automatically loaded when required. You must execute `:UpdateRemotePlugins`
every time a remote plugin is installed, updated, or deleted.
`:UpdateRemotePlugins` will generate the remote plugin manifest, a special
vimscript file containing declarations for all vimscript entities
`:UpdateRemotePlugins` generates the remote plugin manifest, a special
Vimscript file containing declarations for all Vimscript entities
(commands/autocommands/functions) defined by all remote plugins, with each
entity associated with the host and plugin path. The manifest can be seen as a
generated extension to the user's vimrc (it even has the vimrc filename
prepended).
entity associated with the host and plugin path. The manifest is a generated
extension to the user's vimrc (it even has the vimrc filename prepended).
The manifest declarations are nothing but calls to the remote#host#RegisterPlugin
function, which will take care of bootstrapping the host as soon as the
declared command, autocommand, or function is used for the first time.
Manifest declarations are just calls to the `remote#host#RegisterPlugin`
function, which takes care of bootstrapping the host as soon as the declared
command, autocommand, or function is used for the first time.
The manifest generation step is necessary to keep Nvim's startup fast in
situations where a user has remote plugins with different hosts. For example,
say a user has three plugins, for Python, java and .NET hosts respectively. If
say a user has three plugins, for Python, Java and .NET hosts respectively. If
we were to load all three plugins at startup, then three language runtimes
would also be spawned which could take seconds!
would also be spawned, which could take seconds!
With the manifest, each host will only be loaded when required. Continuing
with the example, say the java plugin is a semantic completion engine for java
source files. If it defines the autocommand "BufEnter *.java", then the java
host will only be spawned when files ending with ".java" are loaded.
With the manifest, each host will only be loaded when required. Continuing with
the example, say the Java plugin is a semantic completion engine for Java code.
If it defines the autocommand "BufEnter *.java", then the Java host is spawned
only when Nvim loads a buffer matching "*.java".
If the explicit call to `:UpdateRemotePlugins` seems incovenient, try to see
it like this: It's a way to give IDE-like capabilities to nvim while still
keeping it fast and lightweight for general use. It can also be seen as
analogous to the |:helptags| facility.
If the explicit call to `:UpdateRemotePlugins` seems incovenient, try to see it
like this: It's a way to provide IDE capabilities in Nvim while still keeping
it fast and lightweight for general use. It's also analogous to the |:helptags|
command.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: