Skip to main content

mps/
cli.rs

1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
4#[command(name = "mps", version, about = "Plain-text personal productivity CLI")]
5pub struct Cli {
6    /// Path to config file (default: ~/.mps_config.yaml)
7    #[arg(long, global = true)]
8    pub config_path: Option<String>,
9
10    /// Recreate config even if it exists
11    #[arg(long, global = true, default_value_t = false)]
12    pub force: bool,
13
14    #[command(subcommand)]
15    pub command: Option<Commands>,
16}
17
18#[derive(Subcommand)]
19pub enum Commands {
20    /// Open a date's .mps file in $EDITOR (default: today)
21    Open {
22        /// Date to open (today, yesterday, YYYYMMDD, last friday, …)
23        datesign: Option<String>,
24    },
25
26    /// List elements for a date as an indented tree
27    List {
28        /// Date (default: today)
29        datesign: Option<String>,
30        /// Filter by element type: task, note, log, reminder
31        #[arg(short = 't', long)]
32        r#type: Option<String>,
33        /// Filter by tag name
34        #[arg(short = 'g', long)]
35        tag: Option<String>,
36        /// Filter tasks by status: open, done
37        #[arg(short = 's', long)]
38        status: Option<String>,
39        /// Show elements from SINCE up to DATESIGN
40        #[arg(short = 'S', long)]
41        since: Option<String>,
42        /// Show human-readable ref column (task-1, mps-1.2, …)
43        #[arg(short = 'r', long)]
44        refs: bool,
45        /// List elements across all dates in the archive
46        #[arg(short = 'a', long)]
47        all: bool,
48        /// Filter character entries by person name
49        #[arg(short = 'n', long)]
50        name: Option<String>,
51    },
52
53    /// Append an element to today's file without opening an editor
54    Append {
55        /// Element type: task, note, log, reminder (aliases from config are resolved)
56        kind: String,
57        /// Element body text
58        body: Vec<String>,
59        /// Comma-separated tags (e.g. work,backend)
60        #[arg(long)]
61        tags: Option<String>,
62        /// Task status: open (default) or done
63        #[arg(long)]
64        status: Option<String>,
65        /// Time for reminders (e.g. 5pm, 10:30)
66        #[arg(long)]
67        at: Option<String>,
68        /// Start time for logs (HH:MM)
69        #[arg(long)]
70        start_time: Option<String>,
71        /// End time for logs (HH:MM)
72        #[arg(long)]
73        end_time: Option<String>,
74        /// Person name for character entries
75        #[arg(short = 'n', long)]
76        name: Option<String>,
77    },
78
79    /// Update an element's attributes in-place
80    Update {
81        /// Element ref: human (task-1) or epoch (20260428.1)
82        ref_path: String,
83        /// Set task status: open or done
84        #[arg(long)]
85        status: Option<String>,
86        /// Set log start time (HH:MM)
87        #[arg(long = "start-time")]
88        start_time: Option<String>,
89        /// Set log end time (HH:MM)
90        #[arg(long = "end-time")]
91        end_time: Option<String>,
92        /// Set reminder time
93        #[arg(long)]
94        at: Option<String>,
95        /// Date context for human refs (default: today)
96        #[arg(short = 'd', long)]
97        date: Option<String>,
98    },
99
100    /// Edit an element's body text in $EDITOR
101    Edit {
102        /// Element ref: human (task-1) or epoch (20260428.1)
103        ref_path: String,
104        /// Date context for human refs (default: today)
105        #[arg(short = 'd', long)]
106        date: Option<String>,
107    },
108
109    /// Delete an element from its file
110    Delete {
111        /// Element ref: human (task-1) or epoch (20260428.1)
112        ref_path: String,
113        /// Date context for human refs (default: today)
114        #[arg(short = 'd', long)]
115        date: Option<String>,
116        /// Skip confirmation prompt
117        #[arg(short = 'y', long)]
118        yes: bool,
119    },
120
121    /// Mark a task as done (shorthand for update REFPATH --status done)
122    Done {
123        /// Element ref: human (task-1) or epoch (20260428.1)
124        ref_path: String,
125        /// Date context for human refs (default: today)
126        #[arg(short = 'd', long)]
127        date: Option<String>,
128    },
129
130    /// Full-text search across all .mps files
131    Search {
132        /// Search query
133        query: String,
134        /// Filter by element type
135        #[arg(short = 't', long)]
136        r#type: Option<String>,
137        /// Filter by tag
138        #[arg(short = 'g', long)]
139        tag: Option<String>,
140        /// Search from this date onward
141        #[arg(short = 'S', long)]
142        since: Option<String>,
143        /// Filter character entries by person name
144        #[arg(short = 'n', long)]
145        name: Option<String>,
146    },
147
148    /// Show element counts and log durations
149    Stats {
150        /// Date (default: today)
151        datesign: Option<String>,
152        /// Stats from SINCE up to DATESIGN
153        #[arg(short = 'S', long)]
154        since: Option<String>,
155        /// Stats across all dates in the archive
156        #[arg(short = 'a', long)]
157        all: bool,
158    },
159
160    /// Show tag usage frequency bar chart
161    Tags {
162        /// Date (default: today)
163        datesign: Option<String>,
164        /// Filter by element type
165        #[arg(short = 't', long)]
166        r#type: Option<String>,
167        /// Filter tasks by status
168        #[arg(short = 's', long)]
169        status: Option<String>,
170        /// Tags from SINCE up to DATESIGN
171        #[arg(short = 'S', long)]
172        since: Option<String>,
173        /// Count tags across all dates
174        #[arg(short = 'a', long)]
175        all: bool,
176        /// Filter character entries by person name
177        #[arg(short = 'n', long)]
178        name: Option<String>,
179    },
180
181    /// Export elements to JSON or CSV on stdout
182    Export {
183        /// Date (default: today)
184        datesign: Option<String>,
185        /// Output format: json (default), csv
186        #[arg(short = 'f', long, default_value = "json")]
187        format: String,
188        /// Filter by element type
189        #[arg(short = 't', long)]
190        r#type: Option<String>,
191        /// Export from SINCE up to DATESIGN
192        #[arg(short = 'S', long)]
193        since: Option<String>,
194    },
195
196    /// View or edit MPS configuration
197    Config {
198        /// Subcommand: show (default) or edit
199        subcommand: Option<String>,
200    },
201
202    /// Run git commands inside the storage directory
203    Git {
204        /// Git subcommand and args (auto = full cycle, autocommit = stage+commit)
205        #[arg(trailing_var_arg = true)]
206        args: Vec<String>,
207    },
208
209    /// Stage, commit, pull, and push (equivalent to git auto)
210    Autogit,
211
212    /// Run any shell command inside the storage directory
213    Cmd {
214        /// Command and arguments
215        #[arg(trailing_var_arg = true)]
216        args: Vec<String>,
217    },
218
219    /// Check for due reminders and open tasks; send desktop notifications
220    Notify {
221        /// Show what would be sent without actually sending
222        #[arg(long)]
223        dry_run: bool,
224        /// Override the time window in minutes (default: from config)
225        #[arg(long)]
226        window: Option<u64>,
227        /// Fire even if already notified within the window
228        #[arg(long)]
229        force: bool,
230    },
231
232    /// Manage the background notification daemon (systemd user timer)
233    Daemon {
234        /// Subcommand: install, remove, status, run
235        subcommand: String,
236    },
237
238    /// Inspect or edit the .mps.meta sidecar config file
239    Meta {
240        /// Subcommand: show (default), clear, edit
241        subcommand: Option<String>,
242    },
243
244    /// Print version
245    Version,
246}