diff --git a/render.c b/render.c index 8093b747..5a05e354 100644 --- a/render.c +++ b/render.c @@ -35,6 +35,7 @@ #include "hsl.h" #include "ime.h" #include "quirks.h" +#include "search.h" #include "selection.h" #include "shm.h" #include "sixel.h" @@ -1539,17 +1540,30 @@ render_overlay(struct terminal *term) pixman_region32_clear(see_through); - struct grid *grid = term->grid; - for (int r = 0; r < term->rows; r++) { - struct row *row = grid_row_in_view(grid, r); - int y = term->margins.top + r * term->cell_height; - for (int c = 0; c < term->cols; c++) { - if (row->cells[c].attrs.selected) { - int x = term->margins.left + c * term->cell_width; - pixman_region32_union_rect( - see_through, see_through, - x, y, term->cell_width, term->cell_height); - } + struct search_match_iterator iter = search_matches_new_iter(term); + + for (struct range match = search_matches_next(&iter); + match.start.row >= 0; + match = search_matches_next(&iter)) + { + int r = match.start.row; + int start_col = match.start.col; + const int end_row = match.end.row; + + while (true) { + const int end_col = + r == end_row ? match.end.col : term->cols - 1; + + int x = term->margins.left + start_col * term->cell_width; + int y = term->margins.top + r * term->cell_height; + int width = (end_col + 1 - start_col) * term->cell_width; + int height = 1 * term->cell_height; + + pixman_region32_union_rect( + see_through, see_through, x, y, width, height); + + if (++r > end_row) + break; } } diff --git a/search.c b/search.c index 69dbcccd..52849502 100644 --- a/search.c +++ b/search.c @@ -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) { diff --git a/search.h b/search.h index 18af0d62..24828512 100644 --- a/search.h +++ b/search.h @@ -14,3 +14,11 @@ void search_input( void search_add_chars(struct terminal *term, const char *text, size_t len); void search_selection_cancelled(struct terminal *term); + +struct search_match_iterator { + struct terminal *term; + struct coord start; +}; + +struct search_match_iterator search_matches_new_iter(struct terminal *term); +struct range search_matches_next(struct search_match_iterator *iter);