#[derive(Args, Debug)]
#[derive(Clone)]
pub struct SearchArgs {
#[arg(allow_hyphen_values = true)]
pub pattern: String,
#[arg(default_value = ".", value_hint = ValueHint::AnyPath)]
pub paths: Vec<PathBuf>,
#[arg(
short = 'e',
long,
conflicts_with = "fixed",
help = "Treat pattern as regex (default)",
action = clap::ArgAction::SetTrue
)]
pub regex: bool,
#[arg(
short = 'F',
long,
conflicts_with = "regex",
help = "Treat pattern as fixed string",
action = clap::ArgAction::SetTrue
)]
pub fixed: bool,
#[arg(short = 'w', long, help = "Match whole words only", action = clap::ArgAction::SetTrue)]
pub word: bool,
#[arg(short = 'i', long, help = "Case-insensitive search", action = clap::ArgAction::SetTrue)]
pub case_insensitive: bool,
#[arg(
short = 'S',
long,
help = "Smart case: insensitive if pattern is lowercase",
action = clap::ArgAction::SetTrue
)]
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", action = clap::ArgAction::SetTrue)]
pub count: bool,
#[arg(short = 'l', long, help = "Only show filenames with matches", action = clap::ArgAction::SetTrue)]
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", action = clap::ArgAction::SetTrue)]
pub multiline: bool,
#[arg(long, help = "Show lines that do NOT match", action = clap::ArgAction::SetTrue)]
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)",
action = clap::ArgAction::SetTrue
)]
pub include_fifo: bool,
#[arg(
long,
default_value_t = crate::constants::DEFAULT_SEARCH_MAX_FILESIZE_BYTES,
help = "Skip files larger than N bytes (default: constants::DEFAULT_SEARCH_MAX_FILESIZE_BYTES)"
)]
pub max_filesize: u64,
#[arg(
long,
default_value_t = crate::constants::DEFAULT_SEARCH_MAX_COLUMNS,
help = "Truncate matches longer than N columns (default: constants::DEFAULT_SEARCH_MAX_COLUMNS)"
)]
pub max_columns: usize,
#[arg(
long,
help = "Search binary files (default: skip binary / NUL content)",
action = clap::ArgAction::SetTrue
)]
pub binary: bool,
#[arg(
long,
help = "Suppress begin/end events for files with no matches (cleaner output for empty searches)",
action = clap::ArgAction::SetTrue
)]
pub no_begin_end: bool,
#[arg(
short = 'P',
long,
help = "Use PCRE2 regex engine (requires pcre2 feature)",
action = clap::ArgAction::SetTrue
)]
pub pcre2: bool,
#[arg(
long,
value_enum,
default_value_t = SearchTarget::Content,
help = "Search target: content, files (basename), or both"
)]
pub target: SearchTarget,
#[arg(long, default_value_t = 0, help = "Skip first N matches (pagination offset)")]
pub offset: u64,
#[arg(long, help = "Limit number of match events emitted")]
pub limit: Option<u64>,
}
#[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", action = clap::ArgAction::SetTrue)]
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)", action = clap::ArgAction::SetTrue)]
pub stdin: bool,
}
#[derive(Args, Debug)]
pub struct TransformArgs {
#[arg(default_value = ".", value_hint = ValueHint::AnyPath)]
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", action = clap::ArgAction::SetTrue)]
pub dry_run: bool,
#[arg(long, help = "Apply multiple rules from a YAML file", value_hint = ValueHint::FilePath)]
pub rules: Option<PathBuf>,
#[arg(
long,
allow_hyphen_values = true,
help = "Apply multiple rules from inline YAML string"
)]
pub inline_rules: Option<String>,
#[command(flatten)]
pub backup_opts: BackupOpts,
#[arg(
long,
help = "Re-parse output with tree-sitter to verify syntax (exit 88 on error)",
action = clap::ArgAction::SetTrue
)]
pub verify_parse: bool,
}
#[derive(Args, Debug)]
#[command(group(
clap::ArgGroup::new("prune_policy")
.required(true)
.args(["max_age_secs", "max_count"])
))]
pub struct PruneBackupsArgs {
#[arg(required = true, value_hint = ValueHint::AnyPath)]
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", action = clap::ArgAction::SetTrue)]
pub dry_run: bool,
}
#[derive(Args, Debug)]
pub struct ApplyArgs {
#[arg(value_hint = ValueHint::FilePath)]
pub file: PathBuf,
#[arg(long, value_enum, default_value_t = PatchFormat::Auto, help = "Patch format: auto, unified, search-replace, full, markdown")]
pub format: PatchFormat,
#[command(flatten)]
pub backup_opts: BackupOpts,
#[arg(long, help = "Show what would be done without writing", action = clap::ArgAction::SetTrue)]
pub dry_run: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum IdentifierCase {
Snake,
Camel,
Pascal,
Kebab,
ScreamingSnake,
}
#[derive(Args, Debug)]
pub struct QueryArgs {
#[arg(value_hint = ValueHint::FilePath)]
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 (-Q/--query; global -q is quiet, not query)"
)]
pub query: Option<String>,
#[arg(long, help = "Print the full tree (no S-expression matching)", action = clap::ArgAction::SetTrue)]
pub tree: bool,
#[arg(long, help = "Print all named node kinds in the file (counts)", action = clap::ArgAction::SetTrue)]
pub kinds: bool,
#[arg(
long,
help = "Include byte offsets and start positions for every match",
action = clap::ArgAction::SetTrue
)]
pub positions: bool,
}