summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-08 11:33:43 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-08 11:33:43 -0500
commitabec84f7b2ee0f75c4622a6d4469dbf0c7eaf5ad (patch)
tree9cc6ccef1b897db7127f88a4de55c2f9b85c9535
parentf7828a0718b730ffdc6b9f25e5d11cbfd666acf1 (diff)
find show number of matches
-rw-r--r--buffer.c11
-rw-r--r--find.c64
-rw-r--r--math.c2
-rw-r--r--ted.h2
4 files changed, 66 insertions, 13 deletions
diff --git a/buffer.c b/buffer.c
index 2b23fe7..b00f122 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1937,6 +1937,15 @@ void buffer_check_valid(TextBuffer *buffer) {
}
#endif
+u32 buffer_first_rendered_line(TextBuffer *buffer) {
+ return (u32)buffer->scroll_y;
+}
+
+u32 buffer_last_rendered_line(TextBuffer *buffer) {
+ u32 line = buffer_first_rendered_line(buffer) + (u32)buffer_display_lines(buffer) + 1;
+ return clamp_u32(line, 0, buffer->nlines);
+}
+
// Render the text buffer in the given rectangle
void buffer_render(TextBuffer *buffer, Rect r) {
float x1, y1, x2, y2;
@@ -1956,7 +1965,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
float const padding = settings->padding;
float const border_thickness = settings->border_thickness;
- u32 start_line = (u32)buffer->scroll_y; // line to start rendering from
+ u32 start_line = buffer_first_rendered_line(buffer); // line to start rendering from
Rect bounding_box = rect4(x1, y1, x2, y2);
float render_start_y = y1 - (float)(buffer->scroll_y - start_line) * char_height; // where the 1st line is rendered
diff --git a/find.c b/find.c
index 5bddd0e..0d7b2c4 100644
--- a/find.c
+++ b/find.c
@@ -3,6 +3,8 @@ static void find_open(Ted *ted) {
ted->prev_active_buffer = ted->active_buffer;
ted->active_buffer = &ted->find_buffer;
ted->find = true;
+ ted->find_match_count = 0;
+ buffer_clear(&ted->find_buffer);
}
}
@@ -35,10 +37,12 @@ static void find_menu_frame(Ted *ted) {
u32 const *colors = settings->colors;
bool invalid_search_term = false;
- TextBuffer *buffer = ted->prev_active_buffer;
+ TextBuffer *buffer = ted->prev_active_buffer, *find_buffer = &ted->find_buffer;
assert(buffer);
+
+
- String32 term = buffer_get_line(&ted->find_buffer, 0);
+ String32 term = buffer_get_line(find_buffer, 0);
if (term.len) {
pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL);
if (match_data) {
@@ -46,10 +50,31 @@ static void find_menu_frame(Ted *ted) {
// compile search term
int error = 0; PCRE2_SIZE error_pos = 0;
pcre2_code *code = pcre2_compile(term.str, term.len, PCRE2_LITERAL, &error, &error_pos, NULL);
-
- // @TODO: scroll to first match
if (code) {
- for (u32 line_idx = 0, nlines = buffer->nlines; line_idx < nlines; ++line_idx) {
+ if (find_buffer->modified) { // if search term has been changed,
+ // recompute match count
+ u32 match_count = 0;
+ for (u32 line_idx = 0, end = buffer->nlines; line_idx < end; ++line_idx) {
+ Line *line = &buffer->lines[line_idx];
+ char32_t *str = line->str;
+ u32 len = line->len;
+ u32 start_index = 0;
+ while (start_index < len) {
+ int ret = pcre2_match(code, str, len, start_index, 0, match_data, NULL);
+ if (ret > 0) {
+ u32 match_end = (u32)groups[1];
+ ++match_count;
+ start_index = match_end;
+ } else break;
+ }
+ }
+ ted->find_match_count = match_count;
+ find_buffer->modified = false;
+ }
+
+ // highlight matches
+ for (u32 line_idx = buffer_first_rendered_line(buffer), end = buffer_last_rendered_line(buffer);
+ line_idx < end; ++line_idx) {
Line *line = &buffer->lines[line_idx];
char32_t *str = line->str;
u32 len = line->len;
@@ -75,33 +100,48 @@ static void find_menu_frame(Ted *ted) {
}
pcre2_match_data_free(match_data);
}
+ } else {
+ ted->find_match_count = 0;
}
-
+
+
float x1 = padding, y1 = window_height - menu_height, x2 = window_width - padding, y2 = window_height - padding;
+
Rect menu_bounds = rect4(x1, y1, x2, y2);
+ Rect find_buffer_bounds = rect4(x1 + padding, y1 + char_height_bold, x2 - padding, y1 + char_height_bold + char_height);
+ gl_geometry_rect(menu_bounds, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(menu_bounds, 1, colors[COLOR_BORDER]);
-
+ {
+ float w = 0, h = 0;
+ char str[32];
+ strbuf_printf(str, U32_FMT " matches", ted->find_match_count);
+ text_get_size(font, str, &w, &h);
+ text_utf8(font, str, x2 - (w + padding), rect_ymid(find_buffer_bounds) - h * 0.5f, colors[COLOR_TEXT]);
+ x2 -= w + padding;
+ find_buffer_bounds.size.x -= w + padding;
+ }
text_utf8(font_bold, "Find...", x1 + padding, y1, colors[COLOR_TEXT]);
- text_render(font_bold);
y1 += char_height_bold;
-
- Rect find_buffer_bounds = rect4(x1 + padding, y1, x2 - padding, y1 + char_height);
- buffer_render(&ted->find_buffer, find_buffer_bounds);
-
+
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);
+
}
// go to next find result
static void find_next(Ted *ted) {
TextBuffer *buffer = ted->prev_active_buffer;
+
// create match data
pcre2_match_data *match_data = pcre2_match_data_create(FIND_MAX_GROUPS, NULL);
if (match_data) {
diff --git a/math.c b/math.c
index b833872..e6e90f3 100644
--- a/math.c
+++ b/math.c
@@ -657,6 +657,8 @@ static float rect_x1(Rect r) { return r.pos.x; }
static float rect_y1(Rect r) { return r.pos.y; }
static float rect_x2(Rect r) { return r.pos.x + r.size.x; }
static float rect_y2(Rect r) { return r.pos.y + r.size.y; }
+static float rect_xmid(Rect r) { return r.pos.x + r.size.x * 0.5f; }
+static float rect_ymid(Rect r) { return r.pos.y + r.size.y * 0.5f; }
static void rect_coords(Rect r, float *x1, float *y1, float *x2, float *y2) {
*x1 = r.pos.x;
diff --git a/ted.h b/ted.h
index 9b2c18b..3694858 100644
--- a/ted.h
+++ b/ted.h
@@ -190,6 +190,7 @@ typedef struct Node {
#define TED_MAX_NODES 256
// max tabs per node
#define TED_MAX_TABS 100
+
typedef struct Ted {
SDL_Window *window;
Font *font_bold;
@@ -218,6 +219,7 @@ typedef struct Ted {
bool search_cwd; // should the working directory be searched for files? set to true if the executable isn't "installed"
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?
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