lib.rs

  1mod resolution;
  2mod theme_registry;
  3
  4use gpui::{
  5    color::Color,
  6    elements::{ContainerStyle, ImageStyle, LabelStyle},
  7    fonts::{HighlightStyle, TextStyle},
  8    Border,
  9};
 10use serde::Deserialize;
 11use std::{collections::HashMap, sync::Arc};
 12
 13pub use theme_registry::*;
 14
 15pub const DEFAULT_THEME_NAME: &'static str = "black";
 16
 17#[derive(Deserialize, Default)]
 18pub struct Theme {
 19    #[serde(default)]
 20    pub name: String,
 21    pub workspace: Workspace,
 22    pub chat_panel: ChatPanel,
 23    pub people_panel: PeoplePanel,
 24    pub project_panel: ProjectPanel,
 25    pub selector: Selector,
 26    pub editor: EditorStyle,
 27}
 28
 29#[derive(Deserialize, Default)]
 30pub struct Workspace {
 31    pub background: Color,
 32    pub titlebar: Titlebar,
 33    pub tab: Tab,
 34    pub active_tab: Tab,
 35    pub pane_divider: Border,
 36    pub left_sidebar: Sidebar,
 37    pub right_sidebar: Sidebar,
 38}
 39
 40#[derive(Clone, Deserialize, Default)]
 41pub struct Titlebar {
 42    #[serde(flatten)]
 43    pub container: ContainerStyle,
 44    pub title: TextStyle,
 45    pub avatar_width: f32,
 46    pub offline_icon: OfflineIcon,
 47    pub icon_color: Color,
 48    pub avatar: ImageStyle,
 49    pub outdated_warning: ContainedText,
 50}
 51
 52#[derive(Clone, Deserialize, Default)]
 53pub struct OfflineIcon {
 54    #[serde(flatten)]
 55    pub container: ContainerStyle,
 56    pub width: f32,
 57}
 58
 59#[derive(Clone, Deserialize, Default)]
 60pub struct Tab {
 61    pub height: f32,
 62    #[serde(flatten)]
 63    pub container: ContainerStyle,
 64    #[serde(flatten)]
 65    pub label: LabelStyle,
 66    pub spacing: f32,
 67    pub icon_width: f32,
 68    pub icon_close: Color,
 69    pub icon_close_active: Color,
 70    pub icon_dirty: Color,
 71    pub icon_conflict: Color,
 72}
 73
 74#[derive(Deserialize, Default)]
 75pub struct Sidebar {
 76    #[serde(flatten)]
 77    pub container: ContainerStyle,
 78    pub width: f32,
 79    pub item: SidebarItem,
 80    pub active_item: SidebarItem,
 81    pub resize_handle: ContainerStyle,
 82}
 83
 84#[derive(Deserialize, Default)]
 85pub struct SidebarItem {
 86    pub icon_color: Color,
 87    pub icon_size: f32,
 88    pub height: f32,
 89}
 90
 91#[derive(Deserialize, Default)]
 92pub struct ChatPanel {
 93    #[serde(flatten)]
 94    pub container: ContainerStyle,
 95    pub message: ChatMessage,
 96    pub pending_message: ChatMessage,
 97    pub channel_select: ChannelSelect,
 98    pub input_editor: InputEditorStyle,
 99    pub sign_in_prompt: TextStyle,
100    pub hovered_sign_in_prompt: TextStyle,
101}
102
103#[derive(Debug, Deserialize, Default)]
104pub struct ProjectPanel {
105    #[serde(flatten)]
106    pub container: ContainerStyle,
107    pub entry: ProjectPanelEntry,
108    pub hovered_entry: ProjectPanelEntry,
109    pub selected_entry: ProjectPanelEntry,
110    pub hovered_selected_entry: ProjectPanelEntry,
111}
112
113#[derive(Debug, Deserialize, Default)]
114pub struct ProjectPanelEntry {
115    pub height: f32,
116    #[serde(flatten)]
117    pub container: ContainerStyle,
118    pub text: TextStyle,
119    pub icon_color: Color,
120    pub icon_size: f32,
121    pub icon_spacing: f32,
122}
123
124#[derive(Deserialize, Default)]
125pub struct PeoplePanel {
126    #[serde(flatten)]
127    pub container: ContainerStyle,
128    pub host_row_height: f32,
129    pub host_avatar: ImageStyle,
130    pub host_username: ContainedText,
131    pub tree_branch_width: f32,
132    pub tree_branch_color: Color,
133    pub shared_worktree: WorktreeRow,
134    pub hovered_shared_worktree: WorktreeRow,
135    pub unshared_worktree: WorktreeRow,
136    pub hovered_unshared_worktree: WorktreeRow,
137}
138
139#[derive(Deserialize, Default)]
140pub struct WorktreeRow {
141    #[serde(flatten)]
142    pub container: ContainerStyle,
143    pub height: f32,
144    pub name: ContainedText,
145    pub guest_avatar: ImageStyle,
146    pub guest_avatar_spacing: f32,
147}
148
149#[derive(Deserialize, Default)]
150pub struct ChatMessage {
151    #[serde(flatten)]
152    pub container: ContainerStyle,
153    pub body: TextStyle,
154    pub sender: ContainedText,
155    pub timestamp: ContainedText,
156}
157
158#[derive(Deserialize, Default)]
159pub struct ChannelSelect {
160    #[serde(flatten)]
161    pub container: ContainerStyle,
162    pub header: ChannelName,
163    pub item: ChannelName,
164    pub active_item: ChannelName,
165    pub hovered_item: ChannelName,
166    pub hovered_active_item: ChannelName,
167    pub menu: ContainerStyle,
168}
169
170#[derive(Deserialize, Default)]
171pub struct ChannelName {
172    #[serde(flatten)]
173    pub container: ContainerStyle,
174    pub hash: ContainedText,
175    pub name: TextStyle,
176}
177
178#[derive(Deserialize, Default)]
179pub struct Selector {
180    #[serde(flatten)]
181    pub container: ContainerStyle,
182    pub empty: ContainedLabel,
183    pub input_editor: InputEditorStyle,
184    pub item: ContainedLabel,
185    pub active_item: ContainedLabel,
186}
187
188#[derive(Clone, Debug, Deserialize, Default)]
189pub struct ContainedText {
190    #[serde(flatten)]
191    pub container: ContainerStyle,
192    #[serde(flatten)]
193    pub text: TextStyle,
194}
195
196#[derive(Deserialize, Default)]
197pub struct ContainedLabel {
198    #[serde(flatten)]
199    pub container: ContainerStyle,
200    #[serde(flatten)]
201    pub label: LabelStyle,
202}
203
204#[derive(Clone, Deserialize, Default)]
205pub struct EditorStyle {
206    pub text: TextStyle,
207    #[serde(default)]
208    pub placeholder_text: Option<TextStyle>,
209    pub background: Color,
210    pub selection: SelectionStyle,
211    pub gutter_background: Color,
212    pub active_line_background: Color,
213    pub line_number: Color,
214    pub line_number_active: Color,
215    pub guest_selections: Vec<SelectionStyle>,
216    pub syntax: Arc<SyntaxTheme>,
217}
218
219#[derive(Clone, Copy, Default, Deserialize)]
220pub struct SelectionStyle {
221    pub cursor: Color,
222    pub selection: Color,
223}
224
225#[derive(Clone, Deserialize, Default)]
226pub struct InputEditorStyle {
227    #[serde(flatten)]
228    pub container: ContainerStyle,
229    pub text: TextStyle,
230    #[serde(default)]
231    pub placeholder_text: Option<TextStyle>,
232    pub selection: SelectionStyle,
233}
234
235impl EditorStyle {
236    pub fn placeholder_text(&self) -> &TextStyle {
237        self.placeholder_text.as_ref().unwrap_or(&self.text)
238    }
239}
240
241impl InputEditorStyle {
242    pub fn as_editor(&self) -> EditorStyle {
243        EditorStyle {
244            text: self.text.clone(),
245            placeholder_text: self.placeholder_text.clone(),
246            background: self
247                .container
248                .background_color
249                .unwrap_or(Color::transparent_black()),
250            selection: self.selection,
251            gutter_background: Default::default(),
252            active_line_background: Default::default(),
253            line_number: Default::default(),
254            line_number_active: Default::default(),
255            guest_selections: Default::default(),
256            syntax: Default::default(),
257        }
258    }
259}
260
261#[derive(Default)]
262pub struct SyntaxTheme {
263    pub highlights: Vec<(String, HighlightStyle)>,
264}
265
266impl SyntaxTheme {
267    pub fn new(highlights: Vec<(String, HighlightStyle)>) -> Self {
268        Self { highlights }
269    }
270}
271
272impl<'de> Deserialize<'de> for SyntaxTheme {
273    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
274    where
275        D: serde::Deserializer<'de>,
276    {
277        let syntax_data: HashMap<String, HighlightStyle> = Deserialize::deserialize(deserializer)?;
278
279        let mut result = Self::new(Vec::new());
280        for (key, style) in syntax_data {
281            match result
282                .highlights
283                .binary_search_by(|(needle, _)| needle.cmp(&key))
284            {
285                Ok(i) | Err(i) => {
286                    result.highlights.insert(i, (key, style));
287                }
288            }
289        }
290
291        Ok(result)
292    }
293}