diff options
Diffstat (limited to 'todo.c')
| -rw-r--r-- | todo.c | 110 |
1 files changed, 99 insertions, 11 deletions
@@ -18,6 +18,20 @@ #define TODO_PROGRAM "todo" #define TODO_VERSION "0.1.0" +#define MAX_ITEMS 4096 +#define MAX_TEXT 256 +#define MAX_COMMAND 64 +#define MAX_HISTORY 64 + +_Static_assert(MAX_ITEMS >= 1, "MAX_ITEMS must be positive"); +_Static_assert(MAX_TEXT >= 16, "MAX_TEXT too small"); +_Static_assert(MAX_COMMAND >= 8, "MAX_COMMAND too small"); +_Static_assert(MAX_HISTORY >= 1, "MAX_HISTORY must be positive"); +_Static_assert(LEFT_MARGIN >= 0, "LEFT_MARGIN must be non-negative"); +_Static_assert(SECTION_INDENT >= 0, "SECTION_INDENT must be non-negative"); +_Static_assert(SUBTASK_INDENT >= 0, "SUBTASK_INDENT must be non-negative"); +_Static_assert(WRAP_COLUMN > LEFT_MARGIN + SUBTASK_INDENT + 8, "WRAP_COLUMN too small for the indents"); + #define CLEAR_EOL "\x1b[K" #define CURSOR_HOME "\x1b[H" #define CURSOR_SHOW "\x1b[?25h" @@ -583,35 +597,56 @@ static int archive_done(struct List* list, const char* path) if (file == NULL) return -1; + bool ok = true; int archived = 0; - int kept = 0; - int i = 0; - while (i < list->count) + for (int i = 0; i < list->count; ) { int end = item_block_end(list, i); - bool drop = is_task(&list->items[i]) && list->items[i].state == STATE_DONE; - if (drop) + if (is_task(&list->items[i]) && list->items[i].state == STATE_DONE) for (int j = i; j < end; j++) { const struct Item* it = &list->items[j]; + int written; if (is_section(it) || is_note(it)) - (void) fprintf(file, "%s\n", it->text); + written = fprintf(file, "%s\n", it->text); else - (void) fprintf(file, "[%c] %s\n", state_char(it->state), it->text); + written = fprintf(file, "[%c] %s\n", state_char(it->state), it->text); + + if (written < 0) + ok = false; archived++; } - else + + i = end; + } + + if (ok && fflush(file) != 0) + ok = false; + + (void) fsync(fileno(file)); + + if (fclose(file) != 0) + ok = false; + + if (!ok) + return -1; + + int kept = 0; + for (int i = 0; i < list->count; ) + { + int end = item_block_end(list, i); + + if (!(is_task(&list->items[i]) && list->items[i].state == STATE_DONE)) for (int j = i; j < end; j++) list->items[kept++] = list->items[j]; i = end; } - (void) fclose(file); list->count = kept; return archived; } @@ -632,7 +667,10 @@ static int save(struct List* list, const char* path) { normalize_tasks(list); - FILE* file = fopen(path, "w"); + char tmp[4096]; + (void) snprintf(tmp, sizeof tmp, "%s.tmp", path); + + FILE* file = fopen(tmp, "w"); if (file == NULL) return -1; @@ -651,11 +689,22 @@ static int save(struct List* list, const char* path) ok = false; } + if (ok && fflush(file) != 0) + ok = false; + + (void) fsync(fileno(file)); + if (fclose(file) != 0) ok = false; + if (ok && rename(tmp, path) != 0) + ok = false; + if (!ok) + { + (void) remove(tmp); return -1; + } dirty = false; return 0; @@ -667,6 +716,42 @@ static void commit(struct List* list) sort_list(list); } +static void apply_prose(struct List* list, int skip) +{ + if (!PROSE) + return; + + for (int i = 0; i < list->count; i++) + { + if (i == skip) + continue; + + struct Item* item = &list->items[i]; + int len = (int) strlen(item->text); + + for (int c = 0; c < len; c++) + { + if (item->text[c] >= 'a' && item->text[c] <= 'z') + { + item->text[c] = (char) (item->text[c] - 32); + break; + } + if (item->text[c] >= 'A' && item->text[c] <= 'Z') + break; + } + + if (is_section(item) || is_important(item) || len == 0) + continue; + + char last = item->text[len - 1]; + if (last != '.' && last != '!' && last != '?' && len + 1 < (int) sizeof item->text) + { + item->text[len] = '.'; + item->text[len + 1] = '\0'; + } + } +} + struct Snapshot { struct Item* items; @@ -896,7 +981,8 @@ static void restore_terminal(void) static void on_signal(int signal_number) { (void) signal_number; - exit(EXIT_SUCCESS); + restore_terminal(); + _exit(EXIT_SUCCESS); } static int enter_raw_mode(void) @@ -2988,6 +3074,8 @@ static void run(struct List* list, const char* path) for (;;) { + apply_prose(list, is_editing(editor.mode) ? editor.cursor : -1); + if (editor.cursor >= list->count) editor.cursor = list->count - 1; if (editor.cursor < 0) |
