82 lines
1.9 KiB
Python
82 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Todo.txt Manager - simple CLI todo list using todo.txt format."""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from typing import List
|
|
|
|
TODO_FILE = Path.home() / "todo.txt"
|
|
|
|
|
|
def read_todos() -> List[str]:
|
|
"""Read todos from file."""
|
|
if not TODO_FILE.exists():
|
|
return []
|
|
return TODO_FILE.read_text().strip().split('\n') if TODO_FILE.read_text().strip() else []
|
|
|
|
|
|
def write_todos(todos: List[str]) -> None:
|
|
"""Write todos to file."""
|
|
TODO_FILE.write_text('\n'.join(todos) + '\n')
|
|
|
|
|
|
def add_todo(task: str) -> None:
|
|
"""Add a new todo item."""
|
|
todos = read_todos()
|
|
todo = f"{datetime.now().strftime('%Y-%m-%d')} {task}"
|
|
todos.append(todo)
|
|
write_todos(todos)
|
|
print(f"Added: {todo}")
|
|
|
|
|
|
def list_todos() -> None:
|
|
"""List all todos."""
|
|
todos = read_todos()
|
|
if not todos:
|
|
print("No todos!")
|
|
return
|
|
|
|
for i, todo in enumerate(todos, 1):
|
|
print(f"{i}. {todo}")
|
|
|
|
|
|
def done_todo(index: int) -> None:
|
|
"""Mark todo as done (remove it)."""
|
|
todos = read_todos()
|
|
if 1 <= index <= len(todos):
|
|
removed = todos.pop(index - 1)
|
|
write_todos(todos)
|
|
print(f"Done: {removed}")
|
|
else:
|
|
print(f"Invalid index: {index}")
|
|
|
|
|
|
def clear_todos() -> None:
|
|
"""Clear all todos."""
|
|
write_todos([])
|
|
print("All todos cleared.")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
list_todos()
|
|
return
|
|
|
|
cmd, args = sys.argv[1], sys.argv[2:]
|
|
|
|
if cmd == "add" and args:
|
|
add_todo(' '.join(args))
|
|
elif cmd == "list":
|
|
list_todos()
|
|
elif cmd == "done" and args:
|
|
done_todo(int(args[0]))
|
|
elif cmd == "clear":
|
|
clear_todos()
|
|
else:
|
|
print(f"Usage: {sys.argv[0]} [add <task>|list|done <num>|clear]")
|
|
print("Simple TODO manager using todo.txt format at ~/todo.txt")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |