From aa862462008e647cc4e87fd4618fe5dc5af1076d Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Mon, 8 Feb 2021 13:47:53 -0500 Subject: scroll to find match --- buffer.c | 22 +++++++++++++--------- find.c | 34 ++++++++++++++++++++++++---------- ted.h | 1 + 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/buffer.c b/buffer.c index b00f122..33ae6be 100644 --- a/buffer.c +++ b/buffer.c @@ -786,27 +786,26 @@ static bool buffer_clip_rect(TextBuffer *buffer, Rect *r) { } -// if the cursor is offscreen, this will scroll to make it onscreen. -static void buffer_scroll_to_cursor(TextBuffer *buffer) { +void buffer_scroll_to_pos(TextBuffer *buffer, BufferPos pos) { Settings const *settings = buffer_settings(buffer); - double cursor_line = buffer->cursor_pos.line; - double cursor_col = buffer_index_to_column(buffer, (u32)cursor_line, buffer->cursor_pos.index); + double line = pos.line; + double col = buffer_index_to_column(buffer, pos.line, pos.index); double display_lines = buffer_display_lines(buffer); double display_cols = buffer_display_cols(buffer); double scroll_x = buffer->scroll_x, scroll_y = buffer->scroll_y; double scrolloff = settings->scrolloff; - // scroll left if cursor is off screen in that direction - double max_scroll_x = cursor_col - scrolloff; + // scroll left if pos is off screen in that direction + double max_scroll_x = col - scrolloff; scroll_x = mind(scroll_x, max_scroll_x); // scroll right - double min_scroll_x = cursor_col - display_cols + scrolloff; + double min_scroll_x = col - display_cols + scrolloff; scroll_x = maxd(scroll_x, min_scroll_x); // scroll up - double max_scroll_y = cursor_line - scrolloff; + double max_scroll_y = line - scrolloff; scroll_y = mind(scroll_y, max_scroll_y); // scroll down - double min_scroll_y = cursor_line - display_lines + scrolloff; + double min_scroll_y = line - display_lines + scrolloff; scroll_y = maxd(scroll_y, min_scroll_y); buffer->scroll_x = scroll_x; @@ -814,6 +813,11 @@ static void buffer_scroll_to_cursor(TextBuffer *buffer) { buffer_correct_scroll(buffer); // it's possible that min/max_scroll_x/y go too far } +// if the cursor is offscreen, this will scroll to make it onscreen. +void buffer_scroll_to_cursor(TextBuffer *buffer) { + buffer_scroll_to_pos(buffer, buffer->cursor_pos); +} + // scroll so that the cursor is in the center of the screen void buffer_center_cursor(TextBuffer *buffer) { double cursor_line = buffer->cursor_pos.line; diff --git a/find.c b/find.c index 0d7b2c4..ee7793f 100644 --- a/find.c +++ b/find.c @@ -35,13 +35,10 @@ static void find_menu_frame(Ted *ted) { float const menu_height = find_menu_height(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, *find_buffer = &ted->find_buffer; assert(buffer); - - String32 term = buffer_get_line(find_buffer, 0); if (term.len) { pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL); @@ -53,6 +50,9 @@ static void find_menu_frame(Ted *ted) { if (code) { if (find_buffer->modified) { // if search term has been changed, // recompute match count + BufferPos best_scroll_candidate = {U32_MAX, U32_MAX}; // pos we will scroll to (scroll to first match) + BufferPos cursor_pos = buffer->cursor_pos; + u32 match_count = 0; for (u32 line_idx = 0, end = buffer->nlines; line_idx < end; ++line_idx) { Line *line = &buffer->lines[line_idx]; @@ -62,6 +62,13 @@ static void find_menu_frame(Ted *ted) { while (start_index < len) { int ret = pcre2_match(code, str, len, start_index, 0, match_data, NULL); if (ret > 0) { + // a match! + + BufferPos match_start_pos = {.line = line_idx, .index = (u32)groups[0]}; + if (best_scroll_candidate.line == U32_MAX + || (buffer_pos_cmp(best_scroll_candidate, cursor_pos) < 0 && buffer_pos_cmp(match_start_pos, cursor_pos) >= 0)) + best_scroll_candidate = match_start_pos; + u32 match_end = (u32)groups[1]; ++match_count; start_index = match_end; @@ -70,6 +77,8 @@ static void find_menu_frame(Ted *ted) { } ted->find_match_count = match_count; find_buffer->modified = false; + if (best_scroll_candidate.line != U32_MAX) + buffer_scroll_to_pos(buffer, best_scroll_candidate); } // highlight matches @@ -95,13 +104,16 @@ static void find_menu_frame(Ted *ted) { } } pcre2_code_free(code); + ted->find_invalid_pattern = false; } else { - invalid_search_term = true; + ted->find_invalid_pattern = true; } pcre2_match_data_free(match_data); } - } else { + } else if (find_buffer->modified) { ted->find_match_count = 0; + ted->find_invalid_pattern = false; + buffer_scroll_to_cursor(buffer); } @@ -126,14 +138,16 @@ static void find_menu_frame(Ted *ted) { y1 += char_height_bold; - if (invalid_search_term) { - gl_geometry_rect(find_buffer_bounds, colors[COLOR_ERROR_BG] & 0xFFFFFF7F); - } - gl_geometry_draw(); text_render(font_bold); buffer_render(&ted->find_buffer, find_buffer_bounds); + + if (ted->find_invalid_pattern) + gl_geometry_rect(find_buffer_bounds, colors[COLOR_NO] & 0xFFFFFF3F); // invalid regex + else if (term.len && ted->find_match_count == 0) + gl_geometry_rect(find_buffer_bounds, colors[COLOR_CANCEL] & 0xFFFFFF3F); // no matches + gl_geometry_draw(); } diff --git a/ted.h b/ted.h index 3694858..83c5071 100644 --- a/ted.h +++ b/ted.h @@ -220,6 +220,7 @@ typedef struct Ted { bool quit; // if set to true, the window will close next frame. NOTE: this doesn't check for unsaved changes!! bool find; // is the find menu open? u32 find_match_count; // how many matches of the search term were there? + bool find_invalid_pattern; // invalid regex? Command warn_unsaved; // if non-zero, the user is trying to execute this command, but there are unsaved changes char warn_unsaved_names[TED_PATH_MAX]; // comma-separated list of files with unsaved changes (only applicable if warn_unsaved != 0) char warn_overwrite[TED_PATH_MAX]; // file name user is trying to overwrite -- cgit v1.2.3