search/render: initial support for highlighting all visible matches

Before this patch, only the currently “selected” match was
highlighted (by having the “selected” attribute, and by *not* dimming
it, like the rest of the grid during a scrollback search).

With this patch, we now highlight matches within the viewport. While
searching, only the “primary” match is searched-for, and tracked.

Then, when rendering a frame, we find all “secondary” matches as
well. “holes” are added to the search-mode overlay by the means of an
search-match iterator.

The iterator’s text matching logic is *very* similar to what we do
when the search criteria has been updated, and we re-search the
scrollback. It should be possible to refactor this, and share code.
This commit is contained in:
Daniel Eklöf 2022-04-09 17:57:29 +02:00
parent 78fcdc5787
commit 90c91d6148
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 117 additions and 11 deletions

View file

@ -409,6 +409,90 @@ search_find_next(struct terminal *term)
#undef ROW_DEC
}
struct search_match_iterator
search_matches_new_iter(struct terminal *term)
{
return (struct search_match_iterator){
.term = term,
.start = {0, 0},
};
}
struct range
search_matches_next(struct search_match_iterator *iter)
{
xassert(iter->start.row >= 0);
xassert(iter->start.col >= 0);
struct terminal *term = iter->term;
//xassert(term->is_searching);
if (term->search.match_len == 0)
goto done;
int start_col = iter->start.col;
for (int r = iter->start.row; r < term->rows; r++) {
const struct row *row = grid_row_in_view(term->grid, r);
for (int c = start_col; c < term->cols; c++) {
if (matches_cell(term, &row->cells[c], 0) < 0)
continue;
struct range match = {
.start = {c, r},
.end = {-1, -1},
};
size_t match_len = 0;
for (size_t i = 0; i < term->search.len;) {
if (c >= term->cols) {
if (++r >= term->rows)
break;
row = grid_row_in_view(term->grid, r);
c = 0;
}
if (row->cells[c].wc >= CELL_SPACER) {
c++;
continue;
}
ssize_t additional_chars = matches_cell(term, &row->cells[c], i);
if (additional_chars < 0)
break;
i += additional_chars;
match_len += additional_chars;
c++;
}
if (match_len != term->search.len) {
/* Didn't match (completely) */
continue;
}
match.end = (struct coord){c - 1, r};
LOG_DBG("match at %dx%d-%dx%d",
match.start.row, match.start.col,
match.end.row, match.end.col);
iter->start.row = r;
iter->start.col = c;
return match;
}
start_col = 0;
}
done:
iter->start.row = -1;
iter->start.col = -1;
return (struct range){{-1, -1}, {-1, -1}};
}
static void
add_wchars(struct terminal *term, char32_t *src, size_t count)
{