use clap::builder::styling::{AnsiColor, Styles};
use clap::{ArgAction, ColorChoice, CommandFactory, FromArgMatches, Parser};
use std::io::IsTerminal as _;
use std::path::PathBuf;
mod fs_safemove;
mod graveyard;
mod index;
mod paths;
mod safety;
mod ui;
fn help_styles() -> Styles {
Styles::styled()
.usage(AnsiColor::Yellow.on_default().bold())
.header(AnsiColor::Yellow.on_default().bold())
.literal(AnsiColor::Green.on_default()) .placeholder(AnsiColor::Cyan.on_default()) }
#[derive(Parser)]
#[command(
name = "nrip",
version,
about = "Safe rm with a graveyard",
color = clap::ColorChoice::Auto,
styles = help_styles()
)]
struct Cli {
#[arg(value_name = "PATHS", allow_hyphen_values = true)]
paths: Vec<PathBuf>,
#[arg(
short = 'c',
long = "cremate",
value_name = "TARGET",
num_args = 0..=1, // valeur optionnelle
action = ArgAction::Set, // important !
conflicts_with = "paths"
)]
cremate: Option<Option<String>>,
#[arg(
short = 'r',
long = "resurrect",
value_name = "TARGET",
num_args = 0..=1,
action = ArgAction::Set,
conflicts_with_all = ["paths", "cremate", "target", "list"]
)]
resurrect: Option<Option<String>>,
#[arg(long = "target", requires = "cremate")]
target: Option<String>,
#[arg(short = 'f', long = "force")]
force: bool,
#[arg(short = 'l', long = "list")]
list: bool,
#[arg(long)]
dry_run: bool,
#[arg(short = 'y', long)]
yes: bool,
#[arg(hide = true, long = "__complete", value_names = ["CONTEXT", "PREFIX"], num_args = 1..=2)]
__complete: Vec<String>,
}
fn main() -> anyhow::Result<()> {
let no_color_env = std::env::var_os("NO_COLOR").is_some();
let is_tty = std::io::stdout().is_terminal();
let mut cmd = Cli::command();
cmd = cmd.color(if no_color_env {
ColorChoice::Never
} else {
ColorChoice::Auto
});
let mut matches = cmd.get_matches();
let cli = Cli::from_arg_matches_mut(&mut matches)?;
if no_color_env || !is_tty {
yansi::disable();
} else {
yansi::enable();
}
if !cli.__complete.is_empty() {
let context = cli.__complete[0].as_str();
let prefix = cli.__complete.get(1).map(|s| s.as_str());
match context {
"cremate" | "resurrect" => {
for s in graveyard::completion_candidates(prefix)? {
println!("{s}");
}
}
_ => {}
}
return Ok(());
}
if let Some(res_opt) = cli.resurrect {
let target = res_opt;
graveyard::resurrect_cmd(target, cli.dry_run, cli.yes)?;
return Ok(());
}
if let Some(crem_opt) = cli.cremate {
let target = match (cli.target, crem_opt) {
(Some(t), _) => Some(t), (None, Some(t)) => Some(t),
(None, None) => None,
};
graveyard::cremate(target, cli.dry_run, cli.yes)?;
return Ok(());
}
if cli.list {
graveyard::list()?;
return Ok(());
}
if !cli.paths.is_empty() {
graveyard::bury(&cli.paths, cli.force)?;
return Ok(());
}
let mut cmd = Cli::command();
cmd.print_help()?;
println!();
Ok(())
}