From 1ed4a349be854f6af1546742c19158c05c0cf8d3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 15 Nov 2024 16:10:37 +0530 Subject: [PATCH] Clearance of multicell tests --- kitty/line.h | 1 + kitty/screen.c | 5 ++- kitty_tests/multicell.py | 75 +++++++++++++++++++++++++++++++++++----- kitty_tests/parser.py | 2 +- 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/kitty/line.h b/kitty/line.h index 04d98f6e9..078650a41 100644 --- a/kitty/line.h +++ b/kitty/line.h @@ -19,6 +19,7 @@ // TODO: Handle replay of dumped graphics_command and multicell_command // TODO: Handle rewrap of multiline chars // TODO: Handle rewrap when a character is too wide/tall to fit on resized screen +// TODO: Test serialization to ansi only using escape code for explicitly set multicells typedef union CellAttrs { struct { diff --git a/kitty/screen.c b/kitty/screen.c index ea96e88bb..24e198cc7 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1044,9 +1044,11 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_ RAII_ListOfChars(lc); lc.chars[lc.count++] = ch; lc.chars[lc.count++] = mcd.val; + CPUCell *second = fc + 1; + if (second->is_multicell) nuke_multicell_char_at(self, self->cursor->x + 1, self->cursor->y, true); cell_set_chars(fc, self->text_cache, &lc); fc->x = 0; fc->y = 0; fc->is_multicell = true; - *(fc + 1) = *fc; (fc + 1)->x = 1; + *second = *fc; second->x = 1; s->gp[self->cursor->x + 1] = s->gp[self->cursor->x]; self->cursor->x += 2; } else { @@ -1167,6 +1169,7 @@ screen_handle_multicell_command(Screen *self, const MultiCellCommand *cmd, const CPUCell c = s.cc; c.ch_is_idx = true; c.ch_or_idx = tc_get_or_insert_chars(self->text_cache, self->lc); c.is_multicell = true; + nuke_multicell_char_intersecting_with(self, self->cursor->x, self->cursor->x + width, self->cursor->y, self->cursor->y + height, true); for (index_type y = self->cursor->y; y < self->cursor->y + height; y++) { linebuf_init_cells(self->linebuf, y, &s.cp, &s.gp); linebuf_mark_line_dirty(self->linebuf, y); diff --git a/kitty_tests/multicell.py b/kitty_tests/multicell.py index 073c1b70b..4801af5ff 100644 --- a/kitty_tests/multicell.py +++ b/kitty_tests/multicell.py @@ -23,11 +23,6 @@ def test_multicell(self: TestMulticell) -> None: def ac(x_, y_, **assertions): # assert cell cell = s.cpu_cells(y_, x_) msg = f'Assertion failed for cell at ({x_}, {y_})\n{cell}\n' - if 'is_multicell' in assertions: - if assertions['is_multicell']: - assert cell['mcd'] is not None, msg - else: - assert cell['mcd'] is None, msg def ae(key): if key not in assertions: return @@ -38,7 +33,8 @@ def ae(key): if mcd is None: raise AssertionError(f'{msg}Unexpectedly not a multicell') val = mcd[key] - assert assertions[key] == val, f'{msg}{assertions[key]!r} != {val!r}' + if assertions[key] != val: + raise AssertionError(f'{msg}{assertions[key]!r} != {val!r}') ae('x') ae('y') @@ -48,10 +44,30 @@ def ae(key): ae('vertical_align') ae('text') ae('explicitly_set') + if 'cursor' in assertions: self.ae(assertions['cursor'], (s.cursor.x, s.cursor.y), msg) - s = self.create_screen(cols=5, lines=5) + if 'is_multicell' in assertions: + q = cell['mcd'] + if assertions['is_multicell']: + if q is None: + raise AssertionError(f'{msg}Unexpectedly not a multicell') + else: + if q is not None: + raise AssertionError(f'{msg}Unexpectedly is a multicell') + + def count_multicells(with_text=''): + ans = 0 + for y in range(s.lines): + for x in range(s.columns): + c = s.cpu_cells(y, x) + if c['mcd'] is not None and (not with_text or c['text'] == with_text): + ans += 1 + return ans + + # Test basic multicell drawing + s = self.create_screen(cols=6, lines=6) ac(0, 0, is_multicell=False) multicell(s, 'a') ac(0, 0, is_multicell=True, width=1, scale=1, subscale=0, x=0, y=0, text='a', explicitly_set=True, cursor=(1, 0)) @@ -60,4 +76,47 @@ def ae(key): ac(0, 0, is_multicell=True, width=1, scale=1, subscale=0, x=0, y=0, text='a', explicitly_set=True) ac(1, 0, is_multicell=True, width=2, scale=1, subscale=0, x=0, y=0, text='莊', explicitly_set=False, cursor=(3, 0)) ac(2, 0, is_multicell=True, width=2, scale=1, subscale=0, x=1, y=0, text='', explicitly_set=False) - ac(1, 0, is_multicell=False), ac(1, 1, is_multicell=False) + for x in range(s.columns): + ac(x, 1, is_multicell=False) + s.cursor.x = 0 + multicell(s, 'a', width=2, scale=2, subscale=3) + ac(0, 0, is_multicell=True, width=2, scale=2, subscale=3, x=0, y=0, text='a', explicitly_set=True, cursor=(4, 0)) + for x in range(1, 4): + ac(x, 0, is_multicell=True, width=2, scale=2, subscale=3, x=x, y=0, text='', explicitly_set=True) + for x in range(0, 4): + ac(x, 1, is_multicell=True, width=2, scale=2, subscale=3, x=x, y=1, text='', explicitly_set=True) + + # Test draw with cursor in a multicell + s.reset() + s.draw('莊') + s.cursor.x -= 1 + s.draw('a'), ac(0, 0, is_multicell=False), ac(1, 0, is_multicell=False) + s.reset() + s.draw('莊') + s.cursor.x = 0 + s.draw('a'), ac(0, 0, is_multicell=False), ac(1, 0, is_multicell=False) + s.reset() + multicell(s, 'a', width=2, scale=2, subscale=3) + s.cursor.x, s.cursor.y = 1, 1 + s.draw('b') + self.ae(0, count_multicells()) + s.reset() + s.cursor.x = 1 + s.draw('莊') + s.cursor.x = 0 + s.draw('莊') + ac(2, 0, is_multicell=False, text=' ') + + # Test multicell with cursor in a multicell + def big_a(x, y): + s.reset() + s.cursor.x, s.cursor.y = 1, 1 + multicell(s, 'a', scale=4) + s.cursor.x, s.cursor.y = x, y + multicell(s, 'b', scale=2) + self.ae(4, count_multicells()) + for x in range(1, 5): + ac(x, 4, text=' ') + big_a(0, 0), big_a(1, 1), big_a(2, 2), big_a(5, 1) + + diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 3b581e0dc..aec8c9086 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -611,7 +611,7 @@ def e(cmd, err): e('s', 'Malformed GraphicsCommand control block, no = after key') e('s=', 'Malformed GraphicsCommand control block, expecting an integer value') e('s==', 'Malformed GraphicsCommand control block, expecting an integer value for key: s') - e('s=1=', 'Malformed GraphicsCommand control block, expecting a comma or semi-colon after a value, found: 0x3d') + e('s=1=', 'Malformed GraphicsCommand control block, expecting a , or semi-colon after a value, found: 0x3d') def test_deccara(self): s = self.create_screen()