Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port missed changes from the Python version #370

Merged
merged 9 commits into from
Dec 22, 2024
Merged
294 changes: 153 additions & 141 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"]

[workspace.package]
version = "1.4.11"
version = "2.0.0"
authors = ["Azalea Gui <[email protected]>"]
edition = "2021"
rust-version = "1.75.0"
Expand Down
7 changes: 7 additions & 0 deletions crates/hyfetch/src/bin/hyfetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use hyfetch::presets::{AssignLightness, Preset};
use hyfetch::pride_month;
use hyfetch::types::{AnsiMode, Backend, TerminalTheme};
use hyfetch::utils::{get_cache_path, input};
use hyfetch::font_logo::get_font_logo;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools as _;
use palette::{LinSrgb, Srgb};
Expand Down Expand Up @@ -79,6 +80,12 @@ fn main() -> Result<()> {
return Ok(());
}

if options.print_font_logo {
let logo = get_font_logo(backend).context("failed to get font logo")?;
writeln!(io::stdout(), "{}", logo).context("failed to write logo to stdout")?;
return Ok(());
}

let config = if options.config {
create_config(&options.config_file, distro, backend, debug_mode)
.context("failed to create config")?
Expand Down
44 changes: 35 additions & 9 deletions crates/hyfetch/src/cli_options.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::iter;
use std::path::PathBuf;
use std::str::FromStr as _;

Expand All @@ -6,7 +7,8 @@ use anyhow::Context as _;
use bpaf::ShellComp;
use bpaf::{construct, long, OptionParser, Parser as _};
use directories::BaseDirs;
use strum::VariantNames as _;
use itertools::Itertools as _;
use strum::{VariantArray, VariantNames};

use crate::color_util::{color, Lightness};
use crate::presets::Preset;
Expand All @@ -26,6 +28,7 @@ pub struct Options {
pub debug: bool,
pub distro: Option<String>,
pub ascii_file: Option<PathBuf>,
pub print_font_logo: bool,
pub test_print: bool,
pub ask_exit: bool,
}
Expand Down Expand Up @@ -53,19 +56,36 @@ pub fn options() -> OptionParser<Options> {
.help(&*format!(
"Use preset
PRESET={{{presets}}}",
presets = Preset::VARIANTS.join(",")
presets = <Preset as VariantNames>::VARIANTS
.iter()
.chain(iter::once(&"random"))
.join(",")
))
.argument::<String>("PRESET");
#[cfg(feature = "autocomplete")]
let preset = preset.complete(complete_preset);
let preset = preset
.parse(|s| {
Preset::from_str(&s).with_context(|| {
format!(
"PRESET should be one of {{{presets}}}",
presets = Preset::VARIANTS.join(",")
)
})
Preset::from_str(&s)
.or_else(|e| {
if s == "random" {
let mut rng = fastrand::Rng::new();
Ok(*rng
.choice(<Preset as VariantArray>::VARIANTS)
.expect("preset iterator should not be empty"))
} else {
Err(e)
}
})
.with_context(|| {
format!(
"PRESET should be one of {{{presets}}}",
presets = <Preset as VariantNames>::VARIANTS
.iter()
.chain(iter::once(&"random"))
.join(",")
)
})
})
.optional();
let mode = long("mode")
Expand Down Expand Up @@ -138,6 +158,10 @@ BACKEND={{{backends}}}",
#[cfg(feature = "autocomplete")]
let ascii_file = ascii_file.complete_shell(ShellComp::Nothing);
let ascii_file = ascii_file.optional();
let print_font_logo = long("print-font-logo")
.help("Print the Font Logo / Nerd Font icon of your distro and exit")
.switch();
// hidden
let test_print = long("test-print")
.help("Print the ascii distro and exit")
.switch()
Expand All @@ -160,6 +184,7 @@ BACKEND={{{backends}}}",
debug,
distro,
ascii_file,
print_font_logo,
// hidden
test_print,
ask_exit,
Expand All @@ -177,8 +202,9 @@ BACKEND={{{backends}}}",

#[cfg(feature = "autocomplete")]
fn complete_preset(input: &String) -> Vec<(String, Option<String>)> {
Preset::VARIANTS
<Preset as VariantNames>::VARIANTS
.iter()
.chain(iter::once(&"random"))
.filter_map(|&name| {
if name.starts_with(input) {
Some((name.to_owned(), None))
Expand Down
47 changes: 47 additions & 0 deletions crates/hyfetch/src/font_logo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::neofetch_util::get_distro_name;
use crate::types::Backend;
use crate::utils::get_cache_path;
use anyhow::{Context, Result};
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{Read, Write};

const FONT_LOGOS: &str = r#"{"Alma":"","Alpine":"","AOSC OS":"","Apple":"","Archcraft":"","ArchLabs":"","Arch":"","Arco":"","Arduino":"","Artix":"","Awesome WM":"","Big":"","bspwm":"","Budgie":"","CentOS":"","Cinnamon":"","Codeberg":"","CoreOS":"","Crystal":"","Debian":"","Deepin":"","Devuan":"","Docker":"","dwm":"","elementary OS":"","Endeavour OS":"","Enlightenment":"","F-droid":"","Fedora":"","Fedora (inverse)":"","Ferris":"","Flathub":"","Fluxbox":"","Forgejo":"","FOSDEM":"","FreeBSD":"","FreeCAD":"","freedesktop.org":"","Garuda":"","Gentoo":"","GIMP":"","Gitea":"","GNOME":"","GNU Guix":"","GTK":"","Hyperbola -libre":"","Hyprland":"","i3":"","illumos":"","Inkscape":"","JWM":"","Kali":"","KDE":"","KDE Neon":"","KDE Plasma":"","Kdenlive":"","KiCad":"","Krita":"","Kubuntu":"","Kubuntu (inverse)":"","Mint":"","Mint (inverse)":"","Loc-OS":"","LXDE":"","LXLE":"","LXQt":"","Mageia":"","Mandriva":"","Manjaro":"","MATE":"","mpv":"","MX":"","Neovim":"","NixOS":"","Octoprint":"","OpenBSD":"","OpenSCAD":"","OpenSUSE":"","OSH":"","OSHWA":"","OSI":"","Parabola -libre":"","Parrot OS":"","Pop!_OS":"","PostmarketOS":"","Prusa Slicer":"","Puppy":"","Qt":"","Qtile":"","QubesOS":"","Raspberry pi":"","Red Hat":"","RepRap":"","RISC-V":"","Rocky":"","Sabayon":"","Slackware":"","Slackware (inverse)":"","Snappy":"","Solus":"","Sway":"","Tails":"","Thunderbird":"","Tor Browser":"","Trisquel":"","Tux":"","Ubuntu":"","Ubuntu (inverse)":"","Vanilla OS":"","Void":"","VS Codium":"","Wayland":"","Wikimedia":"","Xero":"","XFCE":"","Xmonad":"","Xorg":"","Zorin OS":"","Windows":""}"#;
teohhanhui marked this conversation as resolved.
Show resolved Hide resolved

pub fn get_font_logo(backend: Backend) -> Result<String> {
// Check if the cache file exists and return its contents if it does
let cache_path = get_cache_path().context("Failed to get cache path")?.join("font_logo");
if cache_path.exists() {
let mut cached_logo = String::new();
File::open(cache_path).context("Failed to open cache file")?
.read_to_string(&mut cached_logo).context("Failed to read from cache file")?;
return Ok(cached_logo);
}

// Deserialize the JSON into a HashMap
let font_logos: HashMap<String, String> = serde_json::from_str::<HashMap<String, String>>(FONT_LOGOS)
.context("Failed to deserialize font logos JSON file")?
.into_iter().map(|(k, v)| (k.to_lowercase(), v)).collect();

// Get the distro name
let distro = get_distro_name(backend).context("Failed to get distro name")?.to_lowercase();

// Find the most likely matching distro from font_logos
let matched_distro = font_logos.keys().find(|&k| distro.contains(k))
.or_else(|| font_logos.keys().find(|k| k.contains(&distro)))
.or_else(|| font_logos.keys().find(|k| k.split_whitespace().any(|part| distro.contains(part))))
.ok_or_else(|| anyhow::anyhow!("No font logo found for distro: {distro}. The supported logos are in https://github.com/Lukas-W/font-logos"))?;

let logo = font_logos.get(matched_distro).unwrap();

// Create parent directories for the cache if they don't exist
if let Some(parent) = cache_path.parent() {
fs::create_dir_all(parent).context("Failed to create cache directory")?;
}

// Write the logo to the cache file
let mut cache_file = File::create(cache_path).context("Failed to create cache file")?;
cache_file.write_all(logo.as_bytes()).context("Failed to write logo to cache file")?;

Ok(logo.clone())
}
1 change: 1 addition & 0 deletions crates/hyfetch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod ascii;
pub mod cli_options;
pub mod color_util;
pub mod distros;
pub mod font_logo;
pub mod models;
pub mod neofetch_util;
pub mod presets;
Expand Down
2 changes: 1 addition & 1 deletion crates/hyfetch/src/neofetch_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ where
}

#[tracing::instrument(level = "debug")]
fn get_distro_name(backend: Backend) -> Result<String> {
pub(crate) fn get_distro_name(backend: Backend) -> Result<String> {
match backend {
Backend::Neofetch => run_neofetch_command_piped(&["ascii_distro_name"])
.context("failed to get distro name from neofetch"),
Expand Down
56 changes: 55 additions & 1 deletion crates/hyfetch/src/presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ pub enum Preset {

Pangender,

/// High-contrast version of pangender flag
#[serde(rename = "pangender.contrast")]
#[strum(serialize = "pangender.contrast")]
PangenderContrast,

#[serde(rename = "gendernonconforming1")]
#[strum(serialize = "gendernonconforming1")]
GenderNonconforming1,
Expand All @@ -143,10 +148,23 @@ pub enum Preset {

NonhumanUnity,

/// For all the dogs
Caninekin,

Plural,

Fraysexual,

Bear,

Butch,

Leather,

Otter,

Twink,

Kenochoric,

Veldian,
Expand Down Expand Up @@ -192,6 +210,8 @@ pub enum Preset {
Burger,

/// Meme flag
#[serde(rename = "throatlozenges")]
#[strum(serialize = "throatlozenges")]
ThroatLozenges,

/// Colors from Gilbert Baker's original 1978 flag design
Expand Down Expand Up @@ -427,6 +447,11 @@ impl Preset {
"#FFF798", "#FEDDCD", "#FFEBFB", "#FFFFFF", "#FFEBFB", "#FEDDCD", "#FFF798",
]),

// high-contrast version of pangender flag
Self::PangenderContrast => ColorProfile::from_hex_colors(vec![
"#ffe87f", "#fcbaa6", "#fbc9f3", "#FFFFFF", "#fbc9f3", "#fcbaa6", "#ffe87f",
]),

Self::GenderNonconforming1 => ColorProfile::from_hex_colors(vec![
"#50284d", "#96467b", "#5c96f7", "#ffe6f7", "#5c96f7", "#96467b", "#50284d",
])
Expand Down Expand Up @@ -474,6 +499,11 @@ impl Preset {
ColorProfile::from_hex_colors(vec!["#177B49", "#FFFFFF", "#593C90"])
},

// used https://www.tumblr.com/zombpawcoins/745062851267493888/caninekin-canine-therian-flag
Self::Caninekin => ColorProfile::from_hex_colors(vec![
"#2d2822", "#543d25", "#9c754d", "#e8dac2", "#cfad8c", "#b77b55", "#954e31",
]),

// used https://pluralpedia.org/w/Plurality#/media/File:Plural-Flag-1.jpg as source and colorpicked
Self::Plural => ColorProfile::from_hex_colors(vec![
"#2D0625", "#543475", "#7675C3", "#89C7B0", "#F3EDBD",
Expand All @@ -484,6 +514,30 @@ impl Preset {
ColorProfile::from_hex_colors(vec!["#226CB5", "#94E7DD", "#FFFFFF", "#636363"])
},

// sourced from https://commons.wikimedia.org/wiki/File:Bear_Brotherhood_flag.svg
Self::Bear => ColorProfile::from_hex_colors(vec![
"#623804", "#D56300", "#FEDD63", "#FEE6B8", "#FFFFFF", "#555555",
]),

// colorpicked from https://commons.wikimedia.org/wiki/File:Butch_Flag.png
Self::Butch => ColorProfile::from_hex_colors(vec![
"#D72800", "#F17623", "#FF9C56", "#FFFDF6", "#FFCE89", "#FEAF02", "#A37000",
]),

// colorpicked from https://commons.wikimedia.org/wiki/File:Leather,_Latex,_and_BDSM_pride_-_Light.svg
Self::Leather => ColorProfile::from_hex_colors(vec![
"#000000", "#252580", "#000000", "#252580", "#FFFFFF", "#252580", "#000000",
"#252580", "#000000",
]),

// colorpicked from https://commons.wikimedia.org/wiki/File:Official_Otter_Pride_Flag_by_Bearbackgear.jpg
Self::Otter => ColorProfile::from_hex_colors(vec![
"#263881", "#5C9DC9", "#FFFFFF", "#3A291D", "#5C9DC9", "#263881",
]),

// colorpicked from https://commons.wikimedia.org/wiki/File:Twink_Pride_Flag_(proposed).svg
Self::Twink => ColorProfile::from_hex_colors(vec!["#FFB2FF", "#FFFFFF", "#FFFF81"]),

Self::Kenochoric => {
ColorProfile::from_hex_colors(vec!["#000000", "#2E1569", "#824DB7", "#C7A1D6"])
},
Expand Down Expand Up @@ -570,7 +624,7 @@ impl Preset {
]),

Self::ThroatLozenges => ColorProfile::from_hex_colors(vec![
"#2759DA", "#03940D", "#F5F100", "#F59B00", "#B71212"
"#2759DA", "#03940D", "#F5F100", "#F59B00", "#B71212",
]),

// used https://gilbertbaker.com/rainbow-flag-color-meanings/ as source and colorpicked
Expand Down
2 changes: 1 addition & 1 deletion crates/hyfetch/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ pub(crate) mod index_map_serde {
}
}

impl<'de, K> Visitor<'de> for KeySeed<K>
impl<K> Visitor<'_> for KeySeed<K>
where
K: FromStr,
K::Err: fmt::Display,
Expand Down