From a61d90c32d4d6448148894872ebd91eb8f10fc2e Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 30 Jan 2021 11:52:25 -0500 Subject: warn when closing tab with unsaved changes --- command.c | 28 +++++++++++++++++++++------- main.c | 2 +- menu.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- ted.c | 3 --- ted.h | 8 +++++++- 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/command.c b/command.c index 5acd922..a7ff287 100644 --- a/command.c +++ b/command.c @@ -111,6 +111,7 @@ void command_execute(Ted *ted, Command c, i64 argument) { case MENU_SAVE_AS: { ted->file_selector.submitted = true; } break; + case MENU_WARN_UNSAVED: break; } } else { buffer_newline(buffer); @@ -173,8 +174,7 @@ void command_execute(Ted *ted, Command c, i64 argument) { break; case CMD_CUT: if (buffer) buffer_cut(buffer); - break; - case CMD_PASTE: + break; case CMD_PASTE: if (buffer) buffer_paste(buffer); break; @@ -194,12 +194,26 @@ void command_execute(Ted *ted, Command c, i64 argument) { } break; case CMD_TAB_CLOSE: { - Node *node = ted->active_node; - if (node) { - node_tab_close(ted, node, node->active_tab); + if (ted->menu) { + menu_close(ted, true); } else { - command_execute(ted, CMD_QUIT, 1); - return; + Node *node = ted->active_node; + if (node) { + u16 tab_idx = node->active_tab; + buffer = &ted->buffers[node->tabs[tab_idx]]; + // (an argument of 2 overrides the unsaved changes dialog) + if (argument != 2 && buffer_unsaved_changes(buffer)) { + // there are unsaved changes! + ted->warn_unsaved = CMD_TAB_CLOSE; + strbuf_printf(ted->warn_unsaved_names, "%s", path_filename(buffer->filename)); + menu_open(ted, MENU_WARN_UNSAVED); + } else { + node_tab_close(ted, node, node->active_tab); + } + } else { + command_execute(ted, CMD_QUIT, 1); + return; + } } } break; case CMD_TAB_NEXT: diff --git a/main.c b/main.c index c7e12f7..8ef9aa2 100644 --- a/main.c +++ b/main.c @@ -47,9 +47,9 @@ no_warn_end #include "ted.c" #include "ui.c" #include "node.c" +#include "menu.c" #include "command.c" #include "config.c" -#include "menu.c" static void die(char const *fmt, ...) { char buf[256] = {0}; diff --git a/menu.c b/menu.c index 415b547..df3c7a0 100644 --- a/menu.c +++ b/menu.c @@ -13,15 +13,29 @@ static void menu_open(Ted *ted, Menu menu) { ted->active_buffer = &ted->line_buffer; ted->file_selector.create_menu = true; break; + case MENU_WARN_UNSAVED: + assert(ted->warn_unsaved); + assert(*ted->warn_unsaved_names); + break; } } static void menu_close(Ted *ted, bool restore_prev_active_buffer) { - ted->menu = MENU_NONE; if (restore_prev_active_buffer) ted->active_buffer = ted->prev_active_buffer; ted->prev_active_buffer = NULL; - file_selector_free(&ted->file_selector); - buffer_clear(&ted->line_buffer); + switch (ted->menu) { + case MENU_NONE: assert(0); break; + case MENU_OPEN: + case MENU_SAVE_AS: + file_selector_free(&ted->file_selector); + buffer_clear(&ted->line_buffer); + break; + case MENU_WARN_UNSAVED: + ted->warn_unsaved = 0; + *ted->warn_unsaved_names = 0; + break; + } + ted->menu = MENU_NONE; } static void menu_escape(Ted *ted) { @@ -108,6 +122,37 @@ static void menu_update(Ted *ted, Menu menu) { free(selected_file); } } break; + case MENU_WARN_UNSAVED: + switch (popup_update(ted)) { + case POPUP_NONE: break; + case POPUP_YES: + // save changes + switch (ted->warn_unsaved) { + case CMD_TAB_CLOSE: + 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! + break; + default: + assert(0); + break; + } + break; + case POPUP_NO: { + // pass in an argument of 2 to override dialog + Command cmd = ted->warn_unsaved; + menu_close(ted, true); + command_execute(ted, cmd, 2); + } break; + case POPUP_CANCEL: + menu_close(ted, true); + break; + } + break; } } @@ -127,12 +172,19 @@ static void menu_render(Ted *ted, Menu menu) { if (*ted->warn_overwrite) { char const *path = ted->warn_overwrite; char const *filename = path_filename(path); - char title[32] = {0}, body[256] = {0}; + char title[64] = {0}, body[1024] = {0}; strbuf_printf(title, "Overwrite %s?", filename); strbuf_printf(body, "Are you sure you want to overwrite %s?", path); popup_render(ted, title, body); return; } + if (menu == MENU_WARN_UNSAVED) { + char title[64] = {0}, body[1024] = {0}; + strbuf_printf(title, "Save changes?"); + strbuf_printf(body, "Do you want to save your changes to %s?", ted->warn_unsaved_names); + popup_render(ted, title, body); + return; + } if (menu == MENU_OPEN || menu == MENU_SAVE_AS) { float padding = settings->padding; diff --git a/ted.c b/ted.c index bc34123..431768e 100644 --- a/ted.c +++ b/ted.c @@ -196,6 +196,3 @@ static bool ted_new_file(Ted *ted) { return false; } } - -static void menu_open(Ted *ted, Menu menu); -static void menu_escape(Ted *ted); diff --git a/ted.h b/ted.h index 6271a6d..74b5145 100644 --- a/ted.h +++ b/ted.h @@ -79,7 +79,8 @@ typedef struct { ENUM_U16 { MENU_NONE, MENU_OPEN, - MENU_SAVE_AS + MENU_SAVE_AS, + MENU_WARN_UNSAVED // warn about unsaved changes } ENUM_U16_END(Menu); // file entries for file selectors @@ -139,6 +140,8 @@ typedef struct Ted { KeyAction key_actions[KEY_COMBO_COUNT]; bool search_cwd; // should the working directory be searched for files? set to true if the executable isn't "installed" bool quit; // if set to true, the window will close next frame. NOTE: this doesn't check for unsaved changes!! + Command warn_unsaved; // if non-zero, the user is trying to execute this command, but there are unsaved changes + char warn_unsaved_names[TED_PATH_MAX]; // comma-separated list of files with unsaved changes (only applicable if warn_unsaved != 0) char warn_overwrite[TED_PATH_MAX]; // file name user is trying to overwrite char local_data_dir[TED_PATH_MAX]; char global_data_dir[TED_PATH_MAX]; @@ -151,3 +154,6 @@ typedef struct Ted { char error[512]; char error_shown[512]; // error display in box on screen } Ted; + +// forward declarations +void command_execute(Ted *ted, Command c, i64 argument); -- cgit v1.2.3