tasker_cli/cli/
interface.rs

1use camino::Utf8PathBuf;
2use clap::{Args, Parser, Subcommand, ValueEnum};
3use lib_tasker::todos::State;
4
5/// A command-line application to manage your daily Tasks.
6#[derive(Debug, Parser)]
7#[command(
8    name = "Tasker CLI",
9    author,
10    version,
11    about,
12    long_about = None,
13    help_template = "\
14{before-help}{name} {version}
15{author-with-newline}{about-with-newline}
16{usage-heading} {usage}
17
18{all-args}{after-help}"
19)]
20pub struct Cli {
21    /// Application subcommand
22    #[command(subcommand)]
23    pub command: Option<Command>,
24
25    /// Path to a file in which to look for and save Tasks
26    #[arg(short = 'T', long)]
27    pub todo_file: Option<Utf8PathBuf>,
28
29    /// Path to an alternative configuration file. Takes precedence over `todo-file`
30    #[arg(short = 'C', long)]
31    pub config_file: Option<Utf8PathBuf>,
32}
33
34#[derive(Debug, Subcommand)]
35#[command(help_template(
36    "\
37{name}
38{about-with-newline}
39{usage-heading} {usage}
40
41{all-args}"
42))]
43pub enum Command {
44    /// Add Task(s)
45    #[command(arg_required_else_help = true, visible_alias = "a")]
46    Add(AddTasks),
47
48    /// Clean completed Tasks
49    #[command(visible_alias = "c")]
50    Clean,
51
52    /// Delete Tasks
53    #[command(arg_required_else_help = true, visible_alias = "d")]
54    Delete(DeleteTasks),
55
56    /// Edit a Task
57    #[command(arg_required_else_help = true, visible_alias = "e")]
58    Edit(EditTask),
59
60    /// List Tasks
61    #[command(visible_alias = "l")]
62    List(ListTasks),
63
64    /// Print default paths for the application
65    #[command(visible_alias = "p")]
66    Paths,
67
68    /// Change the state of a Task
69    #[command(arg_required_else_help = true, visible_alias = "t")]
70    Toggle(ToggleTasks),
71}
72
73#[derive(Args, Debug)]
74#[command(help_template(
75    "\
76{name}
77{about-with-newline}
78{usage-heading} {usage}
79
80{all-args}"
81))]
82pub struct AddTasks {
83    /// Task(s) to accomplish
84    pub descriptions: Vec<String>,
85
86    /// Project the Task(s) belongs to. Defaults to "Inbox"
87    #[arg(short, long)]
88    pub project: Option<String>,
89
90    /// Tag to assign the Task(s). Can be called multiple times
91    #[arg(short, long)]
92    pub tag: Option<Vec<String>>,
93}
94
95#[derive(Args, Debug)]
96#[command(help_template(
97    "\
98{name}
99{about-with-newline}
100{usage-heading} {usage}
101
102{all-args}"
103))]
104pub struct ToggleTasks {
105    /// State to assign the Task(s)
106    #[arg(value_enum)]
107    pub state: ToggleState,
108
109    /// ID(s) of the Task(s) to toggle
110    #[arg(name = "TO-DOS")]
111    pub tasks: Vec<usize>,
112}
113
114#[derive(Debug, ValueEnum, Clone, Copy)]
115pub enum ToggleState {
116    /// This Task hasn't started
117    #[value(name = "todo", alias = "t")]
118    ToDo,
119
120    /// This Task is in progress
121    #[value(alias = "dg")]
122    Doing,
123
124    /// This Task is finished
125    #[value(alias = "dn")]
126    Done,
127
128    /// This Task can't be accomplished due to external reasons
129    #[value(name = "wait", alias = "w")]
130    Waiting,
131}
132
133impl From<ToggleState> for State {
134    fn from(value: ToggleState) -> Self {
135        match value {
136            ToggleState::ToDo => Self::ToDo,
137            ToggleState::Doing => Self::Doing,
138            ToggleState::Done => Self::Done,
139            ToggleState::Waiting => Self::Waiting,
140        }
141    }
142}
143
144#[derive(Args, Debug)]
145#[command(help_template(
146    "\
147{name}
148{about-with-newline}
149{usage-heading} {usage}
150
151{all-args}"
152))]
153pub struct EditTask {
154    /// ID of the Task to edit
155    #[arg(name = "TO-DO")]
156    pub task: usize,
157
158    /// New description
159    #[arg(short, long)]
160    pub description: Option<String>,
161
162    /// New state
163    #[arg(short, long, value_enum)]
164    pub state: Option<ToggleState>,
165
166    /// New project
167    #[arg(short, long)]
168    pub project: Option<String>,
169
170    /// New tags
171    #[arg(short, long)]
172    pub tags: Option<Vec<String>>,
173}
174
175#[derive(Args, Debug)]
176#[command(help_template(
177    "\
178{name}
179{about-with-newline}
180{usage-heading} {usage}
181
182{all-args}"
183))]
184pub struct DeleteTasks {
185    /// Ids of the Task(s) to delete
186    #[arg(name = "TASKS")]
187    pub tasks: Vec<usize>,
188}
189
190#[derive(Args, Debug)]
191#[command(help_template(
192    "\
193{name}
194{about-with-newline}
195{usage-heading} {usage}
196
197{all-args}"
198))]
199pub struct ListTasks {
200    /// Sort Tasks by this field
201    #[arg(short = 'S', long, value_enum)]
202    pub sort_by: Option<SortTasks>,
203
204    /// Only show Tasks containing this text within their descriptions
205    #[arg(short, long)]
206    pub description: Option<String>,
207
208    /// Only show Tasks with this state of progress
209    #[arg(short, long)]
210    pub state: Option<ToggleState>,
211
212    /// Only show Tasks containing these tags. Can be called multiple times
213    #[arg(short, long)]
214    pub tag: Option<Vec<String>>,
215
216    /// Only show Tasks belonging to this project
217    #[arg(short, long)]
218    pub project: Option<String>,
219}
220
221#[derive(Debug, ValueEnum, Clone, Copy)]
222pub enum SortTasks {
223    /// Sort by description [aliases: desc, d]
224    #[value(alias = "desc", alias = "d")]
225    Description,
226
227    /// Sort by project [aliases: pro, p]
228    #[value(alias = "pro", alias = "p")]
229    Project,
230
231    /// Sort by state [aliases: s]
232    #[value(alias = "s")]
233    State,
234
235    /// Sort by ID [aliases: i]
236    #[value(alias = "i")]
237    ID,
238}