use std::path::PathBuf;
use clap::{Parser, Subcommand, ValueEnum, ValueHint};
#[cfg(pagers_normal_build)]
use crate::{SizeRange, parse_size};
#[derive(Parser, Debug)]
#[command(name = "pagers", version, arg_required_else_help = true)]
#[command(styles = styles())]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(clap::Args, Debug)]
pub struct WithCommon<T: clap::Args> {
#[command(flatten)]
pub common: CommonArgs,
#[command(flatten)]
pub output: OutputArgs,
#[command(flatten)]
pub inner: T,
}
impl<T: clap::Args> WithCommon<T> {
pub fn common(&self) -> &CommonArgs {
&self.common
}
pub fn output(&self) -> &OutputArgs {
&self.output
}
}
#[derive(Subcommand, Debug)]
pub enum Command {
Query(WithCommon<()>),
Touch(WithCommon<()>),
Evict(WithCommon<()>),
Lock(WithCommon<LockInner>),
Lockall(WithCommon<LockInner>),
}
impl Command {
pub fn output(&self) -> &OutputArgs {
match self {
Self::Query(a) | Self::Touch(a) | Self::Evict(a) => a.output(),
Self::Lock(a) | Self::Lockall(a) => a.output(),
}
}
}
#[derive(clap::Args, Debug)]
pub struct OutputArgs {
#[arg(short = 'o', long, value_enum)]
pub format: Option<OutputFormatArg>,
#[command(flatten)]
pub verbosity: clap_verbosity_flag::Verbosity<clap_verbosity_flag::WarnLevel>,
}
impl OutputArgs {
pub fn is_quiet(&self) -> bool {
use clap_verbosity_flag::VerbosityFilter;
matches!(
self.verbosity.filter(),
VerbosityFilter::Off | VerbosityFilter::Error
)
}
}
#[derive(Clone, clap::Args, Debug)]
pub struct FilterArgs {
#[arg(short = 'i', long)]
pub ignore: Vec<String>,
#[arg(short = 'I', long = "filter")]
pub filter: Vec<String>,
}
#[derive(clap::Args, Debug)]
pub struct CommonArgs {
#[arg(required_unless_present = "batch", value_hint = ValueHint::AnyPath)]
pub paths: Vec<PathBuf>,
#[arg(short = 'f')]
pub follow_symlinks: bool,
#[arg(short = 'F')]
pub single_filesystem: bool,
#[arg(short = 'H')]
pub count_hardlinks: bool,
#[arg(short = 'm', long, value_parser = parse_size)]
pub max_file_size: Option<u64>,
#[arg(short = 'p', long, value_parser = clap::value_parser!(SizeRange))]
pub range: Option<SizeRange>,
#[command(flatten)]
pub filter: FilterArgs,
#[arg(short = 'b', long, value_hint = ValueHint::FilePath)]
pub batch: Option<PathBuf>,
#[arg(short = '0', requires = "batch")]
pub nul_delim: bool,
#[cfg(feature = "rayon")]
#[arg(short = 'j', long, default_value_t, value_parser = clap::value_parser!(pagers_core::crawl::Threads))]
pub threads: pagers_core::crawl::Threads,
}
#[derive(clap::Args, Debug)]
pub struct LockInner {
#[arg(short, long)]
pub daemon: bool,
#[arg(short, long, requires = "daemon")]
pub wait: bool,
#[arg(short = 'P', long, value_hint = ValueHint::FilePath)]
pub pidfile: Option<PathBuf>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
pub enum OutputFormatArg {
#[default]
Human,
Kv,
Json,
}
impl std::fmt::Display for OutputFormatArg {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Human => write!(f, "human"),
Self::Kv => write!(f, "kv"),
Self::Json => write!(f, "json"),
}
}
}
fn styles() -> clap::builder::Styles {
use anstyle::{AnsiColor, Style};
clap::builder::Styles::styled()
.header(Style::new().bold().fg_color(Some(AnsiColor::Green.into())))
.usage(Style::new().bold().fg_color(Some(AnsiColor::Green.into())))
.literal(Style::new().fg_color(Some(AnsiColor::Cyan.into())))
.placeholder(Style::new().fg_color(Some(AnsiColor::BrightBlack.into())))
.error(Style::new().bold().fg_color(Some(AnsiColor::Red.into())))
.valid(Style::new().fg_color(Some(AnsiColor::Green.into())))
.invalid(Style::new().fg_color(Some(AnsiColor::Yellow.into())))
}