use std::path::PathBuf;
use clap::{Args, ValueEnum};
#[derive(Args, Debug)]
pub struct CompletionsArgs {
#[arg(value_enum)]
pub shell: ShellType,
#[arg(
long,
help = "Install completion script to XDG data directory (Bash: ~/.local/share/bash-completion/completions/atomwrite)"
)]
pub install: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ShellType {
Bash,
Zsh,
Fish,
#[value(name = "powershell")]
PowerShell,
Elvish,
}
#[derive(Args, Debug)]
pub struct HashArgs {
#[arg(required_unless_present = "stdin")]
pub paths: Vec<PathBuf>,
#[arg(long, help = "Verify file checksum against expected BLAKE3 hash")]
pub verify: Option<String>,
#[arg(long, help = "Hash content from stdin instead of files")]
pub stdin: bool,
#[arg(short, long, help = "Recurse into directories")]
pub recursive: bool,
}
#[derive(Args, Debug)]
pub struct VerifyArgs {
pub path: PathBuf,
pub checksum: String,
}
#[derive(Args, Debug)]
pub struct DeleteArgs {
#[arg(required = true)]
pub paths: Vec<PathBuf>,
#[arg(long, help = "Create backup before deleting")]
pub backup: bool,
#[arg(long, default_value_t = 5, help = "Number of backups to retain")]
pub retention: u8,
#[arg(short, long, help = "Recurse into directories")]
pub recursive: bool,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
#[arg(
long,
help = "Only delete files older than duration (e.g. 30d, 24h, 1w)"
)]
pub older_than: Option<String>,
#[arg(
long,
conflicts_with = "dry_run",
help = "List files then ask for confirmation"
)]
pub confirm: bool,
#[arg(long, help = "Show what would be done without deleting")]
pub dry_run: bool,
#[arg(short = 'y', long, help = "Skip confirmation")]
pub yes: bool,
}
#[derive(Args, Debug)]
pub struct CountArgs {
#[arg(default_value = ".")]
pub paths: Vec<PathBuf>,
#[arg(long, help = "Group counts by file extension")]
pub by_extension: bool,
#[arg(long, help = "Sort by file size (top N)")]
pub by_size: bool,
#[arg(long, default_value_t = 10, help = "Number of top results")]
pub top: usize,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
}
#[derive(Args, Debug)]
pub struct DiffArgs {
pub file_a: PathBuf,
pub file_b: PathBuf,
#[arg(long, help = "Output unified diff format")]
pub unified: bool,
#[arg(long, help = "Only show summary statistics")]
pub stat: bool,
#[arg(
short = 'C',
long,
default_value_t = 3,
help = "Lines of context in unified diff"
)]
pub context: usize,
#[arg(long, value_enum, default_value_t = DiffAlgorithm::Patience, help = "Diff algorithm")]
pub algorithm: DiffAlgorithm,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum DiffAlgorithm {
Myers,
Patience,
Lcs,
}
#[derive(Args, Debug)]
pub struct MoveArgs {
pub source: PathBuf,
pub target: PathBuf,
#[arg(long, help = "Create backup of destination if it exists")]
pub backup: bool,
#[arg(long, default_value_t = 5, help = "Number of backups to retain")]
pub retention: u8,
#[arg(short, long, help = "Overwrite destination if it exists")]
pub force: bool,
#[arg(long, help = "Show what would be done without moving")]
pub dry_run: bool,
#[arg(long, help = "Preserve hardlink count on move")]
pub preserve_hardlinks: bool,
}
#[derive(Args, Debug)]
pub struct CopyArgs {
pub source: PathBuf,
pub target: PathBuf,
#[arg(long, help = "Create backup of destination if it exists")]
pub backup: bool,
#[arg(short, long, help = "Overwrite destination if it exists")]
pub force: bool,
#[arg(short, long, help = "Copy directories recursively")]
pub recursive: bool,
#[arg(long, help = "Preserve timestamps and permissions")]
pub preserve: bool,
#[arg(long, help = "Show what would be done without copying")]
pub dry_run: bool,
#[arg(long, help = "Disable reflink optimization; force full byte copy")]
pub no_reflink: bool,
#[arg(long, help = "Preserve extended attributes (xattr) on copy")]
pub preserve_xattr: bool,
}
#[derive(Args, Debug)]
pub struct ReadArgs {
pub path: PathBuf,
#[arg(long, help = "Line range to read (1-based, e.g. 1:50)")]
pub lines: Option<String>,
#[arg(long, help = "Single line number with optional context")]
pub line: Option<usize>,
#[arg(
short = 'C',
long,
default_value_t = 0,
help = "Lines of context around --line"
)]
pub context: usize,
#[arg(long, help = "Read first N lines")]
pub head: Option<usize>,
#[arg(long, help = "Read last N lines")]
pub tail: Option<usize>,
#[arg(long, help = "Return only metadata (no content)")]
pub stat: bool,
#[arg(long, value_enum, default_value_t = OutputFormat::Ndjson, help = "Output format")]
pub format: OutputFormat,
#[arg(long, help = "Verify file checksum against expected BLAKE3 hash")]
pub verify_checksum: Option<String>,
#[arg(
long,
allow_hyphen_values = true,
help = "Filter returned lines to those matching this regex"
)]
pub grep: Option<String>,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum OutputFormat {
Ndjson,
Raw,
}
#[derive(Args, Debug)]
pub struct WriteArgs {
pub target: PathBuf,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(long, default_value_t = 5, help = "Number of backups to retain")]
pub retention: u8,
#[arg(long, help = "Maximum input size in bytes")]
pub max_size: Option<u64>,
#[arg(
long,
conflicts_with = "prepend",
help = "Append content to end of existing file"
)]
pub append: bool,
#[arg(
long,
conflicts_with = "append",
help = "Prepend content to beginning of existing file"
)]
pub prepend: bool,
#[arg(
long,
help = "Run tree-sitter syntax check (G72). Aborts on parse errors (exit 88)."
)]
pub syntax_check: bool,
#[arg(
long,
help = "Only write if current checksum matches (optimistic lock)"
)]
pub expect_checksum: Option<String>,
#[arg(
long,
help = "Allow writes that shrink the file by >50% when --expect-checksum is active"
)]
pub allow_shrink: bool,
#[arg(
long,
value_enum,
default_value_t = crate::line_endings::LineEnding::Auto,
help = "Normalize line endings: lf, crlf, cr, auto (preserve original)"
)]
pub line_ending: crate::line_endings::LineEnding,
#[arg(
long,
help = "Allow zero-byte stdin (G120 L1 guard; default: reject empty stdin)"
)]
pub allow_empty_stdin: bool,
#[arg(
long,
help = "Allow --expect-checksum to be skipped when stdin is empty (G120 L3)"
)]
pub no_checksum_when_empty: bool,
#[arg(
long,
value_enum,
default_value_t = crate::wal::WalPolicy::Auto,
help = "WAL sidecar policy: auto (default), always, never (G119 L1)"
)]
pub wal_policy: crate::wal::WalPolicy,
#[arg(
long,
help = "Preserve original mtime/atime of the target file (default: update to now)"
)]
pub preserve_timestamps: bool,
#[arg(
long,
help = "Require --backup; abort if missing and target file exists (defense-in-depth L2)"
)]
pub require_backup: bool,
#[arg(
long,
help = "Require interactive Y/N confirmation for large files (>100KB) (defense-in-depth L3)"
)]
pub confirm: bool,
#[arg(
long,
help = "Force auto-rotation backup for recently-modified files (<24h) (defense-in-depth L5)"
)]
pub auto_rotate: bool,
#[arg(
long,
value_name = "PERCENT",
default_value_t = 255,
help = "Size delta threshold (percent) to trigger risk warning; default: off (set e.g. 50 to enable)"
)]
pub risk_threshold: u8,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
#[arg(
long,
help = "Keep backup after success (default: delete quietly). On failure backup is always preserved."
)]
pub keep_backup: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum FuzzyMode {
Auto,
Off,
Aggressive,
}
#[derive(Args, Debug)]
pub struct EditArgs {
pub path: PathBuf,
#[arg(long, help = "Insert content from stdin after line N")]
pub after_line: Option<usize>,
#[arg(long, help = "Insert content from stdin before line N")]
pub before_line: Option<usize>,
#[arg(long, help = "Replace line range N:M with stdin content")]
pub range: Option<String>,
#[arg(long, help = "Delete line range N:M")]
pub delete_range: Option<String>,
#[arg(
long,
allow_hyphen_values = true,
help = "Insert stdin content after first match of text"
)]
pub after_match: Option<String>,
#[arg(
long,
allow_hyphen_values = true,
help = "Insert stdin content before first match of text"
)]
pub before_match: Option<String>,
#[arg(
long,
num_args = 2,
allow_hyphen_values = true,
help = "Replace content between two markers with stdin"
)]
pub between: Option<Vec<String>>,
#[arg(long, allow_hyphen_values = true, action = clap::ArgAction::Append, help = "Exact text to find (repeatable; for content >1KB or with special chars, prefer --old-file)")]
pub old: Vec<String>,
#[arg(long, allow_hyphen_values = true, action = clap::ArgAction::Append, help = "Replacement text for --old (repeatable; for content >1KB or with special chars, prefer --new-file)")]
pub new: Vec<String>,
#[arg(long, conflicts_with = "old", action = clap::ArgAction::Append,
help = "Read match text from file (repeatable; alternative to --old for large content)")]
pub old_file: Vec<PathBuf>,
#[arg(long, conflicts_with = "new", action = clap::ArgAction::Append,
help = "Read replacement text from file (repeatable; alternative to --new for large content)")]
pub new_file: Vec<PathBuf>,
#[arg(
long,
value_enum,
default_value_t = FuzzyMode::Auto,
help = "Fuzzy match mode for --old/--new: auto, off, aggressive"
)]
pub fuzzy: FuzzyMode,
#[arg(
long,
help = "Read multiple edit operations as NDJSON from stdin (inherits --fuzzy mode)"
)]
pub multi: bool,
#[arg(long, help = "Only edit if current checksum matches (optimistic lock)")]
pub expect_checksum: Option<String>,
#[arg(
long,
value_enum,
default_value_t = crate::line_endings::LineEnding::Auto,
help = "Normalize line endings: lf, crlf, cr, auto (preserve original)"
)]
pub line_ending: crate::line_endings::LineEnding,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
#[arg(long, help = "Preserve original mtime (default: update mtime to now)")]
pub preserve_timestamps: bool,
#[arg(
long,
help = "Apply matching --old/--new pairs and report the rest (default: all-or-nothing)"
)]
pub partial: bool,
#[arg(long, help = "Override fuzzy similarity threshold (0.0-1.0)")]
pub fuzzy_threshold: Option<f64>,
#[arg(
long,
value_enum,
default_value_t = crate::wal::WalPolicy::Auto,
help = "WAL sidecar policy: auto (default), always, never (G119 L1)"
)]
pub wal_policy: crate::wal::WalPolicy,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(
long,
default_value_t = 5,
help = "Maximum number of backups to retain when --backup is active (default: 5)"
)]
pub retention: u8,
#[arg(
long,
help = "Keep backup after success (default: delete quietly). On failure backup is always preserved."
)]
pub keep_backup: bool,
#[arg(
long,
help = "Accept STATE_DRIFT between sequential edits (default: reject). For agent pipelines that chain edits."
)]
pub allow_sequential_drift: bool,
}
#[derive(Args, Debug)]
pub struct EditLoopArgs {
pub path: PathBuf,
#[arg(
long,
help = "Accept STATE_DRIFT (informational for edit-loop; default: reject)"
)]
pub allow_sequential_drift: bool,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(
long,
default_value_t = 5,
value_name = "N",
help = "Maximum number of backups to retain when --backup is active (default: 5)"
)]
pub retention: u8,
#[arg(
long,
help = "Keep backup after success (default: delete quietly). On failure backup is always preserved."
)]
pub keep_backup: bool,
#[arg(
long,
value_name = "LANG",
help = "Validate syntax of the written file via tree-sitter (e.g. rust, python, js)"
)]
pub syntax_check: Option<String>,
#[arg(
long,
value_enum,
default_value_t = crate::line_endings::LineEnding::Auto,
help = "Normalize line endings: lf, crlf, cr, auto (preserve original)"
)]
pub line_ending: crate::line_endings::LineEnding,
}
#[derive(Args, Debug)]
pub struct SearchArgs {
#[arg(allow_hyphen_values = true)]
pub pattern: String,
#[arg(default_value = ".")]
pub paths: Vec<PathBuf>,
#[arg(
short = 'e',
long,
conflicts_with = "fixed",
help = "Treat pattern as regex (default)"
)]
pub regex: bool,
#[arg(
short = 'F',
long,
conflicts_with = "regex",
help = "Treat pattern as fixed string"
)]
pub fixed: bool,
#[arg(short = 'w', long, help = "Match whole words only")]
pub word: bool,
#[arg(short = 'i', long, help = "Case-insensitive search")]
pub case_insensitive: bool,
#[arg(
short = 'S',
long,
help = "Smart case: insensitive if pattern is lowercase"
)]
pub smart_case: bool,
#[arg(
short = 'C',
long,
default_value_t = 0,
help = "Lines of context around matches"
)]
pub context: usize,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
#[arg(short = 'c', long, help = "Only show match count per file")]
pub count: bool,
#[arg(short = 'l', long, help = "Only show filenames with matches")]
pub files: bool,
#[arg(short = 'm', long, help = "Maximum matches per file")]
pub max_count: Option<u64>,
#[arg(short = 'U', long, help = "Enable multi-line matching")]
pub multiline: bool,
#[arg(long, help = "Show lines that do NOT match")]
pub invert: bool,
#[arg(long, value_enum, help = "Sort results by criterion")]
pub sort: Option<SortBy>,
#[arg(
long,
help = "Include FIFO / named pipe files (default: skip to avoid hangs)"
)]
pub include_fifo: bool,
#[arg(
long,
default_value_t = 10 * 1024 * 1024,
help = "Skip files larger than N bytes (default: 10 MiB)"
)]
pub max_filesize: u64,
#[arg(
long,
default_value_t = 500,
help = "Truncate matches longer than N columns (default: 500)"
)]
pub max_columns: usize,
#[arg(
long,
help = "Suppress begin/end events for files with no matches (cleaner output for empty searches)"
)]
pub no_begin_end: bool,
#[arg(
short = 'P',
long,
help = "Use PCRE2 regex engine (requires pcre2 feature)"
)]
pub pcre2: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum SortBy {
Path,
Modified,
Created,
None,
}
#[derive(Args, Debug)]
pub struct ReplaceArgs {
#[arg(allow_hyphen_values = true)]
pub pattern: String,
#[arg(allow_hyphen_values = true)]
pub replacement: String,
#[arg(default_value = ".")]
pub paths: Vec<PathBuf>,
#[arg(long, conflicts_with = "literal", help = "Treat pattern as regex")]
pub regex: bool,
#[arg(short = 'w', long, help = "Match whole words only")]
pub word: bool,
#[arg(
short = 'F',
long,
conflicts_with = "regex",
help = "Treat pattern as literal string (escape regex chars)"
)]
pub literal: bool,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
#[arg(long, help = "Show diff preview without writing")]
pub preview: bool,
#[arg(short = 'n', long, help = "Maximum replacements per file")]
pub max_replacements: Option<usize>,
#[arg(
long,
help = "Only replace if current checksum matches (optimistic lock)"
)]
pub expect_checksum: Option<String>,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
#[arg(
long,
help = "Preserve original casing (UPPER→UPPER, lower→lower, Title→Title)"
)]
pub preserve_case: bool,
#[arg(long, help = "Preserve original mtime (default: update mtime to now)")]
pub preserve_timestamps: bool,
#[arg(
long,
help = "Keep backup after success (default: delete quietly). On failure backup is always preserved."
)]
pub keep_backup: bool,
}
#[derive(Args, Debug)]
pub struct ListArgs {
#[arg(default_value = ".")]
pub paths: Vec<PathBuf>,
#[arg(short = 'd', long, help = "Maximum directory depth")]
pub depth: Option<usize>,
#[arg(short = 'l', long, help = "Show size and modification time")]
pub long: bool,
#[arg(long, help = "Group file counts by extension")]
pub count_by_ext: bool,
#[arg(long, help = "Show all files including hidden")]
pub all: bool,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
}
#[derive(Args, Debug)]
pub struct ExtractArgs {
pub fields: Vec<String>,
#[arg(
short = 'd',
long,
help = "Delimiter for text mode (default: whitespace)"
)]
pub delimiter: Option<String>,
#[arg(long, help = "Read input from stdin")]
pub stdin: bool,
}
#[derive(Args, Debug)]
pub struct CalcArgs {
#[arg(allow_hyphen_values = true)]
pub expression: Option<String>,
#[arg(long, help = "Read expressions from stdin (one per line)")]
pub stdin: bool,
}
#[derive(Args, Debug)]
pub struct RegexArgs {
#[arg(help = "Example strings (use -- before hyphenated examples)")]
pub examples: Vec<String>,
#[arg(long, help = "Read examples from stdin (one per line)")]
pub stdin: bool,
#[arg(short = 'd', long, help = "Convert digits to \\d")]
pub digits: bool,
#[arg(short = 'w', long, help = "Convert words to \\w")]
pub words: bool,
#[arg(short = 's', long, help = "Convert whitespace to \\s")]
pub spaces: bool,
#[arg(short = 'r', long, help = "Detect repetitions")]
pub repetitions: bool,
#[arg(short = 'i', long, help = "Case-insensitive matching")]
pub case_insensitive: bool,
#[arg(long, help = "Remove anchors (^ and $)")]
pub no_anchors: bool,
}
#[derive(Args, Debug)]
pub struct TransformArgs {
#[arg(default_value = ".")]
pub paths: Vec<PathBuf>,
#[arg(
short = 'p',
long,
allow_hyphen_values = true,
help = "AST pattern to match (single-rule mode)"
)]
pub pattern: Option<String>,
#[arg(
short = 'r',
long,
allow_hyphen_values = true,
help = "Rewrite template (single-rule mode)"
)]
pub rewrite: Option<String>,
#[arg(
short = 'l',
long = "language",
help = "Language (rust, js, ts, py, go, etc.) — required for single-rule mode"
)]
pub language: Option<String>,
#[arg(short = 'g', long, action = clap::ArgAction::Append, help = "Include files matching glob")]
pub include: Vec<String>,
#[arg(long, action = clap::ArgAction::Append, help = "Exclude files matching glob")]
pub exclude: Vec<String>,
#[arg(long, help = "Show diff preview without writing")]
pub dry_run: bool,
#[arg(long, help = "Apply multiple rules from a YAML file")]
pub rules: Option<PathBuf>,
#[arg(
long,
allow_hyphen_values = true,
help = "Apply multiple rules from inline YAML string"
)]
pub inline_rules: Option<String>,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(
long,
help = "Re-parse output with tree-sitter to verify syntax (exit 88 on error)"
)]
pub verify_parse: bool,
}
#[derive(Args, Debug)]
pub struct BatchArgs {
#[arg(long, help = "Show what would be done without executing")]
pub dry_run: bool,
#[arg(long, help = "Read manifest from file instead of stdin")]
pub file: Option<PathBuf>,
#[arg(
long,
help = "All-or-nothing: rollback all changes if any operation fails"
)]
pub transaction: bool,
#[arg(long, help = "Print JSON Schema for the batch input manifest")]
pub input_schema: bool,
#[arg(
long,
default_value_t = 100usize,
help = "Operations to buffer before emitting the summary line (default: 100)"
)]
pub batch_size: usize,
#[arg(
long,
help = "Keep per-op backups after success (default: delete quietly). On failure backups are always preserved."
)]
pub keep_backup: bool,
}
#[derive(Args, Debug)]
pub struct BackupArgs {
#[arg(required = true)]
pub paths: Vec<PathBuf>,
#[arg(long, help = "Directory to store backup files")]
pub output_dir: Option<PathBuf>,
#[arg(long, default_value_t = 5, help = "Number of backup copies to keep")]
pub retention: u8,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct PruneBackupsArgs {
#[arg(required = true)]
pub paths: Vec<PathBuf>,
#[arg(
long,
value_name = "SECONDS",
help = "Drop backups older than N seconds"
)]
pub max_age_secs: Option<u32>,
#[arg(long, value_name = "N", help = "Keep at most N most-recent backups")]
pub max_count: Option<u8>,
#[arg(long, help = "Show what would be pruned without writing")]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct RollbackArgs {
pub path: PathBuf,
#[arg(long, help = "Timestamp of the backup to restore")]
pub timestamp: Option<String>,
#[arg(long, help = "Restore the most recent backup (default)")]
pub latest: bool,
#[arg(long, help = "Verify checksum after restoring")]
pub verify: bool,
#[arg(
long,
help = "Create .bak of the current target before restoring (default: false; paridade com edit)"
)]
pub backup: bool,
#[arg(
long,
help = "Keep pre-rollback snapshot after success (default: delete quietly)"
)]
pub keep_backup: bool,
#[arg(
long,
default_value_t = 5,
help = "Number of backups to retain when --keep-backup is active (default: 5)"
)]
pub retention: u8,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
pub enum PatchFormat {
#[default]
Auto,
Unified,
SearchReplace,
Full,
Markdown,
}
#[derive(Args, Debug)]
pub struct ApplyArgs {
pub file: PathBuf,
#[arg(long, value_enum, default_value_t = PatchFormat::Auto, help = "Patch format: auto, unified, search-replace, full, markdown")]
pub format: PatchFormat,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(
long,
help = "Keep backup after success (default: delete quietly). On failure backup is always preserved."
)]
pub keep_backup: bool,
#[arg(
long,
default_value_t = 5,
help = "Number of backups to retain when --keep-backup is active (default: 5)"
)]
pub retention: u8,
#[arg(long, help = "Show what would be done without writing")]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct SetArgs {
pub path: PathBuf,
pub key_path: String,
pub value: String,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(long, help = "Preserve original mtime/atime")]
pub preserve_timestamps: bool,
}
#[derive(Args, Debug)]
pub struct GetArgs {
pub path: PathBuf,
pub key_path: String,
}
#[derive(Args, Debug)]
pub struct DelArgs {
pub path: PathBuf,
pub key_path: String,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(long, help = "Preserve original mtime/atime")]
pub preserve_timestamps: bool,
#[arg(long, help = "Succeed silently if the key is already missing")]
pub force_missing: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum IdentifierCase {
Snake,
Camel,
Pascal,
Kebab,
ScreamingSnake,
}
#[derive(Args, Debug)]
pub struct CaseArgs {
pub paths: Vec<PathBuf>,
#[arg(
long = "subvert",
num_args = 2,
value_name = "OLD NEW",
help = "Old and new identifier (repeat for multiple pairs)"
)]
pub subvert: Vec<String>,
#[arg(long, value_enum, default_value_t = IdentifierCase::Snake, help = "Target case style")]
pub to: IdentifierCase,
#[arg(
long,
default_value_t = true,
help = "Create backup before mutating (default: true; use --no-backup to disable)"
)]
pub backup: bool,
#[arg(long, help = "Disable automatic pre-write backup")]
pub no_backup: bool,
#[arg(long, help = "Preserve original mtime/atime")]
pub preserve_timestamps: bool,
#[arg(long, help = "Show what would be changed without writing")]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct QueryArgs {
pub path: PathBuf,
#[arg(
long,
value_name = "LANG",
help = "Language override (auto-detected from extension)"
)]
pub language: Option<String>,
#[arg(
short = 'Q',
long,
allow_hyphen_values = true,
value_name = "PATTERN",
help = "S-expression pattern (e.g. '(function_item name: (identifier) @name)')"
)]
pub query: Option<String>,
#[arg(long, help = "Print the full tree (no S-expression matching)")]
pub tree: bool,
#[arg(long, help = "Print all named node kinds in the file (counts)")]
pub kinds: bool,
#[arg(
long,
help = "Include byte offsets and start positions for every match"
)]
pub positions: bool,
}
#[derive(Args, Debug)]
pub struct OutlineArgs {
pub path: PathBuf,
#[arg(
long,
value_name = "LANG",
help = "Language override (auto-detected from extension)"
)]
pub language: Option<String>,
#[arg(
long = "kind",
value_name = "KIND",
help = "Filter by kind (repeat for multiple)"
)]
pub kinds: Vec<String>,
#[arg(long, help = "Include byte offsets and start positions")]
pub positions: bool,
}
#[derive(Args, Debug)]
pub struct WalStatsArgs {
#[arg(long, help = "Show what would be done without scanning")]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct WalHealArgs {
#[arg(
long,
default_value_t = 3600,
help = "Minimum age (seconds) for removal"
)]
pub threshold_secs: u64,
#[arg(
long,
default_value_t = 100,
help = "Wall-clock budget (ms) for the walk"
)]
pub max_duration_ms: u64,
#[arg(long, help = "Show what would be removed without writing")]
pub dry_run: bool,
}