task

creates a plain-text task file in the current directory
git clone git://brookjeynes.dev/bjeynes/task.git
Log | Files | Refs | README | LICENSE

commit 32a1bea865af0764895473525f0a514d7eee640e
parent 131f2bc09460ed05dc105252e9282886275d459f
Author: brookjeynes <me@brookjeynes.dev>
Date:   Thu, 25 Jun 2026 07:17:13 +1000

refactor: move task creation to 'new' subcommand

Task-id: nrqnlxvtksoyytvz
Signed-off-by: brookjeynes <me@brookjeynes.dev>

Diffstat:
Mtask.c | 137+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Atasks/add_subcommands.txt | 9+++++++++
Atasks/consolidate_contexts_and_projects_into_properties_command.txt | 2++
3 files changed, 85 insertions(+), 63 deletions(-)

diff --git a/task.c b/task.c @@ -421,117 +421,81 @@ static void print_related_commits(char *task_id) { git_libgit2_shutdown(); } -int main(int argc, char *argv[]) { - struct options cli_args = {0}; - cli_args.priority = '\0'; - - if (argc > 1 && - (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) { - print_help(argv[0]); - return 0; - } - - if (argc > 1 && (strcmp(argv[1], "--contexts") == 0)) { - print_properties('@'); - return 0; - } - - if (argc > 1 && (strcmp(argv[1], "--projects") == 0)) { - print_properties('+'); - return 0; - } - - if (argc > 1 && (strcmp(argv[1], "--related-commits") == 0)) { - if (argc != 3) { - fprintf(stderr, "err: task id required\n"); - exit(1); - } - - if (strcmp(argv[2], "") == 0) { - fprintf(stderr, "err: task id can not be empty\n"); - exit(1); - } - - char *task_id = argv[2]; - print_related_commits(task_id); - - return 0; - } - +int new_command(int argc, char *argv[], struct options *cli_args) { if (argc == 1) { fprintf(stderr, "err: title required\n"); - exit(1); + return 1; } int positionals = 0; for (int idx = 1; idx < argc; idx++) { if (strcmp(argv[idx], "--priority") == 0 || strcmp(argv[idx], "-p") == 0) { - if (cli_args.priority != '\0') { + if (cli_args->priority != '\0') { fprintf(stderr, "err: priority specified multiple times\n"); - exit(1); + return 1; } if (idx + 1 == argc) { fprintf(stderr, "err: priority required\n"); - exit(1); + return 1; } if (strcmp(argv[idx + 1], "") == 0) { fprintf(stderr, "err: priority can not be empty\n"); - exit(1); + return 1; } if (strlen(argv[idx + 1]) != 1) { fprintf(stderr, "err: priority must be a single letter between [A-Z]\n"); - exit(1); + return 1; } - cli_args.priority = argv[idx + 1][0]; + cli_args->priority = argv[idx + 1][0]; idx++; continue; } if (strcmp(argv[idx], "") == 0) { fprintf(stderr, "err: argument can not be empty\n"); - exit(1); + return 1; } if (positionals == 0) { - cli_args.title = argv[idx]; + cli_args->title = argv[idx]; } positionals++; } - if (cli_args.title == NULL) { + if (cli_args->title == NULL) { fprintf(stderr, "err: title required\n"); - exit(1); + return 1; } - if (cli_args.priority != '\0') { - if (cli_args.priority < 'A' || cli_args.priority > 'Z') { + if (cli_args->priority != '\0') { + if (cli_args->priority < 'A' || cli_args->priority > 'Z') { fprintf(stderr, "err: priority must be between [A-Z]\n"); - exit(1); + return 1; } } - size_t title_len = strlen(cli_args.title); + size_t title_len = strlen(cli_args->title); if (title_len > 251) { fprintf(stderr, "err: title too long for file name\n"); - exit(1); + return 1; } char title_to_file[256]; int in_leading_dots = 1; for (size_t idx = 0; idx < title_len; idx++) { - if ((in_leading_dots && cli_args.title[idx] == '.') || - cli_args.title[idx] == ' ' || cli_args.title[idx] == '/' || - cli_args.title[idx] == '\\') { + if ((in_leading_dots && cli_args->title[idx] == '.') || + cli_args->title[idx] == ' ' || cli_args->title[idx] == '/' || + cli_args->title[idx] == '\\') { title_to_file[idx] = '_'; } else { in_leading_dots = 0; - title_to_file[idx] = cli_args.title[idx]; + title_to_file[idx] = cli_args->title[idx]; } } strcpy(title_to_file + title_len, ".txt"); @@ -545,19 +509,19 @@ int main(int argc, char *argv[]) { FILE *f = fopen(title_to_file, "wx"); if (f == NULL) { fprintf(stderr, "err: failed to open file: %s\n", strerror(errno)); - exit(1); + return 1; } int write_failed = 0; int write_errno = 0; - if (cli_args.priority != '\0') { - if (fprintf(f, "(%c) ", cli_args.priority) < 0) { + if (cli_args->priority != '\0') { + if (fprintf(f, "(%c) ", cli_args->priority) < 0) { write_failed = 1; write_errno = errno; } } - if (fprintf(f, "%s", cli_args.title) < 0) { + if (fprintf(f, "%s", cli_args->title) < 0) { if (!write_failed) { write_failed = 1; write_errno = errno; @@ -607,12 +571,12 @@ int main(int argc, char *argv[]) { if (write_failed) { fprintf(stderr, "err: failed to write file: %s\n", strerror(write_errno)); - exit(1); + return 1; } if (close_failed) { fprintf(stderr, "err: failed to close file: %s\n", strerror(close_errno)); - exit(1); + return 1; } char *editor = getenv("VISUAL"); @@ -635,5 +599,52 @@ int main(int argc, char *argv[]) { execlp("sh", "sh", "-c", "exec $1 \"$2\"", "task", editor, title_to_file, NULL); perror("err: failed to open editor"); + + return 0; +} + +int main(int argc, char *argv[]) { + struct options cli_args = {0}; + cli_args.priority = '\0'; + + if (argc > 1 && + (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) { + print_help(argv[0]); + return 0; + } + + if (argc > 1 && (strcmp(argv[1], "--contexts") == 0)) { + print_properties('@'); + return 0; + } + + if (argc > 1 && (strcmp(argv[1], "--projects") == 0)) { + print_properties('+'); + return 0; + } + + if (argc > 1 && (strcmp(argv[1], "--related-commits") == 0)) { + if (argc != 3) { + fprintf(stderr, "err: task id required\n"); + exit(1); + } + + if (strcmp(argv[2], "") == 0) { + fprintf(stderr, "err: task id can not be empty\n"); + exit(1); + } + + char *task_id = argv[2]; + print_related_commits(task_id); + + return 0; + } + + if (argc > 1 && strcmp(argv[1], "new") == 0) { + if (new_command(argc - 1, argv + 1, &cli_args) != 0) { + return 1; + } + } + return 1; } diff --git a/tasks/add_subcommands.txt b/tasks/add_subcommands.txt @@ -0,0 +1,9 @@ +add subcommands @feat +id: nrqnlxvtksoyytvz + +task doesnt have subcommands. this is a little painful when adding new features +as they are forced behind flags. + +[x] new +[ ] related-commits +[ ] contexts / projects diff --git a/tasks/consolidate_contexts_and_projects_into_properties_command.txt b/tasks/consolidate_contexts_and_projects_into_properties_command.txt @@ -0,0 +1,2 @@ +consolidate contexts and projects into properties command @feat +id: xwqnwoxwwtywnpry