diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-07 22:57:34 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-07 22:57:34 -0500 |
commit | aca791a675c608c7a19a6bd9098255e95faec94d (patch) | |
tree | 869493f4361dcedaf70751c34571597298a056bf /find.c | |
parent | b0506f2a667d0c1f4bddf7429068a4ee2042c039 (diff) |
highlight search results
Diffstat (limited to 'find.c')
-rw-r--r-- | find.c | 153 |
1 files changed, 102 insertions, 51 deletions
@@ -1,7 +1,9 @@ static void find_open(Ted *ted) { - ted->prev_active_buffer = ted->active_buffer; - ted->active_buffer = &ted->find_buffer; - ted->find = true; + if (ted->active_buffer) { + ted->prev_active_buffer = ted->active_buffer; + ted->active_buffer = &ted->find_buffer; + ted->find = true; + } } static void find_close(Ted *ted) { @@ -19,6 +21,8 @@ static float find_menu_height(Ted *ted) { return char_height_bold + char_height + 2 * padding; } +#define FIND_MAX_GROUPS 50 + static void find_menu_frame(Ted *ted) { Font *font = ted->font, *font_bold = ted->font_bold; float const char_height = text_font_char_height(font), @@ -30,75 +34,122 @@ static void find_menu_frame(Ted *ted) { float const window_width = ted->window_width, window_height = ted->window_height; u32 const *colors = settings->colors; + bool invalid_search_term = false; + TextBuffer *buffer = ted->prev_active_buffer; + assert(buffer); + + String32 term = buffer_get_line(&ted->find_buffer, 0); + if (term.len) { + pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL); + if (match_data) { + PCRE2_SIZE *groups = pcre2_get_ovector_pointer(match_data); + // compile search term + int error = 0; PCRE2_SIZE error_pos = 0; + pcre2_code *code = pcre2_compile(term.str, term.len, PCRE2_LITERAL, &error, &error_pos, NULL); + + // @TODO: scroll to first match + if (code) { + for (u32 line_idx = 0, nlines = buffer->nlines; line_idx < nlines; ++line_idx) { + Line *line = &buffer->lines[line_idx]; + char32_t *str = line->str; + u32 len = line->len; + u32 start_index = 0; + while (start_index < len) { + int ret = pcre2_match(code, str, len, start_index, 0, match_data, NULL); + if (ret > 0) { + u32 match_start = (u32)groups[0]; + u32 match_end = (u32)groups[1]; + BufferPos p1 = {.line = line_idx, .index = match_start}; + BufferPos p2 = {.line = line_idx, .index = match_end}; + v2 pos1 = buffer_pos_to_pixels(buffer, p1); + v2 pos2 = buffer_pos_to_pixels(buffer, p2); + pos2.y += char_height; + gl_geometry_rect(rect4(pos1.x, pos1.y, pos2.x, pos2.y), colors[COLOR_FIND_HL]); + start_index = match_end; + } else break; + } + } + pcre2_code_free(code); + } else { + invalid_search_term = true; + } + pcre2_match_data_free(match_data); + } + } + float x1 = padding, y1 = window_height - menu_height, x2 = window_width - padding, y2 = window_height - padding; Rect menu_bounds = rect4(x1, y1, x2, y2); gl_geometry_rect_border(menu_bounds, 1, colors[COLOR_BORDER]); - gl_geometry_draw(); text_utf8(font_bold, "Find...", x1 + padding, y1, colors[COLOR_TEXT]); text_render(font_bold); y1 += char_height_bold; - buffer_render(&ted->find_buffer, rect4(x1 + padding, y1, x2 - padding, y1 + char_height)); + Rect find_buffer_bounds = rect4(x1 + padding, y1, x2 - padding, y1 + char_height); + buffer_render(&ted->find_buffer, find_buffer_bounds); + + if (invalid_search_term) { + gl_geometry_rect(find_buffer_bounds, colors[COLOR_ERROR_BG] & 0xFFFFFF7F); + } + + gl_geometry_draw(); } -#define FIND_MAX_GROUPS 100 // go to next find result static void find_next(Ted *ted) { TextBuffer *buffer = ted->prev_active_buffer; - if (buffer) { - // create match data - pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL); - if (match_data) { - String32 term = buffer_get_line(&ted->find_buffer, 0); - int error = 0; - size_t error_pos = 0; - // compile the search term - pcre2_code *code = pcre2_compile(term.str, term.len, PCRE2_LITERAL, &error, &error_pos, NULL); - if (code) { - // do the searching - BufferPos pos = buffer->cursor_pos; - size_t nsearches = 0; - u32 nlines = buffer->nlines; - - // we need to search the starting line twice, because we might start at a non-zero index - while (nsearches < nlines + 1) { - Line *line = &buffer->lines[pos.line]; - char32_t *str = line->str; - size_t len = line->len; - int ret = pcre2_match(code, str, len, pos.index, 0, match_data, NULL); - if (ret > 0) { - PCRE2_SIZE *groups = pcre2_get_ovector_pointer(match_data); - u32 match_start = (u32)groups[0]; - u32 match_end = (u32)groups[1]; - BufferPos pos_start = {.line = pos.line, .index = match_start}; - BufferPos pos_end = {.line = pos.line, .index = match_end}; - buffer_cursor_move_to_pos(buffer, pos_start); - buffer_select_to_pos(buffer, pos_end); - break; - } + // create match data + pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL); + if (match_data) { + String32 term = buffer_get_line(&ted->find_buffer, 0); + int error = 0; + PCRE2_SIZE error_pos = 0; + // compile the search term + pcre2_code *code = pcre2_compile(term.str, term.len, PCRE2_LITERAL, &error, &error_pos, NULL); + if (code) { + // do the searching + BufferPos pos = buffer->cursor_pos; + size_t nsearches = 0; + u32 nlines = buffer->nlines; - ++nsearches; - pos.index = 0; - pos.line += 1; - pos.line %= nlines; - } - } else { - char32_t buf[256] = {0}; - size_t len = (size_t)pcre2_get_error_message(error, buf, sizeof buf - 1); - char *error_cstr = str32_to_utf8_cstr(str32(buf, len)); - if (error_cstr) { - ted_seterr(ted, "Invalid search term: (at position %zu) %s.", (size_t)error_pos, error_cstr); - free(error_cstr); + // we need to search the starting line twice, because we might start at a non-zero index + while (nsearches < nlines + 1) { + Line *line = &buffer->lines[pos.line]; + char32_t *str = line->str; + size_t len = line->len; + int ret = pcre2_match(code, str, len, pos.index, 0, match_data, NULL); + if (ret > 0) { + PCRE2_SIZE *groups = pcre2_get_ovector_pointer(match_data); + u32 match_start = (u32)groups[0]; + u32 match_end = (u32)groups[1]; + BufferPos pos_start = {.line = pos.line, .index = match_start}; + BufferPos pos_end = {.line = pos.line, .index = match_end}; + buffer_cursor_move_to_pos(buffer, pos_start); + buffer_select_to_pos(buffer, pos_end); + break; } + + ++nsearches; + pos.index = 0; + pos.line += 1; + pos.line %= nlines; } - pcre2_match_data_free(match_data); + pcre2_code_free(code); } else { - ted_seterr(ted, "Out of memory."); + char32_t buf[256] = {0}; + size_t len = (size_t)pcre2_get_error_message(error, buf, sizeof buf - 1); + char *error_cstr = str32_to_utf8_cstr(str32(buf, len)); + if (error_cstr) { + ted_seterr(ted, "Invalid search term (position %zu): %s.", (size_t)error_pos, error_cstr); + free(error_cstr); + } } + pcre2_match_data_free(match_data); + } else { + ted_seterr(ted, "Out of memory."); } } |