summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-30 13:21:53 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-30 13:21:53 -0500
commitb35a780479bbf5038a825d415f9ca49c92f6b425 (patch)
tree44e71007552714b03ae812e466495ec5c8a7e27b
parenta61d90c32d4d6448148894872ebd91eb8f10fc2e (diff)
ctrl+q to quit (with unsaved changes dialog)
-rw-r--r--buffer.c2
-rw-r--r--command.c29
-rw-r--r--command.h2
-rw-r--r--main.c8
-rw-r--r--menu.c7
-rw-r--r--ted.c58
-rw-r--r--ted.cfg1
-rw-r--r--ted.h1
-rw-r--r--util.c3
9 files changed, 103 insertions, 8 deletions
diff --git a/buffer.c b/buffer.c
index 11b1b6c..d7699db 100644
--- a/buffer.c
+++ b/buffer.c
@@ -640,6 +640,8 @@ void buffer_new_file(TextBuffer *buffer, char const *filename) {
buffer->nlines = 1;
}
+// Save the buffer to its current filename. This will rewrite the entire file, regardless of
+// whether there are any unsaved changes.
bool buffer_save(TextBuffer *buffer) {
if (!buffer->is_line_buffer && buffer->filename) {
FILE *out = fopen(buffer->filename, "wb");
diff --git a/command.c b/command.c
index a7ff287..3a52746 100644
--- a/command.c
+++ b/command.c
@@ -159,9 +159,34 @@ void command_execute(Ted *ted, Command c, i64 argument) {
menu_open(ted, MENU_SAVE_AS);
}
break;
+ case CMD_SAVE_ALL:
+ ted_save_all(ted);
+ break;
case CMD_QUIT:
- // @TODO: check for unsaved changes in all buffers
- ted->quit = true;
+ // pass argument of 2 to override dialog
+ if (argument == 2) {
+ ted->quit = true;
+ } else {
+ *ted->warn_unsaved_names = 0;
+ bool *buffers_used = ted->buffers_used;
+ bool first = true;
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
+ if (buffers_used[i]) {
+ buffer = &ted->buffers[i];
+ if (buffer_unsaved_changes(buffer)) {
+ strbuf_catf(ted->warn_unsaved_names, "%s%s", first ? "" : ", ", path_filename(buffer->filename));
+ first = false;
+ }
+ }
+ }
+ if (*ted->warn_unsaved_names) {
+ ted->warn_unsaved = CMD_QUIT;
+ menu_open(ted, MENU_WARN_UNSAVED);
+ } else {
+ // no unsaved changes
+ ted->quit = true;
+ }
+ }
break;
case CMD_UNDO:
if (buffer) buffer_undo(buffer, argument);
diff --git a/command.h b/command.h
index 9c2fba3..63afdb2 100644
--- a/command.h
+++ b/command.h
@@ -41,6 +41,7 @@ ENUM_U16 {
CMD_OPEN, // open a file
CMD_SAVE, // save current buffer
CMD_SAVE_AS,
+ CMD_SAVE_ALL, // save all open buffers with unsaved changes
CMD_NEW,
CMD_UNDO,
CMD_REDO,
@@ -101,6 +102,7 @@ static CommandName const command_names[CMD_COUNT] = {
{"new", CMD_NEW},
{"save", CMD_SAVE},
{"save-as", CMD_SAVE_AS},
+ {"save-all", CMD_SAVE_ALL},
{"quit", CMD_QUIT},
{"undo", CMD_UNDO},
{"redo", CMD_REDO},
diff --git a/main.c b/main.c
index 8ef9aa2..1157ce4 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,5 @@
// @TODO:
-// - when closing tabs/window, warn on unsaved changes
+// - middle click to close tab
// - try opening a file you don't have read permission for -- check for memory leaks!
// - show something informative when there's no nodes open (i.e. ted->active_node == NULL).
@@ -570,9 +570,11 @@ int main(int argc, char **argv) {
SDL_DestroyWindow(window);
SDL_Quit();
for (u16 i = 0; i < TED_MAX_BUFFERS; ++i)
- buffer_free(&ted->buffers[i]);
+ if (ted->buffers_used[i])
+ buffer_free(&ted->buffers[i]);
for (u16 i = 0; i < TED_MAX_NODES; ++i)
- node_free(&ted->nodes[i]);
+ if (ted->nodes_used[i])
+ node_free(&ted->nodes[i]);
buffer_free(&ted->line_buffer);
text_font_free(ted->font);
text_font_free(ted->font_bold);
diff --git a/menu.c b/menu.c
index df3c7a0..5cdf83f 100644
--- a/menu.c
+++ b/menu.c
@@ -129,13 +129,16 @@ static void menu_update(Ted *ted, Menu menu) {
// save changes
switch (ted->warn_unsaved) {
case CMD_TAB_CLOSE:
+ menu_close(ted, true);
if (buffer_save(ted->prev_active_buffer)) {
- menu_close(ted, true);
command_execute(ted, CMD_TAB_CLOSE, 1);
}
break;
case CMD_QUIT:
- assert(0); // @TODO!
+ menu_close(ted, true);
+ if (ted_save_all(ted)) {
+ command_execute(ted, CMD_QUIT, 1);
+ }
break;
default:
assert(0);
diff --git a/ted.c b/ted.c
index 431768e..0e8be05 100644
--- a/ted.c
+++ b/ted.c
@@ -1,3 +1,5 @@
+static void menu_open(Ted *ted, Menu menu);
+
// this is a macro so we get -Wformat warnings
#define ted_seterr(buffer, ...) \
snprintf(ted->error, sizeof ted->error - 1, __VA_ARGS__)
@@ -196,3 +198,59 @@ static bool ted_new_file(Ted *ted) {
return false;
}
}
+
+// sets the active buffer to this buffer, and updates active_node, etc. accordingly
+static void ted_switch_to_buffer(Ted *ted, u16 buffer_idx) {
+ ted->active_buffer = &ted->buffers[buffer_idx];
+ // now we need to figure out where this buffer is
+ bool *nodes_used = ted->nodes_used;
+ for (u16 i = 0; i < TED_MAX_NODES; ++i) {
+ if (nodes_used[i]) {
+ Node *node = &ted->nodes[i];
+ arr_foreach_ptr(node->tabs, u16, tab) {
+ if (buffer_idx == *tab) {
+ node->active_tab = (u16)(tab - node->tabs);
+ ted->active_node = node;
+ return;
+ }
+ }
+ }
+ }
+ assert(0);
+}
+
+// are there any unsaved changes in any buffers?
+static bool ted_any_unsaved_changes(Ted *ted) {
+ bool *buffers_used = ted->buffers_used;
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
+ if (buffers_used[i]) {
+ if (buffer_unsaved_changes(&ted->buffers[i]))
+ return true;
+ }
+ }
+ return false;
+}
+
+// save all changes to all buffers with unsaved changes.
+// returns true if all buffers were saved successfully
+static bool ted_save_all(Ted *ted) {
+ bool success = true;
+ bool *buffers_used = ted->buffers_used;
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
+ if (buffers_used[i]) {
+ TextBuffer *buffer = &ted->buffers[i];
+ if (buffer_unsaved_changes(buffer)) {
+ if (buffer->filename && streq(buffer->filename, TED_UNTITLED)) {
+ ted_switch_to_buffer(ted, i);
+ menu_open(ted, MENU_SAVE_AS);
+ success = false; // we haven't saved this buffer yet; we've just opened the "save as" menu.
+ break;
+ } else {
+ if (!buffer_save(buffer))
+ success = false;
+ }
+ }
+ }
+ }
+ return success;
+}
diff --git a/ted.cfg b/ted.cfg
index e7af61a..c7d0307 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -66,6 +66,7 @@ Ctrl+PageDown = 10 :page-down
Ctrl+o = :open
Ctrl+n = :new
Ctrl+s = :save
+Ctrl+Alt+Shift+s = :save-all
Ctrl+Shift+s = :save-as
Ctrl+q = :quit
Ctrl+z = :undo
diff --git a/ted.h b/ted.h
index 74b5145..7c546ae 100644
--- a/ted.h
+++ b/ted.h
@@ -155,5 +155,4 @@ typedef struct Ted {
char error_shown[512]; // error display in box on screen
} Ted;
-// forward declarations
void command_execute(Ted *ted, Command c, i64 argument);
diff --git a/util.c b/util.c
index 59ece04..7a970a2 100644
--- a/util.c
+++ b/util.c
@@ -57,6 +57,9 @@ static char *str_dup(char const *src) {
// first, check that str is actually an array
#define strbuf_printf(str, ...) assert(sizeof str != 4 && sizeof str != 8), \
str_printf(str, sizeof str, __VA_ARGS__)
+#define str_catf(str, size, ...) str_printf((str) + strlen(str), (size) - strlen(str), __VA_ARGS__)
+#define strbuf_catf(str, ...) assert(sizeof str != 4 && sizeof str != 8), \
+ str_catf(str, sizeof str, __VA_ARGS__)
// on 16-bit systems, this is 16383. on 32/64-bit systems, this is 1073741823
// it is unusual to have a string that long.