diff options
-rw-r--r-- | buffer.c | 2 | ||||
-rw-r--r-- | command.c | 29 | ||||
-rw-r--r-- | command.h | 2 | ||||
-rw-r--r-- | main.c | 8 | ||||
-rw-r--r-- | menu.c | 7 | ||||
-rw-r--r-- | ted.c | 58 | ||||
-rw-r--r-- | ted.cfg | 1 | ||||
-rw-r--r-- | ted.h | 1 | ||||
-rw-r--r-- | util.c | 3 |
9 files changed, 103 insertions, 8 deletions
@@ -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"); @@ -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); @@ -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}, @@ -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); @@ -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); @@ -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; +} @@ -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 @@ -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); @@ -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. |