aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/terminal/buffer_spec.lua19
-rw-r--r--test/unit/fixtures/vterm_test.c37
-rw-r--r--test/unit/vterm_spec.lua83
3 files changed, 107 insertions, 32 deletions
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index e209ed9025..b6de687af9 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -400,15 +400,28 @@ describe(':terminal buffer', function()
assert_alive()
end)
- it('truncates number of composing characters to 5', function()
+ it('truncates the size of grapheme clusters', function()
local chan = api.nvim_open_term(0, {})
local composing = ('a̳'):sub(2)
- api.nvim_chan_send(chan, 'a' .. composing:rep(8))
+ api.nvim_chan_send(chan, 'a' .. composing:rep(20))
retry(nil, nil, function()
- eq('a' .. composing:rep(5), api.nvim_get_current_line())
+ eq('a' .. composing:rep(14), api.nvim_get_current_line())
end)
end)
+ it('handles extended grapheme clusters', function()
+ local screen = Screen.new(50, 7)
+ feed 'i'
+ local chan = api.nvim_open_term(0, {})
+ api.nvim_chan_send(chan, '🏴‍☠️ yarrr')
+ screen:expect([[
+ 🏴‍☠️ yarrr^ |
+ |*5
+ {5:-- TERMINAL --} |
+ ]])
+ eq('🏴‍☠️ yarrr', api.nvim_get_current_line())
+ end)
+
it('handles split UTF-8 sequences #16245', function()
local screen = Screen.new(50, 7)
fn.jobstart({ testprg('shell-test'), 'UTF-8' }, { term = true })
diff --git a/test/unit/fixtures/vterm_test.c b/test/unit/fixtures/vterm_test.c
index f227ae4591..8755e32e7a 100644
--- a/test/unit/fixtures/vterm_test.c
+++ b/test/unit/fixtures/vterm_test.c
@@ -1,4 +1,6 @@
#include <stdio.h>
+#include "nvim/grid.h"
+#include "nvim/mbyte.h"
#include "vterm_test.h"
@@ -202,6 +204,26 @@ int selection_query(VTermSelectionMask mask, void *user)
return 1;
}
+static void print_schar(FILE *f, schar_T schar) {
+ char buf[MAX_SCHAR_SIZE];
+ schar_get(buf, schar);
+ StrCharInfo ci = utf_ptr2StrCharInfo(buf);
+ bool did = false;
+ while (*ci.ptr != 0) {
+ if (did) {
+ fprintf(f, ",");
+ }
+
+ if (ci.chr.len == 1 && ci.chr.value >= 0x80) {
+ fprintf(f, "??%x", ci.chr.value);
+ } else {
+ fprintf(f, "%x", ci.chr.value);
+ }
+ did = true;
+ ci = utf_ptr2StrCharInfo(ci.ptr + ci.chr.len);
+ }
+}
+
bool want_state_putglyph;
int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
{
@@ -211,9 +233,7 @@ int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
FILE *f = fopen(VTERM_TEST_FILE, "a");
fprintf(f, "putglyph ");
- for (int i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
- fprintf(f, i ? ",%x" : "%x", info->chars[i]);
- }
+ print_schar(f, info->schar);
fprintf(f, " %d %d,%d", info->width, pos.row, pos.col);
if (info->protected_cell) {
fprintf(f, " prot");
@@ -443,14 +463,15 @@ int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
}
int eol = cols;
- while (eol && !cells[eol - 1].chars[0]) {
+ while (eol && !cells[eol-1].schar) {
eol--;
}
FILE *f = fopen(VTERM_TEST_FILE, "a");
fprintf(f, "sb_pushline %d =", cols);
for (int c = 0; c < eol; c++) {
- fprintf(f, " %02X", cells[c].chars[0]);
+ fprintf(f, " ");
+ print_schar(f, cells[c].schar);
}
fprintf(f, "\n");
@@ -467,10 +488,10 @@ int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
// All lines of scrollback contain "ABCDE"
for (int col = 0; col < cols; col++) {
- if (col < 5) {
- cells[col].chars[0] = (uint32_t)('A' + col);
+ if(col < 5) {
+ cells[col].schar = schar_from_ascii((uint32_t)('A' + col));
} else {
- cells[col].chars[0] = 0;
+ cells[col].schar = 0;
}
cells[col].width = 1;
diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua
index a05579b4ff..2457525fb7 100644
--- a/test/unit/vterm_spec.lua
+++ b/test/unit/vterm_spec.lua
@@ -17,7 +17,6 @@ local bit = require('bit')
--- @field VTERM_KEY_NONE integer
--- @field VTERM_KEY_TAB integer
--- @field VTERM_KEY_UP integer
---- @field VTERM_MAX_CHARS_PER_CELL integer
--- @field VTERM_MOD_ALT integer
--- @field VTERM_MOD_CTRL integer
--- @field VTERM_MOD_SHIFT integer
@@ -80,6 +79,8 @@ local bit = require('bit')
--- @field vterm_state_set_selection_callbacks function
--- @field vterm_state_set_unrecognised_fallbacks function
local vterm = t.cimport(
+ './src/nvim/mbyte.h',
+ './src/nvim/grid.h',
'./src/vterm/vterm.h',
'./src/vterm/vterm_internal.h',
'./test/unit/fixtures/vterm_test.h'
@@ -302,16 +303,12 @@ local function screen_chars(start_row, start_col, end_row, end_col, expected, sc
rect['end_row'] = end_row
rect['end_col'] = end_col
- local len = vterm.vterm_screen_get_chars(screen, nil, 0, rect)
-
- local chars = t.ffi.new('uint32_t[?]', len)
- vterm.vterm_screen_get_chars(screen, chars, len, rect)
+ local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
- local actual = ''
- for i = 0, tonumber(len) - 1 do
- actual = actual .. string.char(chars[i])
- end
+ local text = t.ffi.new('unsigned char[?]', len)
+ vterm.vterm_screen_get_text(screen, text, len, rect)
+ local actual = t.ffi.string(text, len)
t.eq(expected, actual)
end
@@ -349,7 +346,7 @@ local function screen_row(row, expected, screen, end_col)
local text = t.ffi.new('unsigned char[?]', len)
vterm.vterm_screen_get_text(screen, text, len, rect)
- t.eq(expected, t.ffi.string(text))
+ t.eq(expected, t.ffi.string(text, len))
end
local function screen_cell(row, col, expected, screen)
@@ -360,14 +357,20 @@ local function screen_cell(row, col, expected, screen)
local cell = t.ffi.new('VTermScreenCell')
vterm.vterm_screen_get_cell(screen, pos, cell)
+ local buf = t.ffi.new('unsigned char[32]')
+ vterm.schar_get(buf, cell.schar)
+
local actual = '{'
- for i = 0, vterm.VTERM_MAX_CHARS_PER_CELL - 1 do
- if cell['chars'][i] ~= 0 then
- if i > 0 then
- actual = actual .. ','
- end
- actual = string.format('%s%02x', actual, cell['chars'][i])
+ local i = 0
+ while buf[i] > 0 do
+ local char = vterm.utf_ptr2char(buf + i)
+ local charlen = vterm.utf_ptr2len(buf + i)
+ if i > 0 then
+ actual = actual .. ','
end
+ local invalid = char >= 128 and charlen == 1
+ actual = string.format('%s%s%02x', actual, invalid and '?' or '', char)
+ i = i + charlen
end
actual = string.format('%s} width=%d attrs={', actual, cell['width'])
actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '')
@@ -962,8 +965,8 @@ describe('vterm', function()
-- Spare combining chars get truncated
reset(state, nil)
- push('e' .. string.rep('\xCC\x81', 10), vt)
- expect('putglyph 65,301,301,301,301,301 1 0,0') -- and nothing more
+ push('e' .. string.rep('\xCC\x81', 20), vt)
+ expect('putglyph 65,301,301,301,301,301,301,301,301,301,301,301,301,301,301 1 0,0') -- and nothing more
reset(state, nil)
push('e', vt)
@@ -973,6 +976,34 @@ describe('vterm', function()
push('\xCC\x82', vt)
expect('putglyph 65,301,302 1 0,0')
+ -- emoji with ZWJ and variant selectors, as one chunk
+ reset(state, nil)
+ push('🏳️‍🌈🏳️‍⚧️🏴‍☠️', vt)
+ expect([[putglyph 1f3f3,fe0f,200d,1f308 2 0,0
+putglyph 1f3f3,fe0f,200d,26a7,fe0f 2 0,2
+putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
+
+ -- emoji, one code point at a time
+ reset(state, nil)
+ push('🏳', vt)
+ expect('putglyph 1f3f3 2 0,0')
+ push('\xef\xb8\x8f', vt)
+ expect('putglyph 1f3f3,fe0f 2 0,0')
+ push('\xe2\x80\x8d', vt)
+ expect('putglyph 1f3f3,fe0f,200d 2 0,0')
+ push('🌈', vt)
+ expect('putglyph 1f3f3,fe0f,200d,1f308 2 0,0')
+
+ -- modifier can change width
+ push('❤', vt)
+ expect('putglyph 2764 1 0,2')
+ push('\xef\xb8\x8f', vt)
+ expect('putglyph 2764,fe0f 2 0,2')
+
+ -- also works batched
+ push('❤️', vt)
+ expect('putglyph 2764,fe0f 2 0,4')
+
-- DECSCA protected
reset(state, nil)
push('A\x1b[1"qB\x1b[2"qC', vt)
@@ -3046,7 +3077,7 @@ describe('vterm', function()
screen_cell(
0,
0,
- '{65,301,302,303,304,305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ '{65,301,302,303,304,305,306,307,308,309,30a} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
screen
)
@@ -3063,7 +3094,7 @@ describe('vterm', function()
screen_cell(
0,
0,
- '{65,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ '{65,301,301,301,301,301,301,301,301,301,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
screen
)
@@ -3072,6 +3103,16 @@ describe('vterm', function()
push('\x1b[80G\xEF\xBC\x90', vt)
screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Outputting emoji with ZWJ and variant selectors
+ reset(nil, screen)
+ push('🏳️‍🌈🏳️‍⚧️🏴‍☠️', vt)
+
+ -- stylua: ignore start
+ screen_cell(0, 0, '{1f3f3,fe0f,200d,1f308} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 2, '{1f3f3,fe0f,200d,26a7,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 4, '{1f3f4,200d,2620,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ -- stylua: ignore end
end)
pending('62screen_damage', function() end)
@@ -3125,7 +3166,7 @@ describe('vterm', function()
screen = wantscreen(vt, { b = true })
resize(20, 80, vt)
expect(
- 'sb_pushline 80 = 54 6F 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
+ 'sb_pushline 80 = 54 6f 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
)
-- TODO(dundargoc): fix or remove
-- screen_row( 0 , "",screen)