From 7be42dc83ff694da2f1e66a59a14fe51d3e18fba Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Tue, 9 Feb 2021 10:15:42 -0500 Subject: case sensitivity, regex --- find.c | 40 ++++++++++++++++++++++++++++------------ main.c | 2 +- math.c | 48 ++++++++++++++++++++++++++++++------------------ ted.h | 2 ++ text.c | 7 +++++++ text.h | 1 + ui.c | 18 ++++++++++++------ 7 files changed, 81 insertions(+), 37 deletions(-) diff --git a/find.c b/find.c index 929c253..0d3d3f4 100644 --- a/find.c +++ b/find.c @@ -1,6 +1,11 @@ #define FIND_MAX_GROUPS 50 -static bool find_compile_pattern(Ted *ted, bool error_on_invalid_pattern) { +static u32 find_compilation_flags(Ted *ted) { + return (ted->find_case_sensitive ? 0 : PCRE2_CASELESS) + | (ted->find_regex ? 0 : PCRE2_LITERAL); +} + +static bool find_compile_pattern(Ted *ted) { TextBuffer *find_buffer = &ted->find_buffer; String32 term = buffer_get_line(find_buffer, 0); if (term.len) { @@ -8,7 +13,7 @@ static bool find_compile_pattern(Ted *ted, bool error_on_invalid_pattern) { if (match_data) { int error = 0; PCRE2_SIZE error_pos = 0; - pcre2_code *code = pcre2_compile(term.str, term.len, PCRE2_LITERAL, &error, &error_pos, NULL); + pcre2_code *code = pcre2_compile(term.str, term.len, find_compilation_flags(ted), &error, &error_pos, NULL); if (code) { ted->find_code = code; ted->find_match_data = match_data; @@ -16,7 +21,8 @@ static bool find_compile_pattern(Ted *ted, bool error_on_invalid_pattern) { return true; } else { ted->find_invalid_pattern = true; - if (error_on_invalid_pattern) { + #if 0 + // @TODO: write this to a buffer and check it in find_next_in_direction 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)); @@ -24,7 +30,7 @@ static bool find_compile_pattern(Ted *ted, bool error_on_invalid_pattern) { ted_seterr(ted, "Invalid search term (position %zu): %s.", (size_t)error_pos, error_cstr); free(error_cstr); } - } + #endif } pcre2_match_data_free(match_data); } else { @@ -69,7 +75,7 @@ static float find_menu_height(Ted *ted) { Settings const *settings = &ted->settings; float padding = settings->padding; - return char_height + 4 * padding; + return 2 * char_height + 5 * padding; } // finds the next match in the buffer, returning false if there is no match this line. @@ -93,11 +99,13 @@ static WarnUnusedResult bool find_match(Ted *ted, BufferPos *pos, u32 *match_sta int next_ret = pcre2_match(ted->find_code, str.str, pos->index, last_pos, 0, ted->find_match_data, NULL); if (next_ret > 0) { ret = next_ret; + if (groups[0] == groups[1]) ++groups[1]; // ensure we don't have an infinite loop last_pos = (u32)groups[1]; } else break; } } if (ret > 0) { + if (groups[0] == groups[1]) ++groups[1]; if (match_start) *match_start = (u32)groups[0]; if (match_end) *match_end = (u32)groups[1]; pos->index = (u32)groups[1]; @@ -113,15 +121,19 @@ static WarnUnusedResult bool find_match(Ted *ted, BufferPos *pos, u32 *match_sta } } -static void find_update(Ted *ted, bool error_on_invalid_pattern) { +// check if the search term needs to be recompiled +static void find_update(Ted *ted) { TextBuffer *find_buffer = &ted->find_buffer; - if (!find_buffer->modified) return; - + u32 flags = find_compilation_flags(ted); + if (!find_buffer->modified // check if buffer has been modified, + && ted->find_flags == flags) // or checkboxes have been (un)checked + return; + ted->find_flags = flags; TextBuffer *buffer = ted->prev_active_buffer; find_free_pattern(ted); - if (find_compile_pattern(ted, error_on_invalid_pattern)) { + if (find_compile_pattern(ted)) { BufferPos pos = buffer_start_of_file(buffer); BufferPos best_scroll_candidate = {U32_MAX, U32_MAX}; BufferPos cursor_pos = buffer->cursor_pos; @@ -163,7 +175,7 @@ static void find_menu_frame(Ted *ted) { u32 first_rendered_line = buffer_first_rendered_line(buffer); u32 last_rendered_line = buffer_last_rendered_line(buffer); - find_update(ted, false); + find_update(ted); u32 match_pos = U32_MAX; // index of result we are on arr_foreach_ptr(ted->find_results, FindResult, result) { @@ -216,10 +228,14 @@ static void find_menu_frame(Ted *ted) { } text_utf8(font_bold, "Find...", x1, y1, colors[COLOR_TEXT]); - y1 += char_height_bold; + y1 += char_height_bold + padding; gl_geometry_draw(); text_render(font_bold); + + float x = x1; + x += checkbox_frame(ted, &ted->find_case_sensitive, "Case sensitive", V2(x, y1)).x + 2*padding; + x += checkbox_frame(ted, &ted->find_regex, "Regular expression", V2(x, y1)).x + 2*padding; buffer_render(find_buffer, find_buffer_bounds); @@ -240,7 +256,7 @@ static void find_next_in_direction(Ted *ted, int direction) { BufferPos pos = direction == +1 || !buffer->selection ? buffer->cursor_pos : buffer->selection_pos; u32 nlines = buffer->nlines; - find_update(ted, true); + find_update(ted); // we need to search the starting line twice, because we might start at a non-zero index for (size_t nsearches = 0; nsearches < nlines + 1; ++nsearches) { diff --git a/main.c b/main.c index 9f4b508..e5f6bb9 100644 --- a/main.c +++ b/main.c @@ -47,8 +47,8 @@ no_warn_end #include "syntax.c" #include "buffer.c" #include "ted.c" -#include "find.c" #include "ui.c" +#include "find.c" #include "node.c" #include "menu.c" #include "command.c" diff --git a/math.c b/math.c index e6e90f3..ab7b859 100644 --- a/math.c +++ b/math.c @@ -607,6 +607,25 @@ static v2i V2I(int x, int y) { return v; } +static void rgba_u32_to_floats(u32 rgba, float floats[4]) { + floats[0] = (float)((rgba >> 24) & 0xFF) / 255.f; + floats[1] = (float)((rgba >> 16) & 0xFF) / 255.f; + floats[2] = (float)((rgba >> 8) & 0xFF) / 255.f; + floats[3] = (float)((rgba >> 0) & 0xFF) / 255.f; +} + +static v4 rgba_u32_to_v4(u32 rgba) { + float c[4]; + rgba_u32_to_floats(rgba, c); + return V4(c[0], c[1], c[2], c[3]); +} + +// returns average of red green and blue components of color +static float rgba_brightness(u32 color) { + u8 r = (u8)(color >> 24), g = (u8)(color >> 16), b = (u8)(color >> 8); + return ((float)r+(float)g+(float)b) * (1.0f / 3); +} + static bool rect_contains_point_v2(v2 pos, v2 size, v2 point) { float x1 = pos.x, y1 = pos.y, x2 = pos.x + size.x, y2 = pos.y + size.y, x = point.x, y = point.y; @@ -671,24 +690,6 @@ static void rect_print(Rect r) { printf("Position: (%f, %f), Size: (%f, %f)\n", r.pos.x, r.pos.y, r.size.x, r.size.y); } -static void rgba_u32_to_floats(u32 rgba, float floats[4]) { - floats[0] = (float)((rgba >> 24) & 0xFF) / 255.f; - floats[1] = (float)((rgba >> 16) & 0xFF) / 255.f; - floats[2] = (float)((rgba >> 8) & 0xFF) / 255.f; - floats[3] = (float)((rgba >> 0) & 0xFF) / 255.f; -} - -static v4 rgba_u32_to_v4(u32 rgba) { - float c[4]; - rgba_u32_to_floats(rgba, c); - return V4(c[0], c[1], c[2], c[3]); -} - -// returns average of red green and blue components of color -static float rgba_brightness(u32 color) { - u8 r = (u8)(color >> 24), g = (u8)(color >> 16), b = (u8)(color >> 8); - return ((float)r+(float)g+(float)b) * (1.0f / 3); -} static float rects_intersect(Rect r1, Rect r2) { if (r1.pos.x >= r2.pos.x + r2.size.x) return false; // r1 is to the right of r2 @@ -709,3 +710,14 @@ static bool rect_clip_to_rect(Rect *clipped, Rect clipper) { clipped->size.y = clampf(clipped->size.y, 0, clipper.pos.y + clipper.size.y - clipped->pos.y); return clipped->size.x > 0 && clipped->size.y > 0; } + +// removes `amount` from all sides of r +static Rect rect_shrink(Rect r, float amount) { + r.pos.x += amount; + r.pos.y += amount; + r.size.x -= 2 * amount; + r.size.y -= 2 * amount; + r.size.x = maxf(r.size.x, 0); + r.size.y = maxf(r.size.y, 0); + return r; +} \ No newline at end of file diff --git a/ted.h b/ted.h index 7d7f7c7..be41ac8 100644 --- a/ted.h +++ b/ted.h @@ -227,6 +227,8 @@ 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? + bool find_regex, find_case_sensitive; // find options + u32 find_flags; // flags used last time search term was compiled pcre2_code *find_code; pcre2_match_data *find_match_data; FindResult *find_results; diff --git a/text.c b/text.c index 074dde6..aeb17ea 100644 --- a/text.c +++ b/text.c @@ -374,6 +374,13 @@ void text_get_size(Font *font, char const *text, float *width, float *height) { if (height) *height = y + font->char_height; } +v2 text_get_size_v2(Font *font, char const *text) { + v2 v; + text_get_size(font, text, &v.x, &v.y); + return v; +} + + void text_get_size32(Font *font, char32_t const *text, u64 len, float *width, float *height) { TextRenderState render_state = text_render_state_default; render_state.render = false; diff --git a/text.h b/text.h index 362516a..a60047f 100644 --- a/text.h +++ b/text.h @@ -53,6 +53,7 @@ extern float text_font_char_height(Font *font); extern float text_font_char_width(Font *font); // Get the dimensions of some text. extern void text_get_size(Font *font, char const *text, float *width, float *height); +extern v2 text_get_size_v2(Font *font, char const *text); extern void text_get_size32(Font *font, char32_t const *text, u64 len, float *width, float *height); extern void text_utf8(Font *font, char const *text, float x, float y, u32 color); extern void text_utf8_anchored(Font *font, char const *text, float x, float y, u32 color, Anchor anchor); diff --git a/ui.c b/ui.c index b743d82..7640215 100644 --- a/ui.c +++ b/ui.c @@ -600,12 +600,14 @@ static void popup_render(Ted *ted, u32 options, char const *title, char const *b text_render(font); } -static void checkbox_frame(Ted *ted, bool *value, char const *label, v2 pos) { +// returns the size of the checkbox, including the label +static v2 checkbox_frame(Ted *ted, bool *value, char const *label, v2 pos) { Font *font = ted->font; float char_height = text_font_char_height(font); float checkbox_size = char_height; Settings const *settings = &ted->settings; u32 const *colors = settings->colors; + float padding = settings->padding; Rect checkbox_rect = rect(pos, V2(checkbox_size, checkbox_size)); @@ -615,13 +617,17 @@ static void checkbox_frame(Ted *ted, bool *value, char const *label, v2 pos) { } } - if (*value) - gl_geometry_rect(checkbox_rect, colors[COLOR_TEXT]); - else - gl_geometry_rect_border(checkbox_rect, 1, colors[COLOR_TEXT]); - v2 text_pos = v2_add(pos, V2(checkbox_size, 0)); + checkbox_rect.pos = v2_add(checkbox_rect.pos, V2(0.5f, 0.5f)); + gl_geometry_rect_border(checkbox_rect, 1, colors[COLOR_TEXT]); + if (*value) { + gl_geometry_rect(rect_shrink(checkbox_rect, checkbox_size * 0.2f), colors[COLOR_TEXT]); + } + + v2 text_pos = v2_add(pos, V2(checkbox_size + padding * 0.5f, 0)); + v2 size = text_get_size_v2(font, label); text_utf8(font, label, text_pos.x, text_pos.y, colors[COLOR_TEXT]); gl_geometry_draw(); text_render(font); + return v2_add(size, V2(checkbox_size + padding * 0.5f, 0)); } -- cgit v1.2.3