[+] Read from distro data in rust
This commit is contained in:
+111
-77
@@ -7,16 +7,27 @@ use anyhow::{Context, Result};
|
||||
use fs_extra::dir::CopyOptions;
|
||||
use heck::ToUpperCamelCase;
|
||||
use indexmap::IndexMap;
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use unicode_normalization::UnicodeNormalization as _;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AsciiDistro {
|
||||
pattern: String,
|
||||
color: String,
|
||||
foreground: Vec<u8>,
|
||||
background: Option<u8>,
|
||||
art: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct DistroHeader {
|
||||
#[serde(rename = "match")]
|
||||
pattern: String,
|
||||
color: serde_json::Value,
|
||||
foreground: Option<Vec<u8>>,
|
||||
background: Option<u8>,
|
||||
}
|
||||
|
||||
impl AsciiDistro {
|
||||
fn friendly_name(&self) -> String {
|
||||
self.pattern
|
||||
@@ -37,31 +48,26 @@ fn main() -> Result<()> {
|
||||
let dir = PathBuf::from(env::var_os("CARGO_WORKSPACE_DIR").unwrap_or_else(|| env::var_os("CARGO_MANIFEST_DIR").unwrap()));
|
||||
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
for file in &["neofetch", "hyfetch/data"] {
|
||||
let src = anything_that_exist(&[
|
||||
&dir.join(file),
|
||||
&dir.join("../../").join(file),
|
||||
]).context("couldn't find neofetch")?;
|
||||
let dst = o.join(file);
|
||||
println!("cargo:rerun-if-changed={}", src.display());
|
||||
|
||||
// Copy either file or directory
|
||||
if src.is_dir() {
|
||||
let opt = CopyOptions { overwrite: true, copy_inside: true, ..CopyOptions::default() };
|
||||
println!("copying {} to {}", src.display(), dst.display());
|
||||
fs_extra::dir::copy(&src, &dst, &opt)?;
|
||||
}
|
||||
else { fs::copy(&src, &dst)?; }
|
||||
}
|
||||
let data_dir = anything_that_exist(&[
|
||||
&dir.join("hyfetch/data"),
|
||||
&dir.join("../../hyfetch/data"),
|
||||
]).context("couldn't find hyfetch/data")?;
|
||||
|
||||
let dst_data = o.join("hyfetch/data");
|
||||
fs::create_dir_all(&dst_data)?;
|
||||
|
||||
// Copy hyfetch/data
|
||||
let opt = CopyOptions { overwrite: true, copy_inside: true, ..CopyOptions::default() };
|
||||
fs_extra::dir::copy(&data_dir, &dst_data, &opt)?;
|
||||
|
||||
preset_codegen(&o.join("hyfetch/data/presets.json"), &o.join("presets.rs"))?;
|
||||
export_distros(&o.join("neofetch"), &o)?;
|
||||
export_distros(&data_dir.join("distros"), &o)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn export_distros(neofetch_path: &Path, out_path: &Path) -> Result<()>
|
||||
fn export_distros(distro_dir: &Path, out_path: &Path) -> Result<()>
|
||||
{
|
||||
let distros = parse_ascii_distros(neofetch_path)?;
|
||||
let distros = parse_ascii_distros(distro_dir)?;
|
||||
let mut variants = IndexMap::with_capacity(distros.len());
|
||||
|
||||
for distro in &distros {
|
||||
@@ -164,6 +170,66 @@ impl Distro {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn color(&self) -> &str {
|
||||
match self {
|
||||
"###,
|
||||
);
|
||||
|
||||
for (variant, AsciiDistro { color, .. }) in &variants {
|
||||
write!(buf, r###"
|
||||
Self::{variant} => {color:?},
|
||||
"###, color = color)?;
|
||||
}
|
||||
|
||||
buf.push_str(
|
||||
r###"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foreground(&self) -> &[u8] {
|
||||
match self {
|
||||
"###,
|
||||
);
|
||||
|
||||
for (variant, AsciiDistro { foreground, .. }) in &variants {
|
||||
if foreground.is_empty() {
|
||||
write!(buf, r###"
|
||||
Self::{variant} => &[],
|
||||
"###)?;
|
||||
} else {
|
||||
write!(buf, r###"
|
||||
Self::{variant} => &{:?},
|
||||
"###, foreground)?;
|
||||
}
|
||||
}
|
||||
|
||||
buf.push_str(
|
||||
r###"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn background(&self) -> Option<u8> {
|
||||
match self {
|
||||
"###,
|
||||
);
|
||||
|
||||
for (variant, AsciiDistro { background, .. }) in &variants {
|
||||
if let Some(b) = background {
|
||||
write!(buf, r###"
|
||||
Self::{variant} => Some({b}),
|
||||
"###)?;
|
||||
} else {
|
||||
write!(buf, r###"
|
||||
Self::{variant} => None,
|
||||
"###)?;
|
||||
}
|
||||
}
|
||||
|
||||
buf.push_str(
|
||||
r###"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ascii_art(&self) -> &str {
|
||||
let art = match self {
|
||||
"###,
|
||||
@@ -191,67 +257,35 @@ impl Distro {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses ascii distros from neofetch script.
|
||||
fn parse_ascii_distros(neofetch_path: &Path) -> Result<Vec<AsciiDistro>>
|
||||
fn parse_ascii_distros(distro_dir: &Path) -> Result<Vec<AsciiDistro>>
|
||||
{
|
||||
let nf = {
|
||||
let nf = fs::read_to_string(neofetch_path)?;
|
||||
let mut distros = Vec::new();
|
||||
let mut paths: Vec<_> = fs::read_dir(distro_dir)?
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|e| e.path())
|
||||
.collect();
|
||||
paths.sort();
|
||||
|
||||
// Get the content of "get_distro_ascii" function
|
||||
let (_, nf) = nf
|
||||
.split_once("get_distro_ascii() {\n")
|
||||
.context("couldn't find get_distro_ascii function")?;
|
||||
let (nf, _) = nf
|
||||
.split_once("\n}\n")
|
||||
.context("couldn't find end of get_distro_ascii function")?;
|
||||
|
||||
let mut nf = nf.replace('\t', &" ".repeat(4));
|
||||
|
||||
// Remove trailing spaces
|
||||
while nf.contains(" \n") {
|
||||
nf = nf.replace(" \n", "\n");
|
||||
for path in paths {
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("ascii") {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let (header_line, art) = content.split_once('\n').context("invalid distro file")?;
|
||||
let header: DistroHeader = serde_json::from_str(header_line)?;
|
||||
let color = match header.color {
|
||||
serde_json::Value::String(s) => s,
|
||||
serde_json::Value::Number(n) => n.to_string(),
|
||||
_ => "7".to_owned(),
|
||||
};
|
||||
distros.push(AsciiDistro {
|
||||
pattern: header.pattern,
|
||||
color,
|
||||
foreground: header.foreground.unwrap_or_default(),
|
||||
background: header.background,
|
||||
art: art.to_owned(),
|
||||
});
|
||||
}
|
||||
nf
|
||||
};
|
||||
|
||||
let case_re = Regex::new(r"case .*? in\n")?;
|
||||
let eof_re = Regex::new(r"EOF[ \n]*?;;")?;
|
||||
|
||||
// Split by blocks
|
||||
let mut blocks = Vec::new();
|
||||
for b in case_re.split(&nf) {
|
||||
blocks.extend(eof_re.split(b).map(|sub| sub.trim()));
|
||||
}
|
||||
|
||||
// Parse blocks
|
||||
fn parse_block(block: &str) -> Option<AsciiDistro> {
|
||||
let (block, art) = block.split_once("'EOF'\n")?;
|
||||
|
||||
// Join \
|
||||
//
|
||||
// > A <backslash> that is not quoted shall preserve the literal value of the
|
||||
// > following character, with the exception of a <newline>. If a <newline>
|
||||
// > follows the <backslash>, the shell shall interpret this as line
|
||||
// > continuation. The <backslash> and <newline> shall be removed before
|
||||
// > splitting the input into tokens. Since the escaped <newline> is removed
|
||||
// > entirely from the input and is not replaced by any white space, it cannot
|
||||
// > serve as a token separator.
|
||||
// See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_01
|
||||
let block = block.replace("\\\n", "");
|
||||
|
||||
// Get case pattern
|
||||
let pattern = block
|
||||
.split('\n')
|
||||
.next()
|
||||
.and_then(|pattern| pattern.trim().strip_suffix(')'))?;
|
||||
|
||||
// Unescape backslashes here because backslashes are escaped in neofetch
|
||||
// for printf
|
||||
let art = art.replace(r"\\", r"\");
|
||||
|
||||
Some(AsciiDistro { pattern: pattern.to_owned(), art })
|
||||
}
|
||||
Ok(blocks.iter().filter_map(|block| parse_block(block)).collect())
|
||||
Ok(distros)
|
||||
}
|
||||
|
||||
// Preset parsing
|
||||
|
||||
@@ -372,12 +372,7 @@ impl NormalizedAsciiArt {
|
||||
// Line starts with neofetch color code
|
||||
last = Some(&line[m.span()]);
|
||||
},
|
||||
Some(_) => {
|
||||
new.push_str(last.context(
|
||||
"failed to find neofetch color code from a previous line",
|
||||
)?);
|
||||
},
|
||||
None => {
|
||||
_ => {
|
||||
new.push_str(last.unwrap_or(NEOFETCH_COLOR_PATTERNS[0]));
|
||||
},
|
||||
}
|
||||
@@ -385,7 +380,6 @@ impl NormalizedAsciiArt {
|
||||
|
||||
// Get the last placeholder for the next line
|
||||
if let Some(m) = matches.last() {
|
||||
last.context("non-space character seen before first color code")?;
|
||||
last = Some(&line[m.span()]);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,27 +241,27 @@ pub fn get_distro_ascii<S>(distro: Option<S>, backend: Backend) -> Result<RawAsc
|
||||
where
|
||||
S: AsRef<str> + fmt::Debug,
|
||||
{
|
||||
let distro: Cow<_> = if let Some(distro) = distro.as_ref() {
|
||||
let distro_name: Cow<_> = if let Some(distro) = distro.as_ref() {
|
||||
distro.as_ref().into()
|
||||
} else {
|
||||
get_distro_name(backend)
|
||||
.context("failed to get distro name")?
|
||||
.into()
|
||||
};
|
||||
debug!(%distro, "distro name");
|
||||
debug!(%distro_name, "distro name");
|
||||
|
||||
// Try new codegen-based detection method
|
||||
if let Some(distro) = Distro::detect(&distro) {
|
||||
if let Some(distro) = Distro::detect(&distro_name) {
|
||||
let asc = distro.ascii_art().to_owned();
|
||||
let fg = ascii_foreground(&distro);
|
||||
|
||||
return Ok(RawAsciiArt { asc, fg });
|
||||
}
|
||||
|
||||
debug!(%distro, "could not find a match for distro; falling back to neofetch");
|
||||
debug!(%distro_name, "could not find a match for distro; falling back to neofetch");
|
||||
|
||||
// Old detection method that calls neofetch
|
||||
let asc = run_neofetch_command_piped(&["print_ascii", "--ascii_distro", distro.as_ref()])
|
||||
let asc = run_neofetch_command_piped(&["print_ascii", "--ascii_distro", distro_name.as_ref()])
|
||||
.context("failed to get ascii art from neofetch")?;
|
||||
|
||||
// Unescape backslashes here because backslashes are escaped in neofetch for
|
||||
@@ -728,65 +728,8 @@ fn run_macchina(asc: String, args: Option<&Vec<String>>) -> Result<()> {
|
||||
/// Gets the color indices that should be considered as foreground, for a
|
||||
/// particular distro's ascii art.
|
||||
fn ascii_foreground(distro: &Distro) -> Vec<NeofetchAsciiIndexedColor> {
|
||||
let fg: Vec<u8> = match distro {
|
||||
Distro::Anarchy => vec![2],
|
||||
Distro::Android => vec![2],
|
||||
Distro::Antergos => vec![1],
|
||||
Distro::ArchStrike => vec![2],
|
||||
Distro::Arkane => vec![1],
|
||||
Distro::Asahi => vec![5],
|
||||
Distro::Astra_Linux => vec![2],
|
||||
Distro::BlackArch => vec![3],
|
||||
Distro::CelOS => vec![3],
|
||||
Distro::Chapeau => vec![2],
|
||||
Distro::Chrom => vec![5],
|
||||
Distro::Clear_Linux_OS => vec![2],
|
||||
Distro::Container_Linux_by_CoreOS => vec![3],
|
||||
Distro::CRUX => vec![3],
|
||||
Distro::EuroLinux => vec![2],
|
||||
Distro::eweOS => vec![3],
|
||||
Distro::Fedora => vec![2],
|
||||
Distro::Fedora_Sericea => vec![2],
|
||||
Distro::Fedora_Silverblue => vec![2],
|
||||
Distro::GalliumOS => vec![2],
|
||||
Distro::Gentoo => vec![1],
|
||||
Distro::HarDClanZ => vec![2],
|
||||
Distro::Kibojoe => vec![3],
|
||||
Distro::KrassOS => vec![2],
|
||||
Distro::Kubuntu => vec![2],
|
||||
Distro::Linux => vec![1],
|
||||
Distro::LinuxFromScratch => vec![1, 3],
|
||||
Distro::Lubuntu => vec![2],
|
||||
Distro::openEuler => vec![2],
|
||||
Distro::orchid => vec![1],
|
||||
Distro::Panwah => vec![1],
|
||||
Distro::Peppermint => vec![2],
|
||||
Distro::PNM_Linux => vec![2],
|
||||
Distro::Pop__OS => vec![2],
|
||||
Distro::Reborn_OS => vec![1],
|
||||
Distro::SalentOS => vec![4],
|
||||
Distro::Septor => vec![2],
|
||||
Distro::Ubuntu_Cinnamon => vec![2],
|
||||
Distro::Ubuntu_Kylin => vec![2],
|
||||
Distro::Ubuntu_MATE => vec![2],
|
||||
Distro::Ubuntu_old => vec![2],
|
||||
Distro::Ubuntu_Studio => vec![2],
|
||||
Distro::Ubuntu_Sway => vec![2],
|
||||
Distro::Ultramarine_Linux => vec![2],
|
||||
Distro::Univention => vec![2],
|
||||
Distro::uwuntu => vec![2],
|
||||
Distro::Vanilla => vec![2],
|
||||
Distro::VNux => vec![3, 5],
|
||||
Distro::Void => vec![2],
|
||||
Distro::Xray_OS => vec![2, 3],
|
||||
Distro::Xubuntu => vec![2],
|
||||
_ => Vec::new(),
|
||||
};
|
||||
|
||||
fg.into_iter()
|
||||
.map(|fore| {
|
||||
fore.try_into()
|
||||
.expect("`fore` should be a valid neofetch color index")
|
||||
})
|
||||
distro.foreground()
|
||||
.iter()
|
||||
.map(|&f| f.try_into().expect("neofetch color index should be valid"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user