From 23bb053fb463ad3ae1f5e6e8932d7226e2e891c9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 17 Nov 2024 09:15:32 +0530 Subject: [PATCH] Insert chars with multicell tests --- kitty/screen.c | 31 ++++++++++++++++---- kitty_tests/multicell.py | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/kitty/screen.c b/kitty/screen.c index 24e198cc7..ccfec1045 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -638,6 +638,13 @@ checked_range_line(Screen *self, int y) { return range_line_(self, y); } +static void +nuke_in_line(CPUCell *cp, GPUCell *gp, index_type start, index_type x_limit, char_type ch) { + for (index_type x = start; x < x_limit; x++) { + cell_set_char(cp + x, ch); cp[x].is_multicell = false; + clear_sprite_position(gp[x]); + } +} static void nuke_multicell_char_at(Screen *self, index_type x_, index_type y_, bool replace_with_spaces) { @@ -648,19 +655,17 @@ nuke_multicell_char_at(Screen *self, index_type x_, index_type y_, bool replace_ while (cp[x_].x && x_ > 0) x_--; index_type x_limit = MIN(self->columns, x_ + mcd_x_limit(mcd)); char_type ch = replace_with_spaces ? ' ' : 0; -#define nuke_in_line for (index_type x = x_; x < x_limit; x++) { cell_set_char(cp + x, ch); cp[x].is_multicell = false; clear_sprite_position(gp[x]); } for (index_type y = y_; y < y_max_limit; y++) { linebuf_init_cells(self->linebuf, y, &cp, &gp); - nuke_in_line; linebuf_mark_line_dirty(self->linebuf, y); + nuke_in_line(cp, gp, x_, x_limit, ch); linebuf_mark_line_dirty(self->linebuf, y); } int y_min_limit = -1; if (self->linebuf == self->main_linebuf) y_min_limit = -(self->historybuf->count + 1); for (int y = y_ - 1; y > y_min_limit; y--) { Line *line = range_line_(self, y); cp = line->cpu_cells; gp = line->gpu_cells; - nuke_in_line; if (y > -1) linebuf_mark_line_dirty(self->linebuf, y); + nuke_in_line(cp, gp, x_, x_limit, ch); linebuf_mark_line_dirty(self->linebuf, y); } self->is_dirty = true; -#undef nuke_in_line } static void @@ -707,6 +712,22 @@ nuke_split_multicell_char_at_right_boundary(Screen *self, index_type x, index_ty } } +static void +nuke_incomplete_single_line_multicell_chars_in_range( + Screen *self, index_type start, index_type limit, index_type y, bool replace_with_spaces +) { + CPUCell *cpu_cells; GPUCell *gpu_cells; + linebuf_init_cells(self->linebuf, y, &cpu_cells, &gpu_cells); + for (index_type x = start; x < limit; x++) { + if (cpu_cells[x].is_multicell) { + MultiCellData mcd = cell_multicell_data(cpu_cells + x, self->text_cache); + index_type last_x = x + mcd.width; + if (last_x > limit) nuke_in_line(cpu_cells, gpu_cells, x, limit, replace_with_spaces ? ' ': 0); + x = last_x + 1; + } + } +} + static void insert_characters(Screen *self, index_type at, index_type num, index_type y, bool replace_with_spaces) { // insert num chars at x=at setting them to the value of the num chars at [at, at + num) @@ -714,13 +735,13 @@ insert_characters(Screen *self, index_type at, index_type num, index_type y, boo // and x=at + num - 1 are deleted nuke_multiline_char_intersecting_with(self, at, self->columns, y, y + 1, replace_with_spaces); nuke_split_multicell_char_at_left_boundary(self, at, y, replace_with_spaces); - nuke_split_multicell_char_at_right_boundary(self, at + num - 1, y, replace_with_spaces); CPUCell *cp; GPUCell *gp; linebuf_init_cells(self->linebuf, y, &cp, &gp); // right shift for(index_type i = self->columns - 1; i >= at + num; i--) { cp[i] = cp[i - num]; gp[i] = gp[i - num]; } + nuke_incomplete_single_line_multicell_chars_in_range(self, at, at + num, y, replace_with_spaces); nuke_split_multicell_char_at_right_boundary(self, self->columns - 1, y, replace_with_spaces); } diff --git a/kitty_tests/multicell.py b/kitty_tests/multicell.py index 4801af5ff..9a167422c 100644 --- a/kitty_tests/multicell.py +++ b/kitty_tests/multicell.py @@ -66,6 +66,20 @@ def test_multicell(self: TestMulticell) -> None: ans += 1 return ans + def line_text(y): + def ct(c): + if c['text']: + return c['text'] + if c['mcd']: + return '_' + return '\0' + return ''.join(ct(c) for c in s.cpu_cells(y)) + + def assert_line(text, y=None): + if y is None: + y = s.cursor.y + self.ae(text, line_text(y)) + # Test basic multicell drawing s = self.create_screen(cols=6, lines=6) ac(0, 0, is_multicell=False) @@ -119,4 +133,52 @@ def test_multicell(self: TestMulticell) -> None: ac(x, 4, text=' ') big_a(0, 0), big_a(1, 1), big_a(2, 2), big_a(5, 1) + # Test insert chars with multicell + s.reset() + s.draw('a') + s.cursor.x = 0 + s.insert_characters(1) + assert_line('\0a\0\0\0\0') + s.reset() + multicell(s, 'a', width=2) + s.cursor.x = 0 + s.insert_characters(1) + assert_line('\0a_\0\0\0') + s.reset() + multicell(s, 'a', width=2) + s.cursor.x = 0 + s.insert_characters(2) + assert_line('\0\0a_\0\0') + s.reset() + multicell(s, 'a', width=2) + s.cursor.x = 1 + s.insert_characters(1) + assert_line('\0\0\0\0\0\0') + s.reset() + s.cursor.x = 3 + multicell(s, 'a', width=2) + s.cursor.x = 0 + s.insert_characters(1) + assert_line('\0\0\0\0a_') + s.reset() + s.cursor.x = s.columns - 2 + multicell(s, 'a', width=2) + s.cursor.x = 0 + s.insert_characters(1) + assert_line('\0\0\0\0\0\0') + s.reset() + s.draw('a') + multicell(s, 'b', scale=2) + assert_line('ab_\0\0\0') + assert_line('\0__\0\0\0', 1) + s.cursor.x, s.cursor.y = 0, 0 + s.insert_characters(1) + assert_line('\0a\0\0\0\0') + assert_line('\0\0\0\0\0\0', 1) + s.reset() + multicell(s, 'a', scale=2) + s.cursor.x = 3 + s.insert_characters(1) + assert_line('a_\0\0\0\0') + assert_line('__\0\0\0\0', 1)