From 37ce64c167e12c0d652442b2ff3deb9327d1317d Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 21 Feb 2021 16:14:10 -0500 Subject: generalized selector code seems to work, fix buffer_set_line_len memory leak --- buffer.c | 6 +++- command.c | 16 ++++------ config.c | 2 ++ main.c | 2 -- ted.h | 2 +- ui.c | 106 +++++++++++++++++++++++++++++++++++++++++--------------------- 6 files changed, 84 insertions(+), 50 deletions(-) diff --git a/buffer.c b/buffer.c index 776c9dd..0bf78d2 100644 --- a/buffer.c +++ b/buffer.c @@ -558,7 +558,7 @@ static Status buffer_line_set_len(TextBuffer *buffer, Line *line, u32 new_len) { line->str = new_str; } } - } else if (line->len == 0) { + } else if (line->len == 0 && new_len > 0) { // start by allocating 8 code points line->str = buffer_malloc(buffer, 8 * sizeof *line->str); if (!line->str) { @@ -1616,6 +1616,10 @@ void buffer_insert_utf8_at_cursor(TextBuffer *buffer, char const *utf8) { // insert newline at cursor and auto-indent void buffer_newline(TextBuffer *buffer) { + if (buffer->is_line_buffer) { + buffer->line_buffer_submitted = true; + return; + } Settings const *settings = buffer_settings(buffer); BufferPos cursor_pos = buffer->cursor_pos; String32 line = buffer_get_line(buffer, cursor_pos.line); diff --git a/command.c b/command.c index b00e35b..78d5b24 100644 --- a/command.c +++ b/command.c @@ -118,16 +118,12 @@ void command_execute(Ted *ted, Command c, i64 argument) { break; case CMD_NEWLINE: case CMD_NEWLINE_BACK: - if (!buffer) { - } else if (buffer->is_line_buffer) { - ted->line_buffer_submitted = true; - if (ted->find) { - if (buffer == &ted->find_buffer || buffer == &ted->replace_buffer) { - if (c == CMD_NEWLINE) - find_next(ted); - else - find_prev(ted); - } + if (ted->find) { + if (buffer == &ted->find_buffer || buffer == &ted->replace_buffer) { + if (c == CMD_NEWLINE) + find_next(ted); + else + find_prev(ted); } } else { buffer_newline(buffer); diff --git a/config.c b/config.c index fcdf7c0..efba92e 100644 --- a/config.c +++ b/config.c @@ -324,6 +324,8 @@ void config_read(Ted *ted, char const *filename) { if (!isspace(*src)) *dst++ = *src; *dst = 0; + if (settings->language_extensions[lang]) + free(settings->language_extensions[lang]); settings->language_extensions[lang] = new_str; } } diff --git a/main.c b/main.c index 8af990c..0de7610 100644 --- a/main.c +++ b/main.c @@ -393,8 +393,6 @@ int main(int argc, char **argv) { memset(ted->nmouse_clicks, 0, sizeof ted->nmouse_clicks); ted->scroll_total_x = ted->scroll_total_y = 0; - ted->line_buffer_submitted = false; - ted_update_window_dimensions(ted); u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT | (u32)shift_down << KEY_MODIFIER_SHIFT_BIT diff --git a/ted.h b/ted.h index 6444b5f..0ad4887 100644 --- a/ted.h +++ b/ted.h @@ -139,6 +139,7 @@ typedef struct { bool will_chain_edits; bool chaining_edits; // are we chaining undo events together? bool view_only; + bool line_buffer_submitted; // (line buffers only) set to true when submitted. you have to reset it to false. // If set to true, buffer will be scrolled to the cursor position next frame. // This is to fix the problem that x1,y1,x2,y2 are not updated until the buffer is rendered. bool center_cursor_next_frame; @@ -248,7 +249,6 @@ typedef struct Ted { Menu menu; FileSelector file_selector; TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus - bool line_buffer_submitted; // set to true if the line buffer was just submitted this frame. TextBuffer find_buffer; // use for "find" term in find/find+replace TextBuffer replace_buffer; // "replace" for find+replace TextBuffer build_buffer; // buffer for build output (view only) diff --git a/ui.c b/ui.c index 39a4dc2..737b7ae 100644 --- a/ui.c +++ b/ui.c @@ -3,8 +3,12 @@ #endif static float selector_entries_start_y(Ted const *ted, Selector const *s) { - (void)ted; - return s->bounds.pos.y; + Font *font = ted->font; + float char_height = text_font_char_height(font); + float padding = ted->settings.padding; + + return s->bounds.pos.y + + char_height * 1.25f + padding; // make room for line buffer } // number of entries that can be displayed on the screen @@ -54,9 +58,13 @@ static void selector_down(Ted const *ted, Selector *s, i64 n) { selector_up(ted, s, -n); } -// returns index of entry selected, or -1 for none -static int selector_update(Ted *ted, Selector *s) { - int ret = -1; +// returns a null-terminated UTF-8 string of the option selected, or NULL if none was. +// you should call free() on the return value. +static char *selector_update(Ted *ted, Selector *s) { + char *ret = NULL; + TextBuffer *line_buffer = &ted->line_buffer; + + ted->selector_open = s; for (u32 i = 0; i < s->n_entries; ++i) { // check if this entry was clicked on Rect entry_rect; @@ -64,11 +72,28 @@ static int selector_update(Ted *ted, Selector *s) { for (uint c = 0; c < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++c) { if (rect_contains_point(entry_rect, ted->mouse_clicks[SDL_BUTTON_LEFT][c])) { // this option was selected - ret = (int)i; + ret = str_dup(s->entries[i].name); + break; } } } } + + if (line_buffer->line_buffer_submitted) { + line_buffer->line_buffer_submitted = false; + if (!ret) { + if (s->enable_cursor) { + // select this option + if (s->cursor < s->n_entries) + ret = str_dup(s->entries[s->cursor].name); + + } else { + // user typed in submission + ret = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0)); + } + } + } + // apply scroll float scroll_speed = 2.5f; s->scroll += scroll_speed * (float)ted->scroll_total_y; @@ -80,6 +105,7 @@ static void selector_render(Ted *ted, Selector *s) { Settings const *settings = &ted->settings; u32 const *colors = settings->colors; Font *font = ted->font; + float char_height = text_font_char_height(font); Rect bounds = s->bounds; @@ -95,9 +121,19 @@ static void selector_render(Ted *ted, Selector *s) { } } gl_geometry_draw(); + + float x1, y1, x2, y2; + rect_coords(bounds, &x1, &y1, &x2, &y2); + // search buffer + float line_buffer_height = char_height; + buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y1 + line_buffer_height)); + y1 += line_buffer_height; TextRenderState text_state = text_render_state_default; - rect_coords(bounds, &text_state.min_x, &text_state.min_y, &text_state.max_x, &text_state.max_y); + text_state.min_x = x1; + text_state.max_x = x2; + text_state.min_y = y1; + text_state.max_y = y2; text_state.render = true; // render entries themselves @@ -283,8 +319,10 @@ static bool file_selector_cd(Ted const *ted, FileSelector *fs, char const *path) // returns the name of the selected file, or NULL // if none was selected. the returned pointer should be freed. static char *file_selector_update(Ted *ted, FileSelector *fs) { + TextBuffer *line_buffer = &ted->line_buffer; String32 search_term32 = buffer_get_line(line_buffer, 0); + fs->sel.enable_cursor = !fs->create_menu || search_term32.len == 0; char *const cwd = fs->cwd; if (cwd[0] == '\0') { @@ -326,35 +364,35 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { } } - char *search_term = search_term32.len ? str32_to_utf8_cstr(search_term32) : NULL; + char *option_chosen = selector_update(ted, &fs->sel); + if (option_chosen) { + char path[TED_PATH_MAX]; + strbuf_printf(path, "%s%s%s", cwd, cwd[strlen(cwd)-1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR, option_chosen); + char *ret = NULL; - bool submitted = ted->line_buffer_submitted; - - // user pressed enter in search bar - if (submitted) { - if (fs->create_menu && search_term) { - // user typed in file name to save as - char path[TED_PATH_MAX]; - strbuf_printf(path, "%s%s%s", cwd, cwd[strlen(cwd)-1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR, search_term); - free(search_term); - return str_dup(path); + if (fs->create_menu) { + // don't need to check anything + ret = str_dup(path); } else { - if (fs->sel.cursor < fs->n_entries) { - FileEntry *entry = &fs->entries[fs->sel.cursor]; - switch (entry->type) { - case FS_FILE: - free(search_term); - if (entry->path) return str_dup(entry->path); - break; - case FS_DIRECTORY: - file_selector_cd(ted, fs, entry->name); - buffer_clear(line_buffer); // clear search term - break; - default: break; - } + switch (fs_path_type(path)) { + case FS_NON_EXISTENT: break; + case FS_OTHER: break; + + case FS_FILE: + // selected a file! + ret = str_dup(path); + break; + case FS_DIRECTORY: + // cd there + file_selector_cd(ted, fs, option_chosen); + break; } } + free(option_chosen); + if (ret) { + return ret; + } } // free previous entries @@ -374,6 +412,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { file_selector_cd(ted, fs, ".."); } + char *search_term = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0)); if (files) { u32 nfiles; for (nfiles = 0; files[nfiles]; ++nfiles); @@ -446,11 +485,6 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { text_utf8(font, fs->cwd, x1, y1, colors[COLOR_TEXT]); y1 += char_height + padding; - // search buffer - float line_buffer_height = char_height; - buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y1 + line_buffer_height)); - y1 += line_buffer_height; - // render selector Selector *sel = &fs->sel; sel->bounds = rect4(x1, y1, x2, y2); // selector takes up remaining space -- cgit v1.2.3