From 238f3ecc526600d5c18fead7820469719027b07c Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Thu, 28 Jan 2021 16:22:49 -0500 Subject: got file selector to behave better --- buffer.c | 36 ++++++++++++++++++++++++++++-------- command.c | 8 ++------ config.c | 4 +++- main.c | 11 ++++++----- math.c | 10 ++++++++++ menu.c | 10 ++++++---- ted-base.c | 1 - ted.cfg | 3 ++- ted.h | 2 +- ui.c | 37 +++++++++++++++++++++++++------------ 10 files changed, 83 insertions(+), 39 deletions(-) diff --git a/buffer.c b/buffer.c index 2f656e7..381d7a7 100644 --- a/buffer.c +++ b/buffer.c @@ -43,6 +43,11 @@ static void buffer_clear_undo_history(TextBuffer *buffer) { arr_clear(buffer->undo_history); } + +bool buffer_empty(TextBuffer *buffer) { + return buffer->nlines == 1 && buffer->lines[0].len == 0; +} + // clear all undo and redo events void buffer_clear_undo_redo(TextBuffer *buffer) { buffer_clear_undo_history(buffer); @@ -632,16 +637,17 @@ void buffer_new_file(TextBuffer *buffer, char const *filename) { } bool buffer_save(TextBuffer *buffer) { - if (buffer->filename) { + if (!buffer->is_line_buffer && buffer->filename) { FILE *out = fopen(buffer->filename, "wb"); if (out) { - bool success = true; for (Line *line = buffer->lines, *end = line + buffer->nlines; line != end; ++line) { for (char32_t *p = line->str, *p_end = p + line->len; p != p_end; ++p) { char utf8[4] = {0}; size_t bytes = unicode_utf32_to_utf8(utf8, *p); if (bytes != (size_t)-1) { - fwrite(utf8, 1, bytes, out); + if (fwrite(utf8, 1, bytes, out) != bytes) { + buffer_seterr(buffer, "Couldn't write to %s.", buffer->filename); + } } } @@ -649,14 +655,21 @@ bool buffer_save(TextBuffer *buffer) { putc('\n', out); } } - if (ferror(out)) success = false; - if (fclose(out) != 0) success = false; + if (ferror(out)) { + if (!buffer_haserr(buffer)) + buffer_seterr(buffer, "Couldn't write to %s.", buffer->filename); + } + if (fclose(out) != 0) { + if (!buffer_haserr(buffer)) + buffer_seterr(buffer, "Couldn't close file %s.", buffer->filename); + } + bool success = !buffer_haserr(buffer); if (success) { buffer->modified = false; } return success; } else { - buffer_seterr(buffer, "Couldn't write to file %s.", buffer->filename); + buffer_seterr(buffer, "Couldn't open file %s for writing: %s.", buffer->filename, strerror(errno)); return false; } } else { @@ -667,9 +680,16 @@ bool buffer_save(TextBuffer *buffer) { // save, but with a different file name bool buffer_save_as(TextBuffer *buffer, char const *new_filename) { - free(buffer->filename); + char *prev_filename = buffer->filename; if ((buffer->filename = buffer_strdup(buffer, new_filename))) { - return buffer_save(buffer); + if (buffer_save(buffer)) { + free(prev_filename); + return true; + } else { + free(buffer->filename); + buffer->filename = prev_filename; + return false; + } } else { return false; } diff --git a/command.c b/command.c index eb2d0bf..beb4d9d 100644 --- a/command.c +++ b/command.c @@ -101,7 +101,8 @@ void command_execute(Ted *ted, Command c, i64 argument) { buffer_insert_char_at_cursor(buffer, '\t'); break; case CMD_NEWLINE: - if (buffer->is_line_buffer) { + if (!buffer) { + } else if (buffer->is_line_buffer) { switch (ted->menu) { case MENU_NONE: assert(0); @@ -192,9 +193,4 @@ void command_execute(Ted *ted, Command c, i64 argument) { } break; } - - if (buffer && buffer_haserr(buffer)) { - ted_seterr_to_buferr(ted, buffer); - buffer_clearerr(buffer); - } } diff --git a/config.c b/config.c index 3baa943..bdec0d9 100644 --- a/config.c +++ b/config.c @@ -81,6 +81,8 @@ static u32 config_parse_key_combo(ConfigReader *cfg, char const *str) { {"Period", 0, SDL_SCANCODE_PERIOD, 0}, {"Semicolon", 0, SDL_SCANCODE_SEMICOLON, 0}, {"Slash", 0, SDL_SCANCODE_SLASH, 0}, + {"Enter", 0, SDL_SCANCODE_RETURN, 0}, + {"Keypad Return", 0, SDL_SCANCODE_KP_ENTER, 0}, {"Exclaim", "Exclamation Mark", SDL_SCANCODE_1, 1}, {"!", 0, SDL_SCANCODE_1, 1}, {"At", "@", SDL_SCANCODE_2, 1}, @@ -103,7 +105,7 @@ static u32 config_parse_key_combo(ConfigReader *cfg, char const *str) { {"Greater Than", ">", SDL_SCANCODE_PERIOD, 1}, {"Question Mark", "?", SDL_SCANCODE_SLASH, 1}, {"Question", 0, SDL_SCANCODE_SLASH, 1}, - {"Tilde", "~", SDL_SCANCODE_GRAVE, 1} + {"Tilde", "~", SDL_SCANCODE_GRAVE, 1}, }; // @OPTIMIZE: sort key_names (and split keyname1/2); do a binary search diff --git a/main.c b/main.c index 2e92a18..2e067a0 100644 --- a/main.c +++ b/main.c @@ -1,10 +1,6 @@ // @TODO: -// - warn on: -// - overwrite (from save as menu) -// - file selector: -// - tab to set search term to selected // - tabs, split -// - when closing tabs, warn on unsaved changes +// - when closing tabs/window, warn on unsaved changes // - Windows installation #include "base.h" no_warn_start @@ -467,6 +463,11 @@ int main(int argc, char **argv) { menu_render(ted, menu); } + if (buffer_haserr(&ted->main_buffer)) { + ted_seterr_to_buferr(ted, &ted->main_buffer); + buffer_clearerr(&ted->main_buffer); + } + // check if there's a new error if (ted_haserr(ted)) { ted->error_time = time_get_seconds(); diff --git a/math.c b/math.c index fe28ef1..71afabc 100644 --- a/math.c +++ b/math.c @@ -112,6 +112,16 @@ static i64 mod_i64(i64 a, i64 b) { return ret; } +static i64 abs_i64(i64 x) { + return x < 0 ? -x : +x; +} + +static i64 sgn_i64(i64 x) { + if (x < 0) return -1; + if (x > 0) return +1; + return 0; +} + static float sgnf(float x) { if (x < 0) return -1; if (x > 0) return +1; diff --git a/menu.c b/menu.c index 68f941a..3013920 100644 --- a/menu.c +++ b/menu.c @@ -60,12 +60,14 @@ static void menu_update(Ted *ted, Menu menu) { case POPUP_NONE: // no option selected break; - case POPUP_YES: + case POPUP_YES: { // overwrite it! - if (ted->prev_active_buffer) - buffer_save_as(ted->prev_active_buffer, ted->warn_overwrite); + TextBuffer *buffer = ted->prev_active_buffer; + if (buffer) { + buffer_save_as(buffer, ted->warn_overwrite); + } menu_close(ted, true); - break; + } break; case POPUP_NO: // back to the file selector *ted->warn_overwrite = '\0'; diff --git a/ted-base.c b/ted-base.c index 066e537..fb99711 100644 --- a/ted-base.c +++ b/ted-base.c @@ -96,7 +96,6 @@ static WarnUnusedResult TextBuffer *ted_open_file(Ted *ted, char const *filename ted->active_buffer = open_to; return open_to; } else { - ted_seterr_to_buferr(ted, open_to); return NULL; } } diff --git a/ted.cfg b/ted.cfg index 8173cc4..5bdd43d 100644 --- a/ted.cfg +++ b/ted.cfg @@ -48,7 +48,8 @@ Ctrl+a = :select-all # insertion Tab = :tab -Return = :newline +Enter = :newline +Keypad Enter = :newline # deletion Delete = :delete diff --git a/ted.h b/ted.h index 515a195..33e3116 100644 --- a/ted.h +++ b/ted.h @@ -91,7 +91,7 @@ typedef struct { typedef struct { Rect bounds; u32 n_entries; - u32 selected; // which FileEntry is currently selected + u32 selected; float scroll; FileEntry *entries; char cwd[TED_PATH_MAX]; diff --git a/ui.c b/ui.c index 7207a7d..f0cdb72 100644 --- a/ui.c +++ b/ui.c @@ -57,23 +57,32 @@ static void file_selector_clear_entries(FileSelector *fs) { fs->n_entries = 0; } +// returns true if there are any directory entries +static bool file_selector_any_directories(FileSelector const *fs) { + FileEntry const *entries = fs->entries; + for (u32 i = 0, n_entries = fs->n_entries; i < n_entries; ++i) { + if (entries[i].type == FS_DIRECTORY) + return true; + } + return false; +} + static void file_selector_free(FileSelector *fs) { file_selector_clear_entries(fs); memset(fs, 0, sizeof *fs); } static void file_selector_up(Ted const *ted, FileSelector *fs, i64 n) { - i64 selected = fs->selected - n; - selected = mod_i64(selected, fs->n_entries); - fs->selected = (u32)selected; + if (fs->n_entries == 0) { + // can't do anything + return; + } + fs->selected = (u32)mod_i64(fs->selected - n, fs->n_entries); file_selector_scroll_to_selected(ted, fs); } static void file_selector_down(Ted const *ted, FileSelector *fs, i64 n) { - i64 selected = fs->selected + n; - selected = mod_i64(selected, fs->n_entries); - fs->selected = (u32)selected; - file_selector_scroll_to_selected(ted, fs); + file_selector_up(ted, fs, -n); } static int qsort_file_entry_cmp(void const *av, void const *bv, void *search_termv) { @@ -214,6 +223,7 @@ static Status file_selector_cd_(Ted const *ted, FileSelector *fs, char const *pa // returns false if this path doesn't exist or isn't a directory static bool file_selector_cd(Ted const *ted, FileSelector *fs, char const *path) { fs->selected = 0; + fs->scroll = 0; return file_selector_cd_(ted, fs, path, 0); } @@ -267,9 +277,6 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { char *search_term = search_term32.len ? str32_to_utf8_cstr(search_term32) : NULL; - bool submitted = fs->submitted; - fs->submitted = false; - for (u32 i = 0; i < fs->n_entries; ++i) { Rect r = {0}; FileEntry *entry = &fs->entries[i]; @@ -298,9 +305,13 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { } + bool submitted = fs->submitted; + fs->submitted = false; + // user pressed enter in search bar if (submitted) { - if (fs->create_menu) { + 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); @@ -430,7 +441,9 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { Rect r; if (file_selector_entry_pos(ted, fs, i, &r)) { rect_clip_to_rect(&r, text_bounds); - if (rect_contains_point(r, ted->mouse_pos) || fs->selected == i) { + if (rect_contains_point(r, ted->mouse_pos) || + ((!fs->create_menu || buffer_empty(&ted->line_buffer)) // only highlight selected for create menus if there is no search term (because that will be the name of the file) + && fs->selected == i)) { glBegin(GL_QUADS); gl_color_rgba(colors[COLOR_MENU_HL]); rect_render(r); -- cgit v1.2.3