From 2c380a2e37cdf43f335acb9e603025bf2dcaa898 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 11 Jan 2025 05:40:37 +0530 Subject: [PATCH] More tests for multicell selections --- kitty/history.c | 2 ++ kitty/line-buf.c | 2 ++ kitty/line.c | 18 +++++++++++------- kitty/line.h | 1 - kitty_tests/multicell.py | 17 +++++++++++++++++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/kitty/history.c b/kitty/history.c index 5538b1ffba..2e4f14bc6e 100644 --- a/kitty/history.c +++ b/kitty/history.c @@ -268,6 +268,7 @@ pagerhist_push(HistoryBuf *self, ANSIBuf *as_ansi_buf) { Line l = {.xnum=self->xnum, .text_cache=self->text_cache}; init_line(self, self->start_of_data, &l); ANSILineState s = {.output_buf=as_ansi_buf}; + as_ansi_buf->len = 0; line_as_ansi(&l, &s, 0, l.xnum, 0, true); pagerhist_write_bytes(ph, (const uint8_t*)"\x1b[m", 3); if (pagerhist_write_ucs4(ph, as_ansi_buf->buf, as_ansi_buf->len)) { @@ -351,6 +352,7 @@ as_ansi(HistoryBuf *self, PyObject *callback) { ANSIBuf output = {0}; ANSILineState s = {.output_buf=&output}; for(unsigned int i = 0; i < self->count; i++) { init_line(self, i, &l); + output.len = 0; line_as_ansi(&l, &s, 0, l.xnum, 0, true); if (!l.cpu_cells[l.xnum - 1].next_char_was_wrapped) { ensure_space_for(&output, buf, Py_UCS4, output.len + 1, capacity, 2048, false); diff --git a/kitty/line-buf.c b/kitty/line-buf.c index 2c1fb746fa..ba60ae6ccb 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -470,6 +470,7 @@ as_ansi(LineBuf *self, PyObject *callback) { ANSIBuf output = {0}; ANSILineState s = {.output_buf=&output}; do { init_line(self, &l, self->line_map[ylimit]); + output.len = 0; line_as_ansi(&l, &s, 0, l.xnum, 0, true); if (output.len) break; ylimit--; @@ -477,6 +478,7 @@ as_ansi(LineBuf *self, PyObject *callback) { for(index_type i = 0; i <= ylimit; i++) { bool output_newline = !linebuf_line_ends_with_continuation(self, i); + output.len = 0; init_line(self, &l, self->line_map[i]); line_as_ansi(&l, &s, 0, l.xnum, 0, true); if (output_newline) { diff --git a/kitty/line.c b/kitty/line.c index bee4514ead..938bd6caa9 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -364,11 +364,17 @@ cell_as_utf8_for_fallback(const ListOfChars *lc, char *buf) { bool unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells, bool skip_multiline_non_zero_lines, ANSIBuf *buf) { + static const size_t initial_cap = 4096; ListOfChars lc; + if (!buf->buf) { + buf->buf = malloc(initial_cap * sizeof(buf->buf[0])); + if (!buf->buf) return false; + buf->capacity = initial_cap; + } for (index_type i = start; i < limit; i++) { lc.chars = buf->buf + buf->len; lc.capacity = buf->capacity - buf->len; while (!text_in_cell_without_alloc(self->cpu_cells + i, self->text_cache, &lc)) { - size_t ns = MAX(4096u, 2 * buf->capacity); + size_t ns = MAX(initial_cap, 2 * buf->capacity); char_type *np = realloc(buf->buf, ns); if (!np) return false; buf->capacity = ns; buf->buf = np; @@ -485,7 +491,6 @@ write_mark_to_ansi_buf(ANSILineState *s, const char *m) { bool line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char, bool skip_multiline_non_zero_lines) { - s->output_buf->len = 0; s->limit = MIN(stop_before, xlimit_for_line(self)); s->current_multicell_state = NULL; s->escape_code_written = false; @@ -554,11 +559,9 @@ set_wrapped_flag(Line* self, PyObject *is_wrapped) { static PyObject* __repr__(Line* self) { RAII_ANSIBuf(buf); - PyObject *s = line_as_unicode(self, false, &buf); - if (s == NULL) return NULL; - PyObject *ans = PyObject_Repr(s); - Py_CLEAR(s); - return ans; + RAII_PyObject(s, line_as_unicode(self, false, &buf)); + if (s != NULL) return PyObject_Repr(s); + return NULL; } static PyObject* @@ -972,6 +975,7 @@ as_text_generic(PyObject *args, void *container, get_line_func get_line, index_t Line *line = get_line(container, y); if (!line) { if (PyErr_Occurred()) return NULL; break; } if (need_newline) APPEND(nl); + ansibuf->len = 0; if (as_ansi) { // less has a bug where it resets colors when it sees a \r, so work // around it by resetting SGR at the start of every line. This is diff --git a/kitty/line.h b/kitty/line.h index f67fa7f60e..f1c587c98a 100644 --- a/kitty/line.h +++ b/kitty/line.h @@ -9,7 +9,6 @@ #include "text-cache.h" -// TODO: Handle selection with multicell // TODO: URL detection with multicell typedef union CellAttrs { diff --git a/kitty_tests/multicell.py b/kitty_tests/multicell.py index 5824b0e4f8..2a216d32d6 100644 --- a/kitty_tests/multicell.py +++ b/kitty_tests/multicell.py @@ -630,18 +630,35 @@ def asa(*expected, strip_trailing_whitespace=False): ss(p(), p(x=1, in_left_half_of_cell=False)) asl((0, 0, 2)) ast('ab') + asa(f'a\x1b]{TEXT_SIZE_CODE};w=2;b\x07', '\x1b[m') ss(p(x=2), p(x=3, in_left_half_of_cell=False)) asl((0, 1, 3)) ast('bc') + asa(f'\x1b]{TEXT_SIZE_CODE};w=2;b\x07c', '\x1b[m') s.reset() s.draw('a'), multicell(s, 'b', scale=2), s.draw('c'), multicell(s, 'd', scale=2) ss(p(), p(x=4, in_left_half_of_cell=False)) asl((0, 0, 5), (1, 1, 2), (1, 4, 5)) ast('abcd') + asa(f'a\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07c\x1b]{TEXT_SIZE_CODE};w=1:s=2;d\x07', '\x1b[m') ss(p(y=1, x=1), p(y=1, x=1, in_left_half_of_cell=False)) asl((0, 1, 2), (1, 1, 2)) ast('b') + asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07', '\x1b[m') ss(p(y=1, x=0), p(y=1, x=1, in_left_half_of_cell=False)) # empty leading cell before multiline on y=1 asl((0, 1, 2), (1, 0, 2)) ast(' b') + asa(f' \x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07', '\x1b[m') + + s.reset() + multicell(s, 'X', scale=2), s.draw('123456abcd') + for x in (0, 1, 2): + ss(p(x=x), p(x=3, y=1, in_left_half_of_cell=False)) + asl((0, 0, 7), (1, 0, 3)) + ast('X123456', 'ab') + asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;X\x07123456', 'ab', '\x1b[m') + ss(p(y=1), p(y=1, x=3, in_left_half_of_cell=False)) + asl((0, 0, 1), (1, 0, 3)) + ast('Xab') + asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;X\x07ab', '\x1b[m')