mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
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:
parent
91fcd33787
commit
e8c82372ff
@ -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()|.
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user