mirror of
https://github.com/neovim/neovim
synced 2025-07-17 01:31:48 +00:00
fix(msgpack): flush incomplete big UI event before packing RPC event
This might happen, e.g. if we send a fast RPC reply in a os_breakcheck()
in the middle of redrawing and big ui_ext events are produced.
fixes #31316
(cherry picked from commit b8ee354f12
)
This commit is contained in:
committed by
github-actions[bot]
parent
c4a760c734
commit
ec84c8df0e
@ -45,6 +45,7 @@
|
|||||||
# include "ui_events_remote.generated.h" // IWYU pragma: export
|
# include "ui_events_remote.generated.h" // IWYU pragma: export
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TODO(bfredl): just make UI:s owned by their channels instead
|
||||||
static PMap(uint64_t) connected_uis = MAP_INIT;
|
static PMap(uint64_t) connected_uis = MAP_INIT;
|
||||||
|
|
||||||
static char *mpack_array_dyn16(char **buf)
|
static char *mpack_array_dyn16(char **buf)
|
||||||
@ -89,10 +90,15 @@ void remote_ui_disconnect(uint64_t channel_id, Error *err, bool send_error_exit)
|
|||||||
MAXSIZE_TEMP_ARRAY(args, 1);
|
MAXSIZE_TEMP_ARRAY(args, 1);
|
||||||
ADD_C(args, INTEGER_OBJ(0));
|
ADD_C(args, INTEGER_OBJ(0));
|
||||||
push_call(ui, "error_exit", args);
|
push_call(ui, "error_exit", args);
|
||||||
ui_flush_buf(ui);
|
ui_flush_buf(ui, false);
|
||||||
}
|
}
|
||||||
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
|
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
|
||||||
ui_detach_impl(ui, channel_id);
|
ui_detach_impl(ui, channel_id);
|
||||||
|
Channel *chan = find_channel(channel_id);
|
||||||
|
if (chan && chan->rpc.ui == ui) {
|
||||||
|
chan->rpc.ui = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
remote_ui_destroy(ui);
|
remote_ui_destroy(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +196,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt
|
|||||||
ui->nevents_pos = NULL;
|
ui->nevents_pos = NULL;
|
||||||
ui->nevents = 0;
|
ui->nevents = 0;
|
||||||
ui->flushed_events = false;
|
ui->flushed_events = false;
|
||||||
|
ui->incomplete_event = false;
|
||||||
ui->ncalls_pos = NULL;
|
ui->ncalls_pos = NULL;
|
||||||
ui->ncalls = 0;
|
ui->ncalls = 0;
|
||||||
ui->ncells_pending = 0;
|
ui->ncells_pending = 0;
|
||||||
@ -206,6 +213,11 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt
|
|||||||
current_ui = channel_id;
|
current_ui = channel_id;
|
||||||
ui_attach_impl(ui, channel_id);
|
ui_attach_impl(ui, channel_id);
|
||||||
|
|
||||||
|
Channel *chan = find_channel(channel_id);
|
||||||
|
if (chan) {
|
||||||
|
chan->rpc.ui = ui;
|
||||||
|
}
|
||||||
|
|
||||||
may_trigger_vim_suspend_resume(false);
|
may_trigger_vim_suspend_resume(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +557,7 @@ static void prepare_call(RemoteUI *ui, const char *name)
|
|||||||
{
|
{
|
||||||
if (ui->packer.startptr
|
if (ui->packer.startptr
|
||||||
&& (BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE || ui->ncells_pending >= 500)) {
|
&& (BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE || ui->ncells_pending >= 500)) {
|
||||||
ui_flush_buf(ui);
|
ui_flush_buf(ui, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui->packer.startptr == NULL) {
|
if (ui->packer.startptr == NULL) {
|
||||||
@ -587,7 +599,7 @@ static void push_call(RemoteUI *ui, const char *name, Array args)
|
|||||||
static void ui_flush_callback(PackerBuffer *packer)
|
static void ui_flush_callback(PackerBuffer *packer)
|
||||||
{
|
{
|
||||||
RemoteUI *ui = packer->anydata;
|
RemoteUI *ui = packer->anydata;
|
||||||
ui_flush_buf(ui);
|
ui_flush_buf(ui, true);
|
||||||
ui_alloc_buf(ui);
|
ui_alloc_buf(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +825,7 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
|
|||||||
mpack_w2(&lenpos, nelem);
|
mpack_w2(&lenpos, nelem);
|
||||||
// We only ever set the wrap field on the final "grid_line" event for the line.
|
// We only ever set the wrap field on the final "grid_line" event for the line.
|
||||||
mpack_bool(buf, false);
|
mpack_bool(buf, false);
|
||||||
ui_flush_buf(ui);
|
ui_flush_buf(ui, false);
|
||||||
|
|
||||||
prepare_call(ui, "grid_line");
|
prepare_call(ui, "grid_line");
|
||||||
mpack_array(buf, 5);
|
mpack_array(buf, 5);
|
||||||
@ -886,11 +898,12 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
|
|||||||
///
|
///
|
||||||
/// This might happen multiple times before the actual ui_flush, if the
|
/// This might happen multiple times before the actual ui_flush, if the
|
||||||
/// total redraw size is large!
|
/// total redraw size is large!
|
||||||
static void ui_flush_buf(RemoteUI *ui)
|
static void ui_flush_buf(RemoteUI *ui, bool incomplete_event)
|
||||||
{
|
{
|
||||||
if (!ui->packer.startptr || !BUF_POS(ui)) {
|
if (!ui->packer.startptr || !BUF_POS(ui)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ui->incomplete_event = incomplete_event;
|
||||||
|
|
||||||
flush_event(ui);
|
flush_event(ui);
|
||||||
if (ui->nevents_pos != NULL) {
|
if (ui->nevents_pos != NULL) {
|
||||||
@ -921,11 +934,16 @@ void remote_ui_flush(RemoteUI *ui)
|
|||||||
remote_ui_cursor_goto(ui, ui->cursor_row, ui->cursor_col);
|
remote_ui_cursor_goto(ui, ui->cursor_row, ui->cursor_col);
|
||||||
}
|
}
|
||||||
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
|
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
|
||||||
ui_flush_buf(ui);
|
ui_flush_buf(ui, false);
|
||||||
ui->flushed_events = false;
|
ui->flushed_events = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remote_ui_flush_pending_data(RemoteUI *ui)
|
||||||
|
{
|
||||||
|
ui_flush_buf(ui, false);
|
||||||
|
}
|
||||||
|
|
||||||
static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena)
|
static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena)
|
||||||
{
|
{
|
||||||
Array new_contents = arena_array(arena, contents.size);
|
Array new_contents = arena_array(arena, contents.size);
|
||||||
|
@ -602,6 +602,12 @@ void serialize_response(Channel *channel, MsgpackRpcRequestHandler handler, Mess
|
|||||||
|
|
||||||
static void packer_buffer_init_channels(Channel **chans, size_t nchans, PackerBuffer *packer)
|
static void packer_buffer_init_channels(Channel **chans, size_t nchans, PackerBuffer *packer)
|
||||||
{
|
{
|
||||||
|
for (size_t i = 0; i < nchans; i++) {
|
||||||
|
Channel *chan = chans[i];
|
||||||
|
if (chan->rpc.ui && chan->rpc.ui->incomplete_event) {
|
||||||
|
remote_ui_flush_pending_data(chan->rpc.ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
packer->startptr = alloc_block();
|
packer->startptr = alloc_block();
|
||||||
packer->ptr = packer->startptr;
|
packer->ptr = packer->startptr;
|
||||||
packer->endptr = packer->startptr + ARENA_BLOCK_SIZE;
|
packer->endptr = packer->startptr + ARENA_BLOCK_SIZE;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "nvim/api/private/dispatch.h"
|
#include "nvim/api/private/dispatch.h"
|
||||||
#include "nvim/map_defs.h"
|
#include "nvim/map_defs.h"
|
||||||
|
#include "nvim/ui_defs.h"
|
||||||
|
|
||||||
typedef struct Channel Channel;
|
typedef struct Channel Channel;
|
||||||
typedef struct Unpacker Unpacker;
|
typedef struct Unpacker Unpacker;
|
||||||
@ -38,6 +39,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool closed;
|
bool closed;
|
||||||
Unpacker *unpacker;
|
Unpacker *unpacker;
|
||||||
|
RemoteUI *ui;
|
||||||
uint32_t next_request_id;
|
uint32_t next_request_id;
|
||||||
kvec_t(ChannelCallFrame *) call_stack;
|
kvec_t(ChannelCallFrame *) call_stack;
|
||||||
Dict info;
|
Dict info;
|
||||||
|
@ -72,6 +72,7 @@ typedef struct {
|
|||||||
uint32_t nevents; ///< number of distinct events (top-level args to "redraw"
|
uint32_t nevents; ///< number of distinct events (top-level args to "redraw"
|
||||||
uint32_t ncalls; ///< number of calls made to the current event (plus one for the name!)
|
uint32_t ncalls; ///< number of calls made to the current event (plus one for the name!)
|
||||||
bool flushed_events; ///< events where sent to client without "flush" event
|
bool flushed_events; ///< events where sent to client without "flush" event
|
||||||
|
bool incomplete_event; ///< incomplete event might be pending
|
||||||
|
|
||||||
size_t ncells_pending; ///< total number of cells since last buffer flush
|
size_t ncells_pending; ///< total number of cells since last buffer flush
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user