summaryrefslogtreecommitdiff
path: root/src/main/search-replace.c
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2023-07-12 16:20:50 +0200
committerAlbert Cervin <albert@acervin.com>2023-10-19 22:41:33 +0200
commit54c9b4b533210b77be998f458ff96bdc54272f64 (patch)
treeeb434343bb1083172af50b7372d1e2745af00f8f /src/main/search-replace.c
parent3a8ae83aa13636679c151027cace905fa87ebd8e (diff)
downloaddged-54c9b4b533210b77be998f458ff96bdc54272f64.tar.gz
dged-54c9b4b533210b77be998f458ff96bdc54272f64.tar.xz
dged-54c9b4b533210b77be998f458ff96bdc54272f64.zip
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.
Diffstat (limited to 'src/main/search-replace.c')
-rw-r--r--src/main/search-replace.c105
1 files changed, 51 insertions, 54 deletions
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},
};