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 selector: Selector,
 24    pub editor: Editor,
 25    #[serde(deserialize_with = "deserialize_syntax_theme")]
 26    pub syntax: Vec<(String, TextStyle)>,
 27}
 28
 29#[derive(Debug, Default, Deserialize)]
 30pub struct Workspace {
 31    pub background: Color,
 32    pub tab: Tab,
 33    pub active_tab: Tab,
 34    pub sidebar: ContainerStyle,
 35    pub sidebar_icon: SidebarIcon,
 36    pub active_sidebar_icon: SidebarIcon,
 37}
 38
 39#[derive(Debug, Default, Deserialize)]
 40pub struct Tab {
 41    #[serde(flatten)]
 42    pub container: ContainerStyle,
 43    #[serde(flatten)]
 44    pub label: LabelStyle,
 45    pub icon_close: Color,
 46    pub icon_dirty: Color,
 47    pub icon_conflict: Color,
 48}
 49
 50#[derive(Debug, Default, Deserialize)]
 51pub struct SidebarIcon {
 52    pub color: Color,
 53}
 54
 55#[derive(Debug, Default, Deserialize)]
 56pub struct Selector {
 57    #[serde(flatten)]
 58    pub container: ContainerStyle,
 59    #[serde(flatten)]
 60    pub label: LabelStyle,
 61
 62    pub item: SelectorItem,
 63    pub active_item: SelectorItem,
 64}
 65
 66#[derive(Debug, Default, Deserialize)]
 67pub struct SelectorItem {
 68    #[serde(flatten)]
 69    pub container: ContainerStyle,
 70    #[serde(flatten)]
 71    pub label: LabelStyle,
 72}
 73
 74#[derive(Debug, Deserialize)]
 75pub struct Editor {
 76    pub background: Color,
 77    pub gutter_background: Color,
 78    pub active_line_background: Color,
 79    pub line_number: Color,
 80    pub line_number_active: Color,
 81    pub text: Color,
 82    pub replicas: Vec<Replica>,
 83}
 84
 85#[derive(Clone, Copy, Debug, Default, Deserialize)]
 86pub struct Replica {
 87    pub cursor: Color,
 88    pub selection: Color,
 89}
 90
 91impl Theme {
 92    pub fn highlight_style(&self, id: HighlightId) -> TextStyle {
 93        self.syntax
 94            .get(id.0 as usize)
 95            .map(|entry| entry.1.clone())
 96            .unwrap_or_else(|| TextStyle {
 97                color: self.editor.text,
 98                font_properties: Default::default(),
 99            })
100    }
101
102    #[cfg(test)]
103    pub fn highlight_name(&self, id: HighlightId) -> Option<&str> {
104        self.syntax.get(id.0 as usize).map(|e| e.0.as_str())
105    }
106}
107
108impl Default for Editor {
109    fn default() -> Self {
110        Self {
111            background: Default::default(),
112            gutter_background: Default::default(),
113            active_line_background: Default::default(),
114            line_number: Default::default(),
115            line_number_active: Default::default(),
116            text: Default::default(),
117            replicas: vec![Replica::default()],
118        }
119    }
120}
121
122pub fn deserialize_syntax_theme<'de, D>(
123    deserializer: D,
124) -> Result<Vec<(String, TextStyle)>, D::Error>
125where
126    D: Deserializer<'de>,
127{
128    let mut result = Vec::<(String, TextStyle)>::new();
129
130    let syntax_data: HashMap<String, TextStyle> = Deserialize::deserialize(deserializer)?;
131    for (key, style) in syntax_data {
132        match result.binary_search_by(|(needle, _)| needle.cmp(&key)) {
133            Ok(i) | Err(i) => {
134                result.insert(i, (key, style));
135            }
136        }
137    }
138
139    Ok(result)
140}