1use collections::{HashMap, IndexMap};
2use gpui::{FontFallbacks, FontFeatures, FontStyle, FontWeight};
3use schemars::{JsonSchema, JsonSchema_repr};
4use serde::{Deserialize, Deserializer, Serialize};
5use serde_json::Value;
6use serde_repr::{Deserialize_repr, Serialize_repr};
7use std::sync::Arc;
8
9use serde_with::skip_serializing_none;
10
11/// Settings for rendering text in UI and text buffers.
12
13#[skip_serializing_none]
14#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema)]
15pub struct ThemeSettingsContent {
16 /// The default font size for text in the UI.
17 #[serde(default)]
18 pub ui_font_size: Option<f32>,
19 /// The name of a font to use for rendering in the UI.
20 #[serde(default)]
21 pub ui_font_family: Option<FontFamilyName>,
22 /// The font fallbacks to use for rendering in the UI.
23 #[serde(default)]
24 #[schemars(default = "default_font_fallbacks")]
25 #[schemars(extend("uniqueItems" = true))]
26 pub ui_font_fallbacks: Option<Vec<FontFamilyName>>,
27 /// The OpenType features to enable for text in the UI.
28 #[serde(default)]
29 #[schemars(default = "default_font_features")]
30 pub ui_font_features: Option<FontFeatures>,
31 /// The weight of the UI font in CSS units from 100 to 900.
32 #[serde(default)]
33 pub ui_font_weight: Option<f32>,
34 /// The name of a font to use for rendering in text buffers.
35 #[serde(default)]
36 pub buffer_font_family: Option<FontFamilyName>,
37 /// The font fallbacks to use for rendering in text buffers.
38 #[serde(default)]
39 #[schemars(extend("uniqueItems" = true))]
40 pub buffer_font_fallbacks: Option<Vec<FontFamilyName>>,
41 /// The default font size for rendering in text buffers.
42 #[serde(default)]
43 pub buffer_font_size: Option<f32>,
44 /// The weight of the editor font in CSS units from 100 to 900.
45 #[serde(default)]
46 pub buffer_font_weight: Option<f32>,
47 /// The buffer's line height.
48 #[serde(default)]
49 pub buffer_line_height: Option<BufferLineHeight>,
50 /// The OpenType features to enable for rendering in text buffers.
51 #[serde(default)]
52 #[schemars(default = "default_font_features")]
53 pub buffer_font_features: Option<FontFeatures>,
54 /// The font size for the agent panel. Falls back to the UI font size if unset.
55 #[serde(default)]
56 pub agent_font_size: Option<Option<f32>>,
57 /// The name of the Zed theme to use.
58 #[serde(default)]
59 pub theme: Option<ThemeSelection>,
60 /// The name of the icon theme to use.
61 #[serde(default)]
62 pub icon_theme: Option<IconThemeSelection>,
63
64 /// UNSTABLE: Expect many elements to be broken.
65 ///
66 // Controls the density of the UI.
67 #[serde(rename = "unstable.ui_density", default)]
68 pub ui_density: Option<UiDensity>,
69
70 /// How much to fade out unused code.
71 #[serde(default)]
72 pub unnecessary_code_fade: Option<f32>,
73
74 /// EXPERIMENTAL: Overrides for the current theme.
75 ///
76 /// These values will override the ones on the current theme specified in `theme`.
77 #[serde(rename = "experimental.theme_overrides", default)]
78 pub experimental_theme_overrides: Option<ThemeStyleContent>,
79
80 /// Overrides per theme
81 ///
82 /// These values will override the ones on the specified theme
83 #[serde(default)]
84 pub theme_overrides: HashMap<String, ThemeStyleContent>,
85}
86
87fn default_font_features() -> Option<FontFeatures> {
88 Some(FontFeatures::default())
89}
90
91fn default_font_fallbacks() -> Option<FontFallbacks> {
92 Some(FontFallbacks::default())
93}
94
95/// Represents the selection of a theme, which can be either static or dynamic.
96#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
97#[serde(untagged)]
98pub enum ThemeSelection {
99 /// A static theme selection, represented by a single theme name.
100 Static(ThemeName),
101 /// A dynamic theme selection, which can change based the [ThemeMode].
102 Dynamic {
103 /// The mode used to determine which theme to use.
104 #[serde(default)]
105 mode: ThemeMode,
106 /// The theme to use for light mode.
107 light: ThemeName,
108 /// The theme to use for dark mode.
109 dark: ThemeName,
110 },
111}
112
113/// Represents the selection of an icon theme, which can be either static or dynamic.
114#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
115#[serde(untagged)]
116pub enum IconThemeSelection {
117 /// A static icon theme selection, represented by a single icon theme name.
118 Static(IconThemeName),
119 /// A dynamic icon theme selection, which can change based on the [`ThemeMode`].
120 Dynamic {
121 /// The mode used to determine which theme to use.
122 #[serde(default)]
123 mode: ThemeMode,
124 /// The icon theme to use for light mode.
125 light: IconThemeName,
126 /// The icon theme to use for dark mode.
127 dark: IconThemeName,
128 },
129}
130
131// TODO: Rename ThemeMode -> ThemeAppearanceMode
132/// The mode use to select a theme.
133///
134/// `Light` and `Dark` will select their respective themes.
135///
136/// `System` will select the theme based on the system's appearance.
137#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
138#[serde(rename_all = "snake_case")]
139pub enum ThemeMode {
140 /// Use the specified `light` theme.
141 Light,
142
143 /// Use the specified `dark` theme.
144 Dark,
145
146 /// Use the theme based on the system's appearance.
147 #[default]
148 System,
149}
150
151/// Specifies the density of the UI.
152/// Note: This setting is still experimental. See [this tracking issue](https://github.com/zed-industries/zed/issues/18078)
153#[derive(
154 Debug,
155 Default,
156 PartialEq,
157 Eq,
158 PartialOrd,
159 Ord,
160 Hash,
161 Clone,
162 Copy,
163 Serialize,
164 Deserialize,
165 JsonSchema,
166)]
167#[serde(rename_all = "snake_case")]
168pub enum UiDensity {
169 /// A denser UI with tighter spacing and smaller elements.
170 #[serde(alias = "compact")]
171 Compact,
172 #[default]
173 #[serde(alias = "default")]
174 /// The default UI density.
175 Default,
176 #[serde(alias = "comfortable")]
177 /// A looser UI with more spacing and larger elements.
178 Comfortable,
179}
180
181impl UiDensity {
182 /// The spacing ratio of a given density.
183 /// TODO: Standardize usage throughout the app or remove
184 pub fn spacing_ratio(self) -> f32 {
185 match self {
186 UiDensity::Compact => 0.75,
187 UiDensity::Default => 1.0,
188 UiDensity::Comfortable => 1.25,
189 }
190 }
191}
192
193/// Newtype for font family name. Its `ParameterizedJsonSchema` lists the font families known at
194/// runtime.
195#[skip_serializing_none]
196#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
197#[serde(transparent)]
198pub struct FontFamilyName(pub Arc<str>);
199
200/// The buffer's line height.
201#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
202#[serde(rename_all = "snake_case")]
203pub enum BufferLineHeight {
204 /// A less dense line height.
205 #[default]
206 Comfortable,
207 /// The default line height.
208 Standard,
209 /// A custom line height, where 1.0 is the font's height. Must be at least 1.0.
210 Custom(#[serde(deserialize_with = "deserialize_line_height")] f32),
211}
212
213fn deserialize_line_height<'de, D>(deserializer: D) -> Result<f32, D::Error>
214where
215 D: serde::Deserializer<'de>,
216{
217 let value = f32::deserialize(deserializer)?;
218 if value < 1.0 {
219 return Err(serde::de::Error::custom(
220 "buffer_line_height.custom must be at least 1.0",
221 ));
222 }
223
224 Ok(value)
225}
226
227/// The content of a serialized theme.
228#[skip_serializing_none]
229#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
230#[serde(default)]
231pub struct ThemeStyleContent {
232 #[serde(default, rename = "background.appearance")]
233 pub window_background_appearance: Option<WindowBackgroundContent>,
234
235 #[serde(default)]
236 pub accents: Vec<AccentContent>,
237
238 #[serde(flatten, default)]
239 pub colors: ThemeColorsContent,
240
241 #[serde(flatten, default)]
242 pub status: StatusColorsContent,
243
244 #[serde(default)]
245 pub players: Vec<PlayerColorContent>,
246
247 /// The styles for syntax nodes.
248 #[serde(default)]
249 pub syntax: IndexMap<String, HighlightStyleContent>,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
253pub struct AccentContent(pub Option<String>);
254
255#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
256pub struct PlayerColorContent {
257 pub cursor: Option<String>,
258 pub background: Option<String>,
259 pub selection: Option<String>,
260}
261
262/// Newtype for a theme name. Its `ParameterizedJsonSchema` lists the theme names known at runtime.
263#[skip_serializing_none]
264#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
265#[serde(transparent)]
266pub struct ThemeName(pub Arc<str>);
267
268/// Newtype for a icon theme name. Its `ParameterizedJsonSchema` lists the icon theme names known at
269/// runtime.
270#[skip_serializing_none]
271#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
272#[serde(transparent)]
273pub struct IconThemeName(pub Arc<str>);
274
275#[skip_serializing_none]
276#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
277#[serde(default)]
278pub struct ThemeColorsContent {
279 /// Border color. Used for most borders, is usually a high contrast color.
280 #[serde(rename = "border")]
281 pub border: Option<String>,
282
283 /// Border color. Used for deemphasized borders, like a visual divider between two sections
284 #[serde(rename = "border.variant")]
285 pub border_variant: Option<String>,
286
287 /// Border color. Used for focused elements, like keyboard focused list item.
288 #[serde(rename = "border.focused")]
289 pub border_focused: Option<String>,
290
291 /// Border color. Used for selected elements, like an active search filter or selected checkbox.
292 #[serde(rename = "border.selected")]
293 pub border_selected: Option<String>,
294
295 /// Border color. Used for transparent borders. Used for placeholder borders when an element gains a border on state change.
296 #[serde(rename = "border.transparent")]
297 pub border_transparent: Option<String>,
298
299 /// Border color. Used for disabled elements, like a disabled input or button.
300 #[serde(rename = "border.disabled")]
301 pub border_disabled: Option<String>,
302
303 /// Background color. Used for elevated surfaces, like a context menu, popup, or dialog.
304 #[serde(rename = "elevated_surface.background")]
305 pub elevated_surface_background: Option<String>,
306
307 /// Background Color. Used for grounded surfaces like a panel or tab.
308 #[serde(rename = "surface.background")]
309 pub surface_background: Option<String>,
310
311 /// Background Color. Used for the app background and blank panels or windows.
312 #[serde(rename = "background")]
313 pub background: Option<String>,
314
315 /// Background Color. Used for the background of an element that should have a different background than the surface it's on.
316 ///
317 /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
318 ///
319 /// For an element that should have the same background as the surface it's on, use `ghost_element_background`.
320 #[serde(rename = "element.background")]
321 pub element_background: Option<String>,
322
323 /// Background Color. Used for the hover state of an element that should have a different background than the surface it's on.
324 ///
325 /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
326 #[serde(rename = "element.hover")]
327 pub element_hover: Option<String>,
328
329 /// Background Color. Used for the active state of an element that should have a different background than the surface it's on.
330 ///
331 /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressed.
332 #[serde(rename = "element.active")]
333 pub element_active: Option<String>,
334
335 /// Background Color. Used for the selected state of an element that should have a different background than the surface it's on.
336 ///
337 /// Selected states are triggered by the element being selected (or "activated") by the user.
338 ///
339 /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
340 #[serde(rename = "element.selected")]
341 pub element_selected: Option<String>,
342
343 /// Background Color. Used for the disabled state of an element that should have a different background than the surface it's on.
344 ///
345 /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
346 #[serde(rename = "element.disabled")]
347 pub element_disabled: Option<String>,
348
349 /// Background Color. Used for the background of selections in a UI element.
350 #[serde(rename = "element.selection_background")]
351 pub element_selection_background: Option<String>,
352
353 /// Background Color. Used for the area that shows where a dragged element will be dropped.
354 #[serde(rename = "drop_target.background")]
355 pub drop_target_background: Option<String>,
356
357 /// Border Color. Used for the border that shows where a dragged element will be dropped.
358 #[serde(rename = "drop_target.border")]
359 pub drop_target_border: Option<String>,
360
361 /// Used for the background of a ghost element that should have the same background as the surface it's on.
362 ///
363 /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
364 ///
365 /// For an element that should have a different background than the surface it's on, use `element_background`.
366 #[serde(rename = "ghost_element.background")]
367 pub ghost_element_background: Option<String>,
368
369 /// Background Color. Used for the hover state of a ghost element that should have the same background as the surface it's on.
370 ///
371 /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
372 #[serde(rename = "ghost_element.hover")]
373 pub ghost_element_hover: Option<String>,
374
375 /// Background Color. Used for the active state of a ghost element that should have the same background as the surface it's on.
376 ///
377 /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressed.
378 #[serde(rename = "ghost_element.active")]
379 pub ghost_element_active: Option<String>,
380
381 /// Background Color. Used for the selected state of a ghost element that should have the same background as the surface it's on.
382 ///
383 /// Selected states are triggered by the element being selected (or "activated") by the user.
384 ///
385 /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
386 #[serde(rename = "ghost_element.selected")]
387 pub ghost_element_selected: Option<String>,
388
389 /// Background Color. Used for the disabled state of a ghost element that should have the same background as the surface it's on.
390 ///
391 /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
392 #[serde(rename = "ghost_element.disabled")]
393 pub ghost_element_disabled: Option<String>,
394
395 /// Text Color. Default text color used for most text.
396 #[serde(rename = "text")]
397 pub text: Option<String>,
398
399 /// Text Color. Color of muted or deemphasized text. It is a subdued version of the standard text color.
400 #[serde(rename = "text.muted")]
401 pub text_muted: Option<String>,
402
403 /// Text Color. Color of the placeholder text typically shown in input fields to guide the user to enter valid data.
404 #[serde(rename = "text.placeholder")]
405 pub text_placeholder: Option<String>,
406
407 /// Text Color. Color used for text denoting disabled elements. Typically, the color is faded or grayed out to emphasize the disabled state.
408 #[serde(rename = "text.disabled")]
409 pub text_disabled: Option<String>,
410
411 /// Text Color. Color used for emphasis or highlighting certain text, like an active filter or a matched character in a search.
412 #[serde(rename = "text.accent")]
413 pub text_accent: Option<String>,
414
415 /// Fill Color. Used for the default fill color of an icon.
416 #[serde(rename = "icon")]
417 pub icon: Option<String>,
418
419 /// Fill Color. Used for the muted or deemphasized fill color of an icon.
420 ///
421 /// This might be used to show an icon in an inactive pane, or to deemphasize a series of icons to give them less visual weight.
422 #[serde(rename = "icon.muted")]
423 pub icon_muted: Option<String>,
424
425 /// Fill Color. Used for the disabled fill color of an icon.
426 ///
427 /// Disabled states are shown when a user cannot interact with an element, like a icon button.
428 #[serde(rename = "icon.disabled")]
429 pub icon_disabled: Option<String>,
430
431 /// Fill Color. Used for the placeholder fill color of an icon.
432 ///
433 /// This might be used to show an icon in an input that disappears when the user enters text.
434 #[serde(rename = "icon.placeholder")]
435 pub icon_placeholder: Option<String>,
436
437 /// Fill Color. Used for the accent fill color of an icon.
438 ///
439 /// This might be used to show when a toggleable icon button is selected.
440 #[serde(rename = "icon.accent")]
441 pub icon_accent: Option<String>,
442
443 /// Color used to accent some of the debuggers elements
444 /// Only accent breakpoint & breakpoint related symbols right now
445 #[serde(rename = "debugger.accent")]
446 pub debugger_accent: Option<String>,
447
448 #[serde(rename = "status_bar.background")]
449 pub status_bar_background: Option<String>,
450
451 #[serde(rename = "title_bar.background")]
452 pub title_bar_background: Option<String>,
453
454 #[serde(rename = "title_bar.inactive_background")]
455 pub title_bar_inactive_background: Option<String>,
456
457 #[serde(rename = "toolbar.background")]
458 pub toolbar_background: Option<String>,
459
460 #[serde(rename = "tab_bar.background")]
461 pub tab_bar_background: Option<String>,
462
463 #[serde(rename = "tab.inactive_background")]
464 pub tab_inactive_background: Option<String>,
465
466 #[serde(rename = "tab.active_background")]
467 pub tab_active_background: Option<String>,
468
469 #[serde(rename = "search.match_background")]
470 pub search_match_background: Option<String>,
471
472 #[serde(rename = "panel.background")]
473 pub panel_background: Option<String>,
474
475 #[serde(rename = "panel.focused_border")]
476 pub panel_focused_border: Option<String>,
477
478 #[serde(rename = "panel.indent_guide")]
479 pub panel_indent_guide: Option<String>,
480
481 #[serde(rename = "panel.indent_guide_hover")]
482 pub panel_indent_guide_hover: Option<String>,
483
484 #[serde(rename = "panel.indent_guide_active")]
485 pub panel_indent_guide_active: Option<String>,
486
487 #[serde(rename = "panel.overlay_background")]
488 pub panel_overlay_background: Option<String>,
489
490 #[serde(rename = "panel.overlay_hover")]
491 pub panel_overlay_hover: Option<String>,
492
493 #[serde(rename = "pane.focused_border")]
494 pub pane_focused_border: Option<String>,
495
496 #[serde(rename = "pane_group.border")]
497 pub pane_group_border: Option<String>,
498
499 /// The deprecated version of `scrollbar.thumb.background`.
500 ///
501 /// Don't use this field.
502 #[serde(rename = "scrollbar_thumb.background", skip_serializing)]
503 #[schemars(skip)]
504 pub deprecated_scrollbar_thumb_background: Option<String>,
505
506 /// The color of the scrollbar thumb.
507 #[serde(rename = "scrollbar.thumb.background")]
508 pub scrollbar_thumb_background: Option<String>,
509
510 /// The color of the scrollbar thumb when hovered over.
511 #[serde(rename = "scrollbar.thumb.hover_background")]
512 pub scrollbar_thumb_hover_background: Option<String>,
513
514 /// The color of the scrollbar thumb whilst being actively dragged.
515 #[serde(rename = "scrollbar.thumb.active_background")]
516 pub scrollbar_thumb_active_background: Option<String>,
517
518 /// The border color of the scrollbar thumb.
519 #[serde(rename = "scrollbar.thumb.border")]
520 pub scrollbar_thumb_border: Option<String>,
521
522 /// The background color of the scrollbar track.
523 #[serde(rename = "scrollbar.track.background")]
524 pub scrollbar_track_background: Option<String>,
525
526 /// The border color of the scrollbar track.
527 #[serde(rename = "scrollbar.track.border")]
528 pub scrollbar_track_border: Option<String>,
529
530 /// The color of the minimap thumb.
531 #[serde(rename = "minimap.thumb.background")]
532 pub minimap_thumb_background: Option<String>,
533
534 /// The color of the minimap thumb when hovered over.
535 #[serde(rename = "minimap.thumb.hover_background")]
536 pub minimap_thumb_hover_background: Option<String>,
537
538 /// The color of the minimap thumb whilst being actively dragged.
539 #[serde(rename = "minimap.thumb.active_background")]
540 pub minimap_thumb_active_background: Option<String>,
541
542 /// The border color of the minimap thumb.
543 #[serde(rename = "minimap.thumb.border")]
544 pub minimap_thumb_border: Option<String>,
545
546 #[serde(rename = "editor.foreground")]
547 pub editor_foreground: Option<String>,
548
549 #[serde(rename = "editor.background")]
550 pub editor_background: Option<String>,
551
552 #[serde(rename = "editor.gutter.background")]
553 pub editor_gutter_background: Option<String>,
554
555 #[serde(rename = "editor.subheader.background")]
556 pub editor_subheader_background: Option<String>,
557
558 #[serde(rename = "editor.active_line.background")]
559 pub editor_active_line_background: Option<String>,
560
561 #[serde(rename = "editor.highlighted_line.background")]
562 pub editor_highlighted_line_background: Option<String>,
563
564 /// Background of active line of debugger
565 #[serde(rename = "editor.debugger_active_line.background")]
566 pub editor_debugger_active_line_background: Option<String>,
567
568 /// Text Color. Used for the text of the line number in the editor gutter.
569 #[serde(rename = "editor.line_number")]
570 pub editor_line_number: Option<String>,
571
572 /// Text Color. Used for the text of the line number in the editor gutter when the line is highlighted.
573 #[serde(rename = "editor.active_line_number")]
574 pub editor_active_line_number: Option<String>,
575
576 /// Text Color. Used for the text of the line number in the editor gutter when the line is hovered over.
577 #[serde(rename = "editor.hover_line_number")]
578 pub editor_hover_line_number: Option<String>,
579
580 /// Text Color. Used to mark invisible characters in the editor.
581 ///
582 /// Example: spaces, tabs, carriage returns, etc.
583 #[serde(rename = "editor.invisible")]
584 pub editor_invisible: Option<String>,
585
586 #[serde(rename = "editor.wrap_guide")]
587 pub editor_wrap_guide: Option<String>,
588
589 #[serde(rename = "editor.active_wrap_guide")]
590 pub editor_active_wrap_guide: Option<String>,
591
592 #[serde(rename = "editor.indent_guide")]
593 pub editor_indent_guide: Option<String>,
594
595 #[serde(rename = "editor.indent_guide_active")]
596 pub editor_indent_guide_active: Option<String>,
597
598 /// Read-access of a symbol, like reading a variable.
599 ///
600 /// A document highlight is a range inside a text document which deserves
601 /// special attention. Usually a document highlight is visualized by changing
602 /// the background color of its range.
603 #[serde(rename = "editor.document_highlight.read_background")]
604 pub editor_document_highlight_read_background: Option<String>,
605
606 /// Read-access of a symbol, like reading a variable.
607 ///
608 /// A document highlight is a range inside a text document which deserves
609 /// special attention. Usually a document highlight is visualized by changing
610 /// the background color of its range.
611 #[serde(rename = "editor.document_highlight.write_background")]
612 pub editor_document_highlight_write_background: Option<String>,
613
614 /// Highlighted brackets background color.
615 ///
616 /// Matching brackets in the cursor scope are highlighted with this background color.
617 #[serde(rename = "editor.document_highlight.bracket_background")]
618 pub editor_document_highlight_bracket_background: Option<String>,
619
620 /// Terminal background color.
621 #[serde(rename = "terminal.background")]
622 pub terminal_background: Option<String>,
623
624 /// Terminal foreground color.
625 #[serde(rename = "terminal.foreground")]
626 pub terminal_foreground: Option<String>,
627
628 /// Terminal ANSI background color.
629 #[serde(rename = "terminal.ansi.background")]
630 pub terminal_ansi_background: Option<String>,
631
632 /// Bright terminal foreground color.
633 #[serde(rename = "terminal.bright_foreground")]
634 pub terminal_bright_foreground: Option<String>,
635
636 /// Dim terminal foreground color.
637 #[serde(rename = "terminal.dim_foreground")]
638 pub terminal_dim_foreground: Option<String>,
639
640 /// Black ANSI terminal color.
641 #[serde(rename = "terminal.ansi.black")]
642 pub terminal_ansi_black: Option<String>,
643
644 /// Bright black ANSI terminal color.
645 #[serde(rename = "terminal.ansi.bright_black")]
646 pub terminal_ansi_bright_black: Option<String>,
647
648 /// Dim black ANSI terminal color.
649 #[serde(rename = "terminal.ansi.dim_black")]
650 pub terminal_ansi_dim_black: Option<String>,
651
652 /// Red ANSI terminal color.
653 #[serde(rename = "terminal.ansi.red")]
654 pub terminal_ansi_red: Option<String>,
655
656 /// Bright red ANSI terminal color.
657 #[serde(rename = "terminal.ansi.bright_red")]
658 pub terminal_ansi_bright_red: Option<String>,
659
660 /// Dim red ANSI terminal color.
661 #[serde(rename = "terminal.ansi.dim_red")]
662 pub terminal_ansi_dim_red: Option<String>,
663
664 /// Green ANSI terminal color.
665 #[serde(rename = "terminal.ansi.green")]
666 pub terminal_ansi_green: Option<String>,
667
668 /// Bright green ANSI terminal color.
669 #[serde(rename = "terminal.ansi.bright_green")]
670 pub terminal_ansi_bright_green: Option<String>,
671
672 /// Dim green ANSI terminal color.
673 #[serde(rename = "terminal.ansi.dim_green")]
674 pub terminal_ansi_dim_green: Option<String>,
675
676 /// Yellow ANSI terminal color.
677 #[serde(rename = "terminal.ansi.yellow")]
678 pub terminal_ansi_yellow: Option<String>,
679
680 /// Bright yellow ANSI terminal color.
681 #[serde(rename = "terminal.ansi.bright_yellow")]
682 pub terminal_ansi_bright_yellow: Option<String>,
683
684 /// Dim yellow ANSI terminal color.
685 #[serde(rename = "terminal.ansi.dim_yellow")]
686 pub terminal_ansi_dim_yellow: Option<String>,
687
688 /// Blue ANSI terminal color.
689 #[serde(rename = "terminal.ansi.blue")]
690 pub terminal_ansi_blue: Option<String>,
691
692 /// Bright blue ANSI terminal color.
693 #[serde(rename = "terminal.ansi.bright_blue")]
694 pub terminal_ansi_bright_blue: Option<String>,
695
696 /// Dim blue ANSI terminal color.
697 #[serde(rename = "terminal.ansi.dim_blue")]
698 pub terminal_ansi_dim_blue: Option<String>,
699
700 /// Magenta ANSI terminal color.
701 #[serde(rename = "terminal.ansi.magenta")]
702 pub terminal_ansi_magenta: Option<String>,
703
704 /// Bright magenta ANSI terminal color.
705 #[serde(rename = "terminal.ansi.bright_magenta")]
706 pub terminal_ansi_bright_magenta: Option<String>,
707
708 /// Dim magenta ANSI terminal color.
709 #[serde(rename = "terminal.ansi.dim_magenta")]
710 pub terminal_ansi_dim_magenta: Option<String>,
711
712 /// Cyan ANSI terminal color.
713 #[serde(rename = "terminal.ansi.cyan")]
714 pub terminal_ansi_cyan: Option<String>,
715
716 /// Bright cyan ANSI terminal color.
717 #[serde(rename = "terminal.ansi.bright_cyan")]
718 pub terminal_ansi_bright_cyan: Option<String>,
719
720 /// Dim cyan ANSI terminal color.
721 #[serde(rename = "terminal.ansi.dim_cyan")]
722 pub terminal_ansi_dim_cyan: Option<String>,
723
724 /// White ANSI terminal color.
725 #[serde(rename = "terminal.ansi.white")]
726 pub terminal_ansi_white: Option<String>,
727
728 /// Bright white ANSI terminal color.
729 #[serde(rename = "terminal.ansi.bright_white")]
730 pub terminal_ansi_bright_white: Option<String>,
731
732 /// Dim white ANSI terminal color.
733 #[serde(rename = "terminal.ansi.dim_white")]
734 pub terminal_ansi_dim_white: Option<String>,
735
736 #[serde(rename = "link_text.hover")]
737 pub link_text_hover: Option<String>,
738
739 /// Added version control color.
740 #[serde(rename = "version_control.added")]
741 pub version_control_added: Option<String>,
742
743 /// Deleted version control color.
744 #[serde(rename = "version_control.deleted")]
745 pub version_control_deleted: Option<String>,
746
747 /// Modified version control color.
748 #[serde(rename = "version_control.modified")]
749 pub version_control_modified: Option<String>,
750
751 /// Renamed version control color.
752 #[serde(rename = "version_control.renamed")]
753 pub version_control_renamed: Option<String>,
754
755 /// Conflict version control color.
756 #[serde(rename = "version_control.conflict")]
757 pub version_control_conflict: Option<String>,
758
759 /// Ignored version control color.
760 #[serde(rename = "version_control.ignored")]
761 pub version_control_ignored: Option<String>,
762
763 /// Background color for row highlights of "ours" regions in merge conflicts.
764 #[serde(rename = "version_control.conflict_marker.ours")]
765 pub version_control_conflict_marker_ours: Option<String>,
766
767 /// Background color for row highlights of "theirs" regions in merge conflicts.
768 #[serde(rename = "version_control.conflict_marker.theirs")]
769 pub version_control_conflict_marker_theirs: Option<String>,
770
771 /// Deprecated in favor of `version_control_conflict_marker_ours`.
772 #[deprecated]
773 pub version_control_conflict_ours_background: Option<String>,
774
775 /// Deprecated in favor of `version_control_conflict_marker_theirs`.
776 #[deprecated]
777 pub version_control_conflict_theirs_background: Option<String>,
778}
779
780#[skip_serializing_none]
781#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
782#[serde(default)]
783pub struct HighlightStyleContent {
784 pub color: Option<String>,
785
786 #[serde(deserialize_with = "treat_error_as_none")]
787 pub background_color: Option<String>,
788
789 #[serde(deserialize_with = "treat_error_as_none")]
790 pub font_style: Option<FontStyleContent>,
791
792 #[serde(deserialize_with = "treat_error_as_none")]
793 pub font_weight: Option<FontWeightContent>,
794}
795
796impl HighlightStyleContent {
797 pub fn is_empty(&self) -> bool {
798 self.color.is_none()
799 && self.background_color.is_none()
800 && self.font_style.is_none()
801 && self.font_weight.is_none()
802 }
803}
804
805fn treat_error_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
806where
807 T: Deserialize<'de>,
808 D: Deserializer<'de>,
809{
810 let value: Value = Deserialize::deserialize(deserializer)?;
811 Ok(T::deserialize(value).ok())
812}
813
814#[skip_serializing_none]
815#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
816#[serde(default)]
817pub struct StatusColorsContent {
818 /// Indicates some kind of conflict, like a file changed on disk while it was open, or
819 /// merge conflicts in a Git repository.
820 #[serde(rename = "conflict")]
821 pub conflict: Option<String>,
822
823 #[serde(rename = "conflict.background")]
824 pub conflict_background: Option<String>,
825
826 #[serde(rename = "conflict.border")]
827 pub conflict_border: Option<String>,
828
829 /// Indicates something new, like a new file added to a Git repository.
830 #[serde(rename = "created")]
831 pub created: Option<String>,
832
833 #[serde(rename = "created.background")]
834 pub created_background: Option<String>,
835
836 #[serde(rename = "created.border")]
837 pub created_border: Option<String>,
838
839 /// Indicates that something no longer exists, like a deleted file.
840 #[serde(rename = "deleted")]
841 pub deleted: Option<String>,
842
843 #[serde(rename = "deleted.background")]
844 pub deleted_background: Option<String>,
845
846 #[serde(rename = "deleted.border")]
847 pub deleted_border: Option<String>,
848
849 /// Indicates a system error, a failed operation or a diagnostic error.
850 #[serde(rename = "error")]
851 pub error: Option<String>,
852
853 #[serde(rename = "error.background")]
854 pub error_background: Option<String>,
855
856 #[serde(rename = "error.border")]
857 pub error_border: Option<String>,
858
859 /// Represents a hidden status, such as a file being hidden in a file tree.
860 #[serde(rename = "hidden")]
861 pub hidden: Option<String>,
862
863 #[serde(rename = "hidden.background")]
864 pub hidden_background: Option<String>,
865
866 #[serde(rename = "hidden.border")]
867 pub hidden_border: Option<String>,
868
869 /// Indicates a hint or some kind of additional information.
870 #[serde(rename = "hint")]
871 pub hint: Option<String>,
872
873 #[serde(rename = "hint.background")]
874 pub hint_background: Option<String>,
875
876 #[serde(rename = "hint.border")]
877 pub hint_border: Option<String>,
878
879 /// Indicates that something is deliberately ignored, such as a file or operation ignored by Git.
880 #[serde(rename = "ignored")]
881 pub ignored: Option<String>,
882
883 #[serde(rename = "ignored.background")]
884 pub ignored_background: Option<String>,
885
886 #[serde(rename = "ignored.border")]
887 pub ignored_border: Option<String>,
888
889 /// Represents informational status updates or messages.
890 #[serde(rename = "info")]
891 pub info: Option<String>,
892
893 #[serde(rename = "info.background")]
894 pub info_background: Option<String>,
895
896 #[serde(rename = "info.border")]
897 pub info_border: Option<String>,
898
899 /// Indicates a changed or altered status, like a file that has been edited.
900 #[serde(rename = "modified")]
901 pub modified: Option<String>,
902
903 #[serde(rename = "modified.background")]
904 pub modified_background: Option<String>,
905
906 #[serde(rename = "modified.border")]
907 pub modified_border: Option<String>,
908
909 /// Indicates something that is predicted, like automatic code completion, or generated code.
910 #[serde(rename = "predictive")]
911 pub predictive: Option<String>,
912
913 #[serde(rename = "predictive.background")]
914 pub predictive_background: Option<String>,
915
916 #[serde(rename = "predictive.border")]
917 pub predictive_border: Option<String>,
918
919 /// Represents a renamed status, such as a file that has been renamed.
920 #[serde(rename = "renamed")]
921 pub renamed: Option<String>,
922
923 #[serde(rename = "renamed.background")]
924 pub renamed_background: Option<String>,
925
926 #[serde(rename = "renamed.border")]
927 pub renamed_border: Option<String>,
928
929 /// Indicates a successful operation or task completion.
930 #[serde(rename = "success")]
931 pub success: Option<String>,
932
933 #[serde(rename = "success.background")]
934 pub success_background: Option<String>,
935
936 #[serde(rename = "success.border")]
937 pub success_border: Option<String>,
938
939 /// Indicates some kind of unreachable status, like a block of code that can never be reached.
940 #[serde(rename = "unreachable")]
941 pub unreachable: Option<String>,
942
943 #[serde(rename = "unreachable.background")]
944 pub unreachable_background: Option<String>,
945
946 #[serde(rename = "unreachable.border")]
947 pub unreachable_border: Option<String>,
948
949 /// Represents a warning status, like an operation that is about to fail.
950 #[serde(rename = "warning")]
951 pub warning: Option<String>,
952
953 #[serde(rename = "warning.background")]
954 pub warning_background: Option<String>,
955
956 #[serde(rename = "warning.border")]
957 pub warning_border: Option<String>,
958}
959
960/// The background appearance of the window.
961#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema)]
962#[serde(rename_all = "snake_case")]
963pub enum WindowBackgroundContent {
964 Opaque,
965 Transparent,
966 Blurred,
967}
968
969impl Into<gpui::WindowBackgroundAppearance> for WindowBackgroundContent {
970 fn into(self) -> gpui::WindowBackgroundAppearance {
971 match self {
972 WindowBackgroundContent::Opaque => gpui::WindowBackgroundAppearance::Opaque,
973 WindowBackgroundContent::Transparent => gpui::WindowBackgroundAppearance::Transparent,
974 WindowBackgroundContent::Blurred => gpui::WindowBackgroundAppearance::Blurred,
975 }
976 }
977}
978
979#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
980#[serde(rename_all = "snake_case")]
981pub enum FontStyleContent {
982 Normal,
983 Italic,
984 Oblique,
985}
986
987impl From<FontStyleContent> for FontStyle {
988 fn from(value: FontStyleContent) -> Self {
989 match value {
990 FontStyleContent::Normal => FontStyle::Normal,
991 FontStyleContent::Italic => FontStyle::Italic,
992 FontStyleContent::Oblique => FontStyle::Oblique,
993 }
994 }
995}
996
997#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, JsonSchema_repr, PartialEq)]
998#[repr(u16)]
999pub enum FontWeightContent {
1000 Thin = 100,
1001 ExtraLight = 200,
1002 Light = 300,
1003 Normal = 400,
1004 Medium = 500,
1005 Semibold = 600,
1006 Bold = 700,
1007 ExtraBold = 800,
1008 Black = 900,
1009}
1010
1011impl From<FontWeightContent> for FontWeight {
1012 fn from(value: FontWeightContent) -> Self {
1013 match value {
1014 FontWeightContent::Thin => FontWeight::THIN,
1015 FontWeightContent::ExtraLight => FontWeight::EXTRA_LIGHT,
1016 FontWeightContent::Light => FontWeight::LIGHT,
1017 FontWeightContent::Normal => FontWeight::NORMAL,
1018 FontWeightContent::Medium => FontWeight::MEDIUM,
1019 FontWeightContent::Semibold => FontWeight::SEMIBOLD,
1020 FontWeightContent::Bold => FontWeight::BOLD,
1021 FontWeightContent::ExtraBold => FontWeight::EXTRA_BOLD,
1022 FontWeightContent::Black => FontWeight::BLACK,
1023 }
1024 }
1025}
1026
1027#[cfg(test)]
1028mod tests {
1029 use super::*;
1030 use serde_json::json;
1031
1032 #[test]
1033 fn test_buffer_line_height_deserialize_valid() {
1034 assert_eq!(
1035 serde_json::from_value::<BufferLineHeight>(json!("comfortable")).unwrap(),
1036 BufferLineHeight::Comfortable
1037 );
1038 assert_eq!(
1039 serde_json::from_value::<BufferLineHeight>(json!("standard")).unwrap(),
1040 BufferLineHeight::Standard
1041 );
1042 assert_eq!(
1043 serde_json::from_value::<BufferLineHeight>(json!({"custom": 1.0})).unwrap(),
1044 BufferLineHeight::Custom(1.0)
1045 );
1046 assert_eq!(
1047 serde_json::from_value::<BufferLineHeight>(json!({"custom": 1.5})).unwrap(),
1048 BufferLineHeight::Custom(1.5)
1049 );
1050 }
1051
1052 #[test]
1053 fn test_buffer_line_height_deserialize_invalid() {
1054 assert!(
1055 serde_json::from_value::<BufferLineHeight>(json!({"custom": 0.99}))
1056 .err()
1057 .unwrap()
1058 .to_string()
1059 .contains("buffer_line_height.custom must be at least 1.0")
1060 );
1061 assert!(
1062 serde_json::from_value::<BufferLineHeight>(json!({"custom": 0.0}))
1063 .err()
1064 .unwrap()
1065 .to_string()
1066 .contains("buffer_line_height.custom must be at least 1.0")
1067 );
1068 assert!(
1069 serde_json::from_value::<BufferLineHeight>(json!({"custom": -1.0}))
1070 .err()
1071 .unwrap()
1072 .to_string()
1073 .contains("buffer_line_height.custom must be at least 1.0")
1074 );
1075 }
1076}