172 lines
5.2 KiB
Rust
172 lines
5.2 KiB
Rust
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()
|
|
.fold("".to_string(), |a, LogoPart { color, content }| a
|
|
+ &if !f.alternate() {
|
|
format!("{color}{content}")
|
|
} else {
|
|
format!("{content}")
|
|
})
|
|
)
|
|
}
|
|
}
|
|
|
|
/// 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)?").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 = (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(),
|
|
},
|
|
))
|
|
}
|