summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-28 16:22:49 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-28 16:22:49 -0500
commit238f3ecc526600d5c18fead7820469719027b07c (patch)
treed84cd6606be4a81e32f8f0634aeb924b0457e5f8
parent5b90057859cd38b284573460460ab27bd108aa0e (diff)
got file selector to behave better
-rw-r--r--buffer.c36
-rw-r--r--command.c8
-rw-r--r--config.c4
-rw-r--r--main.c11
-rw-r--r--math.c10
-rw-r--r--menu.c10
-rw-r--r--ted-base.c1
-rw-r--r--ted.cfg3
-rw-r--r--ted.h2
-rw-r--r--ui.c37
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);