aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-07-15 18:35:20 +0800
committerGitHub <noreply@github.com>2024-07-15 18:35:20 +0800
commit594c7f3d77262a1222c9786d86353a0595f2894c (patch)
treed67b95de5f1c770a49317f8a7a0adaf0fdaa5a82
parent04c158fbec9aeeccd7bd1bb16fc8a688edadd353 (diff)
downloadrneovim-594c7f3d77262a1222c9786d86353a0595f2894c.tar.gz
rneovim-594c7f3d77262a1222c9786d86353a0595f2894c.tar.bz2
rneovim-594c7f3d77262a1222c9786d86353a0595f2894c.zip
fix(ui): avoid ambiguity about last chunk when flushing halfway (#29718)
-rw-r--r--src/nvim/api/ui.c26
-rw-r--r--test/functional/terminal/testutil.lua2
-rw-r--r--test/functional/terminal/tui_spec.lua41
3 files changed, 60 insertions, 9 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index fdf25c75d7..852b8b9b48 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -778,16 +778,26 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
for (size_t i = 0; i < ncells; i++) {
repeat++;
if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) {
- if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1
+ if (
+ // 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.
+ UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1
+ // Also if there is a lot of packed cells, pass them off to the UI to
+ // let it start processing them.
|| ui->ncells_pending >= 500) {
- // 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.
- // Also if there is a lot of packed cells, pass them of to the UI to
- // let it start processing them
+ // If the last chunk was all spaces, add an empty clearing chunk,
+ // so it's clear that the last chunk wasn't a clearing chunk.
+ if (was_space) {
+ nelem++;
+ ui->ncells_pending += 1;
+ mpack_array(buf, 3);
+ mpack_str_small(buf, S_LEN(" "));
+ mpack_uint(buf, (uint32_t)clearattr);
+ mpack_uint(buf, 0);
+ }
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);
diff --git a/test/functional/terminal/testutil.lua b/test/functional/terminal/testutil.lua
index 45c73b1dc6..7eb4af4940 100644
--- a/test/functional/terminal/testutil.lua
+++ b/test/functional/terminal/testutil.lua
@@ -169,7 +169,7 @@ local function setup_child_nvim(args, opts)
env.VIMRUNTIME = os.getenv('VIMRUNTIME')
end
- return screen_setup(0, argv, opts.cols, env)
+ return screen_setup(opts.extra_rows, argv, opts.cols, env)
end
return {
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 5269af760a..3e0b907ea2 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -2199,6 +2199,47 @@ describe('TUI', function()
}
end)
+ it('draws screen lines with leading spaces correctly #29711', function()
+ local screen = tt.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'set foldcolumn=6 | call setline(1, ["", repeat("aabb", 1000)]) | echo 42',
+ }, { extra_rows = 10, cols = 66 })
+ screen:expect {
+ grid = [[
+ |
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
+ [No Name] [+] 1,0-1 Top|
+ 42 |
+ -- TERMINAL -- |
+ ]],
+ attr_ids = {},
+ }
+ feed_data('\12') -- Ctrl-L
+ -- The first line counts as 3 cells.
+ -- For the second line, 6 repeated spaces at the start counts as 2 cells,
+ -- so each screen line of the second line counts as 62 cells.
+ -- After drawing the first line and 8 screen lines of the second line,
+ -- 3 + 8 * 62 = 499 cells have been counted.
+ -- The 6 repeated spaces at the start of the next screen line exceeds the
+ -- 500-cell limit, so the buffer is flushed after these spaces.
+ screen:expect {
+ grid = [[
+ |
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
+ [No Name] [+] 1,0-1 Top|
+ |
+ -- TERMINAL -- |
+ ]],
+ attr_ids = {},
+ }
+ end)
+
it('no heap-buffer-overflow when changing &columns', function()
-- Set a different bg colour and change $TERM to something dumber so the `print_spaces()`
-- codepath in `clear_region()` is hit.