quill: add tiny todo.py CLI artifact
This commit is contained in:
1 parent
c6120501b4
commit
f30ea760c3
2 files changed
+111
No files matched your search
@@ -0,0 +1,20 @@
|
||||
# todo.py
|
||||
|
||||
Tiny CLI todo tracker. State is stored in `~/.todo.json`.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
python todo.py add "buy milk"
|
||||
python todo.py list
|
||||
python todo.py all
|
||||
python todo.py done 1
|
||||
python todo.py done
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
- `add <text>` — append a task
|
||||
- `list` — show open tasks
|
||||
- `all` — show every task
|
||||
- `done [id]` — without id: show completed; with id: mark task done
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/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")
|
||||
sub.add_parser("done", help="show done only")
|
||||
d = sub.add_parser("done")
|
||||
d.add_argument("id", type=int, 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 hasattr(args, "id"):
|
||||
cmd_done(args)
|
||||
else:
|
||||
cmd_list(args)
|
||||
else:
|
||||
p.print_help()
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user