Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto detect light/dark mode, changing the theme accordingly #380

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
54 changes: 37 additions & 17 deletions crates/hyfetch/src/bin/hyfetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,16 @@ fn main() -> Result<()> {
};

let color_mode = options.mode.unwrap_or(config.mode);
let theme = config.light_dark;
let auto_detect_light_dark = options
.auto_detect_light_dark
.unwrap_or_else(|| config.auto_detect_light_dark.unwrap_or(false));
let theme = if auto_detect_light_dark {
let res = det_bg();
res?.map(|bg| bg.theme())
.unwrap_or(config.light_dark.unwrap_or_default())
} else {
config.light_dark.unwrap_or_default()
};

// Check if it's June (pride month)
let now =
Expand Down Expand Up @@ -131,7 +140,12 @@ fn main() -> Result<()> {
} else if let Some(lightness) = options.lightness {
color_profile.with_lightness(AssignLightness::Replace(lightness))
} else {
color_profile.with_lightness_adaptive(config.lightness(), theme)
color_profile.with_lightness_adaptive(
config
.lightness
.unwrap_or_else(|| Config::default_lightness(theme)),
theme,
)
};
debug!(?color_profile, "lightened color profile");

Expand Down Expand Up @@ -187,6 +201,22 @@ fn load_config(path: &PathBuf) -> Result<Option<Config>> {
Ok(Some(config))
}

fn det_bg() -> Result<Option<Srgb<u8>>, terminal_colorsaurus::Error> {
if !io::stdout().is_terminal() {
return Ok(None);
}

background_color(QueryOptions::default())
.map(|terminal_colorsaurus::Color { r, g, b }| Some(Srgb::new(r, g, b).into_format()))
.or_else(|err| {
if matches!(err, terminal_colorsaurus::Error::UnsupportedTerminal) {
Ok(None)
} else {
Err(err)
}
})
}

/// Creates config interactively.
///
/// The config is automatically stored to file.
Expand All @@ -197,21 +227,10 @@ fn create_config(
backend: Backend,
debug_mode: bool,
) -> Result<Config> {
// Detect terminal environment (doesn't work for all terminal emulators,
// especially on Windows)
let det_bg = if io::stdout().is_terminal() {
match background_color(QueryOptions::default()) {
Ok(bg) => Some(Srgb::<u16>::new(bg.r, bg.g, bg.b).into_format::<u8>()),
Err(terminal_colorsaurus::Error::UnsupportedTerminal) => None,
Err(err) => {
return Err(err).context("failed to get terminal background color");
},
}
} else {
None
};
let det_bg = det_bg()?;
debug!(?det_bg, "detected background color");
let det_ansi = supports_color::on(supports_color::Stream::Stdout).map(|color_level| {
#[allow(clippy::if_same_then_else)]
if color_level.has_16m {
AnsiMode::Rgb
} else if color_level.has_256 {
Expand All @@ -230,7 +249,7 @@ fn create_config(

let asc = get_distro_ascii(distro, backend).context("failed to get distro ascii")?;
let asc = asc.to_normalized().context("failed to normalize ascii")?;
let theme = det_bg.map(|bg| bg.theme()).unwrap_or(TerminalTheme::Light);
let theme = det_bg.map(|bg| bg.theme()).unwrap_or_default();
let color_mode = det_ansi.unwrap_or(AnsiMode::Ansi256);
let mut title = format!(
"Welcome to {logo} Let's set up some colors first.",
Expand Down Expand Up @@ -1001,7 +1020,8 @@ fn create_config(
let config = Config {
preset,
mode: color_mode,
light_dark: theme,
light_dark: Some(theme),
auto_detect_light_dark: Some(det_bg.is_some()),
lightness: Some(lightness),
color_align,
backend,
Expand Down
6 changes: 6 additions & 0 deletions crates/hyfetch/src/cli_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct Options {
pub print_font_logo: bool,
pub test_print: bool,
pub ask_exit: bool,
pub auto_detect_light_dark: Option<bool>,
}

pub fn options() -> OptionParser<Options> {
Expand Down Expand Up @@ -170,6 +171,10 @@ BACKEND={{{backends}}}",
.help("Ask for input before exiting")
.switch()
.hide();
let auto_detect_light_dark = long("auto-detect-light-dark")
.help("Enables hyfetch to detect light/dark terminal background in runtime")
.argument("BOOL")
.optional();

construct!(Options {
config,
Expand All @@ -188,6 +193,7 @@ BACKEND={{{backends}}}",
// hidden
test_print,
ask_exit,
auto_detect_light_dark,
})
.to_options()
.header(
Expand Down
8 changes: 2 additions & 6 deletions crates/hyfetch/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::types::{AnsiMode, Backend, TerminalTheme};
pub struct Config {
pub preset: Preset,
pub mode: AnsiMode,
pub light_dark: TerminalTheme,
pub auto_detect_light_dark: Option<bool>,
pub light_dark: Option<TerminalTheme>,
pub lightness: Option<Lightness>,
pub color_align: ColorAlignment,
pub backend: Backend,
Expand All @@ -31,11 +32,6 @@ impl Config {
},
}
}

pub fn lightness(&self) -> Lightness {
self.lightness
.unwrap_or_else(|| Self::default_lightness(self.light_dark))
}
}

mod args_serde {
Expand Down
6 changes: 6 additions & 0 deletions crates/hyfetch/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ pub enum TerminalTheme {
Dark,
}

impl Default for TerminalTheme {
fn default() -> Self {
Self::Light
}
}

Comment on lines +39 to +44
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think dark terminals are more popular so maybe setting this default to dark would be better?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, I'll change that

#[derive(
Copy,
Clone,
Expand Down