tasks-cli-rs 0.1.1

Markdown-based TODO task management CLI: each task is a Markdown file with YAML front matter
use std::path::PathBuf;

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "tasks", version, about = "Markdown-based TODO task management CLI")]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Subcommand)]
pub enum Command {
    /// Show version and config info
    Info,
    /// Manage task libraries
    Lib {
        #[command(subcommand)]
        command: LibCommand,
    },
    /// Create a new task
    New {
        title: String,
        /// Priority: low | medium | high | urgent
        #[arg(short, long)]
        priority: Option<String>,
        /// Tags (repeatable)
        #[arg(short, long = "tag")]
        tags: Vec<String>,
        /// Due date (YYYY-MM-DD)
        #[arg(short, long)]
        due: Option<String>,
        /// Subdirectory inside the library to place the task in
        #[arg(long)]
        dir: Option<String>,
    },
    /// List tasks in the active library
    List {
        /// Only list tasks under this subdirectory
        #[arg(long)]
        dir: Option<String>,
        /// Filter by status
        #[arg(short, long)]
        status: Option<String>,
        /// Filter by tag
        #[arg(short, long)]
        tag: Option<String>,
        /// Filter by priority
        #[arg(short, long)]
        priority: Option<String>,
        /// Due on or before this date (YYYY-MM-DD)
        #[arg(long)]
        due_before: Option<String>,
        /// Due on or after this date (YYYY-MM-DD)
        #[arg(long)]
        due_after: Option<String>,
    },
    /// Search tasks by text in title and body
    Search {
        query: String,
        /// Filter by status
        #[arg(short, long)]
        status: Option<String>,
        /// Filter by tag
        #[arg(short, long)]
        tag: Option<String>,
    },
    /// Manage tags
    Tag {
        #[command(subcommand)]
        command: TagCommand,
    },
    /// Show task details
    Show { id: String },
    /// Delete a task
    Delete {
        id: String,
        /// Skip confirmation
        #[arg(short, long)]
        force: bool,
    },
    /// Mark a task as started (in_progress)
    Start { id: String },
    /// Mark a task as done
    Done { id: String },
    /// Cancel a task
    Cancel { id: String },
    /// Set an arbitrary status: todo | in_progress | blocked | in_review | done | cancelled
    Status { id: String, status: String },
    /// Modify task fields
    Set {
        id: String,
        #[arg(long)]
        title: Option<String>,
        /// Priority: low | medium | high | urgent
        #[arg(long)]
        priority: Option<String>,
        /// Due date (YYYY-MM-DD); pass "none" to clear
        #[arg(long)]
        due: Option<String>,
        /// Add a tag (repeatable)
        #[arg(long = "tag-add")]
        tag_add: Vec<String>,
        /// Remove a tag (repeatable)
        #[arg(long = "tag-remove")]
        tag_remove: Vec<String>,
    },
    /// Open a task file (or the library root with --lib) in an editor
    Edit {
        /// Task id; omit when using --lib
        id: Option<String>,
        /// Editor command to use
        #[arg(long)]
        editor: Option<String>,
        /// Open the library root directory instead of a task
        #[arg(long = "lib")]
        lib: bool,
    },
}

#[derive(Subcommand)]
pub enum TagCommand {
    /// Add tags to a task
    Add {
        id: String,
        #[arg(required = true)]
        tags: Vec<String>,
    },
    /// Remove tags from a task
    Remove {
        id: String,
        #[arg(required = true)]
        tags: Vec<String>,
    },
    /// List all tags used in the active library
    List,
}

#[derive(Subcommand)]
pub enum LibCommand {
    /// Register a new library (creates the directory if needed)
    Add { name: String, path: PathBuf },
    /// List all registered libraries
    List,
    /// Switch the active library
    Use { name: String },
    /// Show the currently active library
    Current,
    /// Unregister a library (does not delete files)
    Remove { name: String },
}