use std::env;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Style {
#[default]
Fancy,
Retro,
Legacy,
}
impl Style {
pub fn parse(s: &str) -> Option<Style> {
match s.to_lowercase().as_str() {
"fancy" => Some(Style::Fancy),
"retro" => Some(Style::Retro),
"legacy" => Some(Style::Legacy),
_ => None,
}
}
}
#[derive(Debug, Default)]
pub struct Args {
pub no_logo: bool,
pub logo: Option<String>,
pub license: bool,
pub help: bool,
pub version: bool,
pub completions: Option<String>,
pub style: Style,
pub color: Option<String>,
pub raw: bool,
pub full_cpu_name: bool,
pub logo_long: bool,
pub logo_short: bool,
pub logo_intel_new: bool,
pub logo_intel_old: bool,
pub accurate_pp: bool,
pub measure_max_freq: bool,
pub debug: bool,
pub verbose: bool,
}
impl Args {
pub fn parse() -> Result<Self, String> {
let args: Vec<String> = env::args().collect();
let mut a = Args::default();
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
"-h" | "--help" => a.help = true,
"-V" | "--version" => a.version = true,
"--license" => a.license = true,
"-n" | "--no-logo" => a.no_logo = true,
"-d" | "--debug" => a.debug = true,
"-v" | "--verbose" => a.verbose = true,
"-r" | "--raw" => a.raw = true,
"-F" | "--full-cpu-name" => a.full_cpu_name = true,
"--logo-long" => a.logo_long = true,
"--logo-short" => a.logo_short = true,
"--logo-intel-new" => a.logo_intel_new = true,
"--logo-intel-old" => a.logo_intel_old = true,
"--accurate-pp" => a.accurate_pp = true,
"--measure-max-freq" => a.measure_max_freq = true,
"-l" | "--logo" => {
i += 1;
if i >= args.len() {
return Err("Error: --logo requires a value".to_string());
}
a.logo = Some(args[i].clone());
}
arg if arg.starts_with("--logo=") => {
let value = arg.strip_prefix("--logo=").unwrap();
if value.is_empty() {
return Err("Error: --logo requires a value".to_string());
}
a.logo = Some(value.to_string());
}
"-s" | "--style" => {
i += 1;
if i >= args.len() {
return Err(
"Error: --style requires a value (fancy, retro, legacy)".to_string()
);
}
a.style = Style::parse(&args[i]).ok_or_else(|| {
format!(
"Error: invalid style '{}'. Valid styles: fancy, retro, legacy",
args[i]
)
})?;
}
arg if arg.starts_with("--style=") => {
let value = arg.strip_prefix("--style=").unwrap();
a.style = Style::parse(value).ok_or_else(|| {
format!(
"Error: invalid style '{}'. Valid styles: fancy, retro, legacy",
value
)
})?;
}
"-c" | "--color" => {
i += 1;
if i >= args.len() {
return Err("Error: --color requires a value".to_string());
}
if a.color.is_some() {
return Err("Error: --color specified twice".to_string());
}
a.color = Some(args[i].clone());
}
arg if arg.starts_with("--color=") => {
let value = arg.strip_prefix("--color=").unwrap();
if a.color.is_some() {
return Err("Error: --color specified twice".to_string());
}
a.color = Some(value.to_string());
}
"--completions" => {
i += 1;
if i >= args.len() {
return Err(
"Error: --completions requires a shell name (fish, bash, zsh)"
.to_string(),
);
}
a.completions = Some(args[i].clone());
}
arg => {
return Err(format!("Error: Unknown argument '{}'", arg));
}
}
i += 1;
}
if a.logo_long && a.logo_short {
eprintln!(
"Warning: --logo-long and --logo-short are mutually exclusive; ignoring both"
);
a.logo_long = false;
a.logo_short = false;
}
if a.logo_intel_new && a.logo_intel_old {
eprintln!(
"Warning: --logo-intel-new and --logo-intel-old are mutually exclusive; ignoring both"
);
a.logo_intel_new = false;
a.logo_intel_old = false;
}
Ok(a)
}
}
pub fn print_help() {
println!("rcpufetch {}", env!("CARGO_PKG_VERSION"));
println!("{}", env!("CARGO_PKG_DESCRIPTION"));
println!();
println!("USAGE:");
println!(" rcpufetch [OPTIONS]");
println!();
println!("OPTIONS:");
println!(" -h, --help Print help information");
println!(" -V, --version Print version information");
println!(" --license Display license information");
println!(" --completions <SHELL> Generate shell completions (fish, bash, zsh)");
println!(" -n, --no-logo Disable logo display");
println!(" -l, --logo <VENDOR> Override logo display with specific vendor");
println!(
" Valid vendors: nvidia, powerpc, arm, amd, intel, apple"
);
println!(" -s, --style <STYLE> Set output style: fancy (default), retro, legacy");
println!(" -c, --color <SCHEME> Set color scheme: intel, intel-new, amd, ibm, arm,");
println!(" rockchip, sifive, or R,G,B:R,G,B:R,G,B:R,G,B:R,G,B");
println!(" -r, --raw Dump raw cpuid data (x86 only)");
println!(" -F, --full-cpu-name Show the unabbreviated CPU name (x86 only)");
println!(" --logo-long Force the large logo variant");
println!(" --logo-short Force the small logo variant");
println!(" --logo-intel-new Force the modern Intel logo (x86/Intel only)");
println!(" --logo-intel-old Force the classic Intel logo (x86/Intel only)");
println!(
" --accurate-pp Measure peak performance instead of estimating it (x86+Linux)"
);
println!(
" --measure-max-freq Measure max frequency instead of reading it from the OS"
);
println!(" -d, --debug Print low-level identifying register info and exit");
println!(" -v, --verbose Print diagnostic warnings about info gathering");
println!();
println!("EXAMPLES:");
println!(" rcpufetch Display CPU info with auto-detected logo");
println!(" rcpufetch --no-logo Display CPU info without logo");
println!(" rcpufetch --logo intel Display CPU info with Intel logo");
println!(" rcpufetch --style retro Display CPU info in retro style");
println!(" rcpufetch --license Show license information");
}
pub fn print_version() {
println!(
"{} {} ({} {} build)",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
std::env::consts::OS,
std::env::consts::ARCH
);
}
pub fn print_license() {
println!("Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>");
println!("Licensed under the GNU GPLv3: GNU General Public License version 3.");
println!("rcpufetch comes with ABSOLUTELY NO WARRANTY.");
println!();
println!("A copy of the GNU General Public License Version 3 should");
println!("have been provided with rcpufetch. If not, you can");
println!("find it at: <https://www.gnu.org/licenses/gpl-3.0.html>.");
println!();
println!("This is free software, and you are welcome to redistribute it");
println!(
"under certain conditions, as described above. Type `rcpufetch --help` for assistance."
);
}
pub fn print_completions(shell: &str) {
match shell.to_lowercase().as_str() {
"fish" => print_fish_completions(),
"bash" => print_bash_completions(),
"zsh" => print_zsh_completions(),
_ => {
eprintln!(
"Error: Unsupported shell '{}'. Supported shells: fish, bash, zsh",
shell
);
std::process::exit(1);
}
}
}
const LONG_OPTS: &str = "-h --help -V --version --license -n --no-logo -l --logo -s --style -c --color -r --raw -F --full-cpu-name --logo-long --logo-short --logo-intel-new --logo-intel-old --accurate-pp --measure-max-freq -d --debug -v --verbose --completions";
fn print_fish_completions() {
println!("# Fish completions for rcpufetch");
println!("complete -c rcpufetch -s h -l help -d 'Print help information'");
println!("complete -c rcpufetch -s V -l version -d 'Print version information'");
println!("complete -c rcpufetch -l license -d 'Display license information'");
println!("complete -c rcpufetch -s n -l no-logo -d 'Disable logo display'");
println!(
"complete -c rcpufetch -s l -l logo -x -a 'nvidia powerpc arm amd intel apple' -d 'Override logo display with specific vendor'"
);
println!(
"complete -c rcpufetch -s s -l style -x -a 'fancy retro legacy' -d 'Set output style'"
);
println!(
"complete -c rcpufetch -s c -l color -x -a 'intel intel-new amd ibm arm rockchip sifive' -d 'Set color scheme'"
);
println!("complete -c rcpufetch -s r -l raw -d 'Dump raw cpuid data (x86 only)'");
println!("complete -c rcpufetch -s F -l full-cpu-name -d 'Show the unabbreviated CPU name'");
println!("complete -c rcpufetch -l logo-long -d 'Force the large logo variant'");
println!("complete -c rcpufetch -l logo-short -d 'Force the small logo variant'");
println!("complete -c rcpufetch -l logo-intel-new -d 'Force the modern Intel logo'");
println!("complete -c rcpufetch -l logo-intel-old -d 'Force the classic Intel logo'");
println!(
"complete -c rcpufetch -l accurate-pp -d 'Measure peak performance instead of estimating it'"
);
println!(
"complete -c rcpufetch -l measure-max-freq -d 'Measure max frequency instead of reading it from the OS'"
);
println!(
"complete -c rcpufetch -s d -l debug -d 'Print low-level identifying register info and exit'"
);
println!(
"complete -c rcpufetch -s v -l verbose -d 'Print diagnostic warnings about info gathering'"
);
println!(
"complete -c rcpufetch -l completions -x -a 'fish bash zsh' -d 'Generate shell completions'"
);
}
fn print_bash_completions() {
println!("# Bash completions for rcpufetch");
println!("_rcpufetch() {{");
println!(" local cur prev opts");
println!(" COMPREPLY=()");
println!(" cur=\"${{COMP_WORDS[COMP_CWORD]}}\"");
println!(" prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"");
println!(" opts=\"{}\"", LONG_OPTS);
println!();
println!(" case \"${{prev}}\" in");
println!(" --logo|-l)");
println!(
" COMPREPLY=($(compgen -W \"nvidia powerpc arm amd intel apple\" -- \"${{cur}}\"))"
);
println!(" return 0");
println!(" ;;");
println!(" --style|-s)");
println!(" COMPREPLY=($(compgen -W \"fancy retro legacy\" -- \"${{cur}}\"))");
println!(" return 0");
println!(" ;;");
println!(" --color|-c)");
println!(
" COMPREPLY=($(compgen -W \"intel intel-new amd ibm arm rockchip sifive\" -- \"${{cur}}\"))"
);
println!(" return 0");
println!(" ;;");
println!(" --completions)");
println!(" COMPREPLY=($(compgen -W \"fish bash zsh\" -- \"${{cur}}\"))");
println!(" return 0");
println!(" ;;");
println!(" esac");
println!();
println!(" COMPREPLY=($(compgen -W \"${{opts}}\" -- \"${{cur}}\"))");
println!("}}");
println!("complete -F _rcpufetch rcpufetch");
}
fn print_zsh_completions() {
println!("# Zsh completions for rcpufetch");
println!("#compdef rcpufetch");
println!();
println!("_rcpufetch() {{");
println!(" _arguments \\");
println!(" '(-h --help){{-h,--help}}[Print help information]' \\");
println!(" '(-V --version){{-V,--version}}[Print version information]' \\");
println!(" '--license[Display license information]' \\");
println!(" '(-n --no-logo){{-n,--no-logo}}[Disable logo display]' \\");
println!(
" '(-l --logo){{-l,--logo}}[Override logo display with specific vendor]:vendor:(nvidia powerpc arm amd intel apple)' \\"
);
println!(
" '(-s --style){{-s,--style}}[Set output style]:style:(fancy retro legacy)' \\"
);
println!(
" '(-c --color){{-c,--color}}[Set color scheme]:scheme:(intel intel-new amd ibm arm rockchip sifive)' \\"
);
println!(" '(-r --raw){{-r,--raw}}[Dump raw cpuid data]' \\");
println!(
" '(-F --full-cpu-name){{-F,--full-cpu-name}}[Show the unabbreviated CPU name]' \\"
);
println!(" '--logo-long[Force the large logo variant]' \\");
println!(" '--logo-short[Force the small logo variant]' \\");
println!(" '--logo-intel-new[Force the modern Intel logo]' \\");
println!(" '--logo-intel-old[Force the classic Intel logo]' \\");
println!(" '--accurate-pp[Measure peak performance instead of estimating it]' \\");
println!(
" '--measure-max-freq[Measure max frequency instead of reading it from the OS]' \\"
);
println!(
" '(-d --debug){{-d,--debug}}[Print low-level identifying register info and exit]' \\"
);
println!(
" '(-v --verbose){{-v,--verbose}}[Print diagnostic warnings about info gathering]' \\"
);
println!(" '--completions[Generate shell completions]:shell:(fish bash zsh)'");
println!("}}");
println!();
println!("_rcpufetch \"$@\"");
}