Compare commits
2 commits
5a737d418d
...
030baf137e
| Author | SHA1 | Date | |
|---|---|---|---|
| 030baf137e | |||
| c9fdf7b839 |
2 changed files with 155 additions and 0 deletions
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Ajal Todo CLI
|
||||
|
||||
A todo utility
|
||||
152
todo.py
Executable file
152
todo.py
Executable file
|
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
todo_file = os.path.join(base_dir, "todo.md")
|
||||
|
||||
|
||||
def add_task(task: str, parent=None):
|
||||
todo = parse_todo()
|
||||
if parent and parent not in todo:
|
||||
print(f"Could not find parent task '{parent}' in root task list")
|
||||
exit(1)
|
||||
|
||||
print(f"Adding task '{task}' to '{parent if parent else 'root'}'")
|
||||
if parent:
|
||||
todo[parent]["sub_tasks"][task] = {"completed": False}
|
||||
else:
|
||||
todo[task] = {"completed": False, "sub_tasks": {}}
|
||||
write_todo(todo)
|
||||
|
||||
|
||||
def list_tasks(parent=None):
|
||||
todo = parse_todo()
|
||||
if parent and parent not in todo:
|
||||
print(f"Could not find parent task '{parent}' in root task list")
|
||||
exit(1)
|
||||
|
||||
print(f"Listing tasks in '{parent if parent else 'root'}'")
|
||||
if parent:
|
||||
todo = {parent: todo[parent]}
|
||||
print(build_todo(todo))
|
||||
|
||||
|
||||
def complete_task(task, parent=None):
|
||||
todo = parse_todo()
|
||||
if parent:
|
||||
if parent not in todo:
|
||||
print(f"Could not find parent task '{parent}' in root task list")
|
||||
exit(1)
|
||||
if task not in todo[parent]["sub_tasks"]:
|
||||
print(f"Could not find task '{task}' in parent task '{parent}'")
|
||||
exit(1)
|
||||
if task not in todo:
|
||||
print(f"Could not find task '{task}' in root task list")
|
||||
exit(1)
|
||||
|
||||
print(f"Marking task '{task}' in '{parent if parent else 'root'}' as completed")
|
||||
if parent:
|
||||
task = todo[parent]["sub_tasks"][task]
|
||||
else:
|
||||
task = todo[task]
|
||||
task["completed"] = True
|
||||
write_todo(todo)
|
||||
|
||||
|
||||
def remove_task(task, parent=None):
|
||||
todo = parse_todo()
|
||||
if parent:
|
||||
if parent not in todo:
|
||||
print(f"Could not find parent task '{parent}' in root task list")
|
||||
exit(1)
|
||||
if task not in todo[parent]["sub_tasks"]:
|
||||
print(f"Could not find task '{task}' in parent task '{parent}'")
|
||||
exit(1)
|
||||
if task not in todo:
|
||||
print(f"Could not find task '{task}' in root task list")
|
||||
exit(1)
|
||||
|
||||
print(f"Removing task '{task}' from '{parent if parent else 'root'}'")
|
||||
if parent:
|
||||
del todo[parent]["sub_tasks"][task]
|
||||
else:
|
||||
del todo[task]
|
||||
write_todo(todo)
|
||||
|
||||
|
||||
def print_help():
|
||||
print("""Usage: todo.py [add|complete|remove] TASK [PARENT]
|
||||
todo.py list [PARENT]
|
||||
|
||||
Manages todo.md file as a ToDo file""")
|
||||
|
||||
|
||||
def parse_todo() -> dict[str, dict]:
|
||||
todo = {}
|
||||
with open(todo_file, "r") as f:
|
||||
lines = f.readlines()
|
||||
root_task = None
|
||||
for line in lines:
|
||||
if matches := re.match(r"^-\s+(\[(?P<status>[x ])]\s+)?(?P<task>.*)$", line.rstrip()):
|
||||
root_task_name = matches.group("task")
|
||||
root_task = {
|
||||
"completed": matches.group("status") == "x",
|
||||
"sub_tasks": {},
|
||||
}
|
||||
todo[root_task_name] = root_task
|
||||
elif matches := re.match(r"^\s+-\s+(\[(?P<status>[x ])]\s+)?(?P<task>.*)$", line.rstrip()):
|
||||
leaf_task = matches.group("task")
|
||||
root_task["sub_tasks"][leaf_task] = {
|
||||
"completed": matches.group("status") == "x",
|
||||
}
|
||||
return todo
|
||||
|
||||
|
||||
def build_todo(todo: dict[str, dict]) -> str:
|
||||
lines = ["# A ToDo list", ""]
|
||||
for task, task_data in todo.items(): # type: str, dict
|
||||
lines.append(f"- [{'x' if task_data["completed"] else ' '}] {task}")
|
||||
for leaf_task, leaf_task_data in task_data["sub_tasks"].items():
|
||||
lines.append(f" - [{'x' if leaf_task_data["completed"] else ' '}] {leaf_task}")
|
||||
lines += [""]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def write_todo(todo: dict[str, dict]):
|
||||
with open(todo_file, "w") as f:
|
||||
f.write(build_todo(todo))
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print_help()
|
||||
exit(1)
|
||||
|
||||
match sys.argv[1]:
|
||||
case "help" | "--help" | "h" | "-h":
|
||||
print_help()
|
||||
case "list":
|
||||
match sys.argv[2:]:
|
||||
case [parent, *_]:
|
||||
list_tasks(parent)
|
||||
case _:
|
||||
list_tasks()
|
||||
case "add" | "complete" | "remove" as task_name:
|
||||
task_func = f"{task_name}_task"
|
||||
match sys.argv[2:]:
|
||||
case [task]:
|
||||
globals()[task_func](task)
|
||||
case [parent, task, *_]:
|
||||
globals()[task_func](task, parent)
|
||||
case _:
|
||||
print_help()
|
||||
exit(1)
|
||||
case _:
|
||||
print_help()
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Reference in a new issue