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    pub message: ChatMessage,
 59}
 60
 61#[derive(Debug, Default, Deserialize)]
 62pub struct ChatMessage {
 63    #[serde(flatten)]
 64    pub label: LabelStyle,
 65}
 66
 67#[derive(Debug, Default, Deserialize)]
 68pub struct Selector {
 69    #[serde(flatten)]
 70    pub container: ContainerStyle,
 71    #[serde(flatten)]
 72    pub label: LabelStyle,
 73
 74    pub item: SelectorItem,
 75    pub active_item: SelectorItem,
 76}
 77
 78#[derive(Debug, Default, Deserialize)]
 79pub struct SelectorItem {
 80    #[serde(flatten)]
 81    pub container: ContainerStyle,
 82    #[serde(flatten)]
 83    pub label: LabelStyle,
 84}
 85
 86#[derive(Debug, Deserialize)]
 87pub struct Editor {
 88    pub background: Color,
 89    pub gutter_background: Color,
 90    pub active_line_background: Color,
 91    pub line_number: Color,
 92    pub line_number_active: Color,
 93    pub text: Color,
 94    pub replicas: Vec<Replica>,
 95}
 96
 97#[derive(Clone, Copy, Debug, Default, Deserialize)]
 98pub struct Replica {
 99    pub cursor: Color,
100    pub selection: Color,
101}
102
103impl Theme {
104    pub fn highlight_style(&self, id: HighlightId) -> TextStyle {
105        self.syntax
106            .get(id.0 as usize)
107            .map(|entry| entry.1.clone())
108            .unwrap_or_else(|| TextStyle {
109                color: self.editor.text,
110                font_properties: Default::default(),
111            })
112    }
113
114    #[cfg(test)]
115    pub fn highlight_name(&self, id: HighlightId) -> Option<&str> {
116        self.syntax.get(id.0 as usize).map(|e| e.0.as_str())
117    }
118}
119
120impl Default for Editor {
121    fn default() -> Self {
122        Self {
123            background: Default::default(),
124            gutter_background: Default::default(),
125            active_line_background: Default::default(),
126            line_number: Default::default(),
127            line_number_active: Default::default(),
128            text: Default::default(),
129            replicas: vec![Replica::default()],
130        }
131    }
132}
133
134pub fn deserialize_syntax_theme<'de, D>(
135    deserializer: D,
136) -> Result<Vec<(String, TextStyle)>, D::Error>
137where
138    D: Deserializer<'de>,
139{
140    let mut result = Vec::<(String, TextStyle)>::new();
141
142    let syntax_data: HashMap<String, TextStyle> = Deserialize::deserialize(deserializer)?;
143    for (key, style) in syntax_data {
144        match result.binary_search_by(|(needle, _)| needle.cmp(&key)) {
145            Ok(i) | Err(i) => {
146                result.insert(i, (key, style));
147            }
148        }
149    }
150
151    Ok(result)
152}