diff options
Diffstat (limited to 'ui/src/conf')
-rw-r--r-- | ui/src/conf/themes.rs | 157 |
1 files changed, 129 insertions, 28 deletions
diff --git a/ui/src/conf/themes.rs b/ui/src/conf/themes.rs index 956063d6..75788c3b 100644 --- a/ui/src/conf/themes.rs +++ b/ui/src/conf/themes.rs @@ -22,15 +22,30 @@ use crate::terminal::Color; use crate::Context; use melib::Result; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; #[inline(always)] pub fn color(context: &Context, key: &'static str) -> Color { - (match context.settings.terminal.theme.as_str() { + let theme = match context.settings.terminal.theme.as_str() { "light" => &context.settings.terminal.themes.light, "dark" | _ => &context.settings.terminal.themes.dark, - })[key] + }; + unlink(theme, &Cow::from(key)) +} + +#[inline(always)] +fn unlink<'k, 't: 'k>( + theme: &'t HashMap<Cow<'static, str>, ThemeValue>, + mut key: &'k Cow<'static, str>, +) -> Color { + loop { + match &theme[key] { + ThemeValue::Link(ref new_key) => key = new_key, + ThemeValue::Value(val) => return *val, + } + } } const DEFAULT_KEYS: &'static [&'static str] = &[ @@ -102,12 +117,48 @@ const DEFAULT_KEYS: &'static [&'static str] = &[ "mail.listing.thread_snooze_flag_fg", "mail.listing.thread_snooze_flag_bg", ]; -#[derive(Debug, Clone, Serialize, Deserialize)] + +#[derive(Debug, Clone)] +pub enum ThemeValue { + Value(Color), + Link(Cow<'static, str>), +} + +impl From<Color> for ThemeValue { + fn from(from: Color) -> Self { + ThemeValue::Value(from) + } +} + +impl Default for ThemeValue { + fn default() -> Self { + ThemeValue::Value(Color::Default) + } +} + +impl<'de> Deserialize<'de> for ThemeValue { + fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if let Ok(s) = <String>::deserialize(deserializer) { + if let Ok(c) = Color::from_string_de::<'de, D>(s.clone()) { + Ok(ThemeValue::Value(c)) + } else { + Ok(ThemeValue::Link(s.into())) + } + } else { + Err(de::Error::custom("invalid theme color value")) + } + } +} + +#[derive(Debug, Clone, Deserialize)] pub struct Theme { #[serde(default)] - pub light: HashMap<Cow<'static, str>, Color>, + pub light: HashMap<Cow<'static, str>, ThemeValue>, #[serde(default)] - pub dark: HashMap<Cow<'static, str>, Color>, + pub dark: HashMap<Cow<'static, str>, ThemeValue>, } impl Theme { @@ -139,33 +190,46 @@ impl Default for Theme { let mut dark = HashMap::default(); macro_rules! add { + ($key:literal, light=$light:literal, dark=$dark:literal) => { + light.insert($key.into(), ThemeValue::Link($light.into())); + dark.insert($key.into(), ThemeValue::Link($dark.into())); + }; + ($key:literal, dark=$dark:literal, light=$light:literal) => { + light.insert($key.into(), ThemeValue::Link($light.into())); + dark.insert($key.into(), ThemeValue::Link($dark.into())); + }; + ($key:literal, light=$light:literal) => { + light.insert($key.into(), $ThemeValue::Link(light);) + dark.insert($key.into(), ThemeValue::Value(Color::Default)); + }; + ($key:literal, dark=$dark:literal) => { + light.insert($key.into(),ThemeValue::Value(Color::Default)); + dark.insert($key.into(), ThemeValue::Link($dark.into())); + }; ($key:literal, light=$light:expr, dark=$dark:expr) => { - light.insert($key.into(), $light); - dark.insert($key.into(), $dark); + light.insert($key.into(), ThemeValue::Value($light)); + dark.insert($key.into(), ThemeValue::Value($dark)); }; ($key:literal, dark=$dark:expr, light=$light:expr) => { - light.insert($key.into(), $light); - dark.insert($key.into(), $dark); + light.insert($key.into(), ThemeValue::Value($light)); + dark.insert($key.into(), ThemeValue::Value($dark)); }; ($key:literal, light=$light:expr) => { - light.insert($key.into(), $light); - dark.insert($key.into(), Color::Default); + light.insert($key.into(), $ThemeValue::Value(light);) + dark.insert($key.into(), ThemeValue::Value(Color::Default)); }; ($key:literal, dark=$dark:expr) => { - light.insert($key.into(), Color::Default); - dark.insert($key.into(), $dark); + light.insert($key.into(),ThemeValue::Value(Color::Default)); + dark.insert($key.into(), ThemeValue::Value($dark)); }; ($key:literal) => { - light.insert($key.into(), Color::Default); - dark.insert($key.into(), Color::Default); + light.insert($key.into(), ThemeValue::Value(Color::Default)); + dark.insert($key.into(), ThemeValue::Value(Color::Default)); }; } - light.insert("general.background".into(), Color::Default); - light.insert("general.foreground".into(), Color::Default); - - dark.insert("general.background".into(), Color::Default); - dark.insert("general.foreground".into(), Color::Default); + add!("general.background"); + add!("general.foreground"); /* "general.status_bar_fg", "general.status_bar_bg", @@ -188,19 +252,23 @@ impl Default for Theme { add!("mail.sidebar_highlighted_bg", dark = Color::Byte(15)); add!( "mail.sidebar_highlighted_unread_count_fg", - dark = dark["mail.sidebar_highlighted_fg"] + light = "mail.sidebar_highlighted_fg", + dark = "mail.sidebar_highlighted_fg" ); add!( "mail.sidebar_highlighted_unread_count_bg", - dark = dark["mail.sidebar_highlighted_bg"] + light = "mail.sidebar_highlighted_bg", + dark = "mail.sidebar_highlighted_bg" ); add!( "mail.sidebar_highlighted_index_fg", - dark = dark["mail.sidebar_index_fg"] + light = "mail.sidebar_index_fg", + dark = "mail.sidebar_index_fg" ); add!( "mail.sidebar_highlighted_index_bg", - dark = dark["mail.sidebar_highlighted_bg"] + light = "mail.sidebar_highlighted_bg", + dark = "mail.sidebar_highlighted_bg" ); add!( "mail.sidebar_highlighted_account_fg", @@ -212,19 +280,23 @@ impl Default for Theme { ); add!( "mail.sidebar_highlighted_account_unread_count_fg", - dark = dark["mail.sidebar_unread_count_fg"] + light = "mail.sidebar_unread_count_fg", + dark = "mail.sidebar_unread_count_fg" ); add!( "mail.sidebar_highlighted_account_unread_count_bg", - dark = dark["mail.sidebar_highlighted_fg"] + light = "mail.sidebar_highlighted_account_bg", + dark = "mail.sidebar_highlighted_account_bg" ); add!( "mail.sidebar_highlighted_account_index_fg", - dark = dark["mail.sidebar_index_fg"] + light = "mail.sidebar_index_fg", + dark = "mail.sidebar_index_fg" ); add!( "mail.sidebar_highlighted_account_index_bg", - dark = dark["mail.sidebar_highlighted_bg"] + light = "mail.sidebar_highlighted_account_bg", + dark = "mail.sidebar_highlighted_account_bg" ); /* CompactListing */ @@ -353,3 +425,32 @@ impl Default for Theme { Theme { light, dark } } } + +impl Serialize for Theme { + fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut dark: HashMap<Cow<'static, str>, Color> = Default::default(); + let mut light: HashMap<Cow<'static, str>, Color> = Default::default(); + + for k in self.dark.keys() { + dark.insert(k.clone(), unlink(&self.dark, k)); + } + + for k in self.light.keys() { + light.insert(k.clone(), unlink(&self.light, k)); + } + + #[derive(Serialize)] + struct ThemeSer { + light: HashMap<Cow<'static, str>, Color>, + dark: HashMap<Cow<'static, str>, Color>, + } + use serde::ser::SerializeStruct; + let mut s = serializer.serialize_struct("ThemeSer", 2)?; + s.serialize_field("light", &light)?; + s.serialize_field("dark", &dark)?; + s.end() + } +} |