use anyhow::Result;
use clap::{ArgAction, Parser};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "comment-stripper-rs")]
#[command(about = "Strip non-rustdoc comments from Rust source trees")]
#[command(version)]
struct Cli {
#[arg(
default_value = ".",
value_name = "PATH",
help = "One or more files or directories to process (defaults to the current directory)"
)]
roots: Vec<PathBuf>,
#[arg(short = 'c', long, action = ArgAction::SetTrue, help = "Report files that would change without rewriting them; exit non-zero if any would")]
check: bool,
#[arg(short = 'v', long, action = ArgAction::SetTrue, help = "Print changed file paths")]
verbose: bool,
#[arg(long, action = ArgAction::SetTrue, help = "Include hidden files and directories")]
hidden: bool,
#[arg(long, action = ArgAction::SetTrue, help = "Follow symlinks")]
follow_links: bool,
#[arg(short = 'n', long, action = ArgAction::SetTrue, help = "Do not create backup files when rewriting")]
no_backup: bool,
#[arg(short = 'd', long, action = ArgAction::SetTrue, help = "Also strip rustdoc comments (///, //!, /** */, /*! */)")]
strip_docs: bool,
#[arg(
long,
action = ArgAction::SetTrue,
conflicts_with = "check",
help = "Delete backup files (matching --backup-suffix) instead of stripping comments"
)]
clean_backups: bool,
#[arg(
long,
action = ArgAction::SetTrue,
conflicts_with_all = ["check", "clean_backups"],
help = "Restore backup files (matching --backup-suffix) over their originals instead of stripping comments"
)]
restore_backups: bool,
#[arg(
long,
default_value = ".bak",
help = "Suffix appended to backup files (also matched by --clean-backups)"
)]
backup_suffix: String,
#[arg(
short = 'e',
long,
value_delimiter = ',',
help = "Comma-separated directory names to skip (target and .git are always excluded)"
)]
exclude_dirs: Vec<String>,
#[arg(
short = 'i',
long,
value_delimiter = ',',
help = "Comma-separated glob patterns; only matching files are stripped (e.g. 'src/**/*.rs'). Use '**' to cross directories. Excluded dirs still win."
)]
include: Vec<String>,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let mut exclude_dirs = cli.exclude_dirs;
for forced in ["target", ".git"] {
if !exclude_dirs.iter().any(|d| d == forced) {
exclude_dirs.push(forced.to_string());
}
}
let cfg = comment_stripper_rs::Config {
roots: cli.roots,
check: cli.check,
verbose: cli.verbose,
hidden: cli.hidden,
follow_links: cli.follow_links,
no_backup: cli.no_backup,
strip_doc_comments: cli.strip_docs,
backup_suffix: cli.backup_suffix,
exclude_dirs,
include_globs: cli.include,
};
if cli.clean_backups {
let stats = comment_stripper_rs::remove_backups(&cfg)?;
if cli.verbose {
eprintln!("removed {} backup file(s)", stats.files_changed);
}
return Ok(());
}
if cli.restore_backups {
let stats = comment_stripper_rs::restore_backups(&cfg)?;
if cli.verbose {
eprintln!("restored {} backup file(s)", stats.files_changed);
}
return Ok(());
}
let stats = comment_stripper_rs::run(&cfg)?;
if cli.verbose && !cli.check {
eprintln!(
"scanned {} Rust file(s), changed {}",
stats.files_seen, stats.files_changed
);
}
Ok(())
}