1use gpui2::{AppContext, Hsla, Result, WindowContext};
2use serde::{de::Visitor, Deserialize, Deserializer};
3use std::collections::HashMap;
4use std::fmt;
5use std::sync::Arc;
6
7#[derive(Deserialize, Clone, Default, Debug)]
8pub struct Theme {
9 pub name: String,
10 pub is_light: bool,
11 pub lowest: Layer,
12 pub middle: Layer,
13 pub highest: Layer,
14 pub popover_shadow: Shadow,
15 pub modal_shadow: Shadow,
16 #[serde(deserialize_with = "deserialize_player_colors")]
17 pub players: Vec<PlayerColors>,
18 #[serde(deserialize_with = "deserialize_syntax_colors")]
19 pub syntax: HashMap<String, Hsla>,
20}
21
22#[derive(Deserialize, Clone, Default, Debug)]
23pub struct Layer {
24 pub base: StyleSet,
25 pub variant: StyleSet,
26 pub on: StyleSet,
27 pub accent: StyleSet,
28 pub positive: StyleSet,
29 pub warning: StyleSet,
30 pub negative: StyleSet,
31}
32
33#[derive(Deserialize, Clone, Default, Debug)]
34pub struct StyleSet {
35 #[serde(rename = "default")]
36 pub default: ContainerColors,
37 pub hovered: ContainerColors,
38 pub pressed: ContainerColors,
39 pub active: ContainerColors,
40 pub disabled: ContainerColors,
41 pub inverted: ContainerColors,
42}
43
44#[derive(Deserialize, Clone, Default, Debug)]
45pub struct ContainerColors {
46 pub background: Hsla,
47 pub foreground: Hsla,
48 pub border: Hsla,
49}
50
51#[derive(Deserialize, Clone, Default, Debug)]
52pub struct PlayerColors {
53 pub selection: Hsla,
54 pub cursor: Hsla,
55}
56
57#[derive(Deserialize, Clone, Default, Debug)]
58pub struct Shadow {
59 pub blur: u8,
60 pub color: Hsla,
61 pub offset: Vec<u8>,
62}
63
64fn deserialize_player_colors<'de, D>(deserializer: D) -> Result<Vec<PlayerColors>, D::Error>
65where
66 D: Deserializer<'de>,
67{
68 struct PlayerArrayVisitor;
69
70 impl<'de> Visitor<'de> for PlayerArrayVisitor {
71 type Value = Vec<PlayerColors>;
72
73 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74 formatter.write_str("an object with integer keys")
75 }
76
77 fn visit_map<A: serde::de::MapAccess<'de>>(
78 self,
79 mut map: A,
80 ) -> Result<Self::Value, A::Error> {
81 let mut players = Vec::with_capacity(8);
82 while let Some((key, value)) = map.next_entry::<usize, PlayerColors>()? {
83 if key < 8 {
84 players.push(value);
85 } else {
86 return Err(serde::de::Error::invalid_value(
87 serde::de::Unexpected::Unsigned(key as u64),
88 &"a key in range 0..7",
89 ));
90 }
91 }
92 Ok(players)
93 }
94 }
95
96 deserializer.deserialize_map(PlayerArrayVisitor)
97}
98
99fn deserialize_syntax_colors<'de, D>(deserializer: D) -> Result<HashMap<String, Hsla>, D::Error>
100where
101 D: serde::Deserializer<'de>,
102{
103 #[derive(Deserialize)]
104 struct ColorWrapper {
105 color: Hsla,
106 }
107
108 struct SyntaxVisitor;
109
110 impl<'de> Visitor<'de> for SyntaxVisitor {
111 type Value = HashMap<String, Hsla>;
112
113 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
114 formatter.write_str("a map with keys and objects with a single color field as values")
115 }
116
117 fn visit_map<M>(self, mut map: M) -> Result<HashMap<String, Hsla>, M::Error>
118 where
119 M: serde::de::MapAccess<'de>,
120 {
121 let mut result = HashMap::new();
122 while let Some(key) = map.next_key()? {
123 let wrapper: ColorWrapper = map.next_value()?; // Deserialize values as Hsla
124 result.insert(key, wrapper.color);
125 }
126 Ok(result)
127 }
128 }
129 deserializer.deserialize_map(SyntaxVisitor)
130}
131
132pub fn old_theme(cx: &WindowContext) -> Arc<Theme> {
133 Arc::new(cx.global::<Theme>().clone())
134}
135
136pub fn theme(cx: &AppContext) -> Arc<theme2::Theme> {
137 theme2::active_theme(cx).clone()
138}