summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-21 16:14:10 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-21 16:14:10 -0500
commit37ce64c167e12c0d652442b2ff3deb9327d1317d (patch)
tree8d6ef23080e635955529ef3a851d7d33a53230be
parent617907fb4731d67f6e7aca17b9dd7881f2093aad (diff)
generalized selector code seems to work, fix buffer_set_line_len memory leak
-rw-r--r--buffer.c6
-rw-r--r--command.c16
-rw-r--r--config.c2
-rw-r--r--main.c2
-rw-r--r--ted.h2
-rw-r--r--ui.c106
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