From 5aec5408950ed41fad203e749bda225bd3f86a8b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 16 Jul 2014 23:22:36 +0200 Subject: Allow for merging data files when reloading This allows for merging the (unsaved) items with the items from the data files when invoking the reload operation. To this end, an external merge tool (defaults to vimdiff) is used. Signed-off-by: Lukas Fleischer --- src/args.c | 4 ++-- src/calcurse.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/calcurse.h | 13 +++++++++---- src/io.c | 22 ++++++++++++++++------ src/vars.c | 7 ++++++- src/wins.c | 16 ++++++++++++++++ 6 files changed, 97 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/args.c b/src/args.c index 8b62cb8..8a9aa49 100644 --- a/src/args.c +++ b/src/args.c @@ -707,8 +707,8 @@ int parse_args(int argc, char **argv) io_load_app(); io_load_todo(); io_import_data(IO_IMPORT_ICAL, ifile); - io_save_apts(); - io_save_todo(); + io_save_apts(path_apts); + io_save_todo(path_todo); non_interactive = 1; } if (xflag) { diff --git a/src/calcurse.c b/src/calcurse.c index 149d7bb..cfe8298 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -256,11 +256,54 @@ static inline void key_generic_save(void) static inline void key_generic_reload(void) { - if (io_get_modified() && status_ask_bool(_("By reloading items, you " - "will lose any unsaved modifications. " - "Continue?")) != 1) { - wins_update(FLAG_STA); - return; + if (io_get_modified()) { + const char *msg_um_prefix = + _("There are unsaved modifications:"); + const char *msg_um_discard = _("(d)iscard"); + const char *msg_um_merge = _("(m)erge"); + const char *msg_um_keep = _("(k)eep and cancel"); + const char *msg_um_choice = _("[dmk]"); + + char msg_um_asktype[BUFSIZ]; + snprintf(msg_um_asktype, BUFSIZ, "%s %s, %s, %s", + msg_um_prefix, msg_um_discard, msg_um_merge, + msg_um_keep); + + char *path_apts_backup, *path_todo_backup; + const char *backup_ext = ".sav"; + + switch (status_ask_choice(msg_um_asktype, msg_um_choice, 3)) { + case 1: + break; + case 2: + path_apts_backup = xmalloc(strlen(path_apts) + + strlen(backup_ext) + 1); + path_todo_backup = xmalloc(strlen(path_todo) + + strlen(backup_ext) + 1); + sprintf(path_apts_backup, "%s%s", path_apts, + backup_ext); + sprintf(path_todo_backup, "%s%s", path_todo, + backup_ext); + + io_save_mutex_lock(); + io_save_apts(path_apts_backup); + io_save_todo(path_todo_backup); + io_save_mutex_unlock(); + + wins_launch_external2(path_apts, path_apts_backup, + conf.mergetool); + wins_launch_external2(path_todo, path_todo_backup, + conf.mergetool); + + xfree(path_apts_backup); + xfree(path_todo_backup); + break; + case 3: + /* FALLTHROUGH */ + default: + wins_update(FLAG_STA); + return; + } } /* Reinitialize data structures. */ diff --git a/src/calcurse.h b/src/calcurse.h index ca85690..a1cf9bb 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -103,8 +103,9 @@ #define DPID_PATH DIR_NAME DPID_PATH_NAME #define NOTES_DIR DIR_NAME NOTES_DIR_NAME -#define DEFAULT_EDITOR "vi" -#define DEFAULT_PAGER "less" +#define DEFAULT_EDITOR "vi" +#define DEFAULT_PAGER "less" +#define DEFAULT_MERGETOOL "vimdiff" #define ATTR_FALSE 0 #define ATTR_TRUE 1 @@ -259,6 +260,7 @@ struct conf { unsigned progress_bar; const char *editor; const char *pager; + const char *mergetool; char output_datefmt[BUFSIZ]; /* format for displaying date */ int input_datefmt; /* format for reading date */ }; @@ -753,8 +755,10 @@ void ical_export_data(FILE *); unsigned io_fprintln(const char *, const char *, ...); void io_init(const char *, const char *); void io_extract_data(char *, const char *, int); -unsigned io_save_apts(void); -unsigned io_save_todo(void); +void io_save_mutex_lock(void); +void io_save_mutex_unlock(void); +unsigned io_save_apts(const char *); +unsigned io_save_todo(const char *); unsigned io_save_keys(void); void io_save_cal(enum save_display); void io_load_app(void); @@ -1121,6 +1125,7 @@ void wins_reset(void); void wins_prepare_external(void); void wins_unprepare_external(void); void wins_launch_external(const char *, const char *); +void wins_launch_external2(const char *, const char *, const char *); void wins_status_bar(void); void wins_erase_status_bar(void); void wins_other_status_page(int); diff --git a/src/io.c b/src/io.c index acf624b..f24b0f7 100644 --- a/src/io.c +++ b/src/io.c @@ -319,12 +319,22 @@ void io_extract_data(char *dst_data, const char *org, int len) static pthread_mutex_t io_save_mutex = PTHREAD_MUTEX_INITIALIZER; +void io_save_mutex_lock(void) +{ + pthread_mutex_lock(&io_save_mutex); +} + +void io_save_mutex_unlock(void) +{ + pthread_mutex_unlock(&io_save_mutex); +} + /* * Save the apts data file, which contains the * appointments first, and then the events. * Recursive items are written first. */ -unsigned io_save_apts(void) +unsigned io_save_apts(const char *aptsfile) { llist_item_t *i; FILE *fp; @@ -332,7 +342,7 @@ unsigned io_save_apts(void) if (read_only) return 1; - if ((fp = fopen(path_apts, "w")) == NULL) + if ((fp = fopen(aptsfile, "w")) == NULL) return 0; recur_save_data(fp); @@ -356,7 +366,7 @@ unsigned io_save_apts(void) } /* Save the todo data file. */ -unsigned io_save_todo(void) +unsigned io_save_todo(const char *todofile) { llist_item_t *i; FILE *fp; @@ -364,7 +374,7 @@ unsigned io_save_todo(void) if (read_only) return 1; - if ((fp = fopen(path_todo, "w")) == NULL) + if ((fp = fopen(todofile, "w")) == NULL) return 0; LLIST_FOREACH(&todolist, i) { @@ -419,12 +429,12 @@ void io_save_cal(enum save_display display) if (show_bar) progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_TODO); - if (!io_save_todo()) + if (!io_save_todo(path_todo)) ERROR_MSG("%s", access_pb); if (show_bar) progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_APTS); - if (!io_save_apts()) + if (!io_save_apts(path_apts)) ERROR_MSG("%s", access_pb); if (show_bar) diff --git a/src/vars.c b/src/vars.c index 52a1ed2..16b892a 100644 --- a/src/vars.c +++ b/src/vars.c @@ -126,7 +126,7 @@ struct dmon_conf dmon; */ void vars_init(void) { - const char *ed, *pg; + const char *ed, *pg, *mt; /* Variables for user configuration */ conf.confirm_quit = 1; @@ -159,6 +159,11 @@ void vars_init(void) pg = DEFAULT_PAGER; conf.pager = pg; + mt = getenv("MERGETOOL"); + if (mt == NULL || mt[0] == '\0') + mt = DEFAULT_MERGETOOL; + conf.mergetool = mt; + wins_set_layout(1); ui_calendar_set_first_day_of_week(MONDAY); diff --git a/src/wins.c b/src/wins.c index d4b93d5..7545a59 100644 --- a/src/wins.c +++ b/src/wins.c @@ -611,6 +611,22 @@ void wins_launch_external(const char *file, const char *cmd) wins_unprepare_external(); } +/* + * While inside interactive mode, launch the external command cmd on the given + * two files. + */ +void wins_launch_external2(const char *file1, const char *file2, + const char *cmd) +{ + const char *arg[] = { cmd, file1, file2, NULL }; + int pid; + + wins_prepare_external(); + if ((pid = shell_exec(NULL, NULL, *arg, arg))) + child_wait(NULL, NULL, pid); + wins_unprepare_external(); +} + #define NB_CAL_CMDS 28 /* number of commands while in cal view */ #define NB_APP_CMDS 33 /* same thing while in appointment view */ #define NB_TOD_CMDS 32 /* same thing while in todo view */ -- cgit v1.2.3