ui: reserve the right to split a screen redraw into multiple batches.

This commit is contained in:
Björn Linse 2018-09-29 13:28:53 +02:00
parent 43823acae2
commit bab3b0ad45
3 changed files with 38 additions and 13 deletions

View File

@ -18,9 +18,9 @@ the grid ("externalized").
*ui-options*
The |nvim_ui_attach()| API method is used to tell Nvim that your program wants to draw the
Nvim screen grid with a size of width × height cells. This is typically done
by an embedder, see |ui-startup| below for details, but an UI can also
The |nvim_ui_attach()| API method is used to tell Nvim that your program wants to
draw the Nvim screen grid with a size of width × height cells. This is typically
done by an embedder, see |ui-startup| below for details, but an UI can also
connect to a running nvim instance and invoke this method. `options` must be
a dictionary with these (optional) keys:
`rgb` Decides the color format. *ui-rgb*
@ -45,13 +45,17 @@ Nvim sends msgpack-rpc notifications to all attached UIs, with method name
Each update event is itself an array whose first element is the event name and
remaining elements are event-parameter tuples. This allows multiple events of
the same kind to be sent in a row without the event name being repeated. This
batching is mostly used for "put", because each "put" event puts contents in
one screen cell, but clients must be prepared for multiple argument sets being
batched for all event kinds.
batching is mostly used for "grid_line", because each "grid_line" event puts
contents in one screen line, but clients must be prepared for multiple argument
sets being batched for all event kinds.
Events must be handled in-order. The user should only see the updated screen
state after all events in the same "redraw" batch are processed (not any
intermediate state after processing only part of the array).
Events must be handled in-order. A "flush" event is sent when nvim is done
redrawing the entire screen (so that all windows have a consistent view of
buffer state, options etc). Clients should be prepared that several "redraw"
batches are sent before the entire screen has been redrawn, and only the last
batch will end in "flush". The user should only see the final state when
"flush" is sent, and not any intermediate state after processing only part of
the batch array, nor after a batch not ending with "flush".
By default, Nvim sends |ui-global| and |ui-grid-old| events; these suffice to
implement a terminal-like interface. However there are two revisions of the
@ -81,7 +85,7 @@ to do early initialization. As soon as the UI invokes |nvim_ui_attach()|, the
startup will continue.
A simple UI only need to do a single |nvim_ui_attach()| request and then
be prepared to handle any UI event. A more featureful UI, which might do
be prepared to handle any UI event. A more featureful UI, which might need
additional configuration of the nvim process, should use the following startup
procedure:
@ -199,6 +203,11 @@ the editor.
["visual_bell"]
Notify the user with an audible or visual bell, respectively.
["flush"]
Nvim is done redrawing the screen. For an implementation that renders
to an internal buffer, this is the time to display the redrawn parts
to the user.
==============================================================================
Grid Events (line-based) *ui-linegrid*

View File

@ -511,6 +511,7 @@ static void remote_ui_flush(UI *ui)
if (!ui->ui_ext[kUILinegrid]) {
remote_ui_cursor_goto(ui, data->cursor_row, data->cursor_col);
}
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
rpc_send_event(data->channel_id, "redraw", data->buffer);
data->buffer = (Array)ARRAY_DICT_INIT;
}

View File

@ -386,9 +386,13 @@ function Screen:wait(check, timeout)
local err, checked = false
local success_seen = false
local failure_after_success = false
local did_flush = true
local function notification_cb(method, args)
assert(method == 'redraw')
self:_redraw(args)
did_flush = self:_redraw(args)
if not did_flush then
return
end
err = check()
checked = true
if not err then
@ -402,7 +406,9 @@ function Screen:wait(check, timeout)
return true
end
run(nil, notification_cb, nil, timeout or self.timeout)
if not checked then
if not did_flush then
err = "no flush received"
elseif not checked then
err = check()
end
@ -431,7 +437,8 @@ function Screen:sleep(ms)
end
function Screen:_redraw(updates)
for _, update in ipairs(updates) do
local did_flush = false
for k, update in ipairs(updates) do
-- print('--')
-- print(require('inspect')(update))
local method = update[1]
@ -446,7 +453,11 @@ function Screen:_redraw(updates)
self._on_event(method, update[i])
end
end
if k == #updates and method == "flush" then
did_flush = true
end
end
return did_flush
end
function Screen:set_on_event_handler(callback)
@ -472,6 +483,10 @@ function Screen:_handle_resize(width, height)
}
end
function Screen:_handle_flush()
end
function Screen:_handle_grid_resize(grid, width, height)
assert(grid == 1)
self:_handle_resize(width, height)