From 54c9b4b533210b77be998f458ff96bdc54272f64 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Wed, 12 Jul 2023 16:20:50 +0200 Subject: big buffer/buffer_view rework A buffer is only the text and the corresponding operation. A buffer view holds information about scroll, dot and mark positions. One way to think about it is that a buffer is stateless whereas a buffer view is stateful. --- src/main/cmds.c | 241 ++++++++++++++++++++++------------------------ src/main/main.c | 26 ++--- src/main/search-replace.c | 105 ++++++++++---------- 3 files changed, 178 insertions(+), 194 deletions(-) (limited to 'src/main') diff --git a/src/main/cmds.c b/src/main/cmds.c index ecce343..26e2628 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -9,6 +9,7 @@ #include "dged/binding.h" #include "dged/buffer.h" +#include "dged/buffer_view.h" #include "dged/buffers.h" #include "dged/command.h" #include "dged/display.h" @@ -25,7 +26,7 @@ int32_t _abort(struct command_ctx ctx, int argc, const char *argv[]) { abort_replace(); abort_completion(); minibuffer_abort_prompt(); - buffer_clear_mark(window_buffer_view(ctx.active_window)); + buffer_view_clear_mark(window_buffer_view(ctx.active_window)); reset_minibuffer_keys(minibuffer_buffer()); minibuffer_echo_timeout(4, "💣 aborted"); return 0; @@ -52,11 +53,7 @@ uint32_t g_ncompletions = 0; struct completion g_completions[50] = {0}; static void abort_completion() { - if (!minibuffer_focused()) { - reset_buffer_keys(window_buffer(windows_get_active())); - } else { - reset_minibuffer_keys(minibuffer_buffer()); - } + reset_minibuffer_keys(minibuffer_buffer()); windows_close_popup(); for (uint32_t compi = 0; compi < g_ncompletions; ++compi) { @@ -83,6 +80,8 @@ static void complete_path(const char *path, struct completion results[], size_t len = strlen(p1); char *p2 = strdup(p1); + size_t inlen = strlen(path); + if (len == 0) { goto done; } @@ -94,7 +93,9 @@ static void complete_path(const char *path, struct completion results[], const char *dir = p1; const char *file = ""; - if (dir[len - 1] != '/') { + // check the input path here since + // to_abspath removes trailing slashes + if (path[inlen - 1] != '/') { dir = dirname(p1); file = basename(p2); } @@ -143,20 +144,13 @@ done: *nresults = n; } -void render_completion_line(struct text_chunk *line_data, uint32_t line, - struct command_list *commands, void *userdata) { - command_list_set_show_whitespace(commands, false); - command_list_draw_repeated(commands, 0, line, ' ', 1); -} - -struct update_hook_result -update_completion_buffer(struct buffer_view *view, - struct command_list *commands, uint32_t width, - uint32_t height, uint64_t frame_time, void *userdata) { - struct text_chunk line = buffer_get_line(view->buffer, view->dot.line); +void update_completion_buffer(struct buffer *buffer, uint32_t width, + uint32_t height, void *userdata) { + struct buffer_view *view = (struct buffer_view *)userdata; + struct text_chunk line = buffer_line(buffer, view->dot.line); buffer_add_text_property( - view->buffer, (struct buffer_location){.line = view->dot.line, .col = 0}, - (struct buffer_location){.line = view->dot.line, .col = line.nchars}, + view->buffer, (struct location){.line = view->dot.line, .col = 0}, + (struct location){.line = view->dot.line, .col = line.nchars}, (struct text_property){.type = TextProperty_Colors, .colors = (struct text_property_colors){ .set_bg = false, @@ -168,17 +162,6 @@ update_completion_buffer(struct buffer_view *view, if (line.allocated) { free(line.text); } - - struct update_hook_result res = {0}; - res.margins.left = 1; - res.margins.right = 1; - res.line_render_hook = (struct line_render_hook){ - .callback = render_completion_line, - .empty_callback = NULL, - .userdata = NULL, - }; - - return res; } static int32_t goto_completion(struct command_ctx ctx, int argc, @@ -193,7 +176,7 @@ static int32_t goto_completion(struct command_ctx ctx, int argc, movement_fn(v); if (v->dot.line >= text_num_lines(b->text)) { - buffer_backward_line(v); + buffer_view_backward_line(v); } } @@ -211,15 +194,13 @@ static int32_t insert_completion(struct command_ctx ctx, int argc, char *ins = (char *)g_completions[cv->dot.line].insert; bool complete = g_completions[cv->dot.line].complete; size_t inslen = strlen(ins); - if (minibuffer_focused()) { - buffer_add_text(window_buffer_view(minibuffer_window()), ins, inslen); - } else { - buffer_add_text(window_buffer_view(windows_get_active()), ins, inslen); - } + buffer_view_add(window_buffer_view(windows_get_active()), ins, inslen); - if (complete) { + if (minibuffer_focused() && complete) { minibuffer_execute(); } + + abort_completion(); } } @@ -227,9 +208,9 @@ static int32_t insert_completion(struct command_ctx ctx, int argc, } COMMAND_FN("next-completion", next_completion, goto_completion, - buffer_forward_line); + buffer_view_forward_line); COMMAND_FN("prev-completion", prev_completion, goto_completion, - buffer_backward_line); + buffer_view_backward_line); COMMAND_FN("insert-completion", insert_completion, insert_completion, NULL); static void on_find_file_input(void *userdata) { @@ -237,12 +218,14 @@ static void on_find_file_input(void *userdata) { struct text_chunk txt = minibuffer_content(); struct window *mb = minibuffer_window(); - struct buffer_location mb_dot = window_absolute_cursor_location(mb); + struct location mb_dot = window_buffer_view(mb)->dot; + struct window_position mbpos = window_position(mb); struct buffer *b = buffers_find(buffers, "*completions*"); if (b == NULL) { b = buffers_add(buffers, buffer_create("*completions*")); - buffer_add_update_hook(b, update_completion_buffer, NULL); + buffer_add_update_hook(b, update_completion_buffer, + (void *)window_buffer_view(popup_window())); window_set_buffer_e(popup_window(), b, false, false); } @@ -261,9 +244,10 @@ static void on_find_file_input(void *userdata) { complete_path(path, g_completions, 50, &g_ncompletions); size_t max_width = 0; - struct buffer_location prev_dot = v->dot; + struct location prev_dot = v->dot; - buffer_clear(v); + buffer_clear(v->buffer); + buffer_view_goto(v, (struct location){.line = 0, .col = 0}); if (g_ncompletions > 0) { for (uint32_t compi = 0; compi < g_ncompletions; ++compi) { const char *disp = g_completions[compi].display; @@ -271,17 +255,18 @@ static void on_find_file_input(void *userdata) { if (width > max_width) { max_width = width; } - buffer_add_text(v, (uint8_t *)disp, width); + buffer_view_add(v, (uint8_t *)disp, width); // the extra newline feels weird in navigation if (compi != g_ncompletions - 1) { - buffer_add_text(v, (uint8_t *)"\n", 1); + buffer_view_add(v, (uint8_t *)"\n", 1); } } - buffer_goto(v, prev_dot.line, prev_dot.col); + buffer_view_goto( + v, (struct location){.line = prev_dot.line, .col = prev_dot.col}); if (prev_dot.line >= text_num_lines(b->text)) { - buffer_backward_line(v); + buffer_view_backward_line(v); } if (!popup_window_visible()) { @@ -294,11 +279,12 @@ static void on_find_file_input(void *userdata) { sizeof(bindings) / sizeof(bindings[0])); } - uint32_t width = max_width > 2 ? max_width + 2 : 4, + uint32_t width = max_width > 2 ? max_width : 4, height = g_ncompletions > 10 ? 10 : g_ncompletions; - windows_show_popup(mb_dot.line - height, mb_dot.col, width, height); + windows_show_popup(mbpos.y + mb_dot.line - height, mbpos.x + mb_dot.col, + width, height); } else { - windows_close_popup(); + abort_completion(); } if (txt.allocated) { @@ -313,8 +299,6 @@ int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { "find file: "); } - abort_completion(); - pth = argv[0]; struct stat sb = {0}; if (stat(pth, &sb) < 0 && errno != ENOENT) { @@ -351,7 +335,8 @@ int32_t write_file(struct command_ctx ctx, int argc, const char *argv[]) { } pth = argv[0]; - buffer_write_to(window_buffer(ctx.active_window), pth); + buffer_set_filename(window_buffer(ctx.active_window), pth); + buffer_to_file(window_buffer(ctx.active_window)); return 0; } @@ -432,7 +417,7 @@ void buffer_to_list_line(struct buffer *buffer, void *userdata) { buffer->filename != NULL ? buffer->filename : ""); if (written > 0) { - buffer_add_text(listbuf, (uint8_t *)buf, written); + buffer_view_add(listbuf, (uint8_t *)buf, written); } } @@ -441,7 +426,7 @@ int32_t buflist_visit_cmd(struct command_ctx ctx, int argc, struct window *w = ctx.active_window; struct buffer_view *bv = window_buffer_view(w); - struct text_chunk text = buffer_get_line(bv->buffer, bv->dot.line); + struct text_chunk text = buffer_line(bv->buffer, bv->dot.line); char *end = (char *)memchr(text.text, ' ', text.nbytes); @@ -468,9 +453,9 @@ int32_t buflist_close_cmd(struct command_ctx ctx, int argc, void buflist_refresh(struct buffers *buffers, struct buffer_view *target) { buffer_set_readonly(target->buffer, false); - buffer_clear(target); + buffer_clear(target->buffer); buffers_for_each(buffers, buffer_to_list_line, target); - buffer_goto_beginning(target); + buffer_view_goto_beginning(target); buffer_set_readonly(target->buffer, true); } @@ -535,102 +520,102 @@ void register_global_commands(struct commands *commands, register_search_replace_commands(commands); } -#define BUFFER_WRAPCMD_POS(fn) \ +#define BUFFER_VIEW_WRAPCMD(fn) \ static int32_t fn##_cmd(struct command_ctx ctx, int argc, \ const char *argv[]) { \ - fn(window_buffer_view(ctx.active_window)); \ + buffer_view_##fn(window_buffer_view(ctx.active_window)); \ return 0; \ } #define BUFFER_WRAPCMD(fn) \ static int32_t fn##_cmd(struct command_ctx ctx, int argc, \ const char *argv[]) { \ - fn(window_buffer(ctx.active_window)); \ + buffer_##fn(window_buffer(ctx.active_window)); \ return 0; \ } -BUFFER_WRAPCMD_POS(buffer_kill_line); -BUFFER_WRAPCMD_POS(buffer_forward_delete_char); -BUFFER_WRAPCMD_POS(buffer_backward_delete_char); -BUFFER_WRAPCMD_POS(buffer_forward_delete_word); -BUFFER_WRAPCMD_POS(buffer_backward_delete_word); -BUFFER_WRAPCMD_POS(buffer_backward_char); -BUFFER_WRAPCMD_POS(buffer_backward_word); -BUFFER_WRAPCMD_POS(buffer_forward_char); -BUFFER_WRAPCMD_POS(buffer_forward_word); -BUFFER_WRAPCMD_POS(buffer_backward_line); -BUFFER_WRAPCMD_POS(buffer_forward_line); -BUFFER_WRAPCMD_POS(buffer_end_of_line); -BUFFER_WRAPCMD_POS(buffer_beginning_of_line); -BUFFER_WRAPCMD_POS(buffer_newline); -BUFFER_WRAPCMD_POS(buffer_indent); -BUFFER_WRAPCMD(buffer_to_file); -BUFFER_WRAPCMD(buffer_reload); -BUFFER_WRAPCMD_POS(buffer_set_mark); -BUFFER_WRAPCMD_POS(buffer_clear_mark); -BUFFER_WRAPCMD_POS(buffer_copy); -BUFFER_WRAPCMD_POS(buffer_cut); -BUFFER_WRAPCMD_POS(buffer_paste); -BUFFER_WRAPCMD_POS(buffer_paste_older); -BUFFER_WRAPCMD_POS(buffer_goto_beginning); -BUFFER_WRAPCMD_POS(buffer_goto_end); -BUFFER_WRAPCMD_POS(buffer_undo); - -static int32_t buffer_view_scroll_up_cmd(struct command_ctx ctx, int argc, - const char *argv[]) { - buffer_view_scroll_up(window_buffer_view(ctx.active_window), - window_height(ctx.active_window)); +BUFFER_WRAPCMD(to_file); +BUFFER_WRAPCMD(reload); +BUFFER_VIEW_WRAPCMD(kill_line); +BUFFER_VIEW_WRAPCMD(forward_delete_char); +BUFFER_VIEW_WRAPCMD(backward_delete_char); +BUFFER_VIEW_WRAPCMD(forward_delete_word); +BUFFER_VIEW_WRAPCMD(backward_delete_word); +BUFFER_VIEW_WRAPCMD(backward_char); +BUFFER_VIEW_WRAPCMD(backward_word); +BUFFER_VIEW_WRAPCMD(forward_char); +BUFFER_VIEW_WRAPCMD(forward_word); +BUFFER_VIEW_WRAPCMD(backward_line); +BUFFER_VIEW_WRAPCMD(forward_line); +BUFFER_VIEW_WRAPCMD(goto_end_of_line); +BUFFER_VIEW_WRAPCMD(goto_beginning_of_line); +BUFFER_VIEW_WRAPCMD(newline); +BUFFER_VIEW_WRAPCMD(indent); +BUFFER_VIEW_WRAPCMD(set_mark); +BUFFER_VIEW_WRAPCMD(clear_mark); +BUFFER_VIEW_WRAPCMD(copy); +BUFFER_VIEW_WRAPCMD(cut); +BUFFER_VIEW_WRAPCMD(paste); +BUFFER_VIEW_WRAPCMD(paste_older); +BUFFER_VIEW_WRAPCMD(goto_beginning); +BUFFER_VIEW_WRAPCMD(goto_end); +BUFFER_VIEW_WRAPCMD(undo); + +static int32_t scroll_up_cmd(struct command_ctx ctx, int argc, + const char *argv[]) { + buffer_view_backward_nlines(window_buffer_view(ctx.active_window), + window_height(ctx.active_window) - 1); return 0; }; -static int32_t buffer_view_scroll_down_cmd(struct command_ctx ctx, int argc, - const char *argv[]) { - buffer_view_scroll_down(window_buffer_view(ctx.active_window), - window_height(ctx.active_window)); +static int32_t scroll_down_cmd(struct command_ctx ctx, int argc, + const char *argv[]) { + buffer_view_forward_nlines(window_buffer_view(ctx.active_window), + window_height(ctx.active_window) - 1); return 0; }; -static int32_t buffer_goto_line(struct command_ctx ctx, int argc, - const char *argv[]) { +static int32_t goto_line(struct command_ctx ctx, int argc, const char *argv[]) { if (argc == 0) { return minibuffer_prompt(ctx, "line: "); } uint32_t line = atoi(argv[0]); - buffer_goto(window_buffer_view(ctx.active_window), line - 1, 0); + buffer_view_goto(window_buffer_view(ctx.active_window), + (struct location){.line = line, .col = 0}); } void register_buffer_commands(struct commands *commands) { static struct command buffer_commands[] = { - {.name = "kill-line", .fn = buffer_kill_line_cmd}, - {.name = "delete-word", .fn = buffer_forward_delete_word_cmd}, - {.name = "backward-delete-word", .fn = buffer_backward_delete_word_cmd}, - {.name = "delete-char", .fn = buffer_forward_delete_char_cmd}, - {.name = "backward-delete-char", .fn = buffer_backward_delete_char_cmd}, - {.name = "backward-char", .fn = buffer_backward_char_cmd}, - {.name = "backward-word", .fn = buffer_backward_word_cmd}, - {.name = "forward-char", .fn = buffer_forward_char_cmd}, - {.name = "forward-word", .fn = buffer_forward_word_cmd}, - {.name = "backward-line", .fn = buffer_backward_line_cmd}, - {.name = "forward-line", .fn = buffer_forward_line_cmd}, - {.name = "end-of-line", .fn = buffer_end_of_line_cmd}, - {.name = "beginning-of-line", .fn = buffer_beginning_of_line_cmd}, - {.name = "newline", .fn = buffer_newline_cmd}, - {.name = "indent", .fn = buffer_indent_cmd}, - {.name = "buffer-write-to-file", .fn = buffer_to_file_cmd}, - {.name = "set-mark", .fn = buffer_set_mark_cmd}, - {.name = "clear-mark", .fn = buffer_clear_mark_cmd}, - {.name = "copy", .fn = buffer_copy_cmd}, - {.name = "cut", .fn = buffer_cut_cmd}, - {.name = "paste", .fn = buffer_paste_cmd}, - {.name = "paste-older", .fn = buffer_paste_older_cmd}, - {.name = "goto-beginning", .fn = buffer_goto_beginning_cmd}, - {.name = "goto-end", .fn = buffer_goto_end_cmd}, - {.name = "undo", .fn = buffer_undo_cmd}, - {.name = "scroll-down", .fn = buffer_view_scroll_down_cmd}, - {.name = "scroll-up", .fn = buffer_view_scroll_up_cmd}, - {.name = "reload", .fn = buffer_reload_cmd}, - {.name = "goto-line", .fn = buffer_goto_line}, + {.name = "kill-line", .fn = kill_line_cmd}, + {.name = "delete-word", .fn = forward_delete_word_cmd}, + {.name = "backward-delete-word", .fn = backward_delete_word_cmd}, + {.name = "delete-char", .fn = forward_delete_char_cmd}, + {.name = "backward-delete-char", .fn = backward_delete_char_cmd}, + {.name = "backward-char", .fn = backward_char_cmd}, + {.name = "backward-word", .fn = backward_word_cmd}, + {.name = "forward-char", .fn = forward_char_cmd}, + {.name = "forward-word", .fn = forward_word_cmd}, + {.name = "backward-line", .fn = backward_line_cmd}, + {.name = "forward-line", .fn = forward_line_cmd}, + {.name = "end-of-line", .fn = goto_end_of_line_cmd}, + {.name = "beginning-of-line", .fn = goto_beginning_of_line_cmd}, + {.name = "newline", .fn = newline_cmd}, + {.name = "indent", .fn = indent_cmd}, + {.name = "buffer-write-to-file", .fn = to_file_cmd}, + {.name = "set-mark", .fn = set_mark_cmd}, + {.name = "clear-mark", .fn = clear_mark_cmd}, + {.name = "copy", .fn = copy_cmd}, + {.name = "cut", .fn = cut_cmd}, + {.name = "paste", .fn = paste_cmd}, + {.name = "paste-older", .fn = paste_older_cmd}, + {.name = "goto-beginning", .fn = goto_beginning_cmd}, + {.name = "goto-end", .fn = goto_end_cmd}, + {.name = "undo", .fn = undo_cmd}, + {.name = "scroll-down", .fn = scroll_down_cmd}, + {.name = "scroll-up", .fn = scroll_up_cmd}, + {.name = "reload", .fn = reload_cmd}, + {.name = "goto-line", .fn = goto_line}, }; register_commands(commands, buffer_commands, diff --git a/src/main/main.c b/src/main/main.c index b6ee3c0..fd69cff 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -11,6 +11,7 @@ #include "dged/allocator.h" #include "dged/binding.h" #include "dged/buffer.h" +#include "dged/buffer_view.h" #include "dged/buffers.h" #include "dged/display.h" #include "dged/lang.h" @@ -127,7 +128,7 @@ int main(int argc, char *argv[]) { {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}}; - char *filename = NULL; + const char *filename = NULL; uint32_t jumpline = 1; bool goto_end = false; char ch; @@ -239,9 +240,13 @@ int main(int argc, char *argv[]) { &minibuffer); struct window *active = windows_get_active(); if (goto_end) { - buffer_goto_end(window_buffer_view(active)); + buffer_view_goto_end(window_buffer_view(active)); } else { - buffer_goto(window_buffer_view(active), jumpline > 0 ? jumpline - 1 : 0, 0); + struct location to = { + .line = jumpline > 0 ? jumpline - 1 : 0, + .col = 0, + }; + buffer_view_goto(window_buffer_view(active), to); } DECLARE_TIMER(buffer); @@ -253,7 +258,6 @@ int main(int argc, char *argv[]) { static uint32_t nkeychars = 0; while (running) { - if (display_resized) { windows_resize(display_height(display), display_width(display)); display_resized = false; @@ -265,9 +269,6 @@ int main(int argc, char *argv[]) { TIMED_SCOPE_END(buffer); struct window *active_window = windows_get_active(); - if (minibuffer_focused()) { - active_window = minibuffer_window(); - } /* Update the screen by flushing command lists collected from updating the * buffers. @@ -275,14 +276,15 @@ int main(int argc, char *argv[]) { TIMED_SCOPE_BEGIN(display); display_begin_render(display); windows_render(display); - struct buffer_location cursor = - window_absolute_cursor_location(active_window); - display_move_cursor(display, cursor.line, cursor.col); + struct buffer_view *view = window_buffer_view(active_window); + struct location cursor = buffer_view_dot_to_relative(view); + struct window_position winpos = window_position(active_window); + display_move_cursor(display, winpos.y + cursor.line, winpos.x + cursor.col); display_end_render(display); TIMED_SCOPE_END(display); /* This blocks for events, so if nothing has happened we block here and let - * the CPU do something more useful than updating this narcissistic editor. + * the CPU do something more useful than updating this editor for no reason. * This is also the reason that there is no timed scope around this, it * simply makes no sense. */ @@ -343,7 +345,7 @@ int main(int argc, char *argv[]) { } } } else if (k->mod == 0) { - buffer_add_text(window_buffer_view(active_window), + buffer_view_add(window_buffer_view(active_window), &kbd_upd.raw[k->start], k->end - k->start); } else { char keyname[16]; diff --git a/src/main/search-replace.c b/src/main/search-replace.c index 828ce32..cd12d5d 100644 --- a/src/main/search-replace.c +++ b/src/main/search-replace.c @@ -4,6 +4,7 @@ #include "dged/binding.h" #include "dged/buffer.h" +#include "dged/buffer_view.h" #include "dged/command.h" #include "dged/minibuffer.h" #include "dged/window.h" @@ -13,7 +14,7 @@ static struct replace { char *replace; - struct match *matches; + struct region *matches; uint32_t nmatches; uint32_t current_match; } g_current_replace = {0}; @@ -28,8 +29,8 @@ void abort_replace() { minibuffer_abort_prompt(); } -uint64_t matchdist(struct match *match, struct buffer_location loc) { - struct buffer_location begin = match->begin; +uint64_t matchdist(struct region *match, struct location loc) { + struct location begin = match->begin; int64_t linedist = (int64_t)begin.line - (int64_t)loc.line; int64_t coldist = (int64_t)begin.col - (int64_t)loc.col; @@ -38,26 +39,10 @@ uint64_t matchdist(struct match *match, struct buffer_location loc) { return (linedist * linedist) * 1e6 + coldist * coldist; } -int buffer_loc_cmp(struct buffer_location loc1, struct buffer_location loc2) { - if (loc1.line < loc2.line) { - return -1; - } else if (loc1.line > loc2.line) { - return 1; - } else { - if (loc1.col < loc2.col) { - return -1; - } else if (loc1.col > loc2.col) { - return 1; - } else { - return 0; - } - } -} - -static void highlight_matches(struct buffer *buffer, struct match *matches, +static void highlight_matches(struct buffer *buffer, struct region *matches, uint32_t nmatches, uint32_t current) { for (uint32_t matchi = 0; matchi < nmatches; ++matchi) { - struct match *m = &matches[matchi]; + struct region *m = &matches[matchi]; if (matchi == current) { buffer_add_text_property( buffer, m->begin, m->end, @@ -88,10 +73,12 @@ static int32_t replace_next(struct command_ctx ctx, int argc, struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(windows_get_active()); - struct match *m = &state->matches[state->current_match]; - buffer_set_mark_at(buffer_view, m->begin.line, m->begin.col); - buffer_goto(buffer_view, m->end.line, m->end.col + 1); - buffer_add_text(buffer_view, state->replace, strlen(state->replace)); + struct region *m = &state->matches[state->current_match]; + buffer_view_set_mark_at(buffer_view, (struct location){.line = m->begin.line, + .col = m->begin.col}); + buffer_view_goto(buffer_view, (struct location){.line = m->end.line, + .col = m->end.col + 1}); + buffer_view_add(buffer_view, state->replace, strlen(state->replace)); ++state->current_match; @@ -99,7 +86,8 @@ static int32_t replace_next(struct command_ctx ctx, int argc, abort_replace(); } else { m = &state->matches[state->current_match]; - buffer_goto(buffer_view, m->begin.line, m->begin.col); + buffer_view_goto(buffer_view, (struct location){.line = m->begin.line, + .col = m->begin.col}); highlight_matches(buffer_view->buffer, state->matches, state->nmatches, state->current_match); } @@ -111,8 +99,9 @@ static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(windows_get_active()); - struct match *m = &state->matches[state->current_match]; - buffer_goto(buffer_view, m->end.line, m->end.col + 1); + struct region *m = &state->matches[state->current_match]; + buffer_view_goto(buffer_view, (struct location){.line = m->end.line, + .col = m->end.col + 1}); ++state->current_match; @@ -120,7 +109,8 @@ static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { abort_replace(); } else { m = &state->matches[state->current_match]; - buffer_goto(buffer_view, m->begin.line, m->begin.col); + buffer_view_goto(buffer_view, (struct location){.line = m->begin.line, + .col = m->begin.col}); highlight_matches(buffer_view->buffer, state->matches, state->nmatches, state->current_match); } @@ -132,14 +122,14 @@ 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 match *match1 = (struct match *)m1; - struct match *match2 = (struct match *)m2; - struct buffer_location dot = window_buffer_view(windows_get_active())->dot; + struct region *match1 = (struct region *)m1; + struct region *match2 = (struct region *)m2; + struct location dot = window_buffer_view(windows_get_active())->dot; uint64_t dist1 = matchdist(match1, dot); uint64_t dist2 = matchdist(match2, dot); - int loc1 = buffer_loc_cmp(match1->begin, dot); - int loc2 = buffer_loc_cmp(match2->begin, dot); + int loc1 = location_compare(match1->begin, dot); + int loc2 = location_compare(match2->begin, dot); int64_t score1 = dist1 * loc1; int64_t score2 = dist2 * loc2; @@ -166,7 +156,7 @@ static int32_t replace(struct command_ctx ctx, int argc, const char *argv[]) { } struct buffer_view *buffer_view = window_buffer_view(windows_get_active()); - struct match *matches = NULL; + struct region *matches = NULL; uint32_t nmatches = 0; buffer_find(buffer_view->buffer, argv[0], &matches, &nmatches); @@ -177,7 +167,7 @@ static int32_t replace(struct command_ctx ctx, int argc, const char *argv[]) { } // sort matches - qsort(matches, nmatches, sizeof(struct match), cmp_matches); + qsort(matches, nmatches, sizeof(struct region), cmp_matches); g_current_replace = (struct replace){ .replace = strdup(argv[1]), @@ -186,8 +176,9 @@ static int32_t replace(struct command_ctx ctx, int argc, const char *argv[]) { .current_match = 0, }; - struct match *m = &g_current_replace.matches[0]; - buffer_goto(buffer_view, m->begin.line, m->begin.col); + struct region *m = &g_current_replace.matches[0]; + buffer_view_goto(buffer_view, (struct location){.line = m->begin.line, + .col = m->begin.col}); highlight_matches(buffer_view->buffer, g_current_replace.matches, g_current_replace.nmatches, 0); @@ -203,6 +194,7 @@ static int32_t replace(struct command_ctx ctx, int argc, const char *argv[]) { } static char *g_last_search = NULL; +static bool g_last_search_interactive = false; const char *search_prompt(bool reverse) { const char *txt = "search (down): "; @@ -215,13 +207,13 @@ const char *search_prompt(bool reverse) { struct closest_match { bool found; - struct match closest; + struct region closest; }; static struct closest_match find_closest(struct buffer_view *view, const char *pattern, bool highlight, bool reverse) { - struct match *matches = NULL; + struct region *matches = NULL; uint32_t nmatches = 0; struct closest_match res = { .found = false, @@ -233,10 +225,10 @@ static struct closest_match find_closest(struct buffer_view *view, // find the "nearest" match if (nmatches > 0) { res.found = true; - struct match *closest = &matches[0]; + struct region *closest = &matches[0]; int64_t closest_dist = INT64_MAX; for (uint32_t matchi = 0; matchi < nmatches; ++matchi) { - struct match *m = &matches[matchi]; + struct region *m = &matches[matchi]; if (highlight) { buffer_add_text_property( @@ -249,7 +241,7 @@ static struct closest_match find_closest(struct buffer_view *view, .fg = 0, }}); } - int res = buffer_loc_cmp(m->begin, view->dot); + int res = location_compare(m->begin, view->dot); uint64_t dist = matchdist(m, view->dot); if (((res < 0 && reverse) || (res > 0 && !reverse)) && dist < closest_dist) { @@ -279,12 +271,13 @@ static struct closest_match find_closest(struct buffer_view *view, void do_search(struct buffer_view *view, const char *pattern, bool reverse) { g_last_search = strdup(pattern); - struct buffer_view *buffer_view = window_buffer_view(windows_get_active()); - struct closest_match m = find_closest(buffer_view, pattern, true, reverse); + struct closest_match m = find_closest(view, pattern, true, reverse); // find the "nearest" match if (m.found) { - buffer_goto(buffer_view, m.closest.begin.line, m.closest.begin.col); + buffer_view_goto(view, + (struct location){.line = m.closest.begin.line, + .col = m.closest.begin.col}); } else { minibuffer_echo_timeout(4, "%s not found", pattern); } @@ -292,13 +285,13 @@ void do_search(struct buffer_view *view, const char *pattern, bool reverse) { int32_t search_interactive(struct command_ctx ctx, int argc, const char *argv[]) { + g_last_search_interactive = true; const char *pattern = NULL; if (minibuffer_content().nbytes == 0) { // recall the last search, if any if (g_last_search != NULL) { struct buffer_view *view = window_buffer_view(minibuffer_window()); - buffer_clear(view); - buffer_add_text(view, (uint8_t *)g_last_search, strlen(g_last_search)); + buffer_set_text(view->buffer, (uint8_t *)g_last_search, strlen(g_last_search)); pattern = g_last_search; } } else { @@ -309,11 +302,10 @@ int32_t search_interactive(struct command_ctx ctx, int argc, pattern = p; } - minibuffer_set_prompt(search_prompt(*(bool *)ctx.userdata)); + minibuffer_set_prompt(search_prompt(*(bool*)ctx.userdata)); if (pattern != NULL) { - // ctx.active_window would be the minibuffer window - do_search(window_buffer_view(windows_get_active()), pattern, + do_search(window_buffer_view(minibuffer_target_window()), pattern, *(bool *)ctx.userdata); free((char *)pattern); } @@ -329,7 +321,7 @@ COMMAND_FN("search-backward", search_backward, search_interactive, &search_dir_backward); int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { - bool reverse = strcmp((char *)ctx.userdata, "backward") == 0; + bool reverse = *(bool *)ctx.userdata; if (argc == 0) { struct binding bindings[] = { ANONYMOUS_BINDING(Ctrl, 'S', &search_forward_command), @@ -341,6 +333,11 @@ int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { } reset_minibuffer_keys(minibuffer_buffer()); + if (g_last_search_interactive) { + g_last_search_interactive = false; + return 0; + } + struct text_chunk content = minibuffer_content(); char *pattern = malloc(content.nbytes + 1); strncpy(pattern, content.text, content.nbytes); @@ -354,8 +351,8 @@ int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { void register_search_replace_commands(struct commands *commands) { struct command search_replace_commands[] = { - {.name = "find-next", .fn = find, .userdata = "forward"}, - {.name = "find-prev", .fn = find, .userdata = "backward"}, + {.name = "find-next", .fn = find, .userdata = &search_dir_forward}, + {.name = "find-prev", .fn = find, .userdata = &search_dir_backward}, {.name = "replace", .fn = replace}, }; -- cgit v1.2.3