From e09cc31f7d7393bce5429c4d4c9ca3245fe05454 Mon Sep 17 00:00:00 2001 From: Adrian Groh Date: Wed, 5 Jul 2023 19:00:25 +0200 Subject: [PATCH 1/3] refactor: outsource pfetch logo parser code to separate crate This makes the parse_logo() function accessible at compile-time and runtime --- Cargo.lock | 18 +++- Cargo.toml | 3 +- pfetch-extractor/Cargo.toml | 8 +- pfetch-extractor/src/lib.rs | 69 +------------- pfetch-logo-parser/Cargo.toml | 14 +++ pfetch-logo-parser/src/lib.rs | 170 ++++++++++++++++++++++++++++++++++ src/lib.rs | 47 +--------- src/main.rs | 13 +-- 8 files changed, 215 insertions(+), 127 deletions(-) create mode 100644 pfetch-logo-parser/Cargo.toml create mode 100644 pfetch-logo-parser/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c63011a..33e9ff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,12 +757,22 @@ dependencies = [ "globset", "libmacchina", "pfetch-extractor", + "pfetch-logo-parser", "which", ] [[package]] name = "pfetch-extractor" version = "0.1.5" +dependencies = [ + "pfetch-logo-parser", + "proc-macro2", + "quote", +] + +[[package]] +name = "pfetch-logo-parser" +version = "0.1.0" dependencies = [ "proc-macro2", "quote", @@ -827,9 +837,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick 1.0.1", "memchr", @@ -838,9 +848,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rpm-pkg-count" diff --git a/Cargo.toml b/Cargo.toml index a6de44a..6693bca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["pfetch-extractor"] +members = ["pfetch-extractor", "pfetch-logo-parser"] [package] name = "pfetch" @@ -15,6 +15,7 @@ categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pfetch-logo-parser = { path = "./pfetch-logo-parser", version = "0.1.0" } pfetch-extractor = { path = "./pfetch-extractor", version = "0.1.5" } globset = "0.4.10" dotenvy = "0.15.6" diff --git a/pfetch-extractor/Cargo.toml b/pfetch-extractor/Cargo.toml index 5e6c423..69c32c0 100644 --- a/pfetch-extractor/Cargo.toml +++ b/pfetch-extractor/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pfetch-extractor" version = "0.1.5" -edition = "2021" authors = ["Gobidev"] -description = "A rust proc-macro to extract pfetch logos at compile time" -license = "MIT" +edition = "2021" keywords = ["pfetch"] +license = "MIT" +description = "A rust proc-macro to extract pfetch logos at compile time" [lib] proc-macro = true @@ -13,6 +13,6 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pfetch-logo-parser = { version = "0.1.0", path = "../pfetch-logo-parser", features = ["proc-macro"] } proc-macro2 = "1.0.50" quote = "1.0.23" -regex = "1.7.1" diff --git a/pfetch-extractor/src/lib.rs b/pfetch-extractor/src/lib.rs index 590047c..69a1250 100644 --- a/pfetch-extractor/src/lib.rs +++ b/pfetch-extractor/src/lib.rs @@ -1,6 +1,5 @@ use proc_macro::TokenStream; use quote::quote; -use regex::Regex; #[proc_macro] pub fn parse_logos(_input: TokenStream) -> TokenStream { @@ -18,7 +17,7 @@ pub fn parse_logos(_input: TokenStream) -> TokenStream { let logos = raw_logos .split(";;\n") .filter_map(|raw_logo| { - let (is_tux, logo) = parse_logo(raw_logo)?; + let (is_tux, logo) = pfetch_logo_parser::parse_logo(raw_logo)?; if is_tux { tux = Some(logo.clone()); } @@ -30,69 +29,3 @@ pub fn parse_logos(_input: TokenStream) -> TokenStream { quote! { (#tux, [#(#logos),*]) }.into() } - -fn parse_logo(input: &str) -> Option<(bool, proc_macro2::TokenStream)> { - let input = input.trim().replace('\t', ""); - if input.is_empty() { - return None; - } - let regex = Regex::new(r"^\(?(.*)\)[\s\S]*read_ascii *(\d)? *(\d)?").unwrap(); - - let groups = regex - .captures(&input) - .expect("Error while parsing logos.sh"); - - let pattern = &groups[1]; - let primary_color = match groups.get(2) { - Some(color) => color.as_str().parse::().unwrap(), - None => 7, - }; - let secondary_color = match groups.get(3) { - Some(color) => color.as_str().parse::().unwrap(), - None => (primary_color + 1) % 8, - }; - - let logo = input - .split_once("EOF\n") - .expect("Could not find start of logo") - .1 - .split_once("\nEOF") - .expect("Could not find end of logo") - .0; - - let mut logo_parts = vec![]; - for logo_part in logo.split("${") { - if let Some((new_color, rest)) = logo_part.split_once('}') { - let new_color: u8 = new_color - .get(1..) - .and_then(|num| num.parse().ok()) - .unwrap_or_else(|| panic!("Invalid color: {new_color}")); - let rest = rest.replace("\\\\", "\\"); - let rest = rest.replace("\\`", "`"); - let lines = rest.split('\n').collect::>(); - let last_index = lines.len() - 1; - for (index, line) in lines.into_iter().enumerate() { - let mut line = line.to_owned(); - if index != last_index { - line += "\n"; - } - logo_parts.push(quote! { (Color(Some(#new_color)), #line) }); - } - } else if !logo_part.is_empty() { - let logo_part = logo_part.replace("\\\\", "\\"); - logo_parts.push(quote! { (Color(None), #logo_part) }); - } - } - - Some(( - pattern == "[Ll]inux*", - quote! { - Logo { - primary_color: Color(Some(#primary_color)), - secondary_color: Color(Some(#secondary_color)), - pattern: #pattern, - logo_parts: &[#(#logo_parts),*], - } - }, - )) -} diff --git a/pfetch-logo-parser/Cargo.toml b/pfetch-logo-parser/Cargo.toml new file mode 100644 index 0000000..17e1741 --- /dev/null +++ b/pfetch-logo-parser/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pfetch-logo-parser" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +proc-macro = ["dep:proc-macro2", "dep:quote"] + +[dependencies] +regex = "1.8.4" +proc-macro2 = { version = "1.0.50", optional = true } +quote = { version = "1.0.23", optional = true } diff --git a/pfetch-logo-parser/src/lib.rs b/pfetch-logo-parser/src/lib.rs new file mode 100644 index 0000000..801361c --- /dev/null +++ b/pfetch-logo-parser/src/lib.rs @@ -0,0 +1,170 @@ +use regex::Regex; + +use std::{borrow::Cow, fmt::Display, str::FromStr}; + +#[cfg(feature = "proc-macro")] +use proc_macro2::TokenStream; +#[cfg(feature = "proc-macro")] +use quote::{quote, ToTokens, TokenStreamExt}; + +#[derive(Clone, Copy, Debug)] +pub struct Color(pub Option); + +#[cfg(feature = "proc-macro")] +impl ToTokens for Color { + fn to_tokens(&self, tokens: &mut TokenStream) { + let value = match &self.0 { + Some(val) => quote! { Some(#val) }, + None => quote! { None }, + }; + tokens.append_all(quote! { + ::pfetch_logo_parser::Color(#value) + }); + } +} + +impl Display for Color { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + Some(color @ 0..=7) => write!(f, "\x1b[3{color}m"), + Some(color) => write!(f, "\x1b[38;5;{color}m"), + None => write!(f, "\x1b[39m"), + } + } +} + +impl FromStr for Color { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + Ok(Color(s.parse::().ok())) + } +} + +#[derive(Clone, Debug)] +pub struct LogoPart { + pub color: Color, + pub content: Cow<'static, str>, +} + +#[cfg(feature = "proc-macro")] +impl ToTokens for LogoPart { + fn to_tokens(&self, tokens: &mut TokenStream) { + let color = &self.color; + let content = &self.content; + tokens.append_all(quote! { + ::pfetch_logo_parser::LogoPart { + color: #color, + content: ::std::borrow::Cow::Borrowed(#content), + } + }); + } +} + +#[derive(Clone, Debug)] +pub struct Logo { + pub primary_color: Color, + pub secondary_color: Color, + pub pattern: Cow<'static, str>, + pub logo_parts: Cow<'static, [LogoPart]>, +} + +#[cfg(feature = "proc-macro")] +impl ToTokens for Logo { + fn to_tokens(&self, tokens: &mut TokenStream) { + let primary_color = &self.primary_color; + let secondary_color = &self.secondary_color; + let pattern = &self.pattern; + let logo_parts = &self.logo_parts; + + tokens.append_all(quote! { + ::pfetch_logo_parser::Logo { + primary_color: #primary_color, + secondary_color: #secondary_color, + pattern: ::std::borrow::Cow::Borrowed(#pattern), + logo_parts: ::std::borrow::Cow::Borrowed(&[#(#logo_parts),*]), + } + }); + } +} + +impl Display for Logo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + self.logo_parts + .iter() + .map(|LogoPart { color, content }| format!("{color}{content}")) + .collect::() + ) + } +} + +/// Parses a logo in pfetch formant and returns wether it is the linux (tux) logo and the logo itself +pub fn parse_logo(input: &str) -> Option<(bool, Logo)> { + let input = input.trim().replace('\t', ""); + if input.is_empty() { + return None; + } + let regex = Regex::new(r"^\(?(.*)\)[\s\S]*read_ascii *(\d)? *(\d)?").unwrap(); + + let groups = regex.captures(&input).expect("Error while parsing logo"); + + let pattern = &groups[1]; + let primary_color = match groups.get(2) { + Some(color) => color.as_str().parse::().unwrap(), + None => 7, + }; + let secondary_color = match groups.get(3) { + Some(color) => color.as_str().parse::().unwrap(), + None => (primary_color + 1) % 8, + }; + let logo = input + .split_once("EOF\n") + .expect("Could not find start of logo, make sure to include the `<<- EOF` and to use tabs for indentation") + .1 + .split_once("\nEOF") + .expect("Could not find end of logo, make sure to include the closing EOF and to use tabs for indentation") + .0; + + let mut logo_parts = vec![]; + for logo_part in logo.split("${") { + if let Some((new_color, rest)) = logo_part.split_once('}') { + let new_color: u8 = new_color + .get(1..) + .and_then(|num| num.parse().ok()) + .unwrap_or_else(|| panic!("Invalid color: {new_color}")); + let rest = rest.replace("\\\\", "\\"); + let rest = rest.replace("\\`", "`"); + let lines = rest.split('\n').collect::>(); + let last_index = lines.len() - 1; + for (index, line) in lines.into_iter().enumerate() { + let mut line = line.to_owned(); + if index != last_index { + line += "\n"; + } + logo_parts.push(LogoPart { + color: Color(Some(new_color)), + content: line.into(), + }); + } + } else if !logo_part.is_empty() { + let logo_part = logo_part.replace("\\\\", "\\"); + logo_parts.push(LogoPart { + color: Color(None), + content: logo_part.into(), + }); + } + } + + Some(( + pattern == "[Ll]inux*", + Logo { + primary_color: Color(Some(primary_color)), + secondary_color: Color(Some(secondary_color)), + pattern: pattern.to_owned().into(), + logo_parts: logo_parts.into(), + }, + )) +} diff --git a/src/lib.rs b/src/lib.rs index ecdbeb4..8abcc3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::{env, fmt::Display, fs, io::Result, process::Command, str::FromStr}; +use std::{env, fs, io::Result, process::Command}; use glob::glob; use globset::Glob; @@ -6,48 +6,7 @@ use libmacchina::{ traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _, traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout, }; -use pfetch_extractor::parse_logos; - -#[derive(Clone, Copy, Debug)] -pub struct Color(pub Option); - -impl Display for Color { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.0 { - Some(color @ 0..=7) => write!(f, "\x1b[3{color}m"), - Some(color) => write!(f, "\x1b[38;5;{color}m"), - None => write!(f, "\x1b[39m"), - } - } -} - -impl FromStr for Color { - type Err = String; - - fn from_str(s: &str) -> std::result::Result { - Ok(Color(s.parse::().ok())) - } -} - -pub struct Logo { - pub primary_color: Color, - pub secondary_color: Color, - pub pattern: &'static str, - pub logo_parts: &'static [(Color, &'static str)], -} - -impl Display for Logo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - self.logo_parts - .iter() - .map(|(color, part)| format!("{color}{part}")) - .collect::() - ) - } -} +use pfetch_logo_parser::Logo; #[derive(Debug)] pub enum PackageManager { @@ -353,7 +312,7 @@ pub fn host(general_readout: &GeneralReadout) -> Option { } pub fn logo(logo_name: &str) -> Logo { - let (tux, logos) = parse_logos!(); + let (tux, logos) = pfetch_extractor::parse_logos!(); logos .into_iter() .find(|logo| { diff --git a/src/main.rs b/src/main.rs index 35211f4..437b484 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use libmacchina::{ traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _, traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout, }; +use pfetch_logo_parser::{Color, Logo, LogoPart}; use std::{env, fmt::Display, str::FromStr}; #[derive(Debug, PartialEq)] @@ -53,11 +54,11 @@ impl FromStr for PfetchInfo { } } -fn pfetch(info: Vec<(pfetch::Color, String, String)>, logo: pfetch::Logo, logo_enabled: bool) { +fn pfetch(info: Vec<(Color, String, String)>, logo: Logo, logo_enabled: bool) { let raw_logo = if logo_enabled { logo.logo_parts .iter() - .map(|(_, part)| *part) + .map(|LogoPart { content, .. }| content.as_ref()) .collect::() } else { "".to_string() @@ -126,7 +127,7 @@ fn pfetch(info: Vec<(pfetch::Color, String, String)>, logo: pfetch::Logo, logo_e ), color2 = match dotenvy::var("PF_COL2") { Ok(newcolor) => { - match pfetch::Color::from_str(&newcolor) { + match Color::from_str(&newcolor) { Ok(newcolor) => format!("{newcolor}"), Err(_) => "".to_string(), } @@ -266,7 +267,7 @@ fn main() { // color overrides if let Ok(newcolor) = dotenvy::var("PF_COL1") { - if let Ok(newcolor) = pfetch::Color::from_str(&newcolor) { + if let Ok(newcolor) = Color::from_str(&newcolor) { logo.primary_color = newcolor; } } @@ -274,12 +275,12 @@ fn main() { if let Ok(newcolor) = dotenvy::var("PF_COL3") { if newcolor == "COL1" { logo.secondary_color = logo.primary_color; - } else if let Ok(newcolor) = pfetch::Color::from_str(&newcolor) { + } else if let Ok(newcolor) = Color::from_str(&newcolor) { logo.secondary_color = newcolor; } } - let gathered_pfetch_info: Vec<(pfetch::Color, String, String)> = enabled_pf_info + let gathered_pfetch_info: Vec<(Color, String, String)> = enabled_pf_info .iter() .filter_map(|info| match info { PfetchInfo::Os => Some((logo.primary_color, info.to_string(), os.clone())), From a786e8971e902e847265e9246fc973766ecbf156 Mon Sep 17 00:00:00 2001 From: Adrian Groh Date: Wed, 5 Jul 2023 19:08:54 +0200 Subject: [PATCH 2/3] Add required crate information for publishing --- pfetch-logo-parser/Cargo.toml | 3 +++ pfetch-logo-parser/LICENSE | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 pfetch-logo-parser/LICENSE diff --git a/pfetch-logo-parser/Cargo.toml b/pfetch-logo-parser/Cargo.toml index 17e1741..823f160 100644 --- a/pfetch-logo-parser/Cargo.toml +++ b/pfetch-logo-parser/Cargo.toml @@ -2,6 +2,9 @@ name = "pfetch-logo-parser" version = "0.1.0" edition = "2021" +authors = ["Gobidev"] +license = "MIT" +description = "A parser for pfetch logos" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/pfetch-logo-parser/LICENSE b/pfetch-logo-parser/LICENSE new file mode 100644 index 0000000..eb05d23 --- /dev/null +++ b/pfetch-logo-parser/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2023 Adrian Groh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 62be00b3b93e8ea7a3f17e3e420028f8900c1350 Mon Sep 17 00:00:00 2001 From: Adrian Groh Date: Fri, 7 Jul 2023 16:23:29 +0200 Subject: [PATCH 3/3] feat: add support for custom logos at runtime closes #33 This allows to use the `PF_CUSTOM_LOGOS` option to load a file containing pfetch logos --- README.md | 59 ++++++++++++++++++++++++++++++++++++++++---- custom_logos_example | 34 +++++++++++++++++++++++++ src/lib.rs | 21 +++++++++++++--- 3 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 custom_logos_example diff --git a/README.md b/README.md index 2e60dd7..300b8d2 100644 --- a/README.md +++ b/README.md @@ -85,12 +85,11 @@ value. ## Configuration Like the original `pfetch`, `pfetch-rs` is configured through environment -variables. Your existing config will probably still work, the only difference is +variables. Your existing config will probably still work, the main difference is how padding is configured. -If you want to display a custom logo, you will have to download the source code, -make your changes to `./pfetch-extractor/logos.sh` and build the binary with -`cargo b --release`. +If you want to display a custom logo, use the `PF_CUSTOM_LOGOS` option, an +example for a custom logos file can be found below. ```sh # Which information to display. @@ -106,11 +105,16 @@ PF_INFO="ascii" # Example: Only Information. PF_INFO="title os host kernel uptime pkgs memory" -# A file containing environment variables to source before running pfetch. +# A file containing environment variables to source before running pfetch # Default: unset # Valid: A shell script PF_SOURCE="" +# A file containing pfetch logos to overwrite default logos or add new logos +# Default: unset +# Valid: Path to a file containing pfetch logos (example below) +PF_CUSTOM_LOGOS="~/.config/pfetch_logos" + # Separator between info name and info data. # Default: unset # Valid: string @@ -162,3 +166,48 @@ HOSTNAME="" # Skip package managers that take "long" to query package count (like nix) PF_FAST_PKG_COUNT=1 ``` + +A file containing custom pfetch logos could look like this (also found under +`custom_logos_example`). This will turn the Arch Linux logo red, the Debian Logo +blue and the Fedora logo yellow: + +``` +[Aa]rch*) + read_ascii 1 <<- EOF + ${c1} /\\ + ${c1} / \\ + ${c1} /\\ \\ + ${c1} / \\ + ${c1} / ,, \\ + ${c1} / | | -\\ + ${c1} /_-'' ''-_\\ + EOF + ;; +[Dd]ebian*) + read_ascii 4 <<- EOF + ${c4} _____ + ${c4} / __ \\ + ${c4}| / | + ${c4}| \\___- + ${c4}-_ + ${c4} --_ + EOF + ;; +[Ff]edora*) + read_ascii 3 <<- EOF + ${c3},'''''. + ${c3}| ,. | + ${c3}| | '_' + ${c3} ,....| |.. + ${c3}.' ,_;| ..' + ${c3}| | | | + ${c3}| ',_,' | + ${c3} '. ,' + ${c3}''''' + EOF +``` + +_Note: Make sure to use tabs for indentation and separate logos with `;;`, as +seen above. You only need to add the logos you want to overwrite/add, the +default logos will stay available. The included logos can be found at +`./pfetch-extractor/logos.sh`._ diff --git a/custom_logos_example b/custom_logos_example new file mode 100644 index 0000000..a9054c7 --- /dev/null +++ b/custom_logos_example @@ -0,0 +1,34 @@ +[Aa]rch*) + read_ascii 1 <<- EOF + ${c1} /\\ + ${c1} / \\ + ${c1} /\\ \\ + ${c1} / \\ + ${c1} / ,, \\ + ${c1} / | | -\\ + ${c1} /_-'' ''-_\\ + EOF + ;; +[Dd]ebian*) + read_ascii 4 <<- EOF + ${c4} _____ + ${c4} / __ \\ + ${c4}| / | + ${c4}| \\___- + ${c4}-_ + ${c4} --_ + EOF + ;; + +[Ff]edora*) + read_ascii 3 <<- EOF + ${c3},'''''. + ${c3}| ,. | + ${c3}| | '_' + ${c3} ,....| |.. + ${c3}.' ,_;| ..' + ${c3}| | | | + ${c3}| ',_,' | + ${c3} '. ,' + ${c3}''''' + EOF diff --git a/src/lib.rs b/src/lib.rs index 8abcc3e..b12322c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::{env, fs, io::Result, process::Command}; +use std::{collections::VecDeque, env, fs, io::Result, process::Command}; use glob::glob; use globset::Glob; @@ -6,7 +6,7 @@ use libmacchina::{ traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _, traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout, }; -use pfetch_logo_parser::Logo; +use pfetch_logo_parser::{parse_logo, Logo}; #[derive(Debug)] pub enum PackageManager { @@ -311,8 +311,23 @@ pub fn host(general_readout: &GeneralReadout) -> Option { } } +fn parse_custom_logos(filename: &str) -> Vec> { + let file_contents = fs::read_to_string(filename).expect("Could not open custom logo file"); + file_contents + .split(";;") + .map(|raw_logo| parse_logo(raw_logo).map(|(_, logo)| logo)) + .collect::>() +} + pub fn logo(logo_name: &str) -> Logo { - let (tux, logos) = pfetch_extractor::parse_logos!(); + let (tux, included_logos) = pfetch_extractor::parse_logos!(); + let mut logos: VecDeque<_> = included_logos.into(); + if let Ok(filename) = dotenvy::var("PF_CUSTOM_LOGOS") { + // insert custom logos in front of incuded logos + for custom_logo in parse_custom_logos(&filename).into_iter().flatten() { + logos.insert(0, custom_logo.clone()); + } + }; logos .into_iter() .find(|logo| {