use clap::{Parser, Subcommand};
use crate::models::common::Priority;
#[derive(Parser)]
#[command(name = "tally")]
#[command(about = "A task management tool for TODO.md files")]
#[command(
long_about = "tally is a command-line task manager that uses TODO.md as its storage format.\n\n\
Track tasks, generate changelogs, and integrate with git commits for automatic \
task completion detection.\n\n\
EXAMPLES:\n \
tally add \"Fix parsing error\" --priority high --tags bug,parser\n \
tally done \"Fix parsing error\" --commit abc123f\n \
tally list --tags bug\n \
tally release v0.2.3 --summary"
)]
#[command(version)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(long_about = "Initialize tally in the CWD.")]
Init,
#[command(long_about = "Add a new task to TODO.md.\n\n\
Creates a task with optional priority and tags. Use --dry-run to preview \
the task before adding it.\n\n\
EXAMPLES:\n \
tally add \"Fix parsing error in format.rs\"\n \
tally add \"Implement new feature\" --priority high --tags feature,backend\n \
tally add \"Update docs\" --dry-run")]
Add {
description: String,
#[arg(short, long, value_enum, default_value_t = Priority::Medium)]
priority: Priority,
#[arg(short, long, value_delimiter = ',')]
tags: Option<Vec<String>>,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(long_about = "Mark a task as completed in TODO.md.\n\n\
Fuzzy-matches the description against existing tasks and marks the match \
as done. Optionally associate a git commit or version.\n\n\
EXAMPLES:\n \
tally done \"Fix parsing error\"\n \
tally done \"parsing error\" --commit abc123f\n \
tally done \"Fix bug\" --version v0.2.3 --dry-run")]
Done {
description: String,
#[arg(short, long)]
commit: Option<String>,
#[arg(short, long)]
version: Option<String>,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(
long_about = "Display tasks with optional filtering and formatting.\n\n\
View all tasks, or filter by tags or priority. \
Output as human-readable text or raw JSON.\n\n\
EXAMPLES:\n \
tally list\n \
tally list --tags bug,parser --priority high\n \
tally list --json"
)]
List {
#[arg(short, long, value_delimiter = ',')]
tags: Option<Vec<String>>,
#[arg(short, long, value_enum)]
priority: Option<Priority>,
#[arg(long, default_value_t = false)]
json: bool,
},
#[command(
long_about = "Assign a version to all completed tasks without a version.\n\n\
Additionally sets the project version in the TODO list itself.\n\n\
EXAMPLES:\n \
tally semver v0.2.3\n \
tally semver v1.0.0 --summary\n \
tally semver v0.2.4 --dry-run"
)]
Semver {
version: String,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
summary: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(long_about = "Assign a version to completed tasks and create a git tag.\n\n\
Runs 'tally release' then commits both the todo and command history before creating a git tag. \n
The tag name will always be prefixed with 'v' if not already.\n\n\
EXAMPLES:\n \
tally tag v0.2.3\n \
tally tag v1.0.0 --summary\n \
tally tag v0.2.3 --message \"First stable release\"\n \
tally tag v0.2.4 --dry-run")]
Tag {
version: String,
#[arg(short, long)]
message: Option<String>,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
summary: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(long_about = "Generate a changelog from completed tasks.\n\n\
Create a changelog for a version range or until the current version.\n\n\
EXAMPLES:\n \
tally changelog\n \
tally changelog --from v0.7.2\n \
tally changelog --from v0.2.2 --to v0.2.3")]
Changelog {
#[arg(long)]
from: Option<String>,
#[arg(long)]
to: Option<String>,
},
#[command(long_about = "Remove a task from TODO.md.\n\n\
Fuzzy-matches the description. If the task is completed, it will be \
saved to history.json before removal so it still appears in changelogs.\n\n\
EXAMPLES:\n \
tally remove \"Fix parsing error\"\n \
tally remove \"old task\" --dry-run")]
Remove {
description: String,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(long_about = "Remove completed tasks older than a threshold.\n\n\
Pruned tasks are saved to history.json before removal so they \
still appear in changelogs. Days and hours combine if both are given.\n\n\
EXAMPLES:\n \
tally prune # default: 30 days\n \
tally prune --days 7\n \
tally prune --hours 12\n \
tally prune --days 1 --hours 12 # 1.5 days\n \
tally prune --dry-run")]
Prune {
#[arg(long)]
days: Option<u32>,
#[arg(long)]
hours: Option<u32>,
#[arg(long, default_value_t = false)]
dry_run: bool,
#[arg(long, default_value_t = false)]
auto: bool,
},
#[command(
long_about = "Scan git commit messages to automatically detect completed tasks.\n\n\
Uses fuzzy matching to find tasks that may have been completed based on \
commit messages. Can run automatically or prompt for confirmation.\n\n\
EXAMPLES:\n \
tally scan\n \
tally scan --auto\n \
tally scan --dry-run"
)]
Scan {
#[arg(long, default_value_t = false)]
auto: bool,
#[arg(long, default_value_t = false)]
dry_run: bool,
},
#[command(long_about = "View and modify tally configuration.\n\n\
Configuration is stored in .tally/config.toml and includes settings like \
default priority, editor preferences, and changelog templates.\n\n\
EXAMPLES:\n \
tally config set default_priority medium\n \
tally config get changelog_template\n \
tally config list")]
Config {
#[command(subcommand)]
action: ConfigAction,
},
#[command(long_about = "Display a summary dashboard of your project's tasks.\n\n\
Shows overall progress, open tasks by priority, tag usage, and version \
statistics. Provides a quick overview without needing to piece together \
multiple commands.\n\n\
EXAMPLE:\n \
tally status")]
Status,
}
#[derive(Subcommand)]
pub enum ConfigAction {
#[command(long_about = "Set one or more configuration values.\n\n\
Use dot notation for nested keys if needed. Values are stored in \
.tally/config.toml.\n\n\
EXAMPLES:\n \
tally config set default_priority medium\n \
tally config set editor vim")]
Set {
key: String,
value: String,
},
#[command(long_about = "Retrieve a configuration value.\n\n\
Displays the current value for the specified configuration key.\n\n\
EXAMPLES:\n \
tally config get default_priority\n \
tally config get changelog_template")]
Get {
key: String,
},
#[command(long_about = "Display all configuration settings.\n\n\
Shows all current configuration keys and their values.\n\n\
EXAMPLE:\n \
tally config list")]
List,
}