Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T04:42:42.511Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

theme.rs

1470 lines · 51.9 KB · rust
1use collections::{HashMap, IndexMap};
2use schemars::JsonSchema;
3use serde::{Deserialize, Deserializer, Serialize};
4use serde_json::Value;
5use settings_macros::{MergeFrom, with_fallible_options};
6use std::{borrow::Cow, fmt::Display, sync::Arc};
7
8use crate::serialize_f32_with_two_decimal_places;
9
10/// OpenType font features as a map of feature tag to value.
11/// This is a content type that mirrors `gpui::FontFeatures` but without the Arc wrapper.
12/// Values can be specified as booleans (true=1, false=0) or integers.
13#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, MergeFrom)]
14#[serde(transparent)]
15pub struct FontFeaturesContent(pub IndexMap<String, u32>);
16
17impl FontFeaturesContent {
18    pub fn new() -> Self {
19        Self(IndexMap::default())
20    }
21}
22
23#[derive(Debug, serde::Deserialize)]
24#[serde(untagged)]
25enum FeatureValue {
26    Bool(bool),
27    Number(serde_json::Number),
28}
29
30fn is_valid_feature_tag(tag: &str) -> bool {
31    tag.len() == 4 && tag.chars().all(|c| c.is_ascii_alphanumeric())
32}
33
34impl<'de> Deserialize<'de> for FontFeaturesContent {
35    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36    where
37        D: Deserializer<'de>,
38    {
39        use serde::de::{MapAccess, Visitor};
40        use std::fmt;
41
42        struct FontFeaturesVisitor;
43
44        impl<'de> Visitor<'de> for FontFeaturesVisitor {
45            type Value = FontFeaturesContent;
46
47            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
48                formatter.write_str("a map of font features")
49            }
50
51            fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
52            where
53                M: MapAccess<'de>,
54            {
55                let mut feature_map = IndexMap::default();
56
57                while let Some((key, value)) =
58                    access.next_entry::<String, Option<FeatureValue>>()?
59                {
60                    if !is_valid_feature_tag(&key) {
61                        log::error!("Incorrect font feature tag: {}", key);
62                        continue;
63                    }
64                    if let Some(value) = value {
65                        match value {
66                            FeatureValue::Bool(enable) => {
67                                feature_map.insert(key, if enable { 1 } else { 0 });
68                            }
69                            FeatureValue::Number(value) => {
70                                if value.is_u64() {
71                                    feature_map.insert(key, value.as_u64().unwrap() as u32);
72                                } else {
73                                    log::error!(
74                                        "Incorrect font feature value {} for feature tag {}",
75                                        value,
76                                        key
77                                    );
78                                    continue;
79                                }
80                            }
81                        }
82                    }
83                }
84
85                Ok(FontFeaturesContent(feature_map))
86            }
87        }
88
89        deserializer.deserialize_map(FontFeaturesVisitor)
90    }
91}
92
93impl JsonSchema for FontFeaturesContent {
94    fn schema_name() -> Cow<'static, str> {
95        "FontFeaturesContent".into()
96    }
97
98    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
99        use schemars::json_schema;
100        json_schema!({
101            "type": "object",
102            "patternProperties": {
103                "[0-9a-zA-Z]{4}$": {
104                    "type": ["boolean", "integer"],
105                    "minimum": 0,
106                    "multipleOf": 1
107                }
108            },
109            "additionalProperties": false
110        })
111    }
112}
113
114/// Settings for rendering text in UI and text buffers.
115
116#[with_fallible_options]
117#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
118pub struct ThemeSettingsContent {
119    /// The default font size for text in the UI.
120    pub ui_font_size: Option<FontSize>,
121    /// The name of a font to use for rendering in the UI.
122    pub ui_font_family: Option<FontFamilyName>,
123    /// The font fallbacks to use for rendering in the UI.
124    #[schemars(default = "default_font_fallbacks")]
125    #[schemars(extend("uniqueItems" = true))]
126    pub ui_font_fallbacks: Option<Vec<FontFamilyName>>,
127    /// The OpenType features to enable for text in the UI.
128    #[schemars(default = "default_font_features")]
129    pub ui_font_features: Option<FontFeaturesContent>,
130    /// The weight of the UI font in CSS units from 100 to 900.
131    #[schemars(default = "default_buffer_font_weight")]
132    pub ui_font_weight: Option<FontWeightContent>,
133    /// The name of a font to use for rendering in text buffers.
134    pub buffer_font_family: Option<FontFamilyName>,
135    /// The font fallbacks to use for rendering in text buffers.
136    #[schemars(extend("uniqueItems" = true))]
137    pub buffer_font_fallbacks: Option<Vec<FontFamilyName>>,
138    /// The default font size for rendering in text buffers.
139    pub buffer_font_size: Option<FontSize>,
140    /// The weight of the editor font in CSS units from 100 to 900.
141    #[schemars(default = "default_buffer_font_weight")]
142    pub buffer_font_weight: Option<FontWeightContent>,
143    /// The buffer's line height.
144    pub buffer_line_height: Option<BufferLineHeight>,
145    /// The OpenType features to enable for rendering in text buffers.
146    #[schemars(default = "default_font_features")]
147    pub buffer_font_features: Option<FontFeaturesContent>,
148    /// The font size for agent responses in the agent panel. Falls back to the UI font size if unset.
149    pub agent_ui_font_size: Option<FontSize>,
150    /// The font size for user messages in the agent panel.
151    pub agent_buffer_font_size: Option<FontSize>,
152    pub git_commit_buffer_font_size: Option<FontSize>,
153    /// The name of a font to use for rendering in the markdown preview.
154    /// Falls back to the UI font if unset.
155    pub markdown_preview_font_family: Option<FontFamilyName>,
156    /// The name of a font to use for code (code blocks and inline code) in the
157    /// markdown preview. Falls back to the buffer font if unset.
158    pub markdown_preview_code_font_family: Option<FontFamilyName>,
159    /// The font size to use for rendering in the markdown preview.
160    /// Falls back to the UI font size if unset.
161    pub markdown_preview_font_size: Option<FontSize>,
162    /// The theme to use for the markdown preview.
163    /// Falls back to the main editor theme if unset.
164    pub markdown_preview_theme: Option<ThemeSelection>,
165    /// The name of the Omega theme to use.
166    pub theme: Option<ThemeSelection>,
167    /// The name of the icon theme to use.
168    pub icon_theme: Option<IconThemeSelection>,
169
170    /// UNSTABLE: Expect many elements to be broken.
171    ///
172    // Controls the density of the UI.
173    #[serde(rename = "unstable.ui_density")]
174    pub ui_density: Option<UiDensity>,
175
176    /// How much to fade out unused code.
177    #[schemars(range(min = 0.0, max = 0.9))]
178    pub unnecessary_code_fade: Option<CodeFade>,
179
180    /// EXPERIMENTAL: Overrides for the current theme.
181    ///
182    /// These values will override the ones on the current theme specified in `theme`.
183    #[serde(rename = "experimental.theme_overrides")]
184    pub experimental_theme_overrides: Option<ThemeStyleContent>,
185
186    /// Overrides per theme
187    ///
188    /// These values will override the ones on the specified theme
189    #[serde(default)]
190    pub theme_overrides: HashMap<String, ThemeStyleContent>,
191}
192
193/// A font size value in pixels, wrapping around `f32` for custom settings UI rendering.
194#[derive(
195    Clone,
196    Copy,
197    Debug,
198    Serialize,
199    Deserialize,
200    JsonSchema,
201    MergeFrom,
202    PartialEq,
203    PartialOrd,
204    derive_more::FromStr,
205)]
206#[serde(transparent)]
207pub struct FontSize(#[serde(serialize_with = "serialize_f32_with_two_decimal_places")] pub f32);
208
209impl Display for FontSize {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        write!(f, "{:.2}", self.0)
212    }
213}
214
215impl From<f32> for FontSize {
216    fn from(value: f32) -> Self {
217        Self(value)
218    }
219}
220
221#[derive(
222    Clone,
223    Copy,
224    Debug,
225    Serialize,
226    Deserialize,
227    JsonSchema,
228    MergeFrom,
229    PartialEq,
230    PartialOrd,
231    derive_more::FromStr,
232)]
233#[serde(transparent)]
234pub struct CodeFade(#[serde(serialize_with = "serialize_f32_with_two_decimal_places")] pub f32);
235
236impl Display for CodeFade {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        write!(f, "{:.2}", self.0)
239    }
240}
241
242impl From<f32> for CodeFade {
243    fn from(x: f32) -> Self {
244        Self(x)
245    }
246}
247
248fn default_font_features() -> Option<FontFeaturesContent> {
249    Some(FontFeaturesContent::default())
250}
251
252fn default_font_fallbacks() -> Option<Vec<FontFamilyName>> {
253    Some(Vec::new())
254}
255
256fn default_buffer_font_weight() -> Option<FontWeightContent> {
257    Some(FontWeightContent::NORMAL)
258}
259
260/// Represents the selection of a theme, which can be either static or dynamic.
261#[derive(
262    Clone,
263    Debug,
264    Serialize,
265    Deserialize,
266    JsonSchema,
267    MergeFrom,
268    PartialEq,
269    Eq,
270    strum::EnumDiscriminants,
271)]
272#[strum_discriminants(derive(strum::VariantArray, strum::VariantNames, strum::FromRepr))]
273#[serde(untagged)]
274pub enum ThemeSelection {
275    /// A static theme selection, represented by a single theme name.
276    Static(ThemeName),
277    /// A dynamic theme selection, which can change based the [ThemeMode].
278    Dynamic {
279        /// The mode used to determine which theme to use.
280        #[serde(default)]
281        mode: ThemeAppearanceMode,
282        /// The theme to use for light mode.
283        light: ThemeName,
284        /// The theme to use for dark mode.
285        dark: ThemeName,
286    },
287}
288
289// Aiur is dark-only (omega#70), so the light default comes from Ayu.
290pub const DEFAULT_LIGHT_THEME: &'static str = "Ayu Light";
291pub const DEFAULT_DARK_THEME: &'static str = "Aiur";
292
293impl Default for ThemeSelection {
294    fn default() -> Self {
295        Self::Dynamic {
296            mode: ThemeAppearanceMode::default(),
297            light: ThemeName(DEFAULT_LIGHT_THEME.into()),
298            dark: ThemeName(DEFAULT_DARK_THEME.into()),
299        }
300    }
301}
302
303/// Represents the selection of an icon theme, which can be either static or dynamic.
304#[derive(
305    Clone,
306    Debug,
307    Serialize,
308    Deserialize,
309    JsonSchema,
310    MergeFrom,
311    PartialEq,
312    Eq,
313    strum::EnumDiscriminants,
314)]
315#[strum_discriminants(derive(strum::VariantArray, strum::VariantNames, strum::FromRepr))]
316#[serde(untagged)]
317pub enum IconThemeSelection {
318    /// A static icon theme selection, represented by a single icon theme name.
319    Static(IconThemeName),
320    /// A dynamic icon theme selection, which can change based on the [`ThemeMode`].
321    Dynamic {
322        /// The mode used to determine which theme to use.
323        #[serde(default)]
324        mode: ThemeAppearanceMode,
325        /// The icon theme to use for light mode.
326        light: IconThemeName,
327        /// The icon theme to use for dark mode.
328        dark: IconThemeName,
329    },
330}
331
332/// The mode use to select a theme.
333///
334/// `Light` and `Dark` will select their respective themes.
335///
336/// `System` will select the theme based on the system's appearance.
337#[derive(
338    Debug,
339    PartialEq,
340    Eq,
341    Clone,
342    Copy,
343    Default,
344    Serialize,
345    Deserialize,
346    JsonSchema,
347    MergeFrom,
348    strum::VariantArray,
349    strum::VariantNames,
350)]
351#[serde(rename_all = "snake_case")]
352pub enum ThemeAppearanceMode {
353    /// Use the specified `light` theme.
354    Light,
355
356    /// Use the specified `dark` theme.
357    Dark,
358
359    /// Use the theme based on the system's appearance.
360    #[default]
361    System,
362}
363
364/// Specifies the density of the UI.
365/// Note: This setting is still experimental. See [this tracking issue](https://github.com/zed-industries/zed/issues/18078)
366#[derive(
367    Debug,
368    Default,
369    PartialEq,
370    Eq,
371    PartialOrd,
372    Ord,
373    Hash,
374    Clone,
375    Copy,
376    Serialize,
377    Deserialize,
378    JsonSchema,
379    MergeFrom,
380)]
381#[serde(rename_all = "snake_case")]
382pub enum UiDensity {
383    /// A denser UI with tighter spacing and smaller elements.
384    #[serde(alias = "compact")]
385    Compact,
386    #[default]
387    #[serde(alias = "default")]
388    /// The default UI density.
389    Default,
390    #[serde(alias = "comfortable")]
391    /// A looser UI with more spacing and larger elements.
392    Comfortable,
393}
394
395impl UiDensity {
396    /// The spacing ratio of a given density.
397    /// TODO: Standardize usage throughout the app or remove
398    pub fn spacing_ratio(self) -> f32 {
399        match self {
400            UiDensity::Compact => 0.75,
401            UiDensity::Default => 1.0,
402            UiDensity::Comfortable => 1.25,
403        }
404    }
405}
406
407/// Font family name.
408#[with_fallible_options]
409#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
410#[serde(transparent)]
411pub struct FontFamilyName(pub Arc<str>);
412
413impl AsRef<str> for FontFamilyName {
414    fn as_ref(&self) -> &str {
415        &self.0
416    }
417}
418
419impl From<String> for FontFamilyName {
420    fn from(value: String) -> Self {
421        Self(Arc::from(value))
422    }
423}
424
425impl From<FontFamilyName> for String {
426    fn from(value: FontFamilyName) -> Self {
427        value.0.to_string()
428    }
429}
430
431/// The buffer's line height.
432#[derive(
433    Clone,
434    Copy,
435    Debug,
436    Serialize,
437    Deserialize,
438    PartialEq,
439    JsonSchema,
440    MergeFrom,
441    Default,
442    strum::EnumDiscriminants,
443)]
444#[strum_discriminants(derive(strum::VariantArray, strum::VariantNames, strum::FromRepr))]
445#[serde(rename_all = "snake_case")]
446pub enum BufferLineHeight {
447    /// A less dense line height.
448    #[default]
449    Comfortable,
450    /// The default line height.
451    Standard,
452    /// A custom line height, where 1.0 is the font's height. Must be at least 1.0.
453    Custom(#[serde(deserialize_with = "deserialize_line_height")] f32),
454}
455
456fn deserialize_line_height<'de, D>(deserializer: D) -> Result<f32, D::Error>
457where
458    D: serde::Deserializer<'de>,
459{
460    let value = f32::deserialize(deserializer)?;
461    if value < 1.0 {
462        return Err(serde::de::Error::custom(
463            "buffer_line_height.custom must be at least 1.0",
464        ));
465    }
466
467    Ok(value)
468}
469
470/// The content of a serialized theme.
471#[with_fallible_options]
472#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
473#[serde(default)]
474pub struct ThemeStyleContent {
475    #[serde(rename = "background.appearance")]
476    pub window_background_appearance: Option<WindowBackgroundContent>,
477
478    #[serde(default)]
479    pub accents: Vec<AccentContent>,
480
481    #[serde(flatten, default)]
482    pub colors: ThemeColorsContent,
483
484    #[serde(flatten, default)]
485    pub status: StatusColorsContent,
486
487    #[serde(default)]
488    pub players: Vec<PlayerColorContent>,
489
490    /// The styles for syntax nodes.
491    #[serde(default)]
492    pub syntax: IndexMap<String, HighlightStyleContent>,
493}
494
495#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
496pub struct AccentContent(pub Option<String>);
497
498#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
499pub struct PlayerColorContent {
500    pub cursor: Option<String>,
501    pub background: Option<String>,
502    pub selection: Option<String>,
503}
504
505/// Theme name.
506#[with_fallible_options]
507#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
508#[serde(transparent)]
509pub struct ThemeName(pub Arc<str>);
510
511/// Icon Theme Name
512#[with_fallible_options]
513#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
514#[serde(transparent)]
515pub struct IconThemeName(pub Arc<str>);
516
517#[with_fallible_options]
518#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
519#[serde(default)]
520pub struct ThemeColorsContent {
521    /// Border color. Used for most borders, is usually a high contrast color.
522    #[serde(rename = "border")]
523    pub border: Option<String>,
524
525    /// Border color. Used for deemphasized borders, like a visual divider between two sections
526    #[serde(rename = "border.variant")]
527    pub border_variant: Option<String>,
528
529    /// Border color. Used for focused elements, like keyboard focused list item.
530    #[serde(rename = "border.focused")]
531    pub border_focused: Option<String>,
532
533    /// Border color. Used for selected elements, like an active search filter or selected checkbox.
534    #[serde(rename = "border.selected")]
535    pub border_selected: Option<String>,
536
537    /// Border color. Used for transparent borders. Used for placeholder borders when an element gains a border on state change.
538    #[serde(rename = "border.transparent")]
539    pub border_transparent: Option<String>,
540
541    /// Border color. Used for disabled elements, like a disabled input or button.
542    #[serde(rename = "border.disabled")]
543    pub border_disabled: Option<String>,
544
545    /// Background color. Used for elevated surfaces, like a context menu, popup, or dialog.
546    #[serde(rename = "elevated_surface.background")]
547    pub elevated_surface_background: Option<String>,
548
549    /// Background Color. Used for grounded surfaces like a panel or tab.
550    #[serde(rename = "surface.background")]
551    pub surface_background: Option<String>,
552
553    /// Background Color. Used for the app background and blank panels or windows.
554    #[serde(rename = "background")]
555    pub background: Option<String>,
556
557    /// Background Color. Used for the background of an element that should have a different background than the surface it's on.
558    ///
559    /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
560    ///
561    /// For an element that should have the same background as the surface it's on, use `ghost_element_background`.
562    #[serde(rename = "element.background")]
563    pub element_background: Option<String>,
564
565    /// Background Color. Used for the hover state of an element that should have a different background than the surface it's on.
566    ///
567    /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
568    #[serde(rename = "element.hover")]
569    pub element_hover: Option<String>,
570
571    /// Background Color. Used for the active state of an element that should have a different background than the surface it's on.
572    ///
573    /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressed.
574    #[serde(rename = "element.active")]
575    pub element_active: Option<String>,
576
577    /// Background Color. Used for the selected state of an element that should have a different background than the surface it's on.
578    ///
579    /// Selected states are triggered by the element being selected (or "activated") by the user.
580    ///
581    /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
582    #[serde(rename = "element.selected")]
583    pub element_selected: Option<String>,
584
585    /// Background Color. Used for the disabled state of an element that should have a different background than the surface it's on.
586    ///
587    /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
588    #[serde(rename = "element.disabled")]
589    pub element_disabled: Option<String>,
590
591    /// Background Color. Used for the background of selections in a UI element.
592    #[serde(rename = "element.selection_background")]
593    pub element_selection_background: Option<String>,
594
595    /// Background Color. Used for the area that shows where a dragged element will be dropped.
596    #[serde(rename = "drop_target.background")]
597    pub drop_target_background: Option<String>,
598
599    /// Border Color. Used for the border that shows where a dragged element will be dropped.
600    #[serde(rename = "drop_target.border")]
601    pub drop_target_border: Option<String>,
602
603    /// Used for the background of a ghost element that should have the same background as the surface it's on.
604    ///
605    /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
606    ///
607    /// For an element that should have a different background than the surface it's on, use `element_background`.
608    #[serde(rename = "ghost_element.background")]
609    pub ghost_element_background: Option<String>,
610
611    /// Background Color. Used for the hover state of a ghost element that should have the same background as the surface it's on.
612    ///
613    /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
614    #[serde(rename = "ghost_element.hover")]
615    pub ghost_element_hover: Option<String>,
616
617    /// Background Color. Used for the active state of a ghost element that should have the same background as the surface it's on.
618    ///
619    /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressed.
620    #[serde(rename = "ghost_element.active")]
621    pub ghost_element_active: Option<String>,
622
623    /// Background Color. Used for the selected state of a ghost element that should have the same background as the surface it's on.
624    ///
625    /// Selected states are triggered by the element being selected (or "activated") by the user.
626    ///
627    /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
628    #[serde(rename = "ghost_element.selected")]
629    pub ghost_element_selected: Option<String>,
630
631    /// Background Color. Used for the disabled state of a ghost element that should have the same background as the surface it's on.
632    ///
633    /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
634    #[serde(rename = "ghost_element.disabled")]
635    pub ghost_element_disabled: Option<String>,
636
637    /// Text Color. Default text color used for most text.
638    #[serde(rename = "text")]
639    pub text: Option<String>,
640
641    /// Text Color. Color of muted or deemphasized text. It is a subdued version of the standard text color.
642    #[serde(rename = "text.muted")]
643    pub text_muted: Option<String>,
644
645    /// Text Color. Color of the placeholder text typically shown in input fields to guide the user to enter valid data.
646    #[serde(rename = "text.placeholder")]
647    pub text_placeholder: Option<String>,
648
649    /// Text Color. Color used for text denoting disabled elements. Typically, the color is faded or grayed out to emphasize the disabled state.
650    #[serde(rename = "text.disabled")]
651    pub text_disabled: Option<String>,
652
653    /// Text Color. Color used for emphasis or highlighting certain text, like an active filter or a matched character in a search.
654    #[serde(rename = "text.accent")]
655    pub text_accent: Option<String>,
656
657    /// Fill Color. Used for the default fill color of an icon.
658    #[serde(rename = "icon")]
659    pub icon: Option<String>,
660
661    /// Fill Color. Used for the muted or deemphasized fill color of an icon.
662    ///
663    /// 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.
664    #[serde(rename = "icon.muted")]
665    pub icon_muted: Option<String>,
666
667    /// Fill Color. Used for the disabled fill color of an icon.
668    ///
669    /// Disabled states are shown when a user cannot interact with an element, like a icon button.
670    #[serde(rename = "icon.disabled")]
671    pub icon_disabled: Option<String>,
672
673    /// Fill Color. Used for the placeholder fill color of an icon.
674    ///
675    /// This might be used to show an icon in an input that disappears when the user enters text.
676    #[serde(rename = "icon.placeholder")]
677    pub icon_placeholder: Option<String>,
678
679    /// Fill Color. Used for the accent fill color of an icon.
680    ///
681    /// This might be used to show when a toggleable icon button is selected.
682    #[serde(rename = "icon.accent")]
683    pub icon_accent: Option<String>,
684
685    /// Color used to accent some of the debuggers elements
686    /// Only accent breakpoint & breakpoint related symbols right now
687    #[serde(rename = "debugger.accent")]
688    pub debugger_accent: Option<String>,
689
690    #[serde(rename = "status_bar.background")]
691    pub status_bar_background: Option<String>,
692
693    #[serde(rename = "title_bar.background")]
694    pub title_bar_background: Option<String>,
695
696    #[serde(rename = "title_bar.inactive_background")]
697    pub title_bar_inactive_background: Option<String>,
698
699    #[serde(rename = "toolbar.background")]
700    pub toolbar_background: Option<String>,
701
702    #[serde(rename = "tab_bar.background")]
703    pub tab_bar_background: Option<String>,
704
705    #[serde(rename = "tab.inactive_background")]
706    pub tab_inactive_background: Option<String>,
707
708    #[serde(rename = "tab.active_background")]
709    pub tab_active_background: Option<String>,
710
711    #[serde(rename = "search.match_background")]
712    pub search_match_background: Option<String>,
713
714    #[serde(rename = "search.active_match_background")]
715    pub search_active_match_background: Option<String>,
716
717    #[serde(rename = "panel.background")]
718    pub panel_background: Option<String>,
719
720    #[serde(rename = "panel.focused_border")]
721    pub panel_focused_border: Option<String>,
722
723    #[serde(rename = "panel.indent_guide")]
724    pub panel_indent_guide: Option<String>,
725
726    #[serde(rename = "panel.indent_guide_hover")]
727    pub panel_indent_guide_hover: Option<String>,
728
729    #[serde(rename = "panel.indent_guide_active")]
730    pub panel_indent_guide_active: Option<String>,
731
732    #[serde(rename = "panel.overlay_background")]
733    pub panel_overlay_background: Option<String>,
734
735    #[serde(rename = "panel.overlay_hover")]
736    pub panel_overlay_hover: Option<String>,
737
738    #[serde(rename = "pane.focused_border")]
739    pub pane_focused_border: Option<String>,
740
741    #[serde(rename = "pane_group.border")]
742    pub pane_group_border: Option<String>,
743
744    /// The deprecated version of `scrollbar.thumb.background`.
745    ///
746    /// Don't use this field.
747    #[serde(rename = "scrollbar_thumb.background", skip_serializing)]
748    #[schemars(skip)]
749    pub deprecated_scrollbar_thumb_background: Option<String>,
750
751    /// The color of the scrollbar thumb.
752    #[serde(rename = "scrollbar.thumb.background")]
753    pub scrollbar_thumb_background: Option<String>,
754
755    /// The color of the scrollbar thumb when hovered over.
756    #[serde(rename = "scrollbar.thumb.hover_background")]
757    pub scrollbar_thumb_hover_background: Option<String>,
758
759    /// The color of the scrollbar thumb whilst being actively dragged.
760    #[serde(rename = "scrollbar.thumb.active_background")]
761    pub scrollbar_thumb_active_background: Option<String>,
762
763    /// The border color of the scrollbar thumb.
764    #[serde(rename = "scrollbar.thumb.border")]
765    pub scrollbar_thumb_border: Option<String>,
766
767    /// The background color of the scrollbar track.
768    #[serde(rename = "scrollbar.track.background")]
769    pub scrollbar_track_background: Option<String>,
770
771    /// The border color of the scrollbar track.
772    #[serde(rename = "scrollbar.track.border")]
773    pub scrollbar_track_border: Option<String>,
774
775    /// The color of the minimap thumb.
776    #[serde(rename = "minimap.thumb.background")]
777    pub minimap_thumb_background: Option<String>,
778
779    /// The color of the minimap thumb when hovered over.
780    #[serde(rename = "minimap.thumb.hover_background")]
781    pub minimap_thumb_hover_background: Option<String>,
782
783    /// The color of the minimap thumb whilst being actively dragged.
784    #[serde(rename = "minimap.thumb.active_background")]
785    pub minimap_thumb_active_background: Option<String>,
786
787    /// The border color of the minimap thumb.
788    #[serde(rename = "minimap.thumb.border")]
789    pub minimap_thumb_border: Option<String>,
790
791    #[serde(rename = "editor.foreground")]
792    pub editor_foreground: Option<String>,
793
794    #[serde(rename = "editor.background")]
795    pub editor_background: Option<String>,
796
797    #[serde(rename = "editor.gutter.background")]
798    pub editor_gutter_background: Option<String>,
799
800    #[serde(rename = "editor.subheader.background")]
801    pub editor_subheader_background: Option<String>,
802
803    #[serde(rename = "editor.active_line.background")]
804    pub editor_active_line_background: Option<String>,
805
806    #[serde(rename = "editor.highlighted_line.background")]
807    pub editor_highlighted_line_background: Option<String>,
808
809    /// Background of active line of debugger
810    #[serde(rename = "editor.debugger_active_line.background")]
811    pub editor_debugger_active_line_background: Option<String>,
812
813    /// Text Color. Used for the text of the line number in the editor gutter.
814    #[serde(rename = "editor.line_number")]
815    pub editor_line_number: Option<String>,
816
817    /// Text Color. Used for the text of the line number in the editor gutter when the line is highlighted.
818    #[serde(rename = "editor.active_line_number")]
819    pub editor_active_line_number: Option<String>,
820
821    /// Text Color. Used for the text of the line number in the editor gutter when the line is hovered over.
822    #[serde(rename = "editor.hover_line_number")]
823    pub editor_hover_line_number: Option<String>,
824
825    /// Text Color. Used to mark invisible characters in the editor.
826    ///
827    /// Example: spaces, tabs, carriage returns, etc.
828    #[serde(rename = "editor.invisible")]
829    pub editor_invisible: Option<String>,
830
831    #[serde(rename = "editor.wrap_guide")]
832    pub editor_wrap_guide: Option<String>,
833
834    #[serde(rename = "editor.active_wrap_guide")]
835    pub editor_active_wrap_guide: Option<String>,
836
837    #[serde(rename = "editor.indent_guide")]
838    pub editor_indent_guide: Option<String>,
839
840    #[serde(rename = "editor.indent_guide_active")]
841    pub editor_indent_guide_active: Option<String>,
842
843    /// Read-access of a symbol, like reading a variable.
844    ///
845    /// A document highlight is a range inside a text document which deserves
846    /// special attention. Usually a document highlight is visualized by changing
847    /// the background color of its range.
848    #[serde(rename = "editor.document_highlight.read_background")]
849    pub editor_document_highlight_read_background: Option<String>,
850
851    /// Read-access of a symbol, like reading a variable.
852    ///
853    /// A document highlight is a range inside a text document which deserves
854    /// special attention. Usually a document highlight is visualized by changing
855    /// the background color of its range.
856    #[serde(rename = "editor.document_highlight.write_background")]
857    pub editor_document_highlight_write_background: Option<String>,
858
859    /// Highlighted brackets background color.
860    ///
861    /// Matching brackets in the cursor scope are highlighted with this background color.
862    #[serde(rename = "editor.document_highlight.bracket_background")]
863    pub editor_document_highlight_bracket_background: Option<String>,
864
865    /// Filled background color for added diff hunk row highlights in the editor.
866    #[serde(rename = "editor.diff_hunk.added.background")]
867    pub editor_diff_hunk_added_background: Option<String>,
868
869    /// Hollow background color for added diff hunk row highlights in the editor.
870    #[serde(rename = "editor.diff_hunk.added.hollow_background")]
871    pub editor_diff_hunk_added_hollow_background: Option<String>,
872
873    /// Hollow border color for added diff hunk row highlights in the editor.
874    #[serde(rename = "editor.diff_hunk.added.hollow_border")]
875    pub editor_diff_hunk_added_hollow_border: Option<String>,
876
877    /// Filled background color for deleted diff hunk row highlights in the editor.
878    #[serde(rename = "editor.diff_hunk.deleted.background")]
879    pub editor_diff_hunk_deleted_background: Option<String>,
880
881    /// Hollow background color for deleted diff hunk row highlights in the editor.
882    #[serde(rename = "editor.diff_hunk.deleted.hollow_background")]
883    pub editor_diff_hunk_deleted_hollow_background: Option<String>,
884
885    /// Hollow border color for deleted diff hunk row highlights in the editor.
886    #[serde(rename = "editor.diff_hunk.deleted.hollow_border")]
887    pub editor_diff_hunk_deleted_hollow_border: Option<String>,
888
889    /// Terminal background color.
890    #[serde(rename = "terminal.background")]
891    pub terminal_background: Option<String>,
892
893    /// Terminal foreground color.
894    #[serde(rename = "terminal.foreground")]
895    pub terminal_foreground: Option<String>,
896
897    /// Terminal ANSI background color.
898    #[serde(rename = "terminal.ansi.background")]
899    pub terminal_ansi_background: Option<String>,
900
901    /// Bright terminal foreground color.
902    #[serde(rename = "terminal.bright_foreground")]
903    pub terminal_bright_foreground: Option<String>,
904
905    /// Dim terminal foreground color.
906    #[serde(rename = "terminal.dim_foreground")]
907    pub terminal_dim_foreground: Option<String>,
908
909    /// Black ANSI terminal color.
910    #[serde(rename = "terminal.ansi.black")]
911    pub terminal_ansi_black: Option<String>,
912
913    /// Bright black ANSI terminal color.
914    #[serde(rename = "terminal.ansi.bright_black")]
915    pub terminal_ansi_bright_black: Option<String>,
916
917    /// Dim black ANSI terminal color.
918    #[serde(rename = "terminal.ansi.dim_black")]
919    pub terminal_ansi_dim_black: Option<String>,
920
921    /// Red ANSI terminal color.
922    #[serde(rename = "terminal.ansi.red")]
923    pub terminal_ansi_red: Option<String>,
924
925    /// Bright red ANSI terminal color.
926    #[serde(rename = "terminal.ansi.bright_red")]
927    pub terminal_ansi_bright_red: Option<String>,
928
929    /// Dim red ANSI terminal color.
930    #[serde(rename = "terminal.ansi.dim_red")]
931    pub terminal_ansi_dim_red: Option<String>,
932
933    /// Green ANSI terminal color.
934    #[serde(rename = "terminal.ansi.green")]
935    pub terminal_ansi_green: Option<String>,
936
937    /// Bright green ANSI terminal color.
938    #[serde(rename = "terminal.ansi.bright_green")]
939    pub terminal_ansi_bright_green: Option<String>,
940
941    /// Dim green ANSI terminal color.
942    #[serde(rename = "terminal.ansi.dim_green")]
943    pub terminal_ansi_dim_green: Option<String>,
944
945    /// Yellow ANSI terminal color.
946    #[serde(rename = "terminal.ansi.yellow")]
947    pub terminal_ansi_yellow: Option<String>,
948
949    /// Bright yellow ANSI terminal color.
950    #[serde(rename = "terminal.ansi.bright_yellow")]
951    pub terminal_ansi_bright_yellow: Option<String>,
952
953    /// Dim yellow ANSI terminal color.
954    #[serde(rename = "terminal.ansi.dim_yellow")]
955    pub terminal_ansi_dim_yellow: Option<String>,
956
957    /// Blue ANSI terminal color.
958    #[serde(rename = "terminal.ansi.blue")]
959    pub terminal_ansi_blue: Option<String>,
960
961    /// Bright blue ANSI terminal color.
962    #[serde(rename = "terminal.ansi.bright_blue")]
963    pub terminal_ansi_bright_blue: Option<String>,
964
965    /// Dim blue ANSI terminal color.
966    #[serde(rename = "terminal.ansi.dim_blue")]
967    pub terminal_ansi_dim_blue: Option<String>,
968
969    /// Magenta ANSI terminal color.
970    #[serde(rename = "terminal.ansi.magenta")]
971    pub terminal_ansi_magenta: Option<String>,
972
973    /// Bright magenta ANSI terminal color.
974    #[serde(rename = "terminal.ansi.bright_magenta")]
975    pub terminal_ansi_bright_magenta: Option<String>,
976
977    /// Dim magenta ANSI terminal color.
978    #[serde(rename = "terminal.ansi.dim_magenta")]
979    pub terminal_ansi_dim_magenta: Option<String>,
980
981    /// Cyan ANSI terminal color.
982    #[serde(rename = "terminal.ansi.cyan")]
983    pub terminal_ansi_cyan: Option<String>,
984
985    /// Bright cyan ANSI terminal color.
986    #[serde(rename = "terminal.ansi.bright_cyan")]
987    pub terminal_ansi_bright_cyan: Option<String>,
988
989    /// Dim cyan ANSI terminal color.
990    #[serde(rename = "terminal.ansi.dim_cyan")]
991    pub terminal_ansi_dim_cyan: Option<String>,
992
993    /// White ANSI terminal color.
994    #[serde(rename = "terminal.ansi.white")]
995    pub terminal_ansi_white: Option<String>,
996
997    /// Bright white ANSI terminal color.
998    #[serde(rename = "terminal.ansi.bright_white")]
999    pub terminal_ansi_bright_white: Option<String>,
1000
1001    /// Dim white ANSI terminal color.
1002    #[serde(rename = "terminal.ansi.dim_white")]
1003    pub terminal_ansi_dim_white: Option<String>,
1004
1005    #[serde(rename = "link_text.hover")]
1006    pub link_text_hover: Option<String>,
1007
1008    /// Added version control color.
1009    #[serde(rename = "version_control.added")]
1010    pub version_control_added: Option<String>,
1011
1012    /// Deleted version control color.
1013    #[serde(rename = "version_control.deleted")]
1014    pub version_control_deleted: Option<String>,
1015
1016    /// Modified version control color.
1017    #[serde(rename = "version_control.modified")]
1018    pub version_control_modified: Option<String>,
1019
1020    /// Renamed version control color.
1021    #[serde(rename = "version_control.renamed")]
1022    pub version_control_renamed: Option<String>,
1023
1024    /// Conflict version control color.
1025    #[serde(rename = "version_control.conflict")]
1026    pub version_control_conflict: Option<String>,
1027
1028    /// Ignored version control color.
1029    #[serde(rename = "version_control.ignored")]
1030    pub version_control_ignored: Option<String>,
1031
1032    /// Color for added words in word diffs.
1033    #[serde(rename = "version_control.word_added")]
1034    pub version_control_word_added: Option<String>,
1035
1036    /// Color for deleted words in word diffs.
1037    #[serde(rename = "version_control.word_deleted")]
1038    pub version_control_word_deleted: Option<String>,
1039
1040    /// Background color for row highlights of "ours" regions in merge conflicts.
1041    #[serde(rename = "version_control.conflict_marker.ours")]
1042    pub version_control_conflict_marker_ours: Option<String>,
1043
1044    /// Background color for row highlights of "theirs" regions in merge conflicts.
1045    #[serde(rename = "version_control.conflict_marker.theirs")]
1046    pub version_control_conflict_marker_theirs: Option<String>,
1047
1048    /// Deprecated in favor of `version_control_conflict_marker_ours`.
1049    #[deprecated]
1050    pub version_control_conflict_ours_background: Option<String>,
1051
1052    /// Deprecated in favor of `version_control_conflict_marker_theirs`.
1053    #[deprecated]
1054    pub version_control_conflict_theirs_background: Option<String>,
1055
1056    /// Background color for Vim Normal mode indicator.
1057    #[serde(rename = "vim.normal.background")]
1058    pub vim_normal_background: Option<String>,
1059    /// Background color for Vim Insert mode indicator.
1060    #[serde(rename = "vim.insert.background")]
1061    pub vim_insert_background: Option<String>,
1062    /// Background color for Vim Replace mode indicator.
1063    #[serde(rename = "vim.replace.background")]
1064    pub vim_replace_background: Option<String>,
1065    /// Background color for Vim Visual mode indicator.
1066    #[serde(rename = "vim.visual.background")]
1067    pub vim_visual_background: Option<String>,
1068    /// Background color for Vim Visual Line mode indicator.
1069    #[serde(rename = "vim.visual_line.background")]
1070    pub vim_visual_line_background: Option<String>,
1071    /// Background color for Vim Visual Block mode indicator.
1072    #[serde(rename = "vim.visual_block.background")]
1073    pub vim_visual_block_background: Option<String>,
1074    /// Background color for Vim yank highlight.
1075    #[serde(rename = "vim.yank.background")]
1076    pub vim_yank_background: Option<String>,
1077    /// Foreground color for Helix jump labels.
1078    #[serde(rename = "vim.helix_jump_label.foreground")]
1079    pub vim_helix_jump_label_foreground: Option<String>,
1080    /// Background color for Vim Helix Normal mode indicator.
1081    #[serde(rename = "vim.helix_normal.background")]
1082    pub vim_helix_normal_background: Option<String>,
1083    /// Background color for Vim Helix Select mode indicator.
1084    #[serde(rename = "vim.helix_select.background")]
1085    pub vim_helix_select_background: Option<String>,
1086    /// Background color for Vim Normal mode indicator.
1087    #[serde(rename = "vim.normal.foreground")]
1088    pub vim_normal_foreground: Option<String>,
1089    /// Foreground color for Vim Insert mode indicator.
1090    #[serde(rename = "vim.insert.foreground")]
1091    pub vim_insert_foreground: Option<String>,
1092    /// Foreground color for Vim Replace mode indicator.
1093    #[serde(rename = "vim.replace.foreground")]
1094    pub vim_replace_foreground: Option<String>,
1095    /// Foreground color for Vim Visual mode indicator.
1096    #[serde(rename = "vim.visual.foreground")]
1097    pub vim_visual_foreground: Option<String>,
1098    /// Foreground color for Vim Visual Line mode indicator.
1099    #[serde(rename = "vim.visual_line.foreground")]
1100    pub vim_visual_line_foreground: Option<String>,
1101    /// Foreground color for Vim Visual Block mode indicator.
1102    #[serde(rename = "vim.visual_block.foreground")]
1103    pub vim_visual_block_foreground: Option<String>,
1104    /// Foreground color for Vim Helix Normal mode indicator.
1105    #[serde(rename = "vim.helix_normal.foreground")]
1106    pub vim_helix_normal_foreground: Option<String>,
1107    /// Foreground color for Vim Helix Select mode indicator.
1108    #[serde(rename = "vim.helix_select.foreground")]
1109    pub vim_helix_select_foreground: Option<String>,
1110}
1111
1112#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
1113#[serde(default)]
1114pub struct HighlightStyleContent {
1115    pub color: Option<String>,
1116
1117    #[serde(
1118        skip_serializing_if = "Option::is_none",
1119        deserialize_with = "treat_error_as_none"
1120    )]
1121    pub background_color: Option<String>,
1122
1123    #[serde(
1124        skip_serializing_if = "Option::is_none",
1125        deserialize_with = "treat_error_as_none"
1126    )]
1127    pub font_style: Option<FontStyleContent>,
1128
1129    #[serde(
1130        skip_serializing_if = "Option::is_none",
1131        deserialize_with = "treat_error_as_none"
1132    )]
1133    pub font_weight: Option<FontWeightContent>,
1134}
1135
1136impl HighlightStyleContent {
1137    pub fn is_empty(&self) -> bool {
1138        self.color.is_none()
1139            && self.background_color.is_none()
1140            && self.font_style.is_none()
1141            && self.font_weight.is_none()
1142    }
1143}
1144
1145fn treat_error_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
1146where
1147    T: Deserialize<'de>,
1148    D: Deserializer<'de>,
1149{
1150    let value: Value = Deserialize::deserialize(deserializer)?;
1151    Ok(T::deserialize(value).ok())
1152}
1153
1154#[with_fallible_options]
1155#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
1156#[serde(default)]
1157pub struct StatusColorsContent {
1158    /// Indicates some kind of conflict, like a file changed on disk while it was open, or
1159    /// merge conflicts in a Git repository.
1160    #[serde(rename = "conflict")]
1161    pub conflict: Option<String>,
1162
1163    #[serde(rename = "conflict.background")]
1164    pub conflict_background: Option<String>,
1165
1166    #[serde(rename = "conflict.border")]
1167    pub conflict_border: Option<String>,
1168
1169    /// Indicates something new, like a new file added to a Git repository.
1170    #[serde(rename = "created")]
1171    pub created: Option<String>,
1172
1173    #[serde(rename = "created.background")]
1174    pub created_background: Option<String>,
1175
1176    #[serde(rename = "created.border")]
1177    pub created_border: Option<String>,
1178
1179    /// Indicates that something no longer exists, like a deleted file.
1180    #[serde(rename = "deleted")]
1181    pub deleted: Option<String>,
1182
1183    #[serde(rename = "deleted.background")]
1184    pub deleted_background: Option<String>,
1185
1186    #[serde(rename = "deleted.border")]
1187    pub deleted_border: Option<String>,
1188
1189    /// Indicates a system error, a failed operation or a diagnostic error.
1190    #[serde(rename = "error")]
1191    pub error: Option<String>,
1192
1193    #[serde(rename = "error.background")]
1194    pub error_background: Option<String>,
1195
1196    #[serde(rename = "error.border")]
1197    pub error_border: Option<String>,
1198
1199    /// Represents a hidden status, such as a file being hidden in a file tree.
1200    #[serde(rename = "hidden")]
1201    pub hidden: Option<String>,
1202
1203    #[serde(rename = "hidden.background")]
1204    pub hidden_background: Option<String>,
1205
1206    #[serde(rename = "hidden.border")]
1207    pub hidden_border: Option<String>,
1208
1209    /// Indicates a hint or some kind of additional information.
1210    #[serde(rename = "hint")]
1211    pub hint: Option<String>,
1212
1213    #[serde(rename = "hint.background")]
1214    pub hint_background: Option<String>,
1215
1216    #[serde(rename = "hint.border")]
1217    pub hint_border: Option<String>,
1218
1219    /// Indicates that something is deliberately ignored, such as a file or operation ignored by Git.
1220    #[serde(rename = "ignored")]
1221    pub ignored: Option<String>,
1222
1223    #[serde(rename = "ignored.background")]
1224    pub ignored_background: Option<String>,
1225
1226    #[serde(rename = "ignored.border")]
1227    pub ignored_border: Option<String>,
1228
1229    /// Represents informational status updates or messages.
1230    #[serde(rename = "info")]
1231    pub info: Option<String>,
1232
1233    #[serde(rename = "info.background")]
1234    pub info_background: Option<String>,
1235
1236    #[serde(rename = "info.border")]
1237    pub info_border: Option<String>,
1238
1239    /// Indicates a changed or altered status, like a file that has been edited.
1240    #[serde(rename = "modified")]
1241    pub modified: Option<String>,
1242
1243    #[serde(rename = "modified.background")]
1244    pub modified_background: Option<String>,
1245
1246    #[serde(rename = "modified.border")]
1247    pub modified_border: Option<String>,
1248
1249    /// Indicates something that is predicted, like automatic code completion, or generated code.
1250    #[serde(rename = "predictive")]
1251    pub predictive: Option<String>,
1252
1253    #[serde(rename = "predictive.background")]
1254    pub predictive_background: Option<String>,
1255
1256    #[serde(rename = "predictive.border")]
1257    pub predictive_border: Option<String>,
1258
1259    /// Represents a renamed status, such as a file that has been renamed.
1260    #[serde(rename = "renamed")]
1261    pub renamed: Option<String>,
1262
1263    #[serde(rename = "renamed.background")]
1264    pub renamed_background: Option<String>,
1265
1266    #[serde(rename = "renamed.border")]
1267    pub renamed_border: Option<String>,
1268
1269    /// Indicates a successful operation or task completion.
1270    #[serde(rename = "success")]
1271    pub success: Option<String>,
1272
1273    #[serde(rename = "success.background")]
1274    pub success_background: Option<String>,
1275
1276    #[serde(rename = "success.border")]
1277    pub success_border: Option<String>,
1278
1279    /// Indicates some kind of unreachable status, like a block of code that can never be reached.
1280    #[serde(rename = "unreachable")]
1281    pub unreachable: Option<String>,
1282
1283    #[serde(rename = "unreachable.background")]
1284    pub unreachable_background: Option<String>,
1285
1286    #[serde(rename = "unreachable.border")]
1287    pub unreachable_border: Option<String>,
1288
1289    /// Represents a warning status, like an operation that is about to fail.
1290    #[serde(rename = "warning")]
1291    pub warning: Option<String>,
1292
1293    #[serde(rename = "warning.background")]
1294    pub warning_background: Option<String>,
1295
1296    #[serde(rename = "warning.border")]
1297    pub warning_border: Option<String>,
1298}
1299
1300/// The background appearance of the window.
1301#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema, MergeFrom)]
1302#[serde(rename_all = "snake_case")]
1303pub enum WindowBackgroundContent {
1304    Opaque,
1305    Transparent,
1306    Blurred,
1307}
1308
1309#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
1310#[serde(rename_all = "snake_case")]
1311pub enum FontStyleContent {
1312    Normal,
1313    Italic,
1314    Oblique,
1315}
1316
1317#[derive(
1318    Clone,
1319    Copy,
1320    Debug,
1321    PartialEq,
1322    PartialOrd,
1323    Serialize,
1324    Deserialize,
1325    MergeFrom,
1326    derive_more::FromStr,
1327)]
1328#[serde(transparent)]
1329pub struct FontWeightContent(pub f32);
1330
1331impl Display for FontWeightContent {
1332    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1333        write!(f, "{}", self.0)
1334    }
1335}
1336
1337impl From<f32> for FontWeightContent {
1338    fn from(weight: f32) -> Self {
1339        FontWeightContent(weight)
1340    }
1341}
1342
1343impl Default for FontWeightContent {
1344    fn default() -> Self {
1345        Self::NORMAL
1346    }
1347}
1348
1349impl FontWeightContent {
1350    pub const THIN: FontWeightContent = FontWeightContent(100.0);
1351    pub const EXTRA_LIGHT: FontWeightContent = FontWeightContent(200.0);
1352    pub const LIGHT: FontWeightContent = FontWeightContent(300.0);
1353    pub const NORMAL: FontWeightContent = FontWeightContent(400.0);
1354    pub const MEDIUM: FontWeightContent = FontWeightContent(500.0);
1355    pub const SEMIBOLD: FontWeightContent = FontWeightContent(600.0);
1356    pub const BOLD: FontWeightContent = FontWeightContent(700.0);
1357    pub const EXTRA_BOLD: FontWeightContent = FontWeightContent(800.0);
1358    pub const BLACK: FontWeightContent = FontWeightContent(900.0);
1359}
1360
1361impl schemars::JsonSchema for FontWeightContent {
1362    fn schema_name() -> std::borrow::Cow<'static, str> {
1363        "FontWeightContent".into()
1364    }
1365
1366    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
1367        use schemars::json_schema;
1368        json_schema!({
1369            "type": "number",
1370            "minimum": Self::THIN.0,
1371            "maximum": Self::BLACK.0,
1372            "default": Self::NORMAL.0,
1373            "description": "Font weight value between 100 (thin) and 900 (black)"
1374        })
1375    }
1376}
1377
1378#[cfg(test)]
1379mod tests {
1380    use super::*;
1381    use serde_json::json;
1382
1383    #[test]
1384    fn test_buffer_line_height_deserialize_valid() {
1385        assert_eq!(
1386            serde_json::from_value::<BufferLineHeight>(json!("comfortable")).unwrap(),
1387            BufferLineHeight::Comfortable
1388        );
1389        assert_eq!(
1390            serde_json::from_value::<BufferLineHeight>(json!("standard")).unwrap(),
1391            BufferLineHeight::Standard
1392        );
1393        assert_eq!(
1394            serde_json::from_value::<BufferLineHeight>(json!({"custom": 1.0})).unwrap(),
1395            BufferLineHeight::Custom(1.0)
1396        );
1397        assert_eq!(
1398            serde_json::from_value::<BufferLineHeight>(json!({"custom": 1.5})).unwrap(),
1399            BufferLineHeight::Custom(1.5)
1400        );
1401    }
1402
1403    #[test]
1404    fn test_buffer_line_height_deserialize_invalid() {
1405        assert!(
1406            serde_json::from_value::<BufferLineHeight>(json!({"custom": 0.99}))
1407                .err()
1408                .unwrap()
1409                .to_string()
1410                .contains("buffer_line_height.custom must be at least 1.0")
1411        );
1412        assert!(
1413            serde_json::from_value::<BufferLineHeight>(json!({"custom": 0.0}))
1414                .err()
1415                .unwrap()
1416                .to_string()
1417                .contains("buffer_line_height.custom must be at least 1.0")
1418        );
1419        assert!(
1420            serde_json::from_value::<BufferLineHeight>(json!({"custom": -1.0}))
1421                .err()
1422                .unwrap()
1423                .to_string()
1424                .contains("buffer_line_height.custom must be at least 1.0")
1425        );
1426    }
1427
1428    #[test]
1429    fn test_buffer_font_weight_schema_has_default() {
1430        use schemars::schema_for;
1431
1432        let schema = schema_for!(ThemeSettingsContent);
1433        let schema_value = serde_json::to_value(&schema).unwrap();
1434
1435        let properties = &schema_value["properties"];
1436        let buffer_font_weight = &properties["buffer_font_weight"];
1437
1438        assert!(
1439            buffer_font_weight.get("default").is_some(),
1440            "buffer_font_weight should have a default value in the schema"
1441        );
1442
1443        let default_value = &buffer_font_weight["default"];
1444        assert_eq!(
1445            default_value.as_f64(),
1446            Some(FontWeightContent::NORMAL.0 as f64),
1447            "buffer_font_weight default should be 400.0 (FontWeightContent::NORMAL)"
1448        );
1449
1450        let defs = &schema_value["$defs"];
1451        let font_weight_def = &defs["FontWeightContent"];
1452
1453        assert_eq!(
1454            font_weight_def["minimum"].as_f64(),
1455            Some(FontWeightContent::THIN.0 as f64),
1456            "FontWeightContent should have minimum of 100.0"
1457        );
1458        assert_eq!(
1459            font_weight_def["maximum"].as_f64(),
1460            Some(FontWeightContent::BLACK.0 as f64),
1461            "FontWeightContent should have maximum of 900.0"
1462        );
1463        assert_eq!(
1464            font_weight_def["default"].as_f64(),
1465            Some(FontWeightContent::NORMAL.0 as f64),
1466            "FontWeightContent should have default of 400.0"
1467        );
1468    }
1469}
1470
Served at tenant.openagents/omega Member data and write actions are omitted.