summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-07 19:49:53 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-07 19:49:53 -0500
commitb0506f2a667d0c1f4bddf7429068a4ee2042c039 (patch)
treed3d77d0b281f49e1707c722f092ff87ab96f9ec8
parente802f33329f5c9c2a0630693d42c737d4b75b409 (diff)
simple find menu
-rw-r--r--command.c14
-rw-r--r--find.c82
-rw-r--r--main.c6
-rw-r--r--menu.c1
-rw-r--r--ted.h1
5 files changed, 96 insertions, 8 deletions
diff --git a/command.c b/command.c
index 5c6ae29..0dd2b34 100644
--- a/command.c
+++ b/command.c
@@ -104,9 +104,15 @@ void command_execute(Ted *ted, Command c, i64 argument) {
if (!buffer) {
} else if (buffer->is_line_buffer) {
switch (ted->menu) {
+ case MENU_NONE:
+ if (ted->find) {
+ if (buffer == &ted->find_buffer) {
+ find_next(ted);
+ }
+ }
+ break;
case MENU_ASK_RELOAD:
case MENU_WARN_UNSAVED:
- case MENU_NONE:
break;
case MENU_OPEN:
case MENU_SAVE_AS: {
@@ -252,9 +258,7 @@ void command_execute(Ted *ted, Command c, i64 argument) {
break;
case CMD_FIND:
- ted->find = true;
- buffer_clear(&ted->find_buffer);
- ted->active_buffer = &ted->find_buffer;
+ find_open(ted);
break;
case CMD_ESCAPE:
@@ -263,6 +267,8 @@ void command_execute(Ted *ted, Command c, i64 argument) {
*ted->error_shown = '\0';
} else if (ted->menu) {
menu_escape(ted);
+ } else if (ted->find) {
+ find_close(ted);
} else if (buffer) {
buffer_disable_selection(buffer);
}
diff --git a/find.c b/find.c
index 85816ba..309923d 100644
--- a/find.c
+++ b/find.c
@@ -1,3 +1,14 @@
+static void find_open(Ted *ted) {
+ ted->prev_active_buffer = ted->active_buffer;
+ ted->active_buffer = &ted->find_buffer;
+ ted->find = true;
+}
+
+static void find_close(Ted *ted) {
+ ted->find = false;
+ ted->active_buffer = ted->prev_active_buffer;
+}
+
static float find_menu_height(Ted *ted) {
Font *font = ted->font, *font_bold = ted->font_bold;
float char_height = text_font_char_height(font),
@@ -5,7 +16,7 @@ static float find_menu_height(Ted *ted) {
Settings const *settings = &ted->settings;
float padding = settings->padding;
- return char_height_bold + char_height + 4 * padding;
+ return char_height_bold + char_height + 2 * padding;
}
static void find_menu_frame(Ted *ted) {
@@ -19,10 +30,75 @@ static void find_menu_frame(Ted *ted) {
float const window_width = ted->window_width, window_height = ted->window_height;
u32 const *colors = settings->colors;
- Rect menu_bounds = rect(V2(padding, window_height - menu_height), V2(window_width - 2*padding, menu_height - padding));
+ 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();
- (void)char_height; (void)char_height_bold;
+
+ 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));
+}
+
+#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;
+ }
+
+ ++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);
+ }
+ }
+ pcre2_match_data_free(match_data);
+ } else {
+ ted_seterr(ted, "Out of memory.");
+ }
+ }
}
diff --git a/main.c b/main.c
index e6deb96..0090071 100644
--- a/main.c
+++ b/main.c
@@ -46,12 +46,12 @@ no_warn_end
#include "syntax.c"
#include "buffer.c"
#include "ted.c"
+#include "find.c"
#include "ui.c"
#include "node.c"
#include "menu.c"
#include "command.c"
#include "config.c"
-#include "find.c"
#if PROFILE
#define PROFILE_TIME(var) double var = time_get_seconds();
@@ -305,6 +305,8 @@ int main(int argc, char **argv) {
if (buffer_haserr(lbuffer))
die("Error creating line buffer: %s", buffer_geterr(lbuffer));
}
+ line_buffer_create(&ted->find_buffer, ted);
+ line_buffer_create(&ted->replace_buffer, ted);
{
@@ -693,6 +695,8 @@ int main(int argc, char **argv) {
if (ted->nodes_used[i])
node_free(&ted->nodes[i]);
buffer_free(&ted->line_buffer);
+ buffer_free(&ted->find_buffer);
+ buffer_free(&ted->replace_buffer);
text_font_free(ted->font);
text_font_free(ted->font_bold);
settings_free(&ted->settings);
diff --git a/menu.c b/menu.c
index 60bdd7a..c4502e0 100644
--- a/menu.c
+++ b/menu.c
@@ -1,4 +1,5 @@
static void menu_open(Ted *ted, Menu menu) {
+ if (ted->find) find_close(ted);
ted->menu = menu;
ted->prev_active_buffer = ted->active_buffer;
ted->active_buffer = NULL;
diff --git a/ted.h b/ted.h
index f1570e5..9b2c18b 100644
--- a/ted.h
+++ b/ted.h
@@ -212,6 +212,7 @@ typedef struct Ted {
FileSelector file_selector;
TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus
TextBuffer find_buffer; // use for "find" term in find/find+replace
+ TextBuffer replace_buffer; // "replace" for find+replace
double error_time; // time error box was opened (in seconds -- see time_get_seconds)
KeyAction key_actions[KEY_COMBO_COUNT];
bool search_cwd; // should the working directory be searched for files? set to true if the executable isn't "installed"