summaryrefslogtreecommitdiff
path: root/src/snapshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/snapshot.c')
-rw-r--r--src/snapshot.c59
1 files changed, 47 insertions, 12 deletions
diff --git a/src/snapshot.c b/src/snapshot.c
index 29ed98c..6578c9a 100644
--- a/src/snapshot.c
+++ b/src/snapshot.c
@@ -73,6 +73,20 @@ static bool reserve(struct term_snapshot *s, int cols, int rows)
return true;
}
+/* The public contract makes every failed update an empty, retryable snapshot. */
+static void invalidate(struct term_snapshot *s)
+{
+ s->view = (struct term_view){ .palette = s->palette };
+ s->source = 0;
+ s->arena_len = 0;
+ s->arena_dead = 0;
+ if (s->row_cap > 0) {
+ memset(s->keys, 0, (size_t)s->row_cap * sizeof(*s->keys));
+ memset(s->row_clusters, 0, (size_t)s->row_cap * sizeof(*s->row_clusters));
+ memset(s->selection, 0, (size_t)s->row_cap * sizeof(*s->selection));
+ }
+}
+
/* Attribute contributions of the low and high byte of cell flags. */
static uint16_t lo_attrs[256], hi_attrs[256];
static uint8_t hi_underline[256];
@@ -100,7 +114,8 @@ void term_snapshot_tables_init(void)
}
}
-static uint32_t arena_add(struct term_snapshot *s, const struct gstore *g, uint32_t handle)
+static uint32_t arena_add(struct term_snapshot *s, const struct gstore *g, uint32_t handle,
+ bool *ok)
{
uint32_t cps[GRAPHEME_MAX_LEN];
int n = term_gstore_expand(g, handle, cps, GRAPHEME_MAX_LEN);
@@ -110,8 +125,10 @@ static uint32_t arena_add(struct term_snapshot *s, const struct gstore *g, uint3
uint32_t cap = term_grow_cap32(s->arena_cap ? s->arena_cap * 2 : 256,
s->arena_len + (uint32_t)n + 1);
uint32_t *a = realloc(s->arena, cap * sizeof(*a));
- if (!a)
- return cps[0];
+ if (!a) {
+ *ok = false;
+ return 0;
+ }
s->arena = a;
s->arena_cap = cap;
}
@@ -125,7 +142,7 @@ static uint32_t arena_add(struct term_snapshot *s, const struct gstore *g, uint3
/* Convert one stored row; returns the number of arena words it added. */
static uint32_t convert_row(struct term_snapshot *s, const struct gstore *g,
struct term_cell *dst,
- const struct cell *src, int cols)
+ const struct cell *src, int cols, bool *ok)
{
uint32_t before = s->arena_len;
for (int x = 0; x < cols; x++) {
@@ -138,8 +155,11 @@ static uint32_t convert_row(struct term_snapshot *s, const struct gstore *g,
uint32_t text = c->c;
if (TERM_EXPECT(text < 0x20, 0))
text = text ? ' ' : 0;
- else if (TERM_EXPECT(grapheme_is_handle(text), 0))
- text = arena_add(s, g, text);
+ else if (TERM_EXPECT(grapheme_is_handle(text), 0)) {
+ text = arena_add(s, g, text, ok);
+ if (!*ok)
+ return 0;
+ }
dst[x] = (struct term_cell){
.text = text,
.fg = c->fg,
@@ -158,8 +178,7 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
return false;
int cols = t->cols, rows = t->rows;
if (!reserve(s, cols, rows)) {
- s->view.size = (struct term_vector2i){ 0 };
- s->source = 0;
+ invalidate(s);
return false;
}
@@ -175,13 +194,17 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
bool changed = all;
term_hist_prepare_rows(&t->hist, cols);
- if (!term_hist_view_sync(&t->view, &t->hist, cols))
+ if (!term_hist_view_sync(&t->view, &t->hist, cols)) {
+ invalidate(s);
return false;
+ }
term_hist_view_refine(&t->view, &t->hist, cols, rows);
uint64_t stack_keys[256];
uint64_t *new_keys = rows <= 256 ? stack_keys : malloc((size_t)rows * sizeof(uint64_t));
- if (!new_keys)
+ if (!new_keys) {
+ invalidate(s);
return false;
+ }
for (int y = 0; y < rows; y++)
new_keys[y] = term_screen_view_row_key(t, y);
@@ -230,6 +253,8 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
if (scrolled > 0) {
int k = scrolled;
+ for (int y = 0; y < k; y++)
+ s->arena_dead += s->row_clusters[y];
memmove(s->cells, s->cells + (size_t)k * cols,
(size_t)(rows - k) * cols * sizeof(struct term_cell));
memmove(s->row_clusters, s->row_clusters + k,
@@ -247,7 +272,15 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
if (!all)
s->arena_dead += s->row_clusters[y];
const struct cell *src = term_screen_view_row(t, y);
- s->row_clusters[y] = convert_row(s, t->gstore, s->cells + (size_t)y * cols, src, cols);
+ bool converted = true;
+ s->row_clusters[y] = convert_row(s, t->gstore, s->cells + (size_t)y * cols,
+ src, cols, &converted);
+ if (!converted) {
+ if (new_keys != stack_keys)
+ free(new_keys);
+ invalidate(s);
+ return false;
+ }
s->keys[y] = key;
changed = true;
}
@@ -256,8 +289,10 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
int stack[2][256];
int *c0 = rows <= 256 ? stack[0] : malloc((size_t)rows * 2 * sizeof(int));
- if (!c0)
+ if (!c0) {
+ invalidate(s);
return false;
+ }
int *c1 = rows <= 256 ? stack[1] : c0 + rows;
term_selection_view_spans(t, c0, c1);
for (int y = 0; y < rows; y++) {