use clap::error::ErrorKind;
use clap::{Parser, Subcommand, ValueEnum, ValueHint};
use clap_complete::Shell;
use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Default)]
pub enum ValidationStrictness {
Lenient,
#[default]
Normal,
Paranoid,
}
#[derive(Parser)]
#[command(name = "fontlift")]
#[command(about = "Install, uninstall, list, and remove fonts cross-platform", long_about = None)]
#[command(version = env!("GIT_VERSION"))]
pub struct Cli {
#[arg(
global = true,
long,
help = "Print intended actions without mutating fonts"
)]
pub dry_run: bool,
#[arg(
global = true,
short = 'q',
long,
help = "Silence routine status output",
conflicts_with = "verbose"
)]
pub quiet: bool,
#[arg(
global = true,
short = 'v',
long,
help = "Show verbose status messages",
conflicts_with = "quiet"
)]
pub verbose: bool,
#[arg(global = true, short = 'j', long, help = "Output results as JSON")]
pub json: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(alias = "l")]
List {
#[arg(short, long, help = "Show font file paths")]
path: bool,
#[arg(short, long, help = "Show PostScript names of installed font faces")]
name: bool,
#[arg(short, long, help = "Sort output and remove duplicates")]
sorted: bool,
},
#[command(alias = "i")]
Install {
#[arg(
value_name = "FONT|DIR",
num_args = 1..,
value_hint = ValueHint::AnyPath,
help = "Font file(s) or directories to install"
)]
font_inputs: Vec<PathBuf>,
#[arg(
short,
long,
help = "Install system-wide for all users (requires admin privileges)"
)]
admin: bool,
#[arg(short = 'V', long, help = "Skip font validation before installing")]
no_validate: bool,
#[arg(
long,
value_enum,
default_value = "normal",
help = "Validation strictness: lenient | normal | paranoid"
)]
validation_strictness: ValidationStrictness,
#[arg(
short = 'c',
long,
help = "Copy font to the fonts directory then register (default behaviour)",
conflicts_with = "inplace"
)]
copy: bool,
#[arg(
short = 'i',
long,
help = "Register font at its current path without copying",
conflicts_with = "copy"
)]
inplace: bool,
},
#[command(alias = "u")]
Uninstall {
#[arg(short, long, help = "PostScript or full name of the font to uninstall")]
name: Option<String>,
#[arg(
value_name = "FONT|DIR",
num_args = 0..,
value_hint = ValueHint::AnyPath,
help = "Font file(s) or directories to uninstall"
)]
font_inputs: Vec<PathBuf>,
#[arg(
short,
long,
help = "Uninstall from system scope (requires admin privileges)"
)]
admin: bool,
},
#[command(alias = "rm")]
Remove {
#[arg(short, long, help = "PostScript or full name of the font to remove")]
name: Option<String>,
#[arg(
value_name = "FONT|DIR",
num_args = 0..,
value_hint = ValueHint::AnyPath,
help = "Font file(s) or directories to remove"
)]
font_inputs: Vec<PathBuf>,
#[arg(
short,
long,
help = "Remove from system scope (requires admin privileges)"
)]
admin: bool,
},
#[command(alias = "c")]
Cleanup {
#[arg(
short,
long,
help = "Include system-wide cleanup (requires admin privileges)"
)]
admin: bool,
#[arg(
short = 'p',
long,
help = "Prune stale registrations only; skip cache clearing",
conflicts_with = "cache_only"
)]
prune_only: bool,
#[arg(
short = 'C',
long,
help = "Clear font caches only; skip pruning stale registrations",
conflicts_with = "prune_only"
)]
cache_only: bool,
},
Completions {
#[arg(value_enum, help = "Shell to generate completions for")]
shell: Shell,
},
#[command(alias = "d")]
Doctor {
#[arg(short = 'P', long, help = "Show recovery plan without executing it")]
preview: bool,
},
}
pub fn exit_code_for_clap_error(kind: ErrorKind) -> i32 {
match kind {
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => 0,
_ => 1,
}
}