From 981acc2922ce9a5f214ba14acbb1e444748855f2 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 1 Jun 2023 02:15:14 -0700 Subject: [PATCH] fix(ui): propagate line wrapping state on grid_line events This fixes the TUI's line-wrapping behavior, which was broken with the migration to the msgpack-based UI protocol (see https://github.com/neovim/neovim/issues/7369#issuecomment-1571812273). --- runtime/doc/ui.txt | 22 ++++++++++++++-------- src/nvim/api/ui.c | 17 +++++++++++++---- src/nvim/api/ui_events.in.h | 2 +- src/nvim/grid_defs.h | 1 + src/nvim/msgpack_rpc/unpacker.c | 11 ++++++++--- src/nvim/ui_client.c | 4 +--- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index c64c450aa1..d3bd82ba27 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -78,14 +78,14 @@ Example of a typical "redraw" batch in a single RPC notification: > [ ['grid_resize', [2, 77, 36]], ['grid_line', - [2, 0, 0, [[' ' , 0, 77]]], - [2, 1, 0, [['~', 7], [' ', 7, 76]]], - [2, 9, 0, [['~', 7], [' ', 7, 76]]], + [2, 0, 0, [[' ' , 0, 77]], false], + [2, 1, 0, [['~', 7], [' ', 7, 76]], false], + [2, 9, 0, [['~', 7], [' ', 7, 76]], false], ... - [2, 35, 0, [['~', 7], [' ', 7, 76]]], - [1, 36, 0, [['[', 9], ['N'], ['o'], [' '], ['N'], ['a'], ['m'], ['e'], [']']]], - [1, 36, 9, [[' ', 9, 50]]], - [1, 36, 59, [['0', 9], [','], ['0'], ['-' ], ['1'], [' ', 9, 10], ['A'], ['l', 9, 2]]] + [2, 35, 0, [['~', 7], [' ', 7, 76]], false], + [1, 36, 0, [['[', 9], ['N'], ['o'], [' '], ['N'], ['a'], ['m'], ['e'], [']']], false], + [1, 36, 9, [[' ', 9, 50]], false], + [1, 36, 59, [['0', 9], [','], ['0'], ['-' ], ['1'], [' ', 9, 10], ['A'], ['l', 9, 2]], false] ], ['msg_showmode', [[]]], ['win_pos', [2, 1000, 0, 0, 77, 36]], @@ -360,7 +360,7 @@ numerical highlight ids to the actual attributes. use the |hl-Pmenu| family of builtin highlights. *ui-event-grid_line* -["grid_line", grid, row, col_start, cells] ~ +["grid_line", grid, row, col_start, cells, wrap] ~ Redraw a continuous part of a `row` on a `grid`, starting at the column `col_start`. `cells` is an array of arrays each with 1 to 3 items: `[text(, hl_id, repeat)]` . `text` is the UTF-8 text that should be put in @@ -379,6 +379,12 @@ numerical highlight ids to the actual attributes. enough to cover the remaining line, will be sent when the rest of the line should be cleared. + `wrap` is a boolean indicating that this line wraps to the next row. + When redrawing a line which wraps to the next row, Nvim will emit a + `grid_line` event covering the last column of the line with `wrap` set + to true, followed immediately by a `grid_line` event starting at the + first column of the next row. + ["grid_clear", grid] ~ Clear a `grid`. diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e98c589189..861ce100cd 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -73,6 +73,11 @@ static void mpack_uint(char **buf, uint32_t val) } } +static void mpack_bool(char **buf, bool val) +{ + mpack_w(buf, 0xc2 | val); +} + static void mpack_array(char **buf, uint32_t len) { if (len < 0x10) { @@ -809,7 +814,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int data->ncalls++; char **buf = &data->buf_wptr; - mpack_array(buf, 4); + mpack_array(buf, 5); mpack_uint(buf, (uint32_t)grid); mpack_uint(buf, (uint32_t)row); mpack_uint(buf, (uint32_t)startcol); @@ -823,17 +828,20 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] || strcmp(chunk[i], chunk[i + 1]) != 0) { - if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5)) { + if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. // For simplicity leave place for the final "clear" element // as well, hence the factor of 2 in the check. mpack_w2(&lenpos, nelem); + + // We only ever set the wrap field on the final "grid_line" event for the line. + mpack_bool(buf, false); remote_ui_flush_buf(ui); prepare_call(ui, "grid_line"); data->ncalls++; - mpack_array(buf, 4); + mpack_array(buf, 5); mpack_uint(buf, (uint32_t)grid); mpack_uint(buf, (uint32_t)row); mpack_uint(buf, (uint32_t)startcol + (uint32_t)i - repeat + 1); @@ -865,9 +873,10 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int mpack_uint(buf, (uint32_t)(clearcol - endcol)); } mpack_w2(&lenpos, nelem); + mpack_bool(buf, flags & kLineFlagWrap); if (data->ncells_pending > 500) { - // pass of cells to UI to let it start processing them + // pass off cells to UI to let it start processing them remote_ui_flush_buf(ui); } } else { diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index b93f521ca3..fc70215352 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -82,7 +82,7 @@ void grid_clear(Integer grid) FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL; void grid_cursor_goto(Integer grid, Integer row, Integer col) FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL; -void grid_line(Integer grid, Integer row, Integer col_start, Array data) +void grid_line(Integer grid, Integer row, Integer col_start, Array data, Boolean wrap) FUNC_API_SINCE(5) FUNC_API_REMOTE_ONLY FUNC_API_CLIENT_IMPL; void grid_scroll(Integer grid, Integer top, Integer bot, Integer left, Integer right, Integer rows, Integer cols) diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index 830c74e86d..aae61cc719 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -117,6 +117,7 @@ typedef struct { int coloff; int cur_attr; int clear_width; + bool wrap; } GridLineEvent; #endif // NVIM_GRID_DEFS_H diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index 25edf2e21d..4128f91b6e 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -441,7 +441,7 @@ redo: case 14: NEXT_TYPE(tok, MPACK_TOKEN_ARRAY); int eventarrsize = (int)tok.length; - if (eventarrsize != 4) { + if (eventarrsize != 5) { p->state = -1; return false; } @@ -509,11 +509,16 @@ redo: } g->icell++; - p->read_ptr = data; - p->read_size = size; if (g->icell == g->ncells) { + NEXT_TYPE(tok, MPACK_TOKEN_BOOLEAN); + g->wrap = mpack_unpack_boolean(tok); + p->read_ptr = data; + p->read_size = size; return true; } + + p->read_ptr = data; + p->read_size = size; goto redo; case 12: diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index 1918b0b800..9395ff2f1e 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -210,9 +210,7 @@ void ui_client_event_raw_line(GridLineEvent *g) int grid = g->args[0], row = g->args[1], startcol = g->args[2]; Integer endcol = startcol + g->coloff; Integer clearcol = endcol + g->clear_width; - - // TODO(hlpr98): Accommodate other LineFlags when included in grid_line - LineFlags lineflags = 0; + LineFlags lineflags = g->wrap ? kLineFlagWrap : 0; tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags, (const schar_T *)grid_line_buf_char, grid_line_buf_attr);