diff options
Diffstat (limited to 'src/main/search-replace.c')
| -rw-r--r-- | src/main/search-replace.c | 209 |
1 files changed, 117 insertions, 92 deletions
diff --git a/src/main/search-replace.c b/src/main/search-replace.c index 50beb1e..32c514c 100644 --- a/src/main/search-replace.c +++ b/src/main/search-replace.c @@ -45,6 +45,55 @@ static struct search { buffer_keymap_id keymap_id; } g_current_search = {0}; +static void highlight_match(struct buffer *buffer, struct region match, + bool current) { + if (current) { + buffer_add_text_property( + buffer, match.begin, match.end, + (struct text_property){.type = TextProperty_Colors, + .data.colors = (struct text_property_colors){ + .set_bg = true, + .bg = 3, + .set_fg = true, + .fg = 0, + }}); + + } else { + buffer_add_text_property( + buffer, match.begin, match.end, + (struct text_property){.type = TextProperty_Colors, + .data.colors = (struct text_property_colors){ + .set_bg = true, + .bg = 6, + .set_fg = true, + .fg = 0, + }}); + } +} + +static void search_highlight_hook(struct buffer *buffer, void *userdata) { + (void)userdata; + + for (uint32_t matchi = 0; matchi < g_current_search.nmatches; ++matchi) { + highlight_match(buffer, g_current_search.matches[matchi], + matchi == g_current_search.current_match); + } +} + +static void replace_highlight_hook(struct buffer *buffer, void *userdata) { + (void)userdata; + + for (uint32_t matchi = 0; matchi < g_current_replace.nmatches; ++matchi) { + struct match *m = &g_current_replace.matches[matchi]; + if (m->state != Todo) { + continue; + } + + highlight_match(buffer, m->region, + matchi == g_current_replace.current_match); + } +} + static void clear_replace(void) { buffer_remove_keymap(g_current_replace.keymap_id); free(g_current_replace.matches); @@ -89,6 +138,36 @@ void abort_search(void) { minibuffer_abort_prompt(); } +static void start_search(struct buffer *buffer, const char *pattern) { + if (buffer != g_current_search.buffer) { + clear_search(); + } + + g_current_search.buffer = buffer; + g_current_search.active = true; + + // if we are in a new buffer, add the update hook for it. + if (g_current_search.highlight_hook == (uint32_t)-1) { + g_current_search.highlight_hook = + buffer_add_update_hook(buffer, search_highlight_hook, NULL); + } + + // replace the pattern if needed + if (g_current_search.pattern == NULL || + !s8eq(s8(g_current_search.pattern), s8(pattern))) { + char *new_pattern = strdup(pattern); + free(g_current_search.pattern); + g_current_search.pattern = new_pattern; + } + + // clear out any old search results + if (g_current_search.matches != NULL) { + free(g_current_search.matches); + g_current_search.matches = NULL; + g_current_search.nmatches = 0; + } +} + uint64_t matchdist(struct region *match, struct location loc) { struct location begin = match->begin; @@ -98,64 +177,21 @@ uint64_t matchdist(struct region *match, struct location loc) { // into the line it is, otherwise check the distance from location int64_t coldist = begin.col; if (linedist == 0) { - int64_t coldist = (int64_t)begin.col - (int64_t)loc.col; + coldist = (int64_t)begin.col - (int64_t)loc.col; } // arbitrary row scaling, best effort to avoid counting line length + // this is not technically correct if you have lines longer than + // 1e6 but otoh, that seems excessive return (linedist * linedist) * 1e6 + coldist * coldist; } -static void highlight_match(struct buffer *buffer, struct region match, - bool current) { - if (current) { - buffer_add_text_property( - buffer, match.begin, match.end, - (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ - .set_bg = true, - .bg = 3, - .set_fg = true, - .fg = 0, - }}); - - } else { - buffer_add_text_property( - buffer, match.begin, match.end, - (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ - .set_bg = true, - .bg = 6, - .set_fg = true, - .fg = 0, - }}); - } -} - -static void search_highlight_hook(struct buffer *buffer, void *userdata) { - (void)userdata; - - for (uint32_t matchi = 0; matchi < g_current_search.nmatches; ++matchi) { - highlight_match(buffer, g_current_search.matches[matchi], - matchi == g_current_search.current_match); - } -} - -static void replace_highlight_hook(struct buffer *buffer, void *userdata) { - (void)userdata; - - for (uint32_t matchi = 0; matchi < g_current_replace.nmatches; ++matchi) { - struct match *m = &g_current_replace.matches[matchi]; - if (m->state != Todo) { - continue; - } - - highlight_match(buffer, m->region, - matchi == g_current_replace.current_match); - } -} - static int32_t replace_next(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(state->window); struct buffer *buffer = buffer_view->buffer; @@ -207,6 +243,10 @@ static int32_t replace_next(struct command_ctx ctx, int argc, } static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(state->window); @@ -230,8 +270,8 @@ static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -COMMAND_FN("replace-next", replace_next, replace_next, NULL); -COMMAND_FN("skip-next", skip_next, skip_next, NULL); +COMMAND_FN("replace-next", replace_next, replace_next, NULL) +COMMAND_FN("skip-next", skip_next, skip_next, NULL) static int cmp_matches(const void *m1, const void *m2) { struct region *match1 = (struct region *)m1; @@ -350,35 +390,9 @@ static struct region *find_closest(struct region *matches, uint32_t nmatches, return closest; } -static void do_search(struct buffer_view *view, const char *pattern, +static bool do_search(struct buffer_view *view, const char *pattern, bool reverse) { - if (view->buffer != g_current_search.buffer) { - clear_search(); - } - - g_current_search.buffer = view->buffer; - g_current_search.active = true; - - // if we are in a new buffer, add the update hook for it. - if (g_current_search.highlight_hook == (uint32_t)-1) { - g_current_search.highlight_hook = - buffer_add_update_hook(view->buffer, search_highlight_hook, NULL); - } - - // replace the pattern if needed - if (g_current_search.pattern == NULL || - !s8eq(s8(g_current_search.pattern), s8(pattern))) { - char *new_pattern = strdup(pattern); - free(g_current_search.pattern); - g_current_search.pattern = new_pattern; - } - - // clear out any old search results first - if (g_current_search.matches != NULL) { - free(g_current_search.matches); - g_current_search.matches = NULL; - g_current_search.nmatches = 0; - } + start_search(view->buffer, pattern); buffer_find(view->buffer, g_current_search.pattern, &g_current_search.matches, &g_current_search.nmatches); @@ -391,10 +405,10 @@ static void do_search(struct buffer_view *view, const char *pattern, view->dot, reverse, &closest_idx); buffer_view_goto(view, closest->begin); g_current_search.current_match = closest_idx; - } else { - abort_search(); - minibuffer_echo_timeout(4, "%s not found", pattern); + return true; } + + return false; } static const char *get_pattern() { @@ -424,12 +438,18 @@ int32_t search_interactive(struct command_ctx ctx, int argc, } minibuffer_set_prompt(search_prompt(*(bool *)ctx.userdata)); + buffer_view_goto_end(window_buffer_view(minibuffer_window())); if (pattern != NULL) { - do_search(window_buffer_view(minibuffer_target_window()), pattern, - *(bool *)ctx.userdata); + if (!do_search(window_buffer_view(minibuffer_target_window()), pattern, + *(bool *)ctx.userdata)) { + abort_search(); + minibuffer_echo_timeout(4, "%s not found", pattern); + } + free((char *)pattern); } + return 0; } @@ -437,11 +457,13 @@ static bool search_dir_backward = true; static bool search_dir_forward = false; COMMAND_FN("search-forward", search_forward, search_interactive, - &search_dir_forward); + &search_dir_forward) COMMAND_FN("search-backward", search_backward, search_interactive, - &search_dir_backward); + &search_dir_backward) int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argv; + bool reverse = *(bool *)ctx.userdata; if (argc == 0) { struct binding bindings[] = { @@ -454,17 +476,21 @@ int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { return minibuffer_prompt(ctx, search_prompt(reverse)); } + // allow enter to end the interactive search if (g_current_search.active) { abort_search(); return 0; } buffer_remove_keymap(g_current_search.keymap_id); - do_search(window_buffer_view(ctx.active_window), argv[0], reverse); + bool found = + do_search(window_buffer_view(ctx.active_window), argv[0], reverse); - if (g_current_search.active) { - abort_search(); + abort_search(); + if (!found) { + minibuffer_echo_timeout(4, "%s not found", argv[0]); } + return 0; } @@ -481,11 +507,10 @@ void register_search_replace_commands(struct commands *commands) { } void cleanup_search_replace(void) { + clear_replace(); clear_search(); if (g_current_search.pattern != NULL) { free(g_current_search.pattern); g_current_search.pattern = NULL; } - - clear_replace(); } |
