diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 0d4bdc7f41..a0f1b0770e 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -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* diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 9c16525a6b..01f8c9f71c 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -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; } diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 0b265d6867..691bf9f64c 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -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)