refactor: outsource pfetch logo parser code to separate crate
This makes the parse_logo() function accessible at compile-time and runtime
This commit is contained in:
parent
7a898206fa
commit
e09cc31f7d
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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::<u8>().unwrap(),
|
||||
None => 7,
|
||||
};
|
||||
let secondary_color = match groups.get(3) {
|
||||
Some(color) => color.as_str().parse::<u8>().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::<Vec<_>>();
|
||||
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),*],
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
14
pfetch-logo-parser/Cargo.toml
Normal file
14
pfetch-logo-parser/Cargo.toml
Normal file
@ -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 }
|
||||
170
pfetch-logo-parser/src/lib.rs
Normal file
170
pfetch-logo-parser/src/lib.rs
Normal file
@ -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<u8>);
|
||||
|
||||
#[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<Self, Self::Err> {
|
||||
Ok(Color(s.parse::<u8>().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::<String>()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::<u8>().unwrap(),
|
||||
None => 7,
|
||||
};
|
||||
let secondary_color = match groups.get(3) {
|
||||
Some(color) => color.as_str().parse::<u8>().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::<Vec<_>>();
|
||||
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(),
|
||||
},
|
||||
))
|
||||
}
|
||||
47
src/lib.rs
47
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<u8>);
|
||||
|
||||
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<Self, Self::Err> {
|
||||
Ok(Color(s.parse::<u8>().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::<String>()
|
||||
)
|
||||
}
|
||||
}
|
||||
use pfetch_logo_parser::Logo;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PackageManager {
|
||||
@ -353,7 +312,7 @@ pub fn host(general_readout: &GeneralReadout) -> Option<String> {
|
||||
}
|
||||
|
||||
pub fn logo(logo_name: &str) -> Logo {
|
||||
let (tux, logos) = parse_logos!();
|
||||
let (tux, logos) = pfetch_extractor::parse_logos!();
|
||||
logos
|
||||
.into_iter()
|
||||
.find(|logo| {
|
||||
|
||||
13
src/main.rs
13
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::<String>()
|
||||
} 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())),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user