use crate::{clear_terminal_screen, Algorithm, MyResult};
use clap::{CommandFactory, Parser, ValueEnum};
use clap_complete::{generate, Generator, Shell};
use serde::Serialize;
use std::{fs, io, ops::RangeInclusive, path::PathBuf, process};
#[derive(Debug, Default, Clone, ValueEnum, Serialize)]
pub enum ResultFormat {
Json,
Yaml,
#[default]
Personal,
}
fn get_styles() -> clap::builder::Styles {
let cyan = anstyle::Color::Ansi(anstyle::AnsiColor::Cyan);
let green = anstyle::Color::Ansi(anstyle::AnsiColor::Green);
let yellow = anstyle::Color::Ansi(anstyle::AnsiColor::Yellow);
clap::builder::Styles::styled()
.placeholder(anstyle::Style::new().fg_color(Some(yellow)))
.usage(anstyle::Style::new().fg_color(Some(cyan)).bold())
.header(
anstyle::Style::new()
.fg_color(Some(cyan))
.bold()
.underline(),
)
.literal(anstyle::Style::new().fg_color(Some(green)))
}
const APPLET_TEMPLATE: &str = "\
{before-help}
{about-with-newline}
{usage-heading} {usage}
{all-args}
{after-help}";
#[derive(Parser, Debug)]
#[command(
// Read from `Cargo.toml`
author, version, about,
long_about = None,
next_line_help = true,
help_template = APPLET_TEMPLATE,
styles=get_styles(),
)]
pub struct Arguments {
#[arg(short('a'), long("algorithm"), value_enum, default_value_t = Algorithm::default())]
pub algorithm: Algorithm,
#[arg(short('b'), long("min_size"), required = false)]
pub min_size: Option<u64>,
#[arg(short('B'), long("max_size"), required = false)]
pub max_size: Option<u64>,
#[arg(short('c'), long("csv_dir"), required = false)]
pub csv_dir: Option<PathBuf>,
#[arg(short('d'), long("min_depth"), required = false)]
pub min_depth: Option<usize>,
#[arg(short('D'), long("max_depth"), required = false)]
pub max_depth: Option<usize>,
#[arg(short('f'), long("full_path"), default_value_t = false)]
pub full_path: bool,
#[arg(short('g'), long("generate"), value_enum)]
pub generator: Option<Shell>,
#[arg(short('i'), long("input_dir"), required = false)]
pub input_dir: Option<PathBuf>,
#[arg(short('n'), long("min_number"), required = false)]
pub min_number: Option<usize>,
#[arg(short('N'), long("max_number"), required = false)]
pub max_number: Option<usize>,
#[arg(short('o'), long("omit_hidden"), default_value_t = false)]
pub omit_hidden: bool,
#[arg(short('r'), long("result_format"), value_enum, default_value_t = ResultFormat::default())]
pub result_format: ResultFormat,
#[arg(short('s'), long("sort"), default_value_t = false)]
pub sort: bool,
#[arg(short('t'), long("time"), default_value_t = false)]
pub time: bool,
#[arg(short('v'), long("verbose"), default_value_t = false)]
pub verbose: bool,
#[arg(short('w'), long("wipe_terminal"), default_value_t = false)]
pub wipe_terminal: bool,
#[arg(short('x'), long("xlsx_dir"), required = false)]
pub xlsx_dir: Option<PathBuf>,
}
impl Arguments {
pub fn build() -> MyResult<Arguments> {
let args: Arguments = Arguments::parse();
if let Some(generator) = args.generator {
args.print_completions(generator);
}
if args.wipe_terminal {
clear_terminal_screen();
}
args.validate_dir_path()?;
Ok(args)
}
fn print_completions<G>(&self, gen: G)
where
G: Generator + std::fmt::Debug,
{
let mut cmd = Arguments::command();
let cmd_name = cmd.get_name().to_string();
let mut stdout = io::stdout();
eprintln!("Generating completion file for {gen:?}...");
generate(gen, &mut cmd, cmd_name, &mut stdout);
process::exit(1);
}
pub fn get_size_range(&self) -> RangeInclusive<u64> {
let min_size: u64 = self.min_size.unwrap_or(0);
let max_size: u64 = self.max_size.unwrap_or(std::u64::MAX);
min_size..=max_size
}
pub fn validate_dir_path(&self) -> MyResult<()> {
let paths = [&self.input_dir, &self.csv_dir, &self.xlsx_dir];
for dir_path in paths.into_iter().flatten() {
if !std::path::Path::new(&dir_path).try_exists()? {
eprintln!("fn validate_dir_path()");
panic!("The path {dir_path:?} was not found!");
};
if !dir_path.is_dir() {
eprintln!("fn validate_dir_path()");
panic!("{dir_path:?} is not a directory!");
}
let metadada = fs::metadata(dir_path)?;
if metadada.permissions().readonly() {
eprintln!("fn validate_dir_path()");
eprintln!("No write permission");
panic!("{dir_path:?} is readonly!");
}
}
Ok(())
}
}