Files
troupe-standup/wizard-work/quill/todo.py
T

92 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""Tiny CLI todo tracker. Data lives in ~/.todo.json."""
import argparse
import json
import os
from datetime import datetime, timezone
DEFAULT_PATH = os.path.expanduser("~/.todo.json")
def load(path=DEFAULT_PATH):
if not os.path.exists(path):
return []
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
def save(items, path=DEFAULT_PATH):
with open(path, "w", encoding="utf-8") as f:
json.dump(items, f, indent=2)
def cmd_add(args):
items = load()
entry = {
"id": max((i.get("id", 0) for i in items), default=0) + 1,
"task": args.task,
"done": False,
"created": datetime.now(timezone.utc).isoformat(),
}
items.append(entry)
save(items)
print(f"added {entry['id']}: {args.task}")
def cmd_list(args):
items = load()
if args.done_only:
items = [i for i in items if i.get("done")]
elif not args.all:
items = [i for i in items if not i.get("done")]
for i in items:
status = "x" if i.get("done") else " "
print(f"[{status}] {i['id']}: {i['task']}")
if not items:
print("(none)")
def cmd_done(args):
items = load()
for i in items:
if i.get("id") == args.id:
i["done"] = True
i["finished"] = datetime.now(timezone.utc).isoformat()
save(items)
print(f"done {i['id']}")
return
print(f"id {args.id} not found", flush=True)
raise SystemExit(2)
def main():
p = argparse.ArgumentParser(description="Tiny todo CLI")
sub = p.add_subparsers(dest="cmd")
a = sub.add_parser("add")
a.add_argument("task", help="task text")
sub.add_parser("list", help="show todos")
sub.add_parser("all", help="show all including done")
d = sub.add_parser("done", help="show done only or mark todo done by id")
d.add_argument("id", type=int, nargs="?", help="todo id to mark done")
args = p.parse_args()
if args.cmd == "add":
cmd_add(args)
elif args.cmd == "list":
cmd_list(args)
elif args.cmd == "all":
cmd_list(args)
elif args.cmd == "done":
if args.id is not None:
cmd_done(args)
else:
args.done_only = True
cmd_list(args)
else:
p.print_help()
raise SystemExit(1)
if __name__ == "__main__":
main()