diff options
Diffstat (limited to 'src/options/theme.rs')
-rw-r--r-- | src/options/theme.rs | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/src/options/theme.rs b/src/options/theme.rs index 2d853ada..7c1dbce8 100644 --- a/src/options/theme.rs +++ b/src/options/theme.rs @@ -1,3 +1,5 @@ +use std::io::{stdout, IsTerminal}; + /// Delta doesn't have a formal concept of a "theme". What it has is /// (a) the choice of syntax-highlighting theme /// (b) the choice of light-background-mode vs dark-background-mode, which determine certain @@ -9,7 +11,7 @@ use bat; use bat::assets::HighlightingAssets; -use crate::cli; +use crate::cli::{self, DetectDarkLight}; #[allow(non_snake_case)] pub fn set__is_light_mode__syntax_theme__syntax_set( @@ -20,7 +22,7 @@ pub fn set__is_light_mode__syntax_theme__syntax_set( let (is_light_mode, syntax_theme_name) = get_is_light_mode_and_syntax_theme_name( opt.syntax_theme.as_ref(), syntax_theme_name_from_bat_theme.as_ref(), - opt.light, + get_is_light(opt), ); opt.computed.is_light_mode = is_light_mode; @@ -36,13 +38,14 @@ pub fn is_light_syntax_theme(theme: &str) -> bool { LIGHT_SYNTAX_THEMES.contains(&theme) || theme.to_lowercase().contains("light") } -const LIGHT_SYNTAX_THEMES: [&str; 6] = [ +const LIGHT_SYNTAX_THEMES: [&str; 7] = [ "GitHub", "gruvbox-light", "gruvbox-white", "Monokai Extended Light", "OneHalfLight", "Solarized (light)", + "Catppuccin-latte", ]; const DEFAULT_LIGHT_SYNTAX_THEME: &str = "GitHub"; @@ -83,9 +86,9 @@ fn is_no_syntax_highlighting_syntax_theme_name(theme_name: &str) -> bool { fn get_is_light_mode_and_syntax_theme_name( theme_arg: Option<&String>, bat_theme_env_var: Option<&String>, - light_mode_arg: bool, + light_mode: bool, ) -> (bool, String) { - match (theme_arg, bat_theme_env_var, light_mode_arg) { + match (theme_arg, bat_theme_env_var, light_mode) { (None, None, false) => (false, DEFAULT_DARK_SYNTAX_THEME.to_string()), (Some(theme_name), _, false) => (is_light_syntax_theme(theme_name), theme_name.to_string()), (None, Some(theme_name), false) => { @@ -97,8 +100,72 @@ fn get_is_light_mode_and_syntax_theme_name( } } +fn get_is_light(opt: &cli::Opt) -> bool { + get_is_light_opt(opt) + .or_else(|| should_detect_dark_light(opt).then(detect_light_mode)) + .unwrap_or_default() +} + +fn get_is_light_opt(opt: &cli::Opt) -> Option<bool> { + if opt.light { + Some(true) + } else if opt.dark { + Some(false) + } else { + None + } +} + +/// See [`cli::Opt::detect_dark_light`] for a detailed explanation. +fn should_detect_dark_light(opt: &cli::Opt) -> bool { + match opt.detect_dark_light { + DetectDarkLight::Auto => opt.color_only || stdout().is_terminal(), + DetectDarkLight::Always => true, + DetectDarkLight::Never => false, + } +} + +fn detect_light_mode() -> bool { + use terminal_colorsaurus::{color_scheme, QueryOptions}; + + #[cfg(test)] + if let Some(value) = test_utils::DETECT_LIGHT_MODE_OVERRIDE.get() { + return value; + } + + color_scheme(QueryOptions::default()) + .map(|c| c.is_dark_on_light()) + .unwrap_or_default() +} + +#[cfg(test)] +pub(crate) mod test_utils { + thread_local! { + pub(super) static DETECT_LIGHT_MODE_OVERRIDE: std::cell::Cell<Option<bool>> = const { std::cell::Cell::new(None) }; + } + + pub(crate) struct DetectLightModeOverride { + old_value: Option<bool>, + } + + impl DetectLightModeOverride { + pub(crate) fn new(value: bool) -> Self { + let old_value = DETECT_LIGHT_MODE_OVERRIDE.get(); + DETECT_LIGHT_MODE_OVERRIDE.set(Some(value)); + DetectLightModeOverride { old_value } + } + } + + impl Drop for DetectLightModeOverride { + fn drop(&mut self) { + DETECT_LIGHT_MODE_OVERRIDE.set(self.old_value) + } + } +} + #[cfg(test)] mod tests { + use super::test_utils::DetectLightModeOverride; use super::*; use crate::color; use crate::tests::integration_test_utils; @@ -106,6 +173,8 @@ mod tests { // TODO: Test influence of BAT_THEME env var. E.g. see utils::process::tests::FakeParentArgs. #[test] fn test_syntax_theme_selection() { + let _override = DetectLightModeOverride::new(false); + #[derive(PartialEq)] enum Mode { Light, |