diff options
-rw-r--r-- | src/nvim/tui/tui.c | 4 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 26 |
2 files changed, 29 insertions, 1 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 3205547324..066567a87f 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1635,11 +1635,13 @@ static void unibi_goto(UI *ui, int row, int col) } \ if (str) { \ unibi_var_t vars[26 + 26]; \ + unibi_var_t params[9]; \ size_t orig_pos = data->bufpos; \ memset(&vars, 0, sizeof(vars)); \ data->cork = true; \ retry: \ - unibi_format(vars, vars + 26, str, data->params, out, ui, pad, ui); \ + memcpy(params, data->params, sizeof(params)); \ + unibi_format(vars, vars + 26, str, params, out, ui, pad, ui); \ if (data->overflow) { \ data->bufpos = orig_pos; \ flush_buf(ui); \ diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 7c2269e453..e31f76a444 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -13,6 +13,7 @@ local feed_command = helpers.feed_command local feed_data = thelpers.feed_data local clear = helpers.clear local command = helpers.command +local dedent = helpers.dedent local exec = helpers.exec local testprg = helpers.testprg local retry = helpers.retry @@ -1443,6 +1444,31 @@ describe('TUI', function() child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 1}}}) screen:expect(singlewidth_screen, attrs) end) + + it('draws correctly when cursor_address overflows #21643', function() + helpers.skip(helpers.is_ci('github'), 'FIXME: flaky on GitHub CI') + screen:try_resize(75, 60) + -- The composing character takes 3 bytes. + local composing = ('a︠'):sub(2) + -- The composed character takes 1 + 5 * 3 = 16 bytes. + local c = 'a' .. composing:rep(5) + -- Going to top-left corner needs 3 bytes. + -- With screen width 75, 4088 characters need 54 full screen lines. + -- Drawing each full screen line needs 75 * 16 + 2 = 1202 bytes (2 bytes for CR LF). + -- The incomplete screen line needs 38 * 16 + 8 + 3 = 619 bytes. + -- The whole line needs 3 + 54 * 1202 + 619 = 65530 bytes. + -- The cursor_address that comes after will overflow the 65535-byte buffer. + local line = c:rep(4088) .. ('b'):rep(8) .. '℃' + child_session:request('nvim_buf_set_lines', 0, 0, -1, true, {line, 'c'}) + screen:expect( + '{1:' .. c .. '}' .. c:rep(74) .. '|\n' .. (c:rep(75) .. '|\n'):rep(53) + .. c:rep(38) .. ('b'):rep(8) .. '℃' .. (' '):rep(28) .. '|\n' .. dedent([[ + c | + {4:~ }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} |]])) + end) end) describe('TUI', function() |