Tie fore-back to distro ascii instead of config

This commit is contained in:
Teoh Han Hui 2024-07-10 23:53:39 +08:00
parent d773c69918
commit f3b1840e92
No known key found for this signature in database
GPG key ID: D43E2BABAF97DCAE
3 changed files with 115 additions and 36 deletions

View file

@ -9,7 +9,7 @@ use hyfetch::cli_options::options;
use hyfetch::models::Config; use hyfetch::models::Config;
#[cfg(windows)] #[cfg(windows)]
use hyfetch::neofetch_util::ensure_git_bash; use hyfetch::neofetch_util::ensure_git_bash;
use hyfetch::neofetch_util::{self, get_distro_ascii}; use hyfetch::neofetch_util::{self, get_distro_ascii, ColorAlignment};
use hyfetch::presets::AssignLightness; use hyfetch::presets::AssignLightness;
use hyfetch::utils::get_cache_path; use hyfetch::utils::get_cache_path;
use tracing::debug; use tracing::debug;
@ -33,10 +33,8 @@ fn main() -> Result<()> {
ensure_git_bash().context("failed to find git bash")?; ensure_git_bash().context("failed to find git bash")?;
if options.test_print { if options.test_print {
println!( let (asc, _) = get_distro_ascii(distro).context("failed to get distro ascii")?;
"{}", println!("{asc}");
get_distro_ascii(distro).context("failed to get distro ascii")?
);
return Ok(()); return Ok(());
} }
@ -94,13 +92,28 @@ fn main() -> Result<()> {
}; };
debug!(?color_profile, "lightened color profile"); debug!(?color_profile, "lightened color profile");
let asc = if let Some(path) = options.ascii_file { let (asc, fore_back) = if let Some(path) = options.ascii_file {
fs::read_to_string(&path).with_context(|| format!("failed to read ascii from {path:?}"))? (
fs::read_to_string(&path)
.with_context(|| format!("failed to read ascii from {path:?}"))?,
None,
)
} else { } else {
get_distro_ascii(distro).context("failed to get distro ascii")? get_distro_ascii(distro).context("failed to get distro ascii")?
}; };
let asc = config let color_align = if fore_back.is_some() {
.color_align match config.color_align {
ca @ ColorAlignment::Horizontal { .. } | ca @ ColorAlignment::Vertical { .. } => {
ca.with_fore_back(fore_back).context(
"failed to create color alignment with foreground-background configuration",
)?
},
ca @ ColorAlignment::Custom { .. } => ca,
}
} else {
config.color_align
};
let asc = color_align
.recolor_ascii(asc, color_profile, color_mode, config.light_dark) .recolor_ascii(asc, color_profile, color_mode, config.light_dark)
.context("failed to recolor ascii")?; .context("failed to recolor ascii")?;
neofetch_util::run(asc, backend, args).context("failed to run")?; neofetch_util::run(asc, backend, args).context("failed to run")?;

View file

@ -27,15 +27,19 @@ use crate::types::{AnsiMode, Backend, LightDark};
const NEOFETCH_COLOR_PATTERNS: [&str; 6] = ["${c1}", "${c2}", "${c3}", "${c4}", "${c5}", "${c6}"]; const NEOFETCH_COLOR_PATTERNS: [&str; 6] = ["${c1}", "${c2}", "${c3}", "${c4}", "${c5}", "${c6}"];
static NEOFETCH_COLORS_AC: OnceLock<AhoCorasick> = OnceLock::new(); static NEOFETCH_COLORS_AC: OnceLock<AhoCorasick> = OnceLock::new();
type ForeBackColorPair = (NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor);
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)] #[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
#[serde(tag = "mode")] #[serde(tag = "mode")]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum ColorAlignment { pub enum ColorAlignment {
Horizontal { Horizontal {
fore_back: Option<(NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor)>, #[serde(skip)]
fore_back: Option<ForeBackColorPair>,
}, },
Vertical { Vertical {
fore_back: Option<(NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor)>, #[serde(skip)]
fore_back: Option<ForeBackColorPair>,
}, },
Custom { Custom {
#[serde(rename = "custom_colors")] #[serde(rename = "custom_colors")]
@ -45,8 +49,35 @@ pub enum ColorAlignment {
} }
impl ColorAlignment { impl ColorAlignment {
/// Creates a new color alignment, with the specified foreground-background
/// configuration.
pub fn with_fore_back(&self, fore_back: Option<ForeBackColorPair>) -> Result<Self> {
match self {
Self::Horizontal { .. } => Ok(Self::Horizontal { fore_back }),
Self::Vertical { .. } => {
if fore_back.is_some() {
debug!(
"foreground-background configuration not implemented for vertical color \
alignment; ignoring"
);
}
Ok(Self::Vertical { fore_back: None })
},
Self::Custom { colors } => {
if fore_back.is_some() {
return Err(anyhow!(
"foreground-background configuration not supported for custom colors"
));
}
Ok(Self::Custom {
colors: colors.clone(),
})
},
}
}
/// Uses the color alignment to recolor an ascii art. /// Uses the color alignment to recolor an ascii art.
#[tracing::instrument(level = "debug")] #[tracing::instrument(level = "debug", skip(asc))]
pub fn recolor_ascii( pub fn recolor_ascii(
&self, &self,
asc: String, asc: String,
@ -54,19 +85,20 @@ impl ColorAlignment {
color_mode: AnsiMode, color_mode: AnsiMode,
term: LightDark, term: LightDark,
) -> Result<String> { ) -> Result<String> {
let asc = fill_starting(asc).context("failed to fill in starting neofetch color codes")?;
let reset = color("&~&*", color_mode).expect("color reset should not be invalid"); let reset = color("&~&*", color_mode).expect("color reset should not be invalid");
let asc = match self { let asc = match self {
Self::Horizontal { &Self::Horizontal {
fore_back: Some((fore, back)), fore_back: Some((fore, back)),
} }
| Self::Vertical { | &Self::Vertical {
fore_back: Some((fore, back)), fore_back: Some((fore, back)),
} => { } => {
let fore: u8 = (*fore).into(); let fore: u8 = fore.into();
let back: u8 = (*back).into(); let back: u8 = back.into();
let asc = fill_starting(asc)
.context("failed to fill in starting neofetch color codes")?;
// Replace foreground colors // Replace foreground colors
let asc = asc.replace( let asc = asc.replace(
@ -191,6 +223,9 @@ impl ColorAlignment {
Self::Custom { Self::Custom {
colors: custom_colors, colors: custom_colors,
} => { } => {
let asc = fill_starting(asc)
.context("failed to fill in starting neofetch color codes")?;
let ColorProfile { colors } = color_profile.unique_colors(); let ColorProfile { colors } = color_profile.unique_colors();
// Apply colors // Apply colors
@ -215,6 +250,39 @@ impl ColorAlignment {
Ok(asc) Ok(asc)
} }
/// Gets recommended foreground-background configuration for distro, or
/// `None` if the distro ascii is not suitable for fore-back configuration.
pub fn fore_back(distro: Distro) -> Option<ForeBackColorPair> {
match distro {
Distro::Anarchy
| Distro::ArchStrike
| Distro::Astra_Linux
| Distro::Chapeau
| Distro::Fedora
| Distro::GalliumOS
| Distro::KrassOS
| Distro::Kubuntu
| Distro::Lubuntu
| Distro::openEuler
| Distro::Peppermint
| Distro::Pop__OS
| Distro::Ubuntu_Cinnamon
| Distro::Ubuntu_Kylin
| Distro::Ubuntu_MATE
| Distro::Ubuntu_old
| Distro::Ubuntu_Studio
| Distro::Ubuntu_Sway
| Distro::Ultramarine_Linux
| Distro::Univention
| Distro::Vanilla
| Distro::Xubuntu => Some((2u8.try_into().unwrap(), 1u8.try_into().unwrap())),
Distro::Antergos => Some((1u8.try_into().unwrap(), 2u8.try_into().unwrap())),
_ => None,
}
}
} }
/// Gets the absolute path of the neofetch command. /// Gets the absolute path of the neofetch command.
@ -318,7 +386,7 @@ pub fn ensure_git_bash() -> Result<PathBuf> {
/// Gets the distro ascii of the current distro. Or if distro is specified, get /// Gets the distro ascii of the current distro. Or if distro is specified, get
/// the specific distro's ascii art instead. /// the specific distro's ascii art instead.
#[tracing::instrument(level = "debug")] #[tracing::instrument(level = "debug")]
pub fn get_distro_ascii<S>(distro: Option<S>) -> Result<String> pub fn get_distro_ascii<S>(distro: Option<S>) -> Result<(String, Option<ForeBackColorPair>)>
where where
S: AsRef<str> + fmt::Debug, S: AsRef<str> + fmt::Debug,
{ {
@ -333,7 +401,10 @@ where
// Try new codegen-based detection method // Try new codegen-based detection method
if let Some(distro) = Distro::detect(&distro) { if let Some(distro) = Distro::detect(&distro) {
return Ok(normalize_ascii(distro.ascii_art())); return Ok((
normalize_ascii(distro.ascii_art()),
ColorAlignment::fore_back(distro),
));
} }
debug!(%distro, "could not find a match for distro; falling back to neofetch"); debug!(%distro, "could not find a match for distro; falling back to neofetch");
@ -346,10 +417,10 @@ where
// printf // printf
let asc = asc.replace(r"\\", r"\"); let asc = asc.replace(r"\\", r"\");
Ok(normalize_ascii(asc)) Ok((normalize_ascii(asc), None))
} }
#[tracing::instrument(level = "debug")] #[tracing::instrument(level = "debug", skip(asc))]
pub fn run(asc: String, backend: Backend, args: Option<&Vec<String>>) -> Result<()> { pub fn run(asc: String, backend: Backend, args: Option<&Vec<String>>) -> Result<()> {
match backend { match backend {
Backend::Neofetch => { Backend::Neofetch => {
@ -432,7 +503,7 @@ where
let mut matches = ac.find_iter(line).peekable(); let mut matches = ac.find_iter(line).peekable();
match matches.peek() { match matches.peek() {
Some(m) if m.start() == 0 => { Some(m) if m.start() == 0 || line[0..m.start()].trim_end_matches(' ').is_empty() => {
// line starts with neofetch color code, do nothing // line starts with neofetch color code, do nothing
}, },
_ => { _ => {
@ -545,7 +616,7 @@ fn get_distro_name() -> Result<String> {
} }
/// Runs neofetch with colors. /// Runs neofetch with colors.
#[tracing::instrument(level = "debug")] #[tracing::instrument(level = "debug", skip(asc))]
fn run_neofetch(asc: String, args: Option<&Vec<String>>) -> Result<()> { fn run_neofetch(asc: String, args: Option<&Vec<String>>) -> Result<()> {
// Escape backslashes here because backslashes are escaped in neofetch for // Escape backslashes here because backslashes are escaped in neofetch for
// printf // printf

View file

@ -59,7 +59,6 @@ pub enum Preset {
Gendervoid, Gendervoid,
Girlflux, Girlflux,
Greygender, Greygender,
#[serde(alias = "biromantic2")]
Greysexual, Greysexual,
Gynesexual, Gynesexual,
Intergender, Intergender,
@ -433,9 +432,10 @@ impl ColorProfile {
pub fn with_length(&self, length: u8) -> Result<Self> { pub fn with_length(&self, length: u8) -> Result<Self> {
let orig_len = self.colors.len(); let orig_len = self.colors.len();
let orig_len: u8 = orig_len.try_into().expect("`orig_len` should fit in `u8`"); let orig_len: u8 = orig_len.try_into().expect("`orig_len` should fit in `u8`");
if length < orig_len { // TODO: I believe weird things can happen because of this...
unimplemented!("compressing length of color profile not implemented"); // if length < orig_len {
} // unimplemented!("compressing length of color profile not implemented");
// }
let center_i = (orig_len as f32 / 2.0).floor() as usize; let center_i = (orig_len as f32 / 2.0).floor() as usize;
// How many copies of each color should be displayed at least? // How many copies of each color should be displayed at least?
@ -448,21 +448,16 @@ impl ColorProfile {
// If there is an odd space left, extend the center by one space // If there is an odd space left, extend the center by one space
if extras % 2 == 1 { if extras % 2 == 1 {
extras -= 1;
weights[center_i] += 1; weights[center_i] += 1;
extras -= 1;
} }
// Add weight to border until there's no space left (extras must be even at this // Add weight to border until there's no space left (extras must be even at this
// point) // point)
// TODO: this gives a horrible result when `extras` is still large relative to let weights_len = weights.len();
// `orig_len` - we should probably distribute even if slightly uneven for border_i in 0..(extras / 2) as usize {
let mut border_i = 0;
while extras > 0 {
extras -= 2;
weights[border_i] += 1; weights[border_i] += 1;
let weights_len = weights.len();
weights[weights_len - border_i - 1] += 1; weights[weights_len - border_i - 1] += 1;
border_i += 1;
} }
self.with_weights(weights) self.with_weights(weights)