use anyhow::Result; use colored::Colorize; use crate::cli::{AddArgs, Command, DoneArgs, EditArgs, ListArgs, RemoveArgs}; use crate::db::{self, ListFilters, Pool}; use crate::display::{print_todo, print_todo_list}; pub struct Ctx<'a> { pub pool: &'a Pool, } pub async fn run(cmd: Command, ctx: &Ctx<'_>) -> Result<()> { match cmd { Command::Add(args) => add(ctx, args).await, Command::List(args) => list(ctx, args).await, Command::Done(args) => done(ctx, args).await, Command::Edit(args) => edit(ctx, args).await, Command::Remove(args) => remove(ctx, args).await, Command::Tags => tags(ctx).await, Command::Purge => purge(ctx).await, Command::McpServe => crate::mcp::serve(ctx.pool).await, } } async fn add(ctx: &Ctx<'_>, args: AddArgs) -> Result<()> { let project = if args.no_project { None } else { db::detect_project() }; let todo = db::insert_todo(ctx.pool, &args.text, &args.priority, project.as_deref(), &args.tag) .await?; print!("{} ", "added:".green().bold()); print_todo(&todo); Ok(()) } async fn list(ctx: &Ctx<'_>, args: ListArgs) -> Result<()> { let project = if args.here { db::detect_project() } else { None }; let todos = db::list_todos( ctx.pool, ListFilters { tags: &args.tag, priority: args.priority.as_ref(), search: args.search.as_deref(), project: project.as_deref(), include_done: args.all, }, ) .await?; if args.json { println!("{}", serde_json::to_string(&todos)?); } else { print_todo_list(&todos); } Ok(()) } async fn done(ctx: &Ctx<'_>, args: DoneArgs) -> Result<()> { for id in args.id { let todo = db::complete_todo(ctx.pool, id).await?; print!("{} ", "done:".green().bold()); print_todo(&todo); } Ok(()) } async fn tags(ctx: &Ctx<'_>) -> Result<()> { let tags = db::list_tags(ctx.pool).await?; if tags.is_empty() { println!("{}", "no tags".dimmed()); } else { for tag in &tags { println!(" {}", format!("#{tag}").blue()); } } Ok(()) } async fn edit(ctx: &Ctx<'_>, args: EditArgs) -> Result<()> { let todo = db::update_todo( ctx.pool, args.id, args.text.as_deref(), args.priority.as_ref(), &args.tag, &args.untag, ) .await?; print!("{} ", "edited:".green().bold()); print_todo(&todo); Ok(()) } async fn remove(ctx: &Ctx<'_>, args: RemoveArgs) -> Result<()> { let todo = db::delete_todo(ctx.pool, args.id).await?; print!("{} ", "removed:".red().bold()); print_todo(&todo); Ok(()) } async fn purge(ctx: &Ctx<'_>) -> Result<()> { let count = db::purge_completed(ctx.pool).await?; println!("{}", format!("purged {count} completed todo(s)").dimmed()); Ok(()) }