From 1a0de0017f7b2061bad0b695a98963ca0f274e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 20 Nov 2021 13:42:07 +0100 Subject: [PATCH] grid: add grid_row_uri_range_erase() This function handles erasing of an URI range. That is, a range of the row is being either erased, or overwritten (from the URI perspective, these two are the same thing). We handle both partial overwrites (split up, or truncate URI), as well as complete overwrites (remove URI). --- grid.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++-- grid.h | 3 +- terminal.c | 74 +------------------------ 3 files changed, 155 insertions(+), 78 deletions(-) diff --git a/grid.c b/grid.c index 733d8ded..d98c4696 100644 --- a/grid.c +++ b/grid.c @@ -236,7 +236,7 @@ grid_resize_without_reflow( .id = it->item.id, .uri = xstrdup(it->item.uri), }; - grid_row_add_uri_range(new_row, range); + grid_row_uri_range_add(new_row, range); } } @@ -303,7 +303,7 @@ reflow_uri_range_start(struct row_uri_range *range, struct row *new_row, .uri = range->uri, }; range->uri = NULL; - grid_row_add_uri_range(new_row, new_range); + grid_row_uri_range_add(new_row, new_range); } static void @@ -366,7 +366,7 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row, .id = range->id, .uri = xstrdup(range->uri), }; - grid_row_add_uri_range(new_row, new_range); + grid_row_uri_range_add(new_row, new_range); } } @@ -845,14 +845,160 @@ ensure_row_has_extra_data(struct row *row) } void -grid_row_add_uri_range(struct row *row, struct row_uri_range range) +grid_row_uri_range_add(struct row *row, struct row_uri_range range) { ensure_row_has_extra_data(row); tll_rforeach(row->extra->uri_ranges, it) { if (it->item.end < range.start) { tll_insert_after(row->extra->uri_ranges, it, range); - return; + goto out; } } + tll_push_front(row->extra->uri_ranges, range); + +out: + ; +#if defined(_DEBUG) + tll_foreach(row->extra->uri_ranges, it1) { + tll_foreach(row->extra->uri_ranges, it2) { + if (&it1->item == &it2->item) + continue; + + xassert(it1->item.start != it2->item.start); + xassert(it1->item.start != it2->item.end); + xassert(it1->item.end != it2->item.start); + xassert(it1->item.end != it2->item.end); + } + } +#endif +} + +void +grid_row_uri_range_erase(struct row *row, int start, int end) +{ + if (likely(row->extra == NULL)) + return; + + /* Split up, or remove, URI ranges affected by the erase */ + tll_foreach(row->extra->uri_ranges, it) { + if (it->item.start > end) { + /* This range, and all subsequent ranges, start *after* + * the erase range */ + break; + } + + if (it->item.start < start && it->item.end >= start) { + /* + * URI crosses the erase *start* point. + * + * Create a new range for the URI part *before* the erased + * cells. + * + * Also modify this URI range’s start point so that we can + * remove it below. + */ + struct row_uri_range range_before = { + .start = it->item.start, + .end = start - 1, + .id = it->item.id, + .uri = it->item.uri != NULL ? xstrdup(it->item.uri) : NULL, + }; + tll_insert_before(row->extra->uri_ranges, it, range_before); + it->item.start = start; + } + + if (it->item.start <= end && it->item.end > end) { + /* + * URI crosses the erase *end* point. + * + * Create a new range for the URI part *after* the erased + * cells. + * + * Also modify the URI range’s end point so that we can + * remove it below. + */ + struct row_uri_range range_after = { + .start = end + 1, + .end = it->item.end, + .id = it->item.id, + .uri = it->item.uri != NULL ? xstrdup(it->item.uri) : NULL, + }; + tll_insert_before(row->extra->uri_ranges, it, range_after); + it->item.end = end; + } + + if (it->item.start >= start && it->item.end <= end) { + /* URI range completey covered by the erase - remove it */ + free(it->item.uri); + tll_remove(row->extra->uri_ranges, it); + } + } +} + +UNITTEST +{ + struct row_data row_data = {.uri_ranges = tll_init()}; + struct row row = {.extra = &row_data}; + +#define row_has_no_overlapping_uris(row) \ + do { \ + tll_foreach((row)->extra->uri_ranges, it1) { \ + tll_foreach((row)->extra->uri_ranges, it2) { \ + if (&it1->item == &it2->item) \ + continue; \ + xassert(it1->item.start != it2->item.start); \ + xassert(it1->item.start != it2->item.end); \ + xassert(it1->item.end != it2->item.start); \ + xassert(it1->item.end != it2->item.end); \ + } \ + } \ + } while (0) + + grid_row_uri_range_add(&row, (struct row_uri_range){1, 10}); + xassert(tll_length(row_data.uri_ranges) == 1); + xassert(tll_front(row_data.uri_ranges).start == 1); + xassert(tll_front(row_data.uri_ranges).end == 10); + row_has_no_overlapping_uris(&row); + + grid_row_uri_range_add(&row, (struct row_uri_range){11, 20}); + xassert(tll_length(row_data.uri_ranges) == 2); + xassert(tll_back(row_data.uri_ranges).start == 11); + xassert(tll_back(row_data.uri_ranges).end == 20); + row_has_no_overlapping_uris(&row); + + /* Erase both URis */ + grid_row_uri_range_erase(&row, 1, 20); + xassert(tll_length(row_data.uri_ranges) == 0); + row_has_no_overlapping_uris(&row); + + /* Two URIs, then erase second half of the first, first half of + the second */ + grid_row_uri_range_add(&row, (struct row_uri_range){1, 10}); + grid_row_uri_range_add(&row, (struct row_uri_range){11, 20}); + grid_row_uri_range_erase(&row, 5, 15); + xassert(tll_length(row_data.uri_ranges) == 2); + xassert(tll_front(row_data.uri_ranges).start == 1); + xassert(tll_front(row_data.uri_ranges).end == 4); + xassert(tll_back(row_data.uri_ranges).start == 16); + xassert(tll_back(row_data.uri_ranges).end == 20); + row_has_no_overlapping_uris(&row); + + tll_pop_back(row_data.uri_ranges); + tll_pop_back(row_data.uri_ranges); + xassert(tll_length(row_data.uri_ranges) == 0); + + /* One URI, erase middle part of it */ + grid_row_uri_range_add(&row, (struct row_uri_range){1, 10}); + grid_row_uri_range_erase(&row, 5, 6); + xassert(tll_length(row_data.uri_ranges) == 2); + xassert(tll_front(row_data.uri_ranges).start == 1); + xassert(tll_front(row_data.uri_ranges).end == 4); + xassert(tll_back(row_data.uri_ranges).start == 7); + xassert(tll_back(row_data.uri_ranges).end == 10); + row_has_no_overlapping_uris(&row); + +#undef row_has_no_overlapping_uris + + tll_free(row_data.uri_ranges); } diff --git a/grid.h b/grid.h index 3537ddb5..e2cd3a63 100644 --- a/grid.h +++ b/grid.h @@ -74,7 +74,8 @@ grid_row_in_view(struct grid *grid, int row_no) return row; } -void grid_row_add_uri_range(struct row *row, struct row_uri_range range); +void grid_row_uri_range_add(struct row *row, struct row_uri_range range); +void grid_row_uri_range_erase(struct row *row, int start, int end); static inline void grid_row_uri_range_destroy(struct row_uri_range *range) diff --git a/terminal.c b/terminal.c index bf13dd46..3100e3a4 100644 --- a/terminal.c +++ b/terminal.c @@ -1781,63 +1781,7 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end) } else memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0])); - if (likely(row->extra == NULL)) - return; - - /* Split up, or remove, URI ranges affected by the erase */ - tll_foreach(row->extra->uri_ranges, it) { - if (it->item.start > end) { - /* This range, and all subsequent ranges, start *after* - * the erase range */ - break; - } - - if (it->item.start < start && it->item.end >= start) { - /* - * URI crosses the erase *start* point. - * - * Create a new range for the URI part *before* the erased - * cells. - * - * Also modify this URI range’s start point so that we can - * remove it below. - */ - struct row_uri_range range_before = { - .start = it->item.start, - .end = start - 1, - .id = it->item.id, - .uri = xstrdup(it->item.uri), - }; - tll_insert_before(row->extra->uri_ranges, it, range_before); - it->item.start = start; - } - - if (it->item.start <= end && it->item.end > end) { - /* - * URI crosses the erase *end* point. - * - * Create a new range for the URI part *after* the erased - * cells. - * - * Also modify the URI range’s end point so that we can - * remove it below. - */ - struct row_uri_range range_after = { - .start = end + 1, - .end = it->item.end, - .id = it->item.id, - .uri = xstrdup(it->item.uri), - }; - tll_insert_before(row->extra->uri_ranges, it, range_after); - it->item.end = end; - } - - if (it->item.start >= start && it->item.end <= end) { - /* URI range completey covered by the erase - remove it */ - free(it->item.uri); - tll_remove(row->extra->uri_ranges, it); - } - } + grid_row_uri_range_erase(row, start, end); } static inline void @@ -3590,21 +3534,7 @@ term_osc8_close(struct terminal *term) .id = term->vt.osc8.id, .uri = xstrdup(term->vt.osc8.uri), }; - grid_row_add_uri_range(row, range); - -#if defined(_DEBUG) - tll_foreach(row->extra->uri_ranges, it1) { - tll_foreach(row->extra->uri_ranges, it2) { - if (&it1->item == &it2->item) - continue; - - xassert(it1->item.start != it2->item.start); - xassert(it1->item.start != it2->item.end); - xassert(it1->item.end != it2->item.start); - xassert(it1->item.end != it2->item.end); - } - } -#endif + grid_row_uri_range_add(row, range); start_col = 0; if (r == end.row)