From b8da20444e42d36656d9aa2835508c17cb373dc1 Mon Sep 17 00:00:00 2001 From: Sinity Date: Sun, 12 Jul 2026 15:27:24 +0200 Subject: [PATCH] Run TextCache GC before drawing text Move the periodic collection check to PREPARE_FOR_DRAW_TEXT so ordinary and fixed-width text share one safe integration point, while tab handling no longer initiates collection. Reset the additions counter only after the live-cell remap completes successfully. Co-Authored-By: Claude --- kitty/screen.c | 6 ++---- kitty/text-cache.c | 4 ++-- kitty/text-cache.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/kitty/screen.c b/kitty/screen.c index a673a227a..cf5fff944 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -941,12 +941,11 @@ screen_garbage_collect_text_cache(Screen *self) { self->text_cache, gc, self->overlay_line.cpu_cells, self->overlay_line.xnum); if (self->overlay_line.original_line.cpu_cells) text_cache_gc_process_cells( self->text_cache, gc, self->overlay_line.original_line.cpu_cells, self->overlay_line.xnum); - tc_gc_end(gc); + tc_gc_end(self->text_cache, gc); } static bool add_combining_char(Screen *self, char_type ch, index_type x, index_type y) { - if (tc_should_gc(self->text_cache)) screen_garbage_collect_text_cache(self); CPUCell *cpu_cells = linebuf_cpu_cells_for_line(self->linebuf, y); CPUCell *cell = cpu_cells + x; if (!cell_has_text(cell) || (cell->is_multicell && cell->y)) return false; // don't allow adding combining chars to a null cell @@ -1252,6 +1251,7 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_ } #define PREPARE_FOR_DRAW_TEXT \ + if (tc_should_gc(self->text_cache)) screen_garbage_collect_text_cache(self); \ const bool force_underline = OPT(underline_hyperlinks) == UNDERLINE_ALWAYS && self->active_hyperlink_id != 0; \ CellAttrs attrs = cursor_to_attrs(self->cursor); \ if (force_underline) attrs.decoration = OPT(url_style); \ @@ -1322,7 +1322,6 @@ handle_fixed_width_multicell_command(Screen *self, CPUCell mcd, ListOfChars *lc) lc->count = MIN(lc->count, MAX_NUM_CODEPOINTS_PER_CELL); PREPARE_FOR_DRAW_TEXT; mcd.hyperlink_id = s.cc.hyperlink_id; - if (tc_should_gc(self->text_cache)) screen_garbage_collect_text_cache(self); cell_set_chars(&mcd, self->text_cache, lc); move_cursor_past_multicell(self, width); if (height > 1) { @@ -2072,7 +2071,6 @@ screen_tab(Screen *self) { cell_set_char(c, ' '); } self->lc->count = 2; self->lc->chars[0] = '\t'; self->lc->chars[1] = diff; - if (tc_should_gc(self->text_cache)) screen_garbage_collect_text_cache(self); cell_set_chars(cpu_cell, self->text_cache, self->lc); } } diff --git a/kitty/text-cache.c b/kitty/text-cache.c index a450f1a40..6203928cd 100644 --- a/kitty/text-cache.c +++ b/kitty/text-cache.c @@ -185,7 +185,6 @@ tc_gc_begin(TextCache *self) { self->array.items = fresh; self->array.capacity = 256; self->array.count = 0; zero_at_ptr(&self->arena); vt_cleanup(&self->map); vt_init(&self->map); - self->adds_since_last_gc = 0; return gc; } @@ -203,7 +202,8 @@ tc_gc_map_index(TextCache *self, TextCacheGCData *gc, char_type old_idx, char_ty } void -tc_gc_end(TextCacheGCData *gc) { +tc_gc_end(TextCache *self, TextCacheGCData *gc) { + self->adds_since_last_gc = 0; free(gc->map); free(gc->old_items); Chars_free_all(&gc->old_arena); free(gc); diff --git a/kitty/text-cache.h b/kitty/text-cache.h index 7a33e8edf..742c2b1f1 100644 --- a/kitty/text-cache.h +++ b/kitty/text-cache.h @@ -62,7 +62,7 @@ bool tc_should_gc(const TextCache *self); typedef struct TextCacheGCData TextCacheGCData; TextCacheGCData* tc_gc_begin(TextCache *self); bool tc_gc_map_index(TextCache *self, TextCacheGCData *gc, char_type old_idx, char_type *new_idx); -void tc_gc_end(TextCacheGCData *gc); +void tc_gc_end(TextCache *self, TextCacheGCData *gc); char_type tc_first_char_at_index(const TextCache *self, char_type idx); char_type tc_last_char_at_index(const TextCache *self, char_type idx); bool tc_chars_at_index_without_alloc(const TextCache *self, char_type idx, ListOfChars *ans);