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 <noreply@anthropic.com>
This commit is contained in:
Sinity 2026-07-12 15:27:24 +02:00
parent b2d5a36283
commit b8da20444e
No known key found for this signature in database
3 changed files with 5 additions and 7 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);