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    },
49
50    /// Append an element to today's file without opening an editor
51    Append {
52        /// Element type: task, note, log, reminder (aliases from config are resolved)
53        kind: String,
54        /// Element body text
55        body: Vec<String>,
56        /// Comma-separated tags (e.g. work,backend)
57        #[arg(long)]
58        tags: Option<String>,
59        /// Task status: open (default) or done
60        #[arg(long)]
61        status: Option<String>,
62        /// Time for reminders (e.g. 5pm, 10:30)
63        #[arg(long)]
64        at: Option<String>,
65        /// Start time for logs (HH:MM)
66        #[arg(long)]
67        start_time: Option<String>,
68        /// End time for logs (HH:MM)
69        #[arg(long)]
70        end_time: Option<String>,
71    },
72
73    /// Update an element's attributes in-place
74    Update {
75        /// Element ref: human (task-1) or epoch (20260428.1)
76        ref_path: String,
77        /// Set task status: open or done
78        #[arg(long)]
79        status: Option<String>,
80        /// Set log start time (HH:MM)
81        #[arg(long = "start-time")]
82        start_time: Option<String>,
83        /// Set log end time (HH:MM)
84        #[arg(long = "end-time")]
85        end_time: Option<String>,
86        /// Set reminder time
87        #[arg(long)]
88        at: Option<String>,
89        /// Date context for human refs (default: today)
90        #[arg(short = 'd', long)]
91        date: Option<String>,
92    },
93
94    /// Mark a task as done (shorthand for update REFPATH --status done)
95    Done {
96        /// Element ref: human (task-1) or epoch (20260428.1)
97        ref_path: String,
98        /// Date context for human refs (default: today)
99        #[arg(short = 'd', long)]
100        date: Option<String>,
101    },
102
103    /// Full-text search across all .mps files
104    Search {
105        /// Search query
106        query: String,
107        /// Filter by element type
108        #[arg(short = 't', long)]
109        r#type: Option<String>,
110        /// Filter by tag
111        #[arg(short = 'g', long)]
112        tag: Option<String>,
113        /// Search from this date onward
114        #[arg(short = 'S', long)]
115        since: Option<String>,
116    },
117
118    /// Show element counts and log durations
119    Stats {
120        /// Date (default: today)
121        datesign: Option<String>,
122        /// Stats from SINCE up to DATESIGN
123        #[arg(short = 'S', long)]
124        since: Option<String>,
125        /// Stats across all dates in the archive
126        #[arg(short = 'a', long)]
127        all: bool,
128    },
129
130    /// Show tag usage frequency bar chart
131    Tags {
132        /// Date (default: today)
133        datesign: Option<String>,
134        /// Filter by element type
135        #[arg(short = 't', long)]
136        r#type: Option<String>,
137        /// Filter tasks by status
138        #[arg(short = 's', long)]
139        status: Option<String>,
140        /// Tags from SINCE up to DATESIGN
141        #[arg(short = 'S', long)]
142        since: Option<String>,
143        /// Count tags across all dates
144        #[arg(short = 'a', long)]
145        all: bool,
146    },
147
148    /// Export elements to JSON or CSV on stdout
149    Export {
150        /// Date (default: today)
151        datesign: Option<String>,
152        /// Output format: json (default), csv
153        #[arg(short = 'f', long, default_value = "json")]
154        format: String,
155        /// Filter by element type
156        #[arg(short = 't', long)]
157        r#type: Option<String>,
158        /// Export from SINCE up to DATESIGN
159        #[arg(short = 'S', long)]
160        since: Option<String>,
161    },
162
163    /// View or edit MPS configuration
164    Config {
165        /// Subcommand: show (default) or edit
166        subcommand: Option<String>,
167    },
168
169    /// Run git commands inside the storage directory
170    Git {
171        /// Git subcommand and args (auto = full cycle, autocommit = stage+commit)
172        #[arg(trailing_var_arg = true)]
173        args: Vec<String>,
174    },
175
176    /// Stage, commit, pull, and push (equivalent to git auto)
177    Autogit,
178
179    /// Run any shell command inside the storage directory
180    Cmd {
181        /// Command and arguments
182        #[arg(trailing_var_arg = true)]
183        args: Vec<String>,
184    },
185
186    /// Print version
187    Version,
188}