Use selected backend to get distro name

This commit is contained in:
Teoh Han Hui 2024-07-13 04:04:14 +08:00
parent d79196a7fc
commit d11f6f0a9f
No known key found for this signature in database
GPG key ID: D43E2BABAF97DCAE
6 changed files with 154 additions and 83 deletions

View file

@ -12,7 +12,7 @@ use hyfetch::models::Config;
use hyfetch::neofetch_util::ensure_git_bash;
use hyfetch::neofetch_util::{self, ascii_size, get_distro_ascii, literal_input, ColorAlignment};
use hyfetch::presets::{AssignLightness, ColorProfile, Preset};
use hyfetch::types::{AnsiMode, LightDark};
use hyfetch::types::{AnsiMode, Backend, TerminalTheme};
use hyfetch::utils::get_cache_path;
use palette::Srgb;
use strum::{EnumCount, VariantArray, VariantNames};
@ -28,34 +28,54 @@ fn main() -> Result<()> {
let options = options().run();
init_tracing_subsriber(options.debug).context("failed to init tracing subscriber")?;
let debug_mode = options.debug;
init_tracing_subsriber(debug_mode).context("failed to init tracing subscriber")?;
debug!(?options, "CLI options");
// Use a custom distro
let distro = options.distro.as_ref();
let backend = options.backend.unwrap_or(Backend::Neofetch);
let use_overlay = options.overlay;
#[cfg(windows)]
ensure_git_bash().context("failed to find git bash")?;
if options.test_print {
let (asc, _) = get_distro_ascii(distro).context("failed to get distro ascii")?;
let (asc, _) = get_distro_ascii(distro, backend).context("failed to get distro ascii")?;
println!("{asc}");
return Ok(());
}
let config = if options.config {
create_config(distro, &options.config_file, options.overlay, options.debug)
.context("failed to create config")?
create_config(
&options.config_file,
distro,
backend,
use_overlay,
debug_mode,
)
.context("failed to create config")?
} else if let Some(config) =
read_config(&options.config_file).context("failed to read config")?
{
config
} else {
create_config(distro, &options.config_file, options.overlay, options.debug)
.context("failed to create config")?
create_config(
&options.config_file,
distro,
backend,
use_overlay,
debug_mode,
)
.context("failed to create config")?
};
let color_mode = options.mode.unwrap_or(config.mode);
let theme = config.light_dark;
// Check if it's June (pride month)
let now =
OffsetDateTime::now_local().context("failed to get current datetime in local timezone")?;
@ -83,7 +103,6 @@ fn main() -> Result<()> {
// Use a custom distro
let distro = options.distro.as_ref().or(config.distro.as_ref());
let color_mode = options.mode.unwrap_or(config.mode);
let backend = options.backend.unwrap_or(config.backend);
let args = options.args.as_ref().or(config.args.as_ref());
@ -98,7 +117,7 @@ fn main() -> Result<()> {
} else if let Some(lightness) = options.lightness {
color_profile.with_lightness(AssignLightness::Replace(lightness))
} else {
color_profile.with_lightness_dl(config.lightness(), config.light_dark, options.overlay)
color_profile.with_lightness_adaptive(config.lightness(), theme, use_overlay)
};
debug!(?color_profile, "lightened color profile");
@ -109,7 +128,7 @@ fn main() -> Result<()> {
None,
)
} else {
get_distro_ascii(distro).context("failed to get distro ascii")?
get_distro_ascii(distro, backend).context("failed to get distro ascii")?
};
let color_align = if fore_back.is_some() {
match config.color_align {
@ -124,7 +143,7 @@ fn main() -> Result<()> {
config.color_align
};
let asc = color_align
.recolor_ascii(asc, color_profile, color_mode, config.light_dark)
.recolor_ascii(asc, color_profile, color_mode, theme)
.context("failed to recolor ascii")?;
neofetch_util::run(asc, backend, args)?;
@ -174,8 +193,9 @@ fn read_config(path: &Path) -> Result<Option<Config>> {
/// The config is automatically stored to file.
#[tracing::instrument(level = "debug")]
fn create_config(
distro: Option<&String>,
path: &Path,
distro: Option<&String>,
backend: Backend,
use_overlay: bool,
debug_mode: bool,
) -> Result<Config> {
@ -202,14 +222,15 @@ fn create_config(
});
debug!(?det_ansi, "detected color mode");
let (asc, fore_back) = get_distro_ascii(distro).context("failed to get distro ascii")?;
let (asc, fore_back) =
get_distro_ascii(distro, backend).context("failed to get distro ascii")?;
let (asc_width, asc_lines) = ascii_size(asc);
let theme = det_bg.map(|bg| bg.theme()).unwrap_or(LightDark::Light);
let theme = det_bg.map(|bg| bg.theme()).unwrap_or(TerminalTheme::Light);
let color_mode = det_ansi.unwrap_or(AnsiMode::Ansi256);
let logo = color(
match theme {
LightDark::Light => "&l&bhyfetch&~&L",
LightDark::Dark => "&l&bhy&ffetch&~&L",
TerminalTheme::Light => "&l&bhyfetch&~&L",
TerminalTheme::Dark => "&l&bhy&ffetch&~&L",
},
color_mode,
)
@ -280,9 +301,9 @@ fn create_config(
};
//////////////////////////////
// 2. Select light/dark mode
// 2. Select theme (light/dark mode)
let select_light_dark = || -> Result<(LightDark, &str)> {
let select_theme = || -> Result<(TerminalTheme, &str)> {
if let Some(det_bg) = det_bg {
return Ok((det_bg.theme(), "Detected background color"));
}
@ -294,11 +315,10 @@ fn create_config(
};
let theme = {
let (light_dark, ttl) =
select_light_dark().context("failed to select light / dark mode")?;
debug!(?light_dark, "selected theme");
update_title(&mut title, &mut option_counter, ttl, light_dark.into());
light_dark
let (selected_theme, ttl) = select_theme().context("failed to select theme")?;
debug!(?selected_theme, "selected theme");
update_title(&mut title, &mut option_counter, ttl, selected_theme.into());
selected_theme
};
//////////////////////////////
@ -400,7 +420,7 @@ fn create_config(
let color_profile: ColorProfile;
let preset_rainbow = Preset::Rainbow
.color_profile()
.with_lightness_dl(Config::default_lightness(theme), theme, use_overlay)
.with_lightness_adaptive(Config::default_lightness(theme), theme, use_overlay)
.color_text(
"preset",
color_mode,
@ -421,7 +441,7 @@ fn create_config(
opts.push("prev");
}
println!("Enter 'next' to go to the next page and 'prev' to go to the previous page.");
let preset = literal_input(
let selection = literal_input(
format!("Which {preset_rainbow} do you want to use? "),
&opts[..],
Preset::Rainbow.into(),
@ -429,18 +449,19 @@ fn create_config(
color_mode,
)
.context("failed to select preset")?;
if preset == "next" {
if selection == "next" {
page += 1;
} else if preset == "prev" {
} else if selection == "prev" {
page -= 1;
} else {
let preset: Preset = preset.parse().expect("selected preset should be valid");
debug!(?preset, "selected preset");
color_profile = preset.color_profile();
let selected_preset: Preset =
selection.parse().expect("selected preset should be valid");
debug!(?selected_preset, "selected preset");
color_profile = selected_preset.color_profile();
{
let preset_name: &'static str = preset.into();
let preset_name: &'static str = selected_preset.into();
let preset_colored_name = color_profile
.with_lightness_dl(Config::default_lightness(theme), theme, use_overlay)
.with_lightness_adaptive(Config::default_lightness(theme), theme, use_overlay)
.color_text(
preset_name,
color_mode,

View file

@ -11,7 +11,7 @@ use palette::{IntoColorMut, LinSrgb, Okhsl, Srgb};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::types::{AnsiMode, LightDark};
use crate::types::{AnsiMode, TerminalTheme};
const MINECRAFT_COLORS: [(&str, &str); 30] = [
// Minecraft formatting codes
@ -114,7 +114,7 @@ pub trait ToAnsiString {
}
pub trait Theme {
fn theme(&self) -> LightDark;
fn theme(&self) -> TerminalTheme;
}
impl Lightness {
@ -227,16 +227,16 @@ impl ToAnsiString for Srgb<u8> {
}
impl Theme for Srgb<u8> {
fn theme(&self) -> LightDark {
fn theme(&self) -> TerminalTheme {
let mut rgb_f32_color: LinSrgb = self.into_linear();
{
let okhsl_f32_color: &mut Okhsl = &mut rgb_f32_color.into_color_mut();
if okhsl_f32_color.lightness > 0.5 {
LightDark::Light
TerminalTheme::Light
} else {
LightDark::Dark
TerminalTheme::Dark
}
}
}

View file

@ -3,13 +3,13 @@ use serde::{Deserialize, Serialize};
use crate::color_util::Lightness;
use crate::neofetch_util::ColorAlignment;
use crate::presets::Preset;
use crate::types::{AnsiMode, Backend, LightDark};
use crate::types::{AnsiMode, Backend, TerminalTheme};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Config {
pub preset: Preset,
pub mode: AnsiMode,
pub light_dark: LightDark,
pub light_dark: TerminalTheme,
lightness: Option<Lightness>,
pub color_align: ColorAlignment,
pub backend: Backend,
@ -21,12 +21,12 @@ pub struct Config {
}
impl Config {
pub fn default_lightness(term: LightDark) -> Lightness {
match term {
LightDark::Dark => {
pub fn default_lightness(theme: TerminalTheme) -> Lightness {
match theme {
TerminalTheme::Dark => {
Lightness::new(0.65).expect("default lightness should not be invalid")
},
LightDark::Light => {
TerminalTheme::Light => {
Lightness::new(0.4).expect("default lightness should not be invalid")
},
}

View file

@ -22,7 +22,7 @@ use crate::color_util::{
};
use crate::distros::Distro;
use crate::presets::ColorProfile;
use crate::types::{AnsiMode, Backend, LightDark};
use crate::types::{AnsiMode, Backend, TerminalTheme};
use crate::utils::{find_file, find_in_path, process_command_status};
const NEOFETCH_COLOR_PATTERNS: [&str; 6] = ["${c1}", "${c2}", "${c3}", "${c4}", "${c5}", "${c6}"];
@ -84,7 +84,7 @@ impl ColorAlignment {
asc: String,
color_profile: ColorProfile,
color_mode: AnsiMode,
term: LightDark,
theme: TerminalTheme,
) -> Result<String> {
let reset = color("&~&*", color_mode).expect("color reset should not be invalid");
@ -105,9 +105,9 @@ impl ColorAlignment {
let asc = asc.replace(
&format!("${{c{fore}}}"),
&color(
match term {
LightDark::Light => "&0",
LightDark::Dark => "&f",
match theme {
TerminalTheme::Light => "&0",
TerminalTheme::Dark => "&f",
},
color_mode,
)
@ -466,14 +466,17 @@ 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, Option<ForeBackColorPair>)>
pub fn get_distro_ascii<S>(
distro: Option<S>,
backend: Backend,
) -> Result<(String, Option<ForeBackColorPair>)>
where
S: AsRef<str> + fmt::Debug,
{
let distro: Cow<_> = if let Some(distro) = distro.as_ref() {
distro.as_ref().into()
} else {
get_distro_name()
get_distro_name(backend)
.context("failed to get distro name")?
.into()
};
@ -500,6 +503,7 @@ where
Ok((normalize_ascii(asc), None))
}
#[tracing::instrument(level = "debug", skip(asc))]
pub fn run(asc: String, backend: Backend, args: Option<&Vec<String>>) -> Result<()> {
match backend {
Backend::Neofetch => {
@ -653,10 +657,60 @@ where
}
}
/// Runs fastfetch command, returning the piped stdout output.
fn run_fastfetch_command_piped<S>(args: &[S]) -> Result<String>
where
S: AsRef<OsStr> + fmt::Debug,
{
let mut command = make_fastfetch_command(args)?;
let output = command
.output()
.context("failed to execute fastfetch as child process")?;
debug!(?output, "fastfetch output");
process_command_status(&output.status).context("fastfetch command exited with error")?;
let out = String::from_utf8(output.stdout)
.context("failed to process fastfetch output as it contains invalid UTF-8")?
.trim()
.to_owned();
Ok(out)
}
fn make_fastfetch_command<S>(args: &[S]) -> Result<Command>
where
S: AsRef<OsStr>,
{
// Find fastfetch binary
let fastfetch_path = fastfetch_path().context("failed to get fastfetch path")?;
let fastfetch_path = fastfetch_path.context("fastfetch command not found")?;
debug!(?fastfetch_path, "fastfetch path");
let mut command = Command::new(fastfetch_path);
command.args(args);
Ok(command)
}
#[tracing::instrument(level = "debug")]
fn get_distro_name() -> Result<String> {
run_neofetch_command_piped(&["ascii_distro_name"])
.context("failed to get distro name from neofetch")
fn get_distro_name(backend: Backend) -> Result<String> {
match backend {
Backend::Neofetch => run_neofetch_command_piped(&["ascii_distro_name"])
.context("failed to get distro name from neofetch"),
Backend::Fastfetch | Backend::FastfetchOld => run_fastfetch_command_piped(&[
"--logo",
"none",
"-s",
"OS",
"--disable-linewrap",
"--os-key",
" ",
])
.context("failed to get distro name from fastfetch"),
Backend::Qwqfetch => {
todo!()
},
}
}
/// Runs neofetch with colors.
@ -676,21 +730,18 @@ fn run_neofetch(asc: String, args: Option<&Vec<String>>) -> Result<()> {
// Call neofetch with the temp file
let temp_file_path = temp_file.into_temp_path();
let args = {
let mut v = vec![
"--ascii",
"--source",
temp_file_path
.to_str()
.expect("temp file path should not contain invalid UTF-8"),
"--ascii-colors",
let mut v: Vec<Cow<OsStr>> = vec![
OsStr::new("--ascii").into(),
OsStr::new("--source").into(),
OsStr::new(&temp_file_path).into(),
OsStr::new("--ascii-colors").into(),
];
if let Some(args) = args {
let args: Vec<_> = args.iter().map(|s| &**s).collect();
v.extend(args);
v.extend(args.iter().map(|arg| OsStr::new(arg).into()));
}
v
};
let mut command = make_neofetch_command(&args)?;
let mut command = make_neofetch_command(&args[..])?;
debug!(?command, "neofetch command");
@ -761,12 +812,6 @@ fn fastfetch_path() -> Result<Option<PathBuf>> {
/// Runs fastfetch with colors.
#[tracing::instrument(level = "debug", skip(asc))]
fn run_fastfetch(asc: String, args: Option<&Vec<String>>, legacy: bool) -> Result<()> {
// Find fastfetch binary
let fastfetch_path = fastfetch_path().context("failed to get fastfetch path")?;
let fastfetch_path = fastfetch_path.context("fastfetch command not found")?;
debug!(?fastfetch_path, "fastfetch path");
// Write temp file
let mut temp_file =
NamedTempFile::with_prefix("ascii.txt").context("failed to create temp file for ascii")?;
@ -776,12 +821,17 @@ fn run_fastfetch(asc: String, args: Option<&Vec<String>>, legacy: bool) -> Resul
// Call fastfetch with the temp file
let temp_file_path = temp_file.into_temp_path();
let mut command = Command::new(fastfetch_path);
command.arg(if legacy { "--raw" } else { "--file-raw" });
command.arg(&temp_file_path);
if let Some(args) = args {
command.args(args);
}
let args = {
let mut v: Vec<Cow<OsStr>> = vec![
OsStr::new(if legacy { "--raw" } else { "--file-raw" }).into(),
OsStr::new(&temp_file_path).into(),
];
if let Some(args) = args {
v.extend(args.iter().map(|arg| OsStr::new(arg).into()));
}
v
};
let mut command = make_fastfetch_command(&args[..])?;
debug!(?command, "fastfetch command");

View file

@ -10,7 +10,7 @@ use tracing::debug;
use unicode_segmentation::UnicodeSegmentation;
use crate::color_util::{ForegroundBackground, Lightness, ToAnsiString};
use crate::types::{AnsiMode, LightDark};
use crate::types::{AnsiMode, TerminalTheme};
#[derive(
Copy,
@ -639,20 +639,20 @@ impl ColorProfile {
}
/// Creates a new color profile, with the colors set to the specified
/// [`Okhsl`] lightness value, with respect to dark/light terminals.
pub fn with_lightness_dl(
/// [`Okhsl`] lightness value, adapted to the terminal theme.
pub fn with_lightness_adaptive(
&self,
lightness: Lightness,
term: LightDark,
theme: TerminalTheme,
use_overlay: bool,
) -> Self {
if use_overlay {
todo!()
}
match term {
LightDark::Dark => self.with_lightness(AssignLightness::ClampMin(lightness)),
LightDark::Light => self.with_lightness(AssignLightness::ClampMax(lightness)),
match theme {
TerminalTheme::Dark => self.with_lightness(AssignLightness::ClampMin(lightness)),
TerminalTheme::Light => self.with_lightness(AssignLightness::ClampMax(lightness)),
}
}

View file

@ -23,7 +23,7 @@ pub enum AnsiMode {
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum LightDark {
pub enum TerminalTheme {
Light,
Dark,
}