theme.rs

  1mod highlight_map;
  2mod theme_registry;
  3
  4use anyhow::Result;
  5use gpui::{
  6    color::Color,
  7    elements::{ContainerStyle, LabelStyle},
  8    fonts::TextStyle,
  9};
 10use serde::{Deserialize, Deserializer};
 11use std::collections::HashMap;
 12
 13pub use highlight_map::*;
 14pub use theme_registry::*;
 15
 16pub const DEFAULT_THEME_NAME: &'static str = "dark";
 17
 18#[derive(Debug, Default, Deserialize)]
 19pub struct Theme {
 20    #[serde(default)]
 21    pub name: String,
 22    pub workspace: Workspace,
 23    pub chat_panel: ChatPanel,
 24    pub selector: Selector,
 25    pub editor: Editor,
 26    #[serde(deserialize_with = "deserialize_syntax_theme")]
 27    pub syntax: Vec<(String, TextStyle)>,
 28}
 29
 30#[derive(Debug, Default, Deserialize)]
 31pub struct Workspace {
 32    pub background: Color,
 33    pub tab: Tab,
 34    pub active_tab: Tab,
 35    pub sidebar: ContainerStyle,
 36    pub sidebar_icon: SidebarIcon,
 37    pub active_sidebar_icon: SidebarIcon,
 38}
 39
 40#[derive(Debug, Default, Deserialize)]
 41pub struct Tab {
 42    #[serde(flatten)]
 43    pub container: ContainerStyle,
 44    #[serde(flatten)]
 45    pub label: LabelStyle,
 46    pub icon_close: Color,
 47    pub icon_dirty: Color,
 48    pub icon_conflict: Color,
 49}
 50
 51#[derive(Debug, Default, Deserialize)]
 52pub struct SidebarIcon {
 53    pub color: Color,
 54}
 55
 56#[derive(Debug, Default, Deserialize)]
 57pub struct ChatPanel {
 58    #[serde(flatten)]
 59    pub container: ContainerStyle,
 60    pub message: ChatMessage,
 61}
 62
 63#[derive(Debug, Default, Deserialize)]
 64pub struct ChatMessage {
 65    pub body: TextStyle,
 66    pub sender: ContainedLabel,
 67    pub timestamp: ContainedLabel,
 68}
 69
 70#[derive(Debug, Default, Deserialize)]
 71pub struct Selector {
 72    #[serde(flatten)]
 73    pub container: ContainerStyle,
 74    #[serde(flatten)]
 75    pub label: LabelStyle,
 76
 77    pub item: ContainedLabel,
 78    pub active_item: ContainedLabel,
 79}
 80
 81#[derive(Debug, Default, Deserialize)]
 82pub struct ContainedLabel {
 83    #[serde(flatten)]
 84    pub container: ContainerStyle,
 85    #[serde(flatten)]
 86    pub label: LabelStyle,
 87}
 88
 89#[derive(Debug, Deserialize)]
 90pub struct Editor {
 91    pub background: Color,
 92    pub gutter_background: Color,
 93    pub active_line_background: Color,
 94    pub line_number: Color,
 95    pub line_number_active: Color,
 96    pub text: Color,
 97    pub replicas: Vec<Replica>,
 98}
 99
100#[derive(Clone, Copy, Debug, Default, Deserialize)]
101pub struct Replica {
102    pub cursor: Color,
103    pub selection: Color,
104}
105
106impl Theme {
107    pub fn highlight_style(&self, id: HighlightId) -> TextStyle {
108        self.syntax
109            .get(id.0 as usize)
110            .map(|entry| entry.1.clone())
111            .unwrap_or_else(|| TextStyle {
112                color: self.editor.text,
113                font_properties: Default::default(),
114            })
115    }
116
117    #[cfg(test)]
118    pub fn highlight_name(&self, id: HighlightId) -> Option<&str> {
119        self.syntax.get(id.0 as usize).map(|e| e.0.as_str())
120    }
121}
122
123impl Default for Editor {
124    fn default() -> Self {
125        Self {
126            background: Default::default(),
127            gutter_background: Default::default(),
128            active_line_background: Default::default(),
129            line_number: Default::default(),
130            line_number_active: Default::default(),
131            text: Default::default(),
132            replicas: vec![Replica::default()],
133        }
134    }
135}
136
137pub fn deserialize_syntax_theme<'de, D>(
138    deserializer: D,
139) -> Result<Vec<(String, TextStyle)>, D::Error>
140where
141    D: Deserializer<'de>,
142{
143    let mut result = Vec::<(String, TextStyle)>::new();
144
145    let syntax_data: HashMap<String, TextStyle> = Deserialize::deserialize(deserializer)?;
146    for (key, style) in syntax_data {
147        match result.binary_search_by(|(needle, _)| needle.cmp(&key)) {
148            Ok(i) | Err(i) => {
149                result.insert(i, (key, style));
150            }
151        }
152    }
153
154    Ok(result)
155}