1use std::collections::BTreeSet;
2
3use clap::{Args, Parser};
4
5use super::SharedJobAttributeToSelect;
6#[derive(Parser, Debug, Clone)]
11#[command(name = "cargo", bin_name = "cargo", version, about, long_about = None)]
12pub enum CargoCliRoot {
13 #[command(name = "plot", about = "Szwajcarski scyzoryk do wizualizacji struktury projektu", version)]
14 Plot(RawCliJob),
15}
16
17#[derive(Args, Debug, Clone)]
22#[command(group(
24 clap::ArgGroup::new("exec_mode")
25 .required(true)
26 .args(["job_blank", "jobs_load", "help_for_pattern", "help_for_config", "jobs_load_only_show"])
27))]
28pub struct RawCliJob {
29 #[arg(help_heading = "Information", short = 'P', long = "help-pattern")]
34 pub help_for_pattern: bool,
35
36 #[arg(help_heading = "Information", short = 'T', long = "help-tasks-make")]
38 pub help_for_config: bool,
39
40 #[arg(
42 help_heading = "Information",
43 short = 'L',
44 long = "help-tasks-show",
45 num_args = 0..=1,
46 default_missing_value = ""
47 )]
48 pub jobs_load_only_show: Option<String>,
49
50
51 #[arg(help_heading = "Run Options", short = 'U', long = "dry-run")]
56 pub dry_run: Option<bool>,
57
58 #[arg(help_heading = "Run Options", short = 'N',long = "no-export", visible_aliases = ["no-save", "only-view"])]
60 pub export_nothing: Option<bool>,
61
62 #[arg(help_heading = "Run Options", short = 'O', long = "clear")]
64 pub print_nothing: Option<bool>,
65
66 #[arg(help_heading = "Run Options", short = 'W', long = "only-warnings")]
68 pub print_warnings: Option<bool>,
69
70 #[arg(help_heading = "Run Options", short = 'E', long = "inspection-in-export")]
72 pub inspection_in_export: Option<bool>,
73
74 #[arg(help_heading = "Run Options", short = 'I', long = "inspection-in-print")]
76 pub inspection_in_print: Option<bool>,
77
78 #[arg(
83 help_heading = "Main Options",
84 short = 'l',
85 long = "jobs-load",
86 num_args = 0..=1,
87 default_missing_value = ""
88 )]
89 pub jobs_load: Option<String>,
90
91 #[arg(
93 help_heading = "Main Options",
94 short = 't',
95 long = "job-ids",
96 value_parser = parse_ids, requires = "jobs_load" )]
99 pub task_id: Option<BTreeSet<String>>,
100
101 #[arg(help_heading = "Main Options", short = 'b', long = "job-blank")]
103 pub job_blank: bool,
104
105 #[arg(help_heading = "Main Options", short = 's', long = "speed", requires = "job_blank")]
107 pub speed: bool,
108
109 #[arg(help_heading = "Scan Options", short = 'd', long = "dir-to-scan", default_value = ".")]
112 pub dir_to_scan: String,
113
114 #[arg(help_heading = "Scan Options", short = 'p', long = "pattern", visible_aliases = ["pat", "patterns"], value_name = "GLOB")]
116 pub patterns: Vec<String>,
117
118 #[arg(help_heading = "Scan Options", short = 'q', long = "query-parts", default_value = "mf, md")]
121 pub query_parts: Vec<String>,
122
123 #[arg(help_heading = "Scan Options", short = 'i', long = "ignore-case")]
125 pub ignore_case: Option<bool>,
126
127 #[arg(
131 help_heading = "Save Options",
132 short = 'o',
133 long = "out-dir",
134 default_value = "./target/.cargo-plot/out/"
135 )]
136 pub out_dir: String,
137
138 #[arg(help_heading = "Save Options", short = 'u', long, help = "Tytuł raportu Markdown")]
139 pub title: Option<String>,
140
141 #[arg(help_heading = "Save Options", short = 'n', long, help = "Nazwa pliku wyjściowego")]
142 pub name: Option<String>,
143
144 #[arg(help_heading = "Save Options", short = 'X', long, help = "Czy nazwa ma być prefiksem zamiast sufiksu?")]
145 pub name_is_first: Option<bool>,
146
147 #[arg(help_heading = "Save Options", long, help = "Zapisz SOTC i COTS jako osobne pliki")]
148 pub save_separately: Option<bool>,
149
150 #[arg(
155 short = 'c',
156 long = "columns",
157 value_parser = parse_attribute, value_delimiter = ',',
159 default_value = "date,time,size,path,item",
160 help_heading = "Layout Options"
161 )]
162 pub attributes: Option<Vec<SharedJobAttributeToSelect>>,
163
164 #[arg(help_heading = "Theme Options", long = "show-colors")]
165 pub show_colors: Option<bool>,
166
167 #[arg(help_heading = "Theme Options", long = "tree-hide")]
168 pub tree_hide: Option<bool>,
169
170 #[arg(help_heading = "Layout Options", long = "icons-hide", conflicts_with = "icon_more")]
171 pub icon_hide: Option<bool>,
172
173 #[arg(help_heading = "Layout Options", long = "name-hide")]
174 pub name_hide: Option<bool>,
175
176 #[arg(help_heading = "Layout Options", long = "align-hide")]
177 pub align_hide: Option<bool>,
178
179 #[arg(help_heading = "Theme Options", long = "icons-more", conflicts_with = "icon_hide")]
180 pub icon_more: Option<bool>,
181
182 #[arg(help_heading = "Theme Options", long = "num-before")]
183 pub num_before: Option<bool>,
184
185 #[arg(help_heading = "Theme Options", short ='B', long = "size-binary")]
186 pub size_binary: Option<bool>,
187
188 #[arg(help_heading = "Theme Options", short ='Y', long = "fmt-date")]
189 pub fmt_date: Option<String>,
190
191 #[arg(help_heading = "Theme Options", short ='H', long = "fmt-time")]
192 pub fmt_time: Option<String>,
193
194
195 #[arg(help_heading = "Pile Options", long = "pile")]
198 pub pile: Option<String>,
199
200 #[arg(
202 help_heading = "Pile Options",
203 long = "dir-first",
204 short = 'D',
205 requires = "pile", )]
207 pub dir_first: Option<bool>,
208
209 #[arg(
211 help_heading = "Pile Options",
212 short = 'G',
213 long = "name-nearby",
214 requires = "pile" )]
216 pub name_nearby: Option<bool>,
217
218 #[arg(help_heading = "Sort Options", long = "sort", value_parser = ["date", "size", "path", "name", "none"])]
221 pub sort: Option<String>,
222
223 #[arg(help_heading = "Sort Options", short = 'R', long = "reverse", requires = "sort")]
225 pub reverse: Option<bool>,
226
227 #[arg(help_heading = "Sort Options", short = 'M', long = "mirror", requires = "sort")]
229 pub mirror: Option<bool>,
230
231 #[arg(
233 help_heading = "Sort Options",
234 short = 'S',
235 long = "strategy",
236 requires = "sort",
237 value_parser = parse_strategy )]
239 pub strategy: Option<String>,
240}
241
242fn parse_attribute(s: &str) -> Result<SharedJobAttributeToSelect, String> {
244 match s.to_lowercase().trim() {
245 "date" => Ok(SharedJobAttributeToSelect::Date),
246 "time" => Ok(SharedJobAttributeToSelect::Time),
247 "size" => Ok(SharedJobAttributeToSelect::Size),
248 "path" => Ok(SharedJobAttributeToSelect::Path),
249 "item" | "treelist" => Ok(SharedJobAttributeToSelect::Item), _ => Err(format!("Nieznana kolumna: '{}'. Dostępne to: date, time, size, path, item", s)),
251 }
252}
253
254fn parse_strategy(s: &str) -> Result<String, String> {
256 let valid_strategies = [
257 "Spec,Num,AZaz",
258 "Spec,Num,azAZ",
259 "Spec,Num,aAzZ",
260 "Spec,Num,AaZz",
261 "Num,Spec,AZaz",
262 "Num,Spec,azAZ",
263 "Num,Spec,aAzZ",
264 "Num,Spec,AaZz",
265 "Spec,AZaz,Num",
266 "Spec,azAZ,Num",
267 "Spec,aAzZ,Num",
268 "Spec,AaZz,Num",
269 "Num,AZaz,Spec",
270 "Num,azAZ,Spec",
271 "Num,aAzZ,Spec",
272 "Num,AaZz,Spec",
273 "AZaz,Num,Spec",
274 "azAZ,Num,Spec",
275 "aAzZ,Num,Spec",
276 "AaZz,Num,Spec",
277 "AZaz,Spec,Num",
278 "azAZ,Spec,Num",
279 "aAzZ,Spec,Num",
280 "AaZz,Spec,Num",
281 ];
282
283 if valid_strategies.contains(&s) {
284 Ok(s.to_string())
285 } else {
286 Err(format!("Nieprawidłowa strategia: '{}'. Przykład poprawnej: 'Spec,Num,AaZz'", s))
287 }
288}
289
290fn parse_ids(s: &str) -> Result<BTreeSet<String>, String> {
292 let ids: BTreeSet<String> = s.split(',').map(|id| id.trim().to_string()).filter(|id| !id.is_empty()).collect();
293
294 if ids.is_empty() {
295 Err("Nie podano prawidłowych identyfikatorów zadań. Użyj formatu np. 'x1,q2'".to_string())
296 } else {
297 Ok(ids)
298 }
299}