fix(ui): avoid ambiguity about last chunk when flushing halfway (#29718)

This commit is contained in:
zeertzjq 2024-07-15 18:35:20 +08:00 committed by GitHub
parent 04c158fbec
commit 594c7f3d77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 60 additions and 9 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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.