diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index d2e0fd98a8..6a87afa3a4 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -45,6 +45,7 @@ # include "ui_events_remote.generated.h" // IWYU pragma: export #endif +// TODO(bfredl): just make UI:s owned by their channels instead static PMap(uint64_t) connected_uis = MAP_INIT; 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); ADD_C(args, INTEGER_OBJ(0)); push_call(ui, "error_exit", args); - ui_flush_buf(ui); + ui_flush_buf(ui, false); } pmap_del(uint64_t)(&connected_uis, channel_id, NULL); 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); } @@ -190,6 +196,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt ui->nevents_pos = NULL; ui->nevents = 0; ui->flushed_events = false; + ui->incomplete_event = false; ui->ncalls_pos = NULL; ui->ncalls = 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; ui_attach_impl(ui, channel_id); + Channel *chan = find_channel(channel_id); + if (chan) { + chan->rpc.ui = ui; + } + may_trigger_vim_suspend_resume(false); } @@ -545,7 +557,7 @@ static void prepare_call(RemoteUI *ui, const char *name) { if (ui->packer.startptr && (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) { @@ -587,7 +599,7 @@ static void push_call(RemoteUI *ui, const char *name, Array args) static void ui_flush_callback(PackerBuffer *packer) { RemoteUI *ui = packer->anydata; - ui_flush_buf(ui); + ui_flush_buf(ui, true); 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); // We only ever set the wrap field on the final "grid_line" event for the line. mpack_bool(buf, false); - ui_flush_buf(ui); + ui_flush_buf(ui, false); prepare_call(ui, "grid_line"); 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 /// 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)) { return; } + ui->incomplete_event = incomplete_event; flush_event(ui); 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); } push_call(ui, "flush", (Array)ARRAY_DICT_INIT); - ui_flush_buf(ui); + ui_flush_buf(ui, 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) { Array new_contents = arena_array(arena, contents.size); diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index f5a4d69a9e..3efd5f5628 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -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) { + 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->ptr = packer->startptr; packer->endptr = packer->startptr + ARENA_BLOCK_SIZE; diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index 871d4e615f..b30f2b65ba 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -5,6 +5,7 @@ #include "nvim/api/private/dispatch.h" #include "nvim/map_defs.h" +#include "nvim/ui_defs.h" typedef struct Channel Channel; typedef struct Unpacker Unpacker; @@ -38,6 +39,7 @@ typedef struct { typedef struct { bool closed; Unpacker *unpacker; + RemoteUI *ui; uint32_t next_request_id; kvec_t(ChannelCallFrame *) call_stack; Dict info; diff --git a/src/nvim/ui_defs.h b/src/nvim/ui_defs.h index b140eee2c5..7da73b1c0b 100644 --- a/src/nvim/ui_defs.h +++ b/src/nvim/ui_defs.h @@ -72,6 +72,7 @@ typedef struct { 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!) 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