1use std::path::PathBuf;
6
7use clap::{Args, ValueEnum};
8
9#[derive(Args, Debug)]
11pub struct CompletionsArgs {
12 #[arg(value_enum)]
14 pub shell: ShellType,
15
16 #[arg(
18 long,
19 help = "Install completion script to XDG data directory (Bash: ~/.local/share/bash-completion/completions/atomwrite)"
20 )]
21 pub install: bool,
22}
23
24#[derive(Debug, Clone, Copy, ValueEnum)]
26pub enum ShellType {
27 Bash,
29 Zsh,
31 Fish,
33 #[value(name = "powershell")]
35 PowerShell,
36 Elvish,
38}
39
40#[derive(Args, Debug)]
42pub struct HashArgs {
43 #[arg(required = true)]
45 pub paths: Vec<PathBuf>,
46
47 #[arg(long, help = "Verify file checksum against expected BLAKE3 hash")]
49 pub verify: Option<String>,
50
51 #[arg(long, help = "Hash content from stdin instead of files")]
53 pub stdin: bool,
54
55 #[arg(short, long, help = "Recurse into directories")]
57 pub recursive: bool,
58}
59
60#[derive(Args, Debug)]
62pub struct DeleteArgs {
63 #[arg(required = true)]
65 pub paths: Vec<PathBuf>,
66
67 #[arg(long, help = "Create backup before deleting")]
69 pub backup: bool,
70
71 #[arg(long, default_value_t = 5, help = "Number of backups to retain")]
73 pub retention: u8,
74
75 #[arg(short, long, help = "Recurse into directories")]
77 pub recursive: bool,
78
79 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
81 pub include: Vec<String>,
82
83 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
85 pub exclude: Vec<String>,
86
87 #[arg(long, help = "Show what would be done without deleting")]
89 pub dry_run: bool,
90
91 #[arg(short = 'y', long, help = "Skip confirmation")]
93 pub yes: bool,
94}
95
96#[derive(Args, Debug)]
98pub struct CountArgs {
99 #[arg(default_value = ".")]
101 pub paths: Vec<PathBuf>,
102
103 #[arg(long, help = "Group counts by file extension")]
105 pub by_extension: bool,
106
107 #[arg(long, help = "Sort by file size (top N)")]
109 pub by_size: bool,
110
111 #[arg(long, default_value_t = 10, help = "Number of top results")]
113 pub top: usize,
114
115 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
117 pub include: Vec<String>,
118
119 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
121 pub exclude: Vec<String>,
122}
123
124#[derive(Args, Debug)]
126pub struct DiffArgs {
127 pub file_a: PathBuf,
129 pub file_b: PathBuf,
131
132 #[arg(long, help = "Output unified diff format")]
134 pub unified: bool,
135
136 #[arg(long, help = "Only show summary statistics")]
138 pub stat: bool,
139
140 #[arg(
142 short = 'C',
143 long,
144 default_value_t = 3,
145 help = "Lines of context in unified diff"
146 )]
147 pub context: usize,
148
149 #[arg(long, value_enum, default_value_t = DiffAlgorithm::Patience, help = "Diff algorithm")]
151 pub algorithm: DiffAlgorithm,
152}
153
154#[derive(Debug, Clone, Copy, ValueEnum)]
156pub enum DiffAlgorithm {
157 Myers,
159 Patience,
161 Lcs,
163}
164
165#[derive(Args, Debug)]
167pub struct MoveArgs {
168 pub source: PathBuf,
170 pub target: PathBuf,
172
173 #[arg(long, help = "Create backup of destination if it exists")]
175 pub backup: bool,
176
177 #[arg(long, default_value_t = 5, help = "Number of backups to retain")]
179 pub retention: u8,
180
181 #[arg(short, long, help = "Overwrite destination if it exists")]
183 pub force: bool,
184
185 #[arg(long, help = "Show what would be done without moving")]
187 pub dry_run: bool,
188}
189
190#[derive(Args, Debug)]
192pub struct CopyArgs {
193 pub source: PathBuf,
195 pub target: PathBuf,
197
198 #[arg(long, help = "Create backup of destination if it exists")]
200 pub backup: bool,
201
202 #[arg(short, long, help = "Overwrite destination if it exists")]
204 pub force: bool,
205
206 #[arg(short, long, help = "Copy directories recursively")]
208 pub recursive: bool,
209
210 #[arg(long, help = "Preserve timestamps and permissions")]
212 pub preserve: bool,
213
214 #[arg(long, help = "Show what would be done without copying")]
216 pub dry_run: bool,
217}
218
219#[derive(Args, Debug)]
221pub struct ReadArgs {
222 pub path: PathBuf,
224
225 #[arg(long, help = "Line range to read (1-based, e.g. 1:50)")]
227 pub lines: Option<String>,
228
229 #[arg(long, help = "Single line number with optional context")]
231 pub line: Option<usize>,
232
233 #[arg(
235 short = 'C',
236 long,
237 default_value_t = 0,
238 help = "Lines of context around --line"
239 )]
240 pub context: usize,
241
242 #[arg(long, help = "Read first N lines")]
244 pub head: Option<usize>,
245
246 #[arg(long, help = "Read last N lines")]
248 pub tail: Option<usize>,
249
250 #[arg(long, help = "Return only metadata (no content)")]
252 pub stat: bool,
253
254 #[arg(long, value_enum, default_value_t = OutputFormat::Ndjson, help = "Output format")]
256 pub format: OutputFormat,
257
258 #[arg(long, help = "Verify file checksum against expected BLAKE3 hash")]
260 pub verify_checksum: Option<String>,
261
262 #[arg(long, help = "Filter returned lines to those matching this regex")]
264 pub grep: Option<String>,
265}
266
267#[derive(Debug, Clone, Copy, ValueEnum)]
269pub enum OutputFormat {
270 Ndjson,
272 Raw,
274}
275
276#[derive(Args, Debug)]
278pub struct WriteArgs {
279 pub target: PathBuf,
281
282 #[arg(long, help = "Create backup before overwriting")]
284 pub backup: bool,
285
286 #[arg(long, default_value_t = 5, help = "Number of backups to retain")]
288 pub retention: u8,
289
290 #[arg(long, help = "Maximum input size in bytes")]
292 pub max_size: Option<u64>,
293
294 #[arg(long, help = "Append content to end of existing file")]
296 pub append: bool,
297
298 #[arg(long, help = "Prepend content to beginning of existing file")]
300 pub prepend: bool,
301
302 #[arg(
304 long,
305 help = "Only write if current checksum matches (optimistic lock)"
306 )]
307 pub expect_checksum: Option<String>,
308
309 #[arg(
311 long,
312 value_enum,
313 default_value_t = crate::line_endings::LineEnding::Auto,
314 help = "Normalize line endings: lf, crlf, cr, auto (preserve original)"
315 )]
316 pub line_ending: crate::line_endings::LineEnding,
317
318 #[arg(long, help = "Show what would be done without writing")]
320 pub dry_run: bool,
321}
322
323#[derive(Debug, Clone, Copy, ValueEnum)]
325pub enum FuzzyMode {
326 Auto,
328 Off,
330 Aggressive,
332}
333
334#[derive(Args, Debug)]
336pub struct EditArgs {
337 pub path: PathBuf,
339
340 #[arg(long, help = "Insert content from stdin after line N")]
342 pub after_line: Option<usize>,
343
344 #[arg(long, help = "Insert content from stdin before line N")]
346 pub before_line: Option<usize>,
347
348 #[arg(long, help = "Replace line range N:M with stdin content")]
350 pub range: Option<String>,
351
352 #[arg(long, help = "Delete line range N:M")]
354 pub delete_range: Option<String>,
355
356 #[arg(long, help = "Insert stdin content after first match of text")]
358 pub after_match: Option<String>,
359
360 #[arg(long, help = "Insert stdin content before first match of text")]
362 pub before_match: Option<String>,
363
364 #[arg(
366 long,
367 num_args = 2,
368 help = "Replace content between two markers with stdin"
369 )]
370 pub between: Option<Vec<String>>,
371
372 #[arg(long, action = clap::ArgAction::Append, help = "Exact text to find (repeatable)")]
374 pub old: Vec<String>,
375
376 #[arg(long, action = clap::ArgAction::Append, help = "Replacement text for --old (repeatable)")]
378 pub new: Vec<String>,
379
380 #[arg(
382 long,
383 value_enum,
384 default_value_t = FuzzyMode::Auto,
385 help = "Fuzzy match mode for --old/--new: auto, off, aggressive"
386 )]
387 pub fuzzy: FuzzyMode,
388
389 #[arg(long, help = "Read multiple edit operations as NDJSON from stdin")]
391 pub multi: bool,
392
393 #[arg(long, help = "Only edit if current checksum matches (optimistic lock)")]
395 pub expect_checksum: Option<String>,
396
397 #[arg(
399 long,
400 value_enum,
401 default_value_t = crate::line_endings::LineEnding::Auto,
402 help = "Normalize line endings: lf, crlf, cr, auto (preserve original)"
403 )]
404 pub line_ending: crate::line_endings::LineEnding,
405
406 #[arg(long, help = "Show what would be done without writing")]
408 pub dry_run: bool,
409
410 #[arg(long, help = "Preserve original mtime (default: update mtime to now)")]
417 pub preserve_timestamps: bool,
418}
419
420#[derive(Args, Debug)]
422pub struct SearchArgs {
423 pub pattern: String,
425
426 #[arg(default_value = ".")]
428 pub paths: Vec<PathBuf>,
429
430 #[arg(short = 'e', long, help = "Treat pattern as regex (default)")]
432 pub regex: bool,
433
434 #[arg(short = 'F', long, help = "Treat pattern as fixed string")]
436 pub fixed: bool,
437
438 #[arg(short = 'w', long, help = "Match whole words only")]
440 pub word: bool,
441
442 #[arg(short = 'i', long, help = "Case-insensitive search")]
444 pub case_insensitive: bool,
445
446 #[arg(
448 short = 'S',
449 long,
450 help = "Smart case: insensitive if pattern is lowercase"
451 )]
452 pub smart_case: bool,
453
454 #[arg(
456 short = 'C',
457 long,
458 default_value_t = 0,
459 help = "Lines of context around matches"
460 )]
461 pub context: usize,
462
463 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
465 pub include: Vec<String>,
466
467 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
469 pub exclude: Vec<String>,
470
471 #[arg(short = 'c', long, help = "Only show match count per file")]
473 pub count: bool,
474
475 #[arg(short = 'l', long, help = "Only show filenames with matches")]
477 pub files: bool,
478
479 #[arg(short = 'm', long, help = "Maximum matches per file")]
481 pub max_count: Option<u64>,
482
483 #[arg(short = 'U', long, help = "Enable multi-line matching")]
485 pub multiline: bool,
486
487 #[arg(long, help = "Show lines that do NOT match")]
489 pub invert: bool,
490
491 #[arg(long, value_enum, help = "Sort results by criterion")]
493 pub sort: Option<SortBy>,
494}
495
496#[derive(Debug, Clone, Copy, ValueEnum)]
498pub enum SortBy {
499 Path,
501 Modified,
503 Created,
505 None,
507}
508
509#[derive(Args, Debug)]
511pub struct ReplaceArgs {
512 pub pattern: String,
514 pub replacement: String,
516
517 #[arg(default_value = ".")]
519 pub paths: Vec<PathBuf>,
520
521 #[arg(long, help = "Treat pattern as regex")]
523 pub regex: bool,
524
525 #[arg(short = 'w', long, help = "Match whole words only")]
527 pub word: bool,
528
529 #[arg(
531 short = 'F',
532 long,
533 help = "Treat pattern as literal string (escape regex chars)"
534 )]
535 pub literal: bool,
536
537 #[arg(long, help = "Create backup before modifying")]
539 pub backup: bool,
540
541 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
543 pub include: Vec<String>,
544
545 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
547 pub exclude: Vec<String>,
548
549 #[arg(long, help = "Show diff preview without writing")]
551 pub preview: bool,
552
553 #[arg(short = 'n', long, help = "Maximum replacements per file")]
555 pub max_replacements: Option<usize>,
556
557 #[arg(
559 long,
560 help = "Only replace if current checksum matches (optimistic lock)"
561 )]
562 pub expect_checksum: Option<String>,
563
564 #[arg(long, help = "Show what would be done without writing")]
566 pub dry_run: bool,
567
568 #[arg(long, help = "Preserve original mtime (default: update mtime to now)")]
575 pub preserve_timestamps: bool,
576}
577
578#[derive(Args, Debug)]
580pub struct ListArgs {
581 #[arg(default_value = ".")]
583 pub paths: Vec<PathBuf>,
584
585 #[arg(short = 'd', long, help = "Maximum directory depth")]
587 pub depth: Option<usize>,
588
589 #[arg(short = 'l', long, help = "Show size and modification time")]
591 pub long: bool,
592
593 #[arg(long, help = "Group file counts by extension")]
595 pub count_by_ext: bool,
596
597 #[arg(long, help = "Show all files including hidden")]
599 pub all: bool,
600
601 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
603 pub include: Vec<String>,
604
605 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
607 pub exclude: Vec<String>,
608}
609
610#[derive(Args, Debug)]
612pub struct ExtractArgs {
613 pub fields: Vec<String>,
615
616 #[arg(
618 short = 'd',
619 long,
620 help = "Delimiter for text mode (default: whitespace)"
621 )]
622 pub delimiter: Option<String>,
623
624 #[arg(long, help = "Read input from stdin")]
626 pub stdin: bool,
627}
628
629#[derive(Args, Debug)]
631pub struct CalcArgs {
632 pub expression: Option<String>,
634
635 #[arg(long, help = "Read expressions from stdin (one per line)")]
637 pub stdin: bool,
638}
639
640#[derive(Args, Debug)]
642pub struct RegexArgs {
643 pub examples: Vec<String>,
645
646 #[arg(long, help = "Read examples from stdin (one per line)")]
648 pub stdin: bool,
649
650 #[arg(short = 'd', long, help = "Convert digits to \\d")]
652 pub digits: bool,
653
654 #[arg(short = 'w', long, help = "Convert words to \\w")]
656 pub words: bool,
657
658 #[arg(short = 's', long, help = "Convert whitespace to \\s")]
660 pub spaces: bool,
661
662 #[arg(short = 'r', long, help = "Detect repetitions")]
664 pub repetitions: bool,
665
666 #[arg(short = 'i', long, help = "Case-insensitive matching")]
668 pub case_insensitive: bool,
669
670 #[arg(long, help = "Remove anchors (^ and $)")]
672 pub no_anchors: bool,
673}
674
675#[derive(Args, Debug)]
677pub struct TransformArgs {
678 #[arg(default_value = ".")]
680 pub paths: Vec<PathBuf>,
681
682 #[arg(short = 'p', long, required = true, help = "AST pattern to match")]
684 pub pattern: String,
685
686 #[arg(short = 'r', long, required = true, help = "Rewrite template")]
688 pub rewrite: String,
689
690 #[arg(
692 short = 'l',
693 long = "language",
694 required = true,
695 help = "Language (rust, js, ts, py, go, etc)"
696 )]
697 pub language: String,
698
699 #[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
701 pub include: Vec<String>,
702
703 #[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
705 pub exclude: Vec<String>,
706
707 #[arg(long, help = "Show diff preview without writing")]
709 pub dry_run: bool,
710
711 #[arg(long, help = "Create backup before modifying")]
713 pub backup: bool,
714}
715
716#[derive(Args, Debug)]
718pub struct BatchArgs {
719 #[arg(long, help = "Show what would be done without executing")]
721 pub dry_run: bool,
722
723 #[arg(long, help = "Read manifest from file instead of stdin")]
725 pub file: Option<PathBuf>,
726
727 #[arg(
729 long,
730 help = "All-or-nothing: rollback all changes if any operation fails"
731 )]
732 pub transaction: bool,
733
734 #[arg(long, help = "Print JSON Schema for the batch input manifest")]
736 pub input_schema: bool,
737}
738
739#[derive(Args, Debug)]
741pub struct BackupArgs {
742 #[arg(required = true)]
744 pub paths: Vec<PathBuf>,
745
746 #[arg(long, help = "Directory to store backup files")]
748 pub output_dir: Option<PathBuf>,
749
750 #[arg(long, default_value_t = 5, help = "Number of backup copies to keep")]
752 pub retention: u8,
753
754 #[arg(long, help = "Show what would be done without writing")]
756 pub dry_run: bool,
757}
758
759#[derive(Args, Debug)]
761pub struct RollbackArgs {
762 pub path: PathBuf,
764
765 #[arg(long, help = "Timestamp of the backup to restore")]
767 pub timestamp: Option<String>,
768
769 #[arg(long, help = "Restore the most recent backup (default)")]
771 pub latest: bool,
772
773 #[arg(long, help = "Verify checksum after restoring")]
775 pub verify: bool,
776
777 #[arg(long, help = "Show what would be done without writing")]
779 pub dry_run: bool,
780}
781
782#[derive(Debug, Clone, Copy, ValueEnum, Default)]
784pub enum PatchFormat {
785 #[default]
787 Auto,
788 Unified,
790 SearchReplace,
792 Full,
794 Markdown,
796}
797
798#[derive(Args, Debug)]
800pub struct ApplyArgs {
801 pub file: PathBuf,
803
804 #[arg(long, value_enum, default_value_t = PatchFormat::Auto, help = "Patch format: auto, unified, search-replace, full, markdown")]
806 pub format: PatchFormat,
807
808 #[arg(long, help = "Create backup of target before patching")]
810 pub backup: bool,
811
812 #[arg(long, help = "Show what would be done without writing")]
814 pub dry_run: bool,
815}