API: Document buffer updates

Originally written by @phodge in
https://github.com/neovim/neovim/pull/5269.
This commit is contained in:
Peter Hodge 2018-01-26 20:37:38 +01:00 committed by KillTheMule
parent edcc73e766
commit db15a3b8f7

View File

@ -241,4 +241,192 @@ 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 the type codes, because a client may be built against one Nvim version but
connect to another with different type codes. connect to another with different type codes.
==============================================================================
6. Live Updates *live-updates* *rpc-live-updates*
A dedicated API has been created to allow co-processes to be notified in
real-time when the user changes a buffer in any way. It is difficult and
error-prone to try and do this with autocommands such as |TextChanged|.
*live-updates-enabling*
Setting Up~
If your API client is a standalone co-process, it can use the
`"nvim_buf_live_updates"`API method to activate Live Update events for a
specific buffer. For example, in python >
import sys, neovim
nvim = neovim.attach('stdio')
bufnr = sys.argv[1]
nvim.buffers[bufnr].live_updates(True)
After the `"nvim_buf_live_updates"` method is called, neovim will send a
series of notifications containing the entire buffer's contents and any
subsequent changes. The buffer's contents are sent via notifications because
if you were to use the other API methods to retrieve the buffer contents, the
buffer could be changed again before you turn on live updates. This can cause
a delay if your plugin activates live updates for a very large buffer, but it
is the the most efficient way to maintain a copy of the entire buffer's
contents inside your plugin.
*live-updates-disabling*
Turning Off~
You can use `"nvim_buf_live_updates"` with an argument of `False` to turn off
notifications. One final notification will be sent to indicate that live
updates are no longer active for the specified buffer. Alternatively, you can
just close the channel.
*live-updates-limitations*
Limitations~
Note that any of the following actions will also turn off live updates because
the buffer contents are unloaded from memory:
- Closing all a buffer's windows (unless 'hidden' is enabled).
- Using |:edit| to reload the buffer
- reloading the buffer after it is changed from outside neovim.
*live-updates-events*
Handling Events~
The co-process will start receiving the notification events which will be
equivilent to the following |rpcnotify()| calls:
1. rpcnotify({channel}, "LiveUpdateStart", *LiveUpdateStart*
[{buf}, {changedtick}, {linedata}, {more}])
Neovim will send at least one of these notifications to provide you
with the original buffer contents. If the buffer is very large, neovim
will send the contents through in multiple events to avoid loading the
entire buffer's contents into memory at once.
{buf} is an API handle for the buffer.
{changedtick} is the value of |b:changedtick| for the buffer. If you
send an API command back to neovim you can check the value of
|b:changedtick| as part of your request to ensure that no other
changes have been made. See |live-update-race-conditions| for more
information.
{linedata} is a list of strings containing the buffer's contents. If
this list contains 100 strings, then they represent lines 1-100 of the
buffer. Newline characters are not included in the strings, so empty
lines will be given as empty strings. If you receive another
`"LiveUpdateStart"` notification with another {linedata} list, then
these lines represent the next N lines of the buffer. I.e., a second
notification with another list of 100 strings will represent lines
101-200 of the buffer.
{linedata} will always have at least 1 item, but the maximum length is
determined by neovim and not guaranteed to be any particular size.
Also the number of {linedata} items may vary between notifications, so
your plugin must be prepared to receive the line data in whatever size
lists neovim decides to split it into.
{more} is a boolean which tells you whether or not to expect more
`"LiveUpdateStart"` notifications. When {more} is false, you can
be certain that you now have the entire buffer's contents.
2. rpcnotify({channel}, "LiveUpdate", *LiveUpdate*
[{buf}, {changedtick}, {firstline}, {numreplaced}, {linedata}])
Indicates that {numreplaced} lines starting at line {firstline} have
been replaced with the new line data contained in the {linedata} list.
All buffer changes (even adding single characters) will be transmitted
as whole-line changes.
{buf} is an API handle for the buffer.
{changedtick} is the value of |b:changedtick| for the buffer. If you
send an API command back to neovim you can check the value of
|b:changedtick| as part of your request to ensure that no other
changes have been made.
{firstline} is the integer line number of the first line that was
replaced. Note that {firstline} is zero-indexed, so if line `1` was
replaced then {firstline} will be `0` instead of `1`. {firstline} is
guaranteed to always be less than or equal to the number of lines that
were in the buffer before the lines were replaced.
{numreplaced} is a positive integer indicating how many lines were
replaced. It will be `0` if new lines were added to the buffer but
none were replaced. If {numreplaced} is `0` then the new lines were
added
before the zero-indexed line number in {firstline}.
{linedata} is a list of strings containing the contents of the new
buffer lines. Newline characters are not included in the strings, so
empty lines will be given as empty strings. If {numreplaced} is `1` or
more, then {linedata} may be an empty list (indicating that lines were
deleted from the buffer). But if {numreplaced} is `0` (indicating that
lines were added to the buffer) then {linedata} is guaranteed to
contain at least 1 item.
Note: sometimes {changedtick} will be |v:null|, which means that the
buffer text *looks* like it has changed, but actually hasn't. In this
case the lines in {linedata} contain the modified text that is shown
to the user, but doesn't reflect the actual buffer contents. Currently
this behaviour is only used for the 'inccommand' option.
3. rpcnotify({channel}, "LiveUpdateTick", *LiveUpdateTick*
[{buf}, {changedtick}])
Indicates that |b:changedtick| was incremented for the buffer {buf},
but no text was changed. This is currently only used by undo/redo.
{buf} is an API handle for the buffer.
{changedtick} is the new value of |b:changedtick| for that buffer.
4. rpcnotify({channel}, "LiveUpdateEnd", [{buf}]) *LiveUpdateEnd*
{buf} is an API handle for the buffer.
Indicates that live updates for the nominated buffer have been
disabled, either by calling the api function `"nvim_buf_live_updates"`
with argument `false`, or because the buffer was unloaded (see
|live-updates-disabling| and |live-updates-limitations| for more
information).
*live-updates-examples*
Example Events~
If live updates are activated a new empty buffer, the following
|LiveUpdateStart| event will be sent: >
rpcnotify({channel}, "LiveUpdateStart", [{buf}, [""], v:false])
If the user adds 2 new lines to the start of a buffer, the following event
would be generated: >
rpcnotify({channel}, "LiveUpdate", [{buf}, 0, 0, ["line1", "line2"]])
If the puts the cursor on a line containing the text `"Hello world"` and adds
a `!` character to the end using insert mode, the following event would be
generated: >
rpcnotify({channel}, "LiveUpdate",
[{buf}, {linenr}, 1, ["Hello world!"]])
If the user moves their cursor to line 3 of a buffer and deletes 20 lines
using `20dd`, the following event will be generated: >
rpcnotify({channel}, "LiveUpdate", [{buf}, 2, 20, []])
If the user selects lines 3-5 of a buffer using |linewise-visual| mode and
then presses `p` to paste in a new block of 6 lines, then the following event
would be sent to the co-process: >
rpcnotify({channel}, "LiveUpdate",
[{buf}, 2, 3, ['pasted line 1', 'pasted line 2',
'pasted line 3', 'pasted line 4',
'pasted line 5', 'pasted line 6']])
If the user uses :edit to reload a buffer then the following event would be
generated: >
rpcnotify({channel}, "LiveUpdateEnd", [{buf}])
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl: