diff options
| author | hachem <im@hachem.wtf> | 2026-09-29 22:30:40 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-29 22:30:40 +0200 |
| commit | e75e6312b3d75238fdbe24787f4fcce0f17f8574 (patch) | |
| tree | 17c4971248aec9121e098016f8d11fd2679d9044 | |
| parent | 53df19a1244eef75e3e01fd2c3a643d95c4a5b06 (diff) | |
fix: bugs
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | todo.c | 103 |
2 files changed, 103 insertions, 6 deletions
@@ -30,6 +30,7 @@ SRC := todo.c PREFIX ?= /usr/local bindir := $(DESTDIR)$(PREFIX)/bin +mandir := $(DESTDIR)$(PREFIX)/share/man/man1 all: $(TARGET) @@ -39,12 +40,15 @@ $(TARGET): $(SRC) clean: rm -rf $(TARGET) $(TARGET).dSYM -install: +install: todo.1 make DEBUG=0 SANITIZE=0 clean all install -d $(bindir) install -m 755 $(TARGET) $(bindir)/$(TARGET) + install -d $(mandir) + install -m 644 todo.1 $(mandir)/todo.1 uninstall: rm -f $(bindir)/$(TARGET) + rm -f $(mandir)/todo.1 .PHONY: all clean install uninstall @@ -44,7 +44,15 @@ enum Mode MODE_NORMAL, MODE_INSERT, MODE_COMMAND, - MODE_SEARCH + MODE_SEARCH, + MODE_CONFIRM +}; + +enum Pending +{ + PENDING_NONE, + PENDING_RESET, + PENDING_CLEAR }; enum Key @@ -63,6 +71,7 @@ static const char* mode_name(enum Mode mode) case MODE_INSERT: return "INSERT"; case MODE_COMMAND: return "COMMAND"; case MODE_SEARCH: return "SEARCH"; + case MODE_CONFIRM: return "CONFIRM"; } return "?"; @@ -388,6 +397,8 @@ static void insert_item(struct List* list, int index); static struct Item yank_register; static int yank_full; +static enum Pending pending_action; + static void paste_item(struct List* list, int index, int* cursor) { if (list->count >= MAX_ITEMS || !yank_full) @@ -691,7 +702,7 @@ static void render(const struct List* list, int cursor, int scroll, enum Mode mo if (is_subtask(item)) { - int indent = base_indent + SUBTASK_INDENT; + int indent = base_indent + number_width + SUBTASK_INDENT; const char* name = item->text; if (!(mode == MODE_INSERT && index == cursor)) @@ -734,6 +745,11 @@ static void render(const struct List* list, int cursor, int scroll, enum Mode mo length += snprintf(buffer + length, sizeof buffer - (size_t) length, "\x1b[%d;1H%*s%c%s\x1b[K", rows, LEFT_MARGIN, "", mode == MODE_SEARCH ? '/' : ':', command); + else if (mode == MODE_CONFIRM) + length += snprintf(buffer + length, sizeof buffer - (size_t) length, + "\x1b[%d;1H%*s%s [y/n]\x1b[K", + rows, LEFT_MARGIN, "", + pending_action == PENDING_CLEAR ? "clear the whole list?" : "reset all items to todo?"); else length += snprintf(buffer + length, sizeof buffer - (size_t) length, "\x1b[%d;1H%*s\x1b[2m[%s] %d/%d done\x1b[0m\x1b[K", @@ -746,7 +762,7 @@ static void render(const struct List* list, int cursor, int scroll, enum Mode mo length += snprintf(buffer + length, sizeof buffer - (size_t) length, "\x1b[%d;%dH\x1b[6 q\x1b[?25h", rows, cursor_column); } - else if (cursor >= 0 && cursor < list->count) + else if (mode != MODE_CONFIRM && cursor >= 0 && cursor < list->count) { int rows_before = 0; @@ -780,7 +796,7 @@ static void render(const struct List* list, int cursor, int scroll, enum Mode mo int text_start; if (is_subtask(&list->items[cursor])) - text_start = base_indent + SUBTASK_INDENT + 5; + text_start = base_indent + number_width + SUBTASK_INDENT + 5; else text_start = base_indent + number_width + 7; @@ -1291,6 +1307,14 @@ static int command_key(struct List* list, const char* path, enum Mode* mode, cha if (key == '\r' || key == '\n') { + if (strcmp(command, "reset") == 0 || strcmp(command, "clear") == 0) + { + pending_action = strcmp(command, "clear") == 0 ? PENDING_CLEAR : PENDING_RESET; + command[0] = '\0'; + *mode = MODE_CONFIRM; + return 1; + } + int write = strchr(command, 'w') != NULL || strcmp(command, "x") == 0; int quit = strchr(command, 'q') != NULL || strcmp(command, "x") == 0; @@ -1368,6 +1392,30 @@ static void search_key(const struct List* list, int* cursor, enum Mode* mode, ch } } +static void confirm_key(struct List* list, enum Mode* mode, int key) +{ + if (key == 'y' || key == 'Y') + { + history_record(list); + + if (pending_action == PENDING_RESET) + { + for (int i = 0; i < list->count; i++) + if (!is_section(&list->items[i])) + list->items[i].state = STATE_TODO; + } + else if (pending_action == PENDING_CLEAR) + { + list->count = 0; + } + + commit(list); + } + + pending_action = PENDING_NONE; + *mode = MODE_NORMAL; +} + static void run(struct List* list, const char* path) { if (enter_raw_mode() != 0) @@ -1449,12 +1497,57 @@ static void run(struct List* list, const char* path) case MODE_SEARCH: search_key(list, &cursor, &mode, command, search, key); break; + + case MODE_CONFIRM: + confirm_key(list, &mode, key); + break; } } } -int main(void) +static void print_version(void) +{ + (void) printf("%s %s\n", TODO_PROGRAM, TODO_VERSION); +} + +static void print_help(void) { + (void) printf( + "%s %s - a little modal todo list\n" + "\n" + "usage: %s open the list ($TODO_FILE, or ~/.todo.txt)\n" + " %s -h | --help\n" + " %s -v | --version\n" + "\n" + "keys:\n" + " h j k l / arrows move w / b words { / } sections\n" + " gg / G top/bottom o new item i insert at cursor\n" + " A append text R replace text 3j 2dd counts\n" + " x toggle done space cycle state\n" + " dd cut item D clear done yy p P yank/paste\n" + " J / K move item or section / n N search u ctrl-r undo/redo\n" + " :w :q :wq :x write / quit :reset all back to todo :clear empty\n" + "\n" + "items: '= name' section, '== name' subsection, '- name' subtask, else a task.\n" + "\n" + "by hachem <im@hachem.wtf>\n", + TODO_PROGRAM, TODO_VERSION, TODO_PROGRAM, TODO_PROGRAM, TODO_PROGRAM); +} + +int main(int argc, char** argv) +{ + if (argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) + { + print_help(); + return EXIT_SUCCESS; + } + + if (argc >= 2 && (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0)) + { + print_version(); + return EXIT_SUCCESS; + } + (void) setlocale(LC_ALL, ""); char path[4096]; |
