1use clap::{Args, Parser, Subcommand};
11
12use crate::models::{DueFilter, Priority, Recurrence, RecurrenceFilter, SortBy, StatusFilter};
13
14#[derive(Parser)]
19#[command(name = "rustodo")]
20#[command(author = "github.com/joaofelipegalvao")]
21#[command(version = "2.8.5")]
22#[command(about = "A modern, powerful task manager built with Rust", long_about = None)]
23#[command(after_help = "EXAMPLES:\n \
24 # Add a task to a project with a natural language date\n \
25 todo add \"Fix login bug\" --project \"Backend\" --priority high --due \"next friday\"\n\n \
26 # Add a task due in 3 days\n \
27 todo add \"Review PR\" --due \"in 3 days\"\n\n \
28 # Add a task with strict date format\n \
29 todo add \"Project deadline\" --due 2026-03-15\n\n \
30 # List all tasks in a project\n \
31 todo list --project \"Backend\"\n\n \
32 # List pending tasks in a project, sorted by due date\n \
33 todo list --project \"Backend\" --status pending --sort due\n\n \
34 # List all projects\n \
35 todo projects\n\n \
36 # Search within a project\n \
37 todo search \"bug\" --project \"Backend\"\n\n \
38 # Edit a task project\n \
39 todo edit 3 --project \"Frontend\"\n\n \
40 # Remove a task from its project\n \
41 todo edit 3 --clear-project\n\n \
42 # Add a recurring task in a project\n \
43 todo add \"Weekly review\" --project \"Management\" --due \"next monday\" --recurrence weekly\n\n \
44 # List overdue tasks sorted by due date\n \
45 todo list --due overdue --sort due\n\n \
46 # Search for tasks\n \
47 todo search rust\n\n \
48 # Mark task as completed (auto-creates next recurrence)\n \
49 todo done 3\n\n \
50 # Set recurrence pattern\n \
51 todo recur 5 daily\n\n\
52For more information, visit: https://github.com/joaofelipegalvao/rustodo
53")]
54pub struct Cli {
55 #[command(subcommand)]
57 pub command: Commands,
58}
59
60#[derive(Subcommand)]
62pub enum Commands {
63 #[command(visible_alias = "a")]
65 #[command(long_about = "Add a new task to your todo list\n\n\
66 Creates a new task with the specified text and optional metadata like priority,\n\
67 tags, and due date. Tasks are saved immediately to todos.json.\n\n\
68 Due dates accept both natural language and strict YYYY-MM-DD format:\n \
69 todo add \"Meeting\" --due tomorrow\n \
70 todo add \"Deploy\" --due \"next friday\"\n \
71 todo add \"Report\" --due \"in 3 days\"\n \
72 todo add \"Deadline\" --due 2026-03-15\n\n\
73 Assign to a project:\n \
74 todo add \"Fix bug\" --project \"Backend\"\n \
75 todo add \"Write docs\" --project \"Documentation\" --tag work\n\n\
76 Use --recurrence to make the task repeat automatically when completed.")]
77 Add(AddArgs),
78
79 #[command(visible_alias = "ls")]
81 #[command(
82 long_about = "List and filter tasks with powerful filtering options\n\n\
83 Examples:\n \
84 todo list --project \"Backend\"\n \
85 todo list --project \"Backend\" --status pending\n \
86 todo list --recurrence daily\n \
87 todo list --status pending --priority high --sort due"
88 )]
89 List {
90 #[arg(long, value_enum, default_value_t = StatusFilter::All)]
92 status: StatusFilter,
93 #[arg(long, value_enum)]
95 priority: Option<Priority>,
96 #[arg(long, value_enum)]
98 due: Option<DueFilter>,
99 #[arg(long, short = 's', value_enum)]
101 sort: Option<SortBy>,
102 #[arg(long, short = 't')]
104 tag: Option<String>,
105 #[arg(long, short = 'p')]
107 project: Option<String>,
108 #[arg(long, short = 'r', value_enum)]
110 recurrence: Option<RecurrenceFilter>,
111 },
112
113 #[command(visible_alias = "complete")]
115 Done {
116 #[arg(value_name = "ID")]
118 id: usize,
119 },
120
121 #[command(visible_alias = "undo")]
123 Undone {
124 #[arg(value_name = "ID")]
126 id: usize,
127 },
128
129 #[command(visible_aliases = ["rm", "delete"])]
131 Remove {
132 #[arg(value_name = "ID")]
134 id: usize,
135 #[arg(long, short = 'y')]
137 yes: bool,
138 },
139
140 #[command(visible_alias = "e")]
142 #[command(long_about = "Edit an existing task\n\n\
143 Modify task properties like text, priority, tags, or due date.\n\
144 Only specify the fields you want to change.\n\n\
145 Due dates accept natural language or YYYY-MM-DD:\n \
146 todo edit 3 --due tomorrow\n \
147 todo edit 3 --due \"next monday\"\n \
148 todo edit 3 --due \"in 5 days\"\n \
149 todo edit 3 --due 2026-04-01\n\n\
150 Tag operations:\n \
151 todo edit 1 --add-tag urgent,critical # Add multiple tags\n \
152 todo edit 1 --remove-tag work,team # Remove multiple tags\n \
153 todo edit 1 --add-tag urgent --remove-tag team # Combine operations\n\n\
154 Project operations:\n \
155 todo edit 3 --project \"Backend\" # Assign to a project\n \
156 todo edit 3 --clear-project # Remove from project")]
157 Edit {
158 #[arg(value_name = "ID")]
160 id: usize,
161
162 #[arg(long)]
164 text: Option<String>,
165 #[arg(long, value_enum)]
167 priority: Option<Priority>,
168 #[arg(long, value_delimiter = ',')]
170 add_tag: Vec<String>,
171 #[arg(long, value_delimiter = ',')]
173 remove_tag: Vec<String>,
174 #[arg(long, short = 'p', conflicts_with = "clear_project")]
176 project: Option<String>,
177 #[arg(long, conflicts_with = "project")]
179 clear_project: bool,
180 #[arg(long, value_name = "DATE|EXPRESSION")]
182 due: Option<String>,
183 #[arg(long, conflicts_with = "due")]
185 clear_due: bool,
186 #[arg(long, conflicts_with_all = ["add_tag", "remove_tag"])]
188 clear_tags: bool,
189 #[arg(long, value_name = "ID", conflicts_with = "clear_deps")]
191 add_dep: Vec<usize>,
192 #[arg(long, value_name = "ID", conflicts_with = "clear_deps")]
194 remove_dep: Vec<usize>,
195 #[arg(long, conflicts_with_all = ["add_dep", "remove_dep"])]
197 clear_deps: bool,
198 },
199
200 #[command(visible_alias = "reset")]
202 Clear {
203 #[arg(long, short = 'y')]
205 yes: bool,
206 },
207
208 #[command(visible_alias = "find")]
210 Search {
211 #[arg(value_name = "QUERY")]
213 query: String,
214 #[arg(long, short = 't')]
216 tag: Option<String>,
217 #[arg(long, short = 'p')]
219 project: Option<String>,
220 #[arg(long, value_enum, default_value_t = StatusFilter::All)]
222 status: StatusFilter,
223 },
224
225 Stats,
227
228 Tags,
230
231 #[command(long_about = "List all projects used across your tasks\n\n\
233 Shows each project name with the count of pending and completed tasks.\n\n\
234 Use 'todo list --project <NAME>' to see tasks within a specific project.")]
235 Projects,
236
237 #[command(long_about = "Show the dependency graph for a task\n\n
239 Displays:\n \
240 • Tasks this task depends on (with completion status)\n \
241 • Tasks that depend on this one\n \
242 • Whether the task is currently blocked\n\n\
243 Examples:\n \
244 todo deps 5\n \
245 todo deps 1")]
246 Deps {
247 #[arg(value_name = "ID")]
249 id: usize,
250 },
251
252 Info,
254
255 Recur {
257 #[arg(value_name = "ID")]
259 id: usize,
260 #[arg(value_enum)]
262 pattern: Recurrence,
263 },
264
265 #[command(visible_alias = "norecur")]
267 #[command(long_about = "Remove recurrence pattern from a task\n\n\
268 Stops a task from repeating automatically. The task will remain\n\
269 but won't create new occurrences when completed.\n\n\
270 Aliases: norecur")]
271 ClearRecur {
272 #[arg(value_name = "ID")]
274 id: usize,
275 },
276}
277
278#[derive(Args)]
283pub struct AddArgs {
284 #[arg(value_name = "DESCRIPTION")]
286 pub text: String,
287 #[arg(long, value_enum, default_value_t = Priority::Medium)]
289 pub priority: Priority,
290 #[arg(long, short = 't', value_name = "TAG", value_delimiter = ',')]
292 pub tag: Vec<String>,
293 #[arg(long, short = 'p', value_name = "PROJECT")]
295 pub project: Option<String>,
296 #[arg(long, value_name = "DATE|EXPRESSION")]
300 pub due: Option<String>,
301 #[arg(long, value_enum)]
303 pub recurrence: Option<Recurrence>,
304 #[arg(long, value_name = "ID")]
306 pub depends_on: Vec<usize>,
307}