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