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;
#[cfg(windows)]
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::utils::get_cache_path;
use tracing::debug;
@ -33,10 +33,8 @@ fn main() -> Result<()> {
ensure_git_bash().context("failed to find git bash")?;
if options.test_print {
println!(
"{}",
get_distro_ascii(distro).context("failed to get distro ascii")?
);
let (asc, _) = get_distro_ascii(distro).context("failed to get distro ascii")?;
println!("{asc}");
return Ok(());
}
@ -94,13 +92,28 @@ fn main() -> Result<()> {
};
debug!(?color_profile, "lightened color profile");
let asc = if let Some(path) = options.ascii_file {
fs::read_to_string(&path).with_context(|| format!("failed to read ascii from {path:?}"))?
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:?}"))?,
None,
)
} else {
get_distro_ascii(distro).context("failed to get distro ascii")?
};
let asc = config
.color_align
let color_align = if fore_back.is_some() {
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)
.context("failed to recolor ascii")?;
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}"];
static NEOFETCH_COLORS_AC: OnceLock<AhoCorasick> = OnceLock::new();
type ForeBackColorPair = (NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor);
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
#[serde(tag = "mode")]
#[serde(rename_all = "lowercase")]
pub enum ColorAlignment {
Horizontal {
fore_back: Option<(NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor)>,
#[serde(skip)]
fore_back: Option<ForeBackColorPair>,
},
Vertical {
fore_back: Option<(NeofetchAsciiIndexedColor, NeofetchAsciiIndexedColor)>,
#[serde(skip)]
fore_back: Option<ForeBackColorPair>,
},
Custom {
#[serde(rename = "custom_colors")]
@ -45,8 +49,35 @@ pub enum 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.
#[tracing::instrument(level = "debug")]
#[tracing::instrument(level = "debug", skip(asc))]
pub fn recolor_ascii(
&self,
asc: String,
@ -54,19 +85,20 @@ impl ColorAlignment {
color_mode: AnsiMode,
term: LightDark,
) -> 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 asc = match self {
Self::Horizontal {
&Self::Horizontal {
fore_back: Some((fore, back)),
}
| Self::Vertical {
| &Self::Vertical {
fore_back: Some((fore, back)),
} => {
let fore: u8 = (*fore).into();
let back: u8 = (*back).into();
let fore: u8 = fore.into();
let back: u8 = back.into();
let asc = fill_starting(asc)
.context("failed to fill in starting neofetch color codes")?;
// Replace foreground colors
let asc = asc.replace(
@ -191,6 +223,9 @@ impl ColorAlignment {
Self::Custom {
colors: custom_colors,
} => {
let asc = fill_starting(asc)
.context("failed to fill in starting neofetch color codes")?;
let ColorProfile { colors } = color_profile.unique_colors();
// Apply colors
@ -215,6 +250,39 @@ impl ColorAlignment {
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.
@ -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
/// the specific distro's ascii art instead.
#[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
S: AsRef<str> + fmt::Debug,
{
@ -333,7 +401,10 @@ where
// Try new codegen-based detection method
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");
@ -346,10 +417,10 @@ where
// printf
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<()> {
match backend {
Backend::Neofetch => {
@ -432,7 +503,7 @@ where
let mut matches = ac.find_iter(line).peekable();
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
},
_ => {
@ -545,7 +616,7 @@ fn get_distro_name() -> Result<String> {
}
/// Runs neofetch with colors.
#[tracing::instrument(level = "debug")]
#[tracing::instrument(level = "debug", skip(asc))]
fn run_neofetch(asc: String, args: Option<&Vec<String>>) -> Result<()> {
// Escape backslashes here because backslashes are escaped in neofetch for
// printf

View file

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