1use std::fmt::Display;
2
3use clap::{Parser, Subcommand};
4
5#[derive(Parser, Debug)]
6#[command(author, version = CliArgs::unstable_version(), about, long_about = None)]
7#[command(name = "flake-edit")]
8#[command(next_line_help = true)]
9pub struct CliArgs {
11 #[arg(long)]
13 flake: Option<String>,
14 #[arg(long)]
16 lock_file: Option<String>,
17 #[arg(long, default_value_t = false)]
19 diff: bool,
20 #[arg(long, default_value_t = false)]
22 no_lock: bool,
23 #[arg(long, default_value_t = false)]
25 non_interactive: bool,
26 #[arg(long, default_value_t = false)]
28 no_cache: bool,
29 #[arg(long)]
31 cache: Option<String>,
32
33 #[command(subcommand)]
34 subcommand: Command,
35}
36
37#[allow(unused)]
38impl CliArgs {
39 fn unstable_version() -> &'static str {
41 const VERSION: &str = env!("CARGO_PKG_VERSION");
42 let date = option_env!("GIT_DATE").unwrap_or("no_date");
43 let rev = option_env!("GIT_REV").unwrap_or("no_rev");
44 Box::leak(format!("{VERSION} - {date} - {rev}").into_boxed_str())
46 }
47
48 pub fn subcommand(&self) -> &Command {
49 &self.subcommand
50 }
51 pub fn list(&self) -> bool {
52 matches!(self.subcommand, Command::List { .. })
53 }
54 pub fn update(&self) -> bool {
55 matches!(self.subcommand, Command::Update { .. })
56 }
57 pub fn pin(&self) -> bool {
58 matches!(self.subcommand, Command::Pin { .. })
59 }
60 pub fn unpin(&self) -> bool {
61 matches!(self.subcommand, Command::Unpin { .. })
62 }
63 pub fn change(&self) -> bool {
64 matches!(self.subcommand, Command::Change { .. })
65 }
66 pub fn follow(&self) -> bool {
67 matches!(self.subcommand, Command::Follow { .. })
68 }
69
70 pub fn flake(&self) -> Option<&String> {
71 self.flake.as_ref()
72 }
73
74 pub fn lock_file(&self) -> Option<&String> {
75 self.lock_file.as_ref()
76 }
77
78 pub fn diff(&self) -> bool {
79 self.diff
80 }
81
82 pub fn no_lock(&self) -> bool {
83 self.no_lock
84 }
85
86 pub fn non_interactive(&self) -> bool {
87 self.non_interactive
88 }
89
90 pub fn no_cache(&self) -> bool {
91 self.no_cache
92 }
93
94 pub fn cache(&self) -> Option<&String> {
95 self.cache.as_ref()
96 }
97}
98
99#[derive(Subcommand, Debug)]
100pub enum Command {
101 #[clap(alias = "a")]
103 Add {
104 id: Option<String>,
106 uri: Option<String>,
108 #[arg(long)]
109 ref_or_rev: Option<String>,
111 #[arg(long, short)]
113 no_flake: bool,
114 #[arg(long, short)]
116 shallow: bool,
117 },
118 #[clap(alias = "rm")]
120 Remove { id: Option<String> },
121 #[clap(alias = "c")]
123 Change {
124 id: Option<String>,
126 uri: Option<String>,
128 #[arg(long)]
129 ref_or_rev: Option<String>,
131 #[arg(long, short)]
133 shallow: bool,
134 },
135 #[clap(alias = "l")]
137 List {
138 #[arg(long, default_value_t = ListFormat::default())]
139 format: ListFormat,
140 },
141 #[clap(alias = "u")]
143 Update {
144 id: Option<String>,
147 #[arg(long)]
150 init: bool,
151 },
152 #[clap(alias = "p")]
154 Pin {
155 id: Option<String>,
157 rev: Option<String>,
159 },
160 #[clap(alias = "up")]
162 Unpin {
163 id: Option<String>,
165 },
166 #[clap(alias = "f")]
174 Follow {
175 input: Option<String>,
178 target: Option<String>,
180 #[arg(long, short)]
182 auto: bool,
183 },
184 #[clap(hide = true)]
185 #[command(name = "completion")]
186 Completion {
188 #[arg(long)]
189 inputs: bool,
190 mode: CompletionMode,
191 },
192}
193
194#[derive(Debug, Clone, Default)]
195pub enum CompletionMode {
197 #[default]
198 None,
199 Add,
200 Change,
201 Follow,
202}
203
204impl From<String> for CompletionMode {
205 fn from(value: String) -> Self {
206 use CompletionMode::*;
207 match value.to_lowercase().as_str() {
208 "add" => Add,
209 "change" => Change,
210 "follow" => Follow,
211 _ => None,
212 }
213 }
214}
215
216#[derive(Debug, Clone, Default)]
217pub enum ListFormat {
218 None,
219 Simple,
220 Toplevel,
221 #[default]
222 Detailed,
223 Raw,
224 Json,
225}
226
227impl From<String> for ListFormat {
228 fn from(value: String) -> Self {
229 use ListFormat::*;
230 match value.to_lowercase().as_str() {
231 "detailed" => Detailed,
232 "simple" => Simple,
233 "toplevel" => Toplevel,
234 "raw" => Raw,
235 "json" => Json,
236 _ => None,
237 }
238 }
239}
240
241impl Display for ListFormat {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 match self {
244 ListFormat::None => write!(f, ""),
245 ListFormat::Simple => write!(f, "simple"),
246 ListFormat::Toplevel => write!(f, "toplevel"),
247 ListFormat::Detailed => write!(f, "detailed"),
248 ListFormat::Raw => write!(f, "raw"),
249 ListFormat::Json => write!(f, "json"),
250 }
251 }
252}