use clap::{Args, Parser, Subcommand};
use crate::models::{
Difficulty, DueFilter, Priority, Recurrence, RecurrenceFilter, ResourceType, SortBy,
StatusFilter,
};
#[derive(Parser)]
#[command(name = "rustodo")]
#[command(author = "github.com/joaofelipegalvao")]
#[command(version)]
#[command(about = "A modern, powerful task manager built with Rust", long_about = None)]
#[command(override_usage = "todo [COMMAND]")]
#[command(after_help = "\
COMMANDS:
Task Management:
add (a), list (ls), done, undone, edit (e), remove (rm), clear, recur, clear-recur
Viewing & Planning:
next (n), calendar (cal), stats, search (find), context (ctx), deps, tags
Organization:
project, note, resource
System:
info, purge, holidays, backup, restore, backup-list, export, import
Run 'todo <COMMAND> --help' for more information on a command.
")]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(visible_alias = "a", hide = true)]
Add(AddArgs),
#[command(visible_alias = "ls", hide = true)]
List {
#[arg(long, value_enum, default_value_t = StatusFilter::All)]
status: StatusFilter,
#[arg(long, value_enum)]
priority: Option<Priority>,
#[arg(long, value_enum)]
due: Option<DueFilter>,
#[arg(long, short = 's', value_enum)]
sort: Option<SortBy>,
#[arg(long, short = 't', value_delimiter = ',')]
tag: Vec<String>,
#[arg(long, short = 'p')]
project: Option<String>,
#[arg(long, short = 'r', value_enum)]
recurrence: Option<RecurrenceFilter>,
},
#[command(visible_alias = "complete", hide = true)]
Done {
#[arg(value_name = "ID")]
id: usize,
},
#[command(visible_alias = "undo", hide = true)]
Undone {
#[arg(value_name = "ID")]
id: usize,
},
#[command(visible_alias = "e", hide = true)]
Edit(EditArgs),
#[command(visible_aliases = ["rm", "delete"], hide = true)]
Remove {
#[arg(value_name = "ID")]
id: usize,
#[arg(long, short = 'y')]
yes: bool,
},
#[command(visible_alias = "reset", hide = true)]
Clear {
#[arg(long, short = 'y')]
yes: bool,
},
#[command(hide = true)]
Recur {
#[arg(value_name = "ID")]
id: usize,
#[arg(value_enum)]
pattern: Recurrence,
},
#[command(visible_alias = "norecur", hide = true)]
ClearRecur {
#[arg(value_name = "ID")]
id: usize,
},
#[command(visible_alias = "n", hide = true)]
Next {
#[arg(long, short = 'n', default_value_t = 5)]
limit: usize,
},
#[command(visible_alias = "cal", hide = true)]
Calendar {
#[arg(value_name = "MONTH")]
month: Option<u32>,
#[arg(value_name = "YEAR")]
year: Option<i32>,
},
#[command(hide = true)]
Stats,
#[command(visible_alias = "find", hide = true)]
Search {
#[arg(value_name = "QUERY")]
query: String,
#[arg(long, short = 't', value_delimiter = ',')]
tag: Vec<String>,
#[arg(long, short = 'p')]
project: Option<String>,
#[arg(long, value_enum, default_value_t = StatusFilter::All)]
status: StatusFilter,
},
#[command(visible_alias = "ctx", hide = true)]
Context {
#[arg(value_name = "ID")]
id: usize,
},
#[command(hide = true)]
Deps {
#[arg(value_name = "ID")]
id: usize,
},
#[command(hide = true)]
Tags {
#[arg(value_name = "TAG")]
tag: Option<String>,
},
#[command(subcommand, hide = true)]
Project(ProjectCommands),
#[command(subcommand, hide = true)]
Note(NoteCommands),
#[command(subcommand, hide = true)]
Resource(ResourceCommands),
#[command(hide = true)]
Export {
#[arg(value_name = "FILE")]
file: Option<std::path::PathBuf>,
},
#[command(hide = true)]
Import {
#[arg(value_name = "FILE")]
file: std::path::PathBuf,
#[arg(long)]
replace: bool,
#[arg(long, short = 'y')]
yes: bool,
},
#[command(hide = true)]
Backup,
#[command(hide = true)]
Restore {
#[arg(value_name = "FILE")]
file: Option<std::path::PathBuf>,
#[arg(long, short = 'y')]
yes: bool,
},
#[command(name = "backup-list", hide = true)]
BackupList,
#[command(hide = true)]
Info,
#[command(hide = true)]
Purge {
#[arg(long, default_value_t = 30)]
days: u32,
#[arg(long)]
dry_run: bool,
#[arg(long, short = 'y')]
yes: bool,
},
#[command(subcommand, hide = true)]
Holidays(HolidaysCommands),
}
#[derive(Subcommand)]
pub enum ProjectCommands {
Add(ProjectAddArgs),
List,
Show {
#[arg(value_name = "ID")]
id: usize,
},
Edit(ProjectEditArgs),
Done {
#[arg(value_name = "ID")]
id: usize,
},
Undone {
#[arg(value_name = "ID")]
id: usize,
},
Remove {
#[arg(value_name = "ID")]
id: usize,
#[arg(long, short = 'y')]
yes: bool,
},
Clear {
#[arg(long, short = 'y')]
yes: bool,
},
}
#[derive(Args)]
pub struct ProjectAddArgs {
#[arg(value_name = "NAME")]
pub name: String,
#[arg(long, value_enum)]
pub difficulty: Option<Difficulty>,
#[arg(long, value_delimiter = ',')]
pub tech: Vec<String>,
#[arg(long, value_name = "DATE|EXPRESSION")]
pub due: Option<String>,
}
#[derive(Args)]
pub struct ProjectEditArgs {
#[arg(value_name = "ID")]
pub id: usize,
#[arg(long)]
pub name: Option<String>,
#[arg(long, value_enum)]
pub difficulty: Option<Difficulty>,
#[arg(long, conflicts_with = "undone")]
pub done: bool,
#[arg(long, conflicts_with = "done")]
pub undone: bool,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tech")]
pub add_tech: Vec<String>,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tech")]
pub remove_tech: Vec<String>,
#[arg(long, conflicts_with_all = ["add_tech", "remove_tech"])]
pub clear_tech: bool,
#[arg(long, value_name = "DATE|EXPRESSION", conflicts_with = "clear_due")]
pub due: Option<String>,
#[arg(long, conflicts_with = "due")]
pub clear_due: bool,
}
#[derive(Subcommand)]
pub enum NoteCommands {
Add(NoteAddArgs),
List(NoteListArgs),
Show {
#[arg(value_name = "ID")]
id: usize,
},
Preview {
#[arg(value_name = "ID")]
id: usize,
},
Edit(NoteEditArgs),
Remove {
#[arg(value_name = "ID")]
id: usize,
#[arg(long, short = 'y')]
yes: bool,
},
Clear {
#[arg(long, short = 'y')]
yes: bool,
},
}
#[derive(Args)]
pub struct NoteAddArgs {
#[arg(value_name = "BODY", conflicts_with_all = ["editor", "file"])]
pub body: Option<String>,
#[arg(long, conflicts_with_all = ["file"])]
pub editor: bool,
#[arg(long, value_name = "PATH", conflicts_with_all = ["editor"])]
pub file: Option<std::path::PathBuf>,
#[arg(long)]
pub title: Option<String>,
#[arg(long, short = 't', value_delimiter = ',')]
pub tag: Vec<String>,
#[arg(long, short = 'l')]
pub language: Option<String>,
#[arg(long, short = 'p')]
pub project: Option<String>,
#[arg(long)]
pub task: Option<usize>,
}
#[derive(Args)]
pub struct NoteListArgs {
#[arg(long, short = 'p')]
pub project: Option<String>,
#[arg(long, short = 't')]
pub tag: Option<String>,
#[arg(long, short = 'l')]
pub language: Option<String>,
}
#[derive(Args)]
pub struct NoteEditArgs {
#[arg(value_name = "ID")]
pub id: usize,
#[arg(long, conflicts_with = "editor")]
pub body: Option<String>,
#[arg(long, conflicts_with = "body")]
pub editor: bool,
#[arg(long, conflicts_with = "clear_title")]
pub title: Option<String>,
#[arg(long, conflicts_with = "title")]
pub clear_title: bool,
#[arg(long, short = 'l', conflicts_with = "clear_language")]
pub language: Option<String>,
#[arg(long, conflicts_with = "language")]
pub clear_language: bool,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tags")]
pub add_tag: Vec<String>,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tags")]
pub remove_tag: Vec<String>,
#[arg(long, conflicts_with_all = ["add_tag", "remove_tag"])]
pub clear_tags: bool,
#[arg(long, short = 'p', conflicts_with = "clear_project")]
pub project: Option<String>,
#[arg(long, conflicts_with = "project")]
pub clear_project: bool,
#[arg(long, conflicts_with = "clear_task")]
pub task: Option<usize>,
#[arg(long, conflicts_with = "task")]
pub clear_task: bool,
#[arg(long, value_name = "ID", conflicts_with = "clear_resources")]
pub add_resource: Vec<usize>,
#[arg(long, value_name = "ID", conflicts_with = "clear_resources")]
pub remove_resource: Vec<usize>,
#[arg(long, conflicts_with_all = ["add_resource", "remove_resource"])]
pub clear_resources: bool,
}
#[derive(Subcommand)]
pub enum ResourceCommands {
Add(ResourceAddArgs),
List(ResourceListArgs),
Show {
#[arg(value_name = "ID")]
id: usize,
},
Edit(ResourceEditArgs),
Remove {
#[arg(value_name = "ID")]
id: usize,
#[arg(long, short = 'y')]
yes: bool,
},
Clear {
#[arg(long, short = 'y')]
yes: bool,
},
}
#[derive(Args)]
pub struct ResourceAddArgs {
#[arg(value_name = "TITLE")]
pub title: String,
#[arg(long, value_enum)]
pub r#type: Option<ResourceType>,
#[arg(long, short = 'u')]
pub url: Option<String>,
#[arg(long, short = 'd')]
pub description: Option<String>,
#[arg(long, short = 't', value_delimiter = ',')]
pub tag: Vec<String>,
}
#[derive(Args)]
pub struct ResourceListArgs {
#[arg(long, short = 't')]
pub tag: Option<String>,
#[arg(long, value_enum)]
pub r#type: Option<ResourceType>,
}
#[derive(Args)]
pub struct ResourceEditArgs {
#[arg(value_name = "ID")]
pub id: usize,
#[arg(long)]
pub title: Option<String>,
#[arg(long, value_enum, conflicts_with = "clear_type")]
pub r#type: Option<ResourceType>,
#[arg(long, conflicts_with = "type")]
pub clear_type: bool,
#[arg(long, short = 'u', conflicts_with = "clear_url")]
pub url: Option<String>,
#[arg(long, conflicts_with = "url")]
pub clear_url: bool,
#[arg(long, short = 'd', conflicts_with = "clear_description")]
pub description: Option<String>,
#[arg(long, conflicts_with = "description")]
pub clear_description: bool,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tags")]
pub add_tag: Vec<String>,
#[arg(long, value_delimiter = ',', conflicts_with = "clear_tags")]
pub remove_tag: Vec<String>,
#[arg(long, conflicts_with_all = ["add_tag", "remove_tag"])]
pub clear_tags: bool,
}
#[derive(Subcommand)]
pub enum SyncCommands {
Init {
#[arg(value_name = "REMOTE")]
remote: String,
},
Push,
Pull,
Status,
}
#[derive(Args)]
pub struct AddArgs {
#[arg(value_name = "DESCRIPTION")]
pub text: String,
#[arg(long, value_enum, default_value_t = Priority::Medium)]
pub priority: Priority,
#[arg(long, short = 't', value_name = "TAG", value_delimiter = ',')]
pub tag: Vec<String>,
#[arg(long, short = 'p', value_name = "PROJECT")]
pub project: Option<String>,
#[arg(long, value_name = "DATE|EXPRESSION")]
pub due: Option<String>,
#[arg(long, value_enum)]
pub recurrence: Option<Recurrence>,
#[arg(long, value_name = "ID")]
pub depends_on: Vec<usize>,
}
#[derive(Args)]
pub struct EditArgs {
#[arg(value_name = "ID")]
pub id: usize,
#[arg(long)]
pub text: Option<String>,
#[arg(long, value_enum)]
pub priority: Option<Priority>,
#[arg(long, value_delimiter = ',')]
pub add_tag: Vec<String>,
#[arg(long, value_delimiter = ',')]
pub remove_tag: Vec<String>,
#[arg(long, short = 'p', conflicts_with = "clear_project")]
pub project: Option<String>,
#[arg(long, conflicts_with = "project")]
pub clear_project: bool,
#[arg(long, value_name = "DATE|EXPRESSION")]
pub due: Option<String>,
#[arg(long, conflicts_with = "due")]
pub clear_due: bool,
#[arg(long, conflicts_with_all = ["add_tag", "remove_tag"])]
pub clear_tags: bool,
#[arg(long, value_name = "ID", conflicts_with = "clear_deps")]
pub add_dep: Vec<usize>,
#[arg(long, value_name = "ID", conflicts_with = "clear_deps")]
pub remove_dep: Vec<usize>,
#[arg(long, conflicts_with_all = ["add_dep", "remove_dep"])]
pub clear_deps: bool,
}
#[derive(Subcommand)]
pub enum HolidaysCommands {
Refresh,
}