1use std::path::PathBuf;
2
3use clap::{ArgAction, Parser, ValueEnum};
4
5#[derive(Debug, Clone, Parser)]
7#[command(
8 name = "f00",
9 version,
10 about = "Fully compliant ls in Rust: coreutils drop-in (--gnu), modern TTY listings, JSON/tree",
11 long_about = "\
12f00 lists directory contents. Written in Rust.
13
14Flag groups:
15 GNU coreutils surface — full ls flag set; use --gnu (or auto non-TTY) for script-safe output
16 Modern TTY — --icons, --git, --color (default on a TTY)
17 f00-only — --json / --json-full, --tree, --csv/--tsv, --update, --browse
18
19Names follow LS_COLORS. Long-format metadata uses the terminal ANSI palette and optional
20F00_COLORS / EZA_COLORS / EXA_COLORS (eza-compatible keys: da, sn, uu, gu, ur, …).
21
22See man f00(1) and https://f00.sh
23",
24 disable_help_flag = true
26)]
27pub struct Args {
28 pub paths: Vec<PathBuf>,
30
31 #[arg(long = "help", action = ArgAction::Help, help = "Print help")]
33 pub help: Option<bool>,
34
35 #[arg(short = 'a', long = "all")]
37 pub all: bool,
38
39 #[arg(short = 'A', long = "almost-all")]
41 pub almost_all: bool,
42
43 #[arg(short = 'l')]
45 pub long: bool,
46
47 #[arg(short = '1')]
49 pub one_per_line: bool,
50
51 #[arg(short = 'C')]
53 pub columns: bool,
54
55 #[arg(short = 'm')]
57 pub commas: bool,
58
59 #[arg(short = 'h', long = "human-readable")]
61 pub human_readable: bool,
62
63 #[arg(long = "si")]
65 pub si: bool,
66
67 #[arg(short = 'R', long = "recursive")]
69 pub recursive: bool,
70
71 #[arg(short = 'r', long = "reverse")]
73 pub reverse: bool,
74
75 #[arg(short = 't')]
77 pub sort_time: bool,
78
79 #[arg(short = 'S')]
81 pub sort_size: bool,
82
83 #[arg(short = 'X')]
85 pub sort_extension: bool,
86
87 #[arg(short = 'v')]
89 pub sort_version: bool,
90
91 #[arg(short = 'U')]
93 pub sort_none: bool,
94
95 #[arg(long = "sort", value_name = "WORD")]
97 pub sort: Option<String>,
98
99 #[arg(long = "time", value_name = "WORD")]
101 pub time: Option<String>,
102
103 #[arg(short = 'u')]
105 pub access_time: bool,
106
107 #[arg(short = 'c')]
109 pub change_time: bool,
110
111 #[arg(
113 long = "color",
114 value_name = "WHEN",
115 default_value = "auto",
116 num_args = 0..=1,
117 default_missing_value = "always",
118 require_equals = true
119 )]
120 pub color: ColorArg,
121
122 #[arg(short = 'j', long = "json")]
124 pub json: bool,
125
126 #[arg(long = "json-full")]
128 pub json_full: bool,
129
130 #[arg(long = "csv")]
132 pub csv: bool,
133
134 #[arg(long = "tsv")]
136 pub tsv: bool,
137
138 #[arg(long = "tree")]
140 pub tree: bool,
141
142 #[arg(long = "gnu", action = ArgAction::SetTrue)]
144 pub gnu: bool,
145
146 #[arg(long = "no-gnu", action = ArgAction::SetTrue, conflicts_with = "gnu")]
149 pub no_gnu: bool,
150
151 #[arg(
153 long = "icons",
154 value_name = "WHEN",
155 default_value = "auto",
156 num_args = 0..=1,
157 default_missing_value = "always",
158 require_equals = true
159 )]
160 pub icons: IconsArg,
161
162 #[arg(
164 short = 'F',
165 long = "classify",
166 value_name = "WHEN",
167 num_args = 0..=1,
168 default_missing_value = "always",
169 require_equals = true
170 )]
171 pub classify: Option<ColorArg>,
172
173 #[arg(short = 'p')]
175 pub indicator_slash: bool,
176
177 #[arg(long = "file-type")]
179 pub file_type: bool,
180
181 #[arg(long = "indicator-style", value_name = "WORD")]
183 pub indicator_style: Option<String>,
184
185 #[arg(long = "group-directories-first", alias = "dirs-first")]
187 pub dirs_first: bool,
188
189 #[arg(short = 'd', long = "directory")]
191 pub directory: bool,
192
193 #[arg(short = 'B', long = "ignore-backups")]
195 pub ignore_backups: bool,
196
197 #[arg(short = 'I', long = "ignore", value_name = "PATTERN", action = ArgAction::Append)]
199 pub ignore: Vec<String>,
200
201 #[arg(long = "hide", value_name = "PATTERN", action = ArgAction::Append)]
203 pub hide: Vec<String>,
204
205 #[arg(short = 'L', long = "dereference")]
207 pub dereference: bool,
208
209 #[arg(short = 'H', long = "dereference-command-line")]
211 pub dereference_command_line: bool,
212
213 #[arg(long = "dereference-command-line-symlink-to-dir")]
215 pub dereference_command_line_symlink_to_dir: bool,
216
217 #[arg(short = 'g')]
219 pub no_owner: bool,
220
221 #[arg(short = 'o')]
223 pub no_group_long: bool,
224
225 #[arg(short = 'G', long = "no-group")]
227 pub no_group: bool,
228
229 #[arg(short = 'n', long = "numeric-uid-gid")]
231 pub numeric_uid_gid: bool,
232
233 #[arg(short = 'i', long = "inode")]
235 pub inode: bool,
236
237 #[arg(short = 's', long = "size")]
239 pub size_blocks: bool,
240
241 #[arg(short = 'k', long = "kibibytes")]
243 pub kibibytes: bool,
244
245 #[arg(long = "block-size", value_name = "SIZE")]
247 pub block_size: Option<String>,
248
249 #[arg(long = "full-time")]
251 pub full_time: bool,
252
253 #[arg(long = "time-style", value_name = "TIME_STYLE")]
255 pub time_style: Option<String>,
256
257 #[arg(short = 'q', long = "hide-control-chars")]
259 pub hide_control_chars: bool,
260
261 #[arg(long = "show-control-chars")]
263 pub show_control_chars: bool,
264
265 #[arg(short = 'b', long = "escape")]
267 pub escape: bool,
268
269 #[arg(short = 'Q', long = "quote-name")]
271 pub quote_name: bool,
272
273 #[arg(short = 'N', long = "literal")]
275 pub literal: bool,
276
277 #[arg(long = "quoting-style", value_name = "WORD")]
279 pub quoting_style: Option<String>,
280
281 #[arg(short = 'x')]
283 pub across: bool,
284
285 #[arg(short = 'f')]
287 pub unsorted_all: bool,
288
289 #[arg(long = "format", value_name = "WORD")]
291 pub format: Option<String>,
292
293 #[arg(short = 'T', long = "tabsize", value_name = "COLS")]
295 pub tabsize: Option<usize>,
296
297 #[arg(short = 'w', long = "width", value_name = "COLS")]
299 pub width: Option<usize>,
300
301 #[arg(short = 'Z', long = "context")]
303 pub context: bool,
304
305 #[arg(long = "zero")]
307 pub zero: bool,
308
309 #[arg(short = 'D', long = "dired")]
311 pub dired: bool,
312
313 #[arg(long = "author")]
315 pub author: bool,
316
317 #[arg(
319 long = "hyperlink",
320 value_name = "WHEN",
321 num_args = 0..=1,
322 default_missing_value = "always",
323 require_equals = true
324 )]
325 pub hyperlink: Option<ColorArg>,
326
327 #[arg(long = "max-depth", value_name = "N")]
329 pub max_depth: Option<usize>,
330
331 #[arg(long = "git", default_value_t = true, action = clap::ArgAction::Set)]
333 pub git: bool,
334
335 #[arg(long = "config", value_name = "PATH")]
337 pub config: Option<PathBuf>,
338
339 #[arg(long = "browse", visible_alias = "tui")]
341 pub browse: bool,
342
343 #[arg(long = "ignore-files")]
345 pub ignore_files: bool,
346
347 #[arg(long = "no-ignore")]
349 pub no_ignore: bool,
350
351 #[arg(long = "archive", default_value_t = true, action = clap::ArgAction::Set)]
353 pub archive: bool,
354
355 #[arg(long = "threads", value_name = "N", default_value_t = 0)]
357 pub threads: usize,
358
359 #[arg(long = "profile")]
361 pub profile: bool,
362
363 #[arg(long = "io-uring", action = ArgAction::Set, default_value_t = true)]
365 pub io_uring: bool,
366
367 #[arg(long = "generate-completions", value_name = "SHELL", hide = true)]
369 pub generate_completions: Option<clap_complete::Shell>,
370
371 #[arg(long = "generate-man", hide = true, action = ArgAction::SetTrue)]
373 pub generate_man: bool,
374
375 #[arg(long = "update", action = ArgAction::SetTrue)]
377 pub update: bool,
378
379 #[arg(long = "check-update", action = ArgAction::SetTrue)]
381 pub check_update: bool,
382
383 #[arg(long = "list-plugins", action = ArgAction::SetTrue)]
385 pub list_plugins: bool,
386}
387
388impl Args {
389 pub fn test_default() -> Self {
391 Self {
392 paths: vec![],
393 help: None,
394 all: false,
395 almost_all: false,
396 long: false,
397 one_per_line: false,
398 columns: false,
399 commas: false,
400 human_readable: false,
401 si: false,
402 recursive: false,
403 reverse: false,
404 sort_time: false,
405 sort_size: false,
406 sort_extension: false,
407 sort_version: false,
408 sort_none: false,
409 sort: None,
410 time: None,
411 access_time: false,
412 change_time: false,
413 color: ColorArg::Auto,
414 json: false,
415 json_full: false,
416 csv: false,
417 tsv: false,
418 tree: false,
419 gnu: false,
420 no_gnu: false,
421 icons: IconsArg::Auto,
422 classify: None,
423 indicator_slash: false,
424 file_type: false,
425 indicator_style: None,
426 dirs_first: false,
427 directory: false,
428 ignore_backups: false,
429 ignore: vec![],
430 hide: vec![],
431 dereference: false,
432 dereference_command_line: false,
433 dereference_command_line_symlink_to_dir: false,
434 no_owner: false,
435 no_group_long: false,
436 no_group: false,
437 numeric_uid_gid: false,
438 inode: false,
439 size_blocks: false,
440 kibibytes: false,
441 block_size: None,
442 full_time: false,
443 time_style: None,
444 hide_control_chars: false,
445 show_control_chars: false,
446 escape: false,
447 quote_name: false,
448 literal: false,
449 quoting_style: None,
450 across: false,
451 unsorted_all: false,
452 format: None,
453 tabsize: None,
454 width: None,
455 context: false,
456 zero: false,
457 dired: false,
458 author: false,
459 hyperlink: None,
460 max_depth: None,
461 git: false,
462 config: None,
463 browse: false,
464 ignore_files: false,
465 no_ignore: false,
466 archive: true,
467 threads: 0,
468 profile: false,
469 io_uring: true,
470 generate_completions: None,
471 generate_man: false,
472 update: false,
473 check_update: false,
474 list_plugins: false,
475 }
476 }
477}
478
479#[derive(Debug, Clone, Copy, Default, ValueEnum)]
480pub enum ColorArg {
481 #[default]
485 #[value(alias = "tty", alias = "if-tty")]
486 Auto,
487 #[value(alias = "yes", alias = "force", alias = "on", alias = "true")]
489 Always,
490 #[value(alias = "no", alias = "none", alias = "off", alias = "false")]
492 Never,
493}
494
495impl From<ColorArg> for f00_core::ColorWhen {
496 fn from(value: ColorArg) -> Self {
497 match value {
498 ColorArg::Auto => Self::Auto,
499 ColorArg::Always => Self::Always,
500 ColorArg::Never => Self::Never,
501 }
502 }
503}
504
505#[derive(Debug, Clone, Copy, Default, ValueEnum, PartialEq, Eq)]
507pub enum IconsArg {
508 #[default]
509 #[value(alias = "tty", alias = "if-tty")]
510 Auto,
511 #[value(alias = "yes", alias = "force", alias = "on", alias = "true")]
512 Always,
513 #[value(alias = "no", alias = "none", alias = "off", alias = "false")]
514 Never,
515}
516
517impl From<IconsArg> for f00_core::IconsWhen {
518 fn from(value: IconsArg) -> Self {
519 match value {
520 IconsArg::Auto => Self::Auto,
521 IconsArg::Always => Self::Always,
522 IconsArg::Never => Self::Never,
523 }
524 }
525}
526
527impl From<f00_core::IconsWhen> for IconsArg {
528 fn from(value: f00_core::IconsWhen) -> Self {
529 match value {
530 f00_core::IconsWhen::Auto => Self::Auto,
531 f00_core::IconsWhen::Always => Self::Always,
532 f00_core::IconsWhen::Never => Self::Never,
533 }
534 }
535}