schema.rs

   1#![allow(missing_docs)]
   2
   3use anyhow::Result;
   4use gpui::{FontStyle, FontWeight, HighlightStyle, Hsla, WindowBackgroundAppearance};
   5use indexmap::IndexMap;
   6use palette::FromColor;
   7use schemars::gen::SchemaGenerator;
   8use schemars::schema::{Schema, SchemaObject};
   9use schemars::JsonSchema;
  10use serde::{Deserialize, Deserializer, Serialize};
  11use serde_json::Value;
  12use serde_repr::{Deserialize_repr, Serialize_repr};
  13
  14use crate::{StatusColorsRefinement, ThemeColorsRefinement};
  15
  16pub(crate) fn try_parse_color(color: &str) -> Result<Hsla> {
  17    let rgba = gpui::Rgba::try_from(color)?;
  18    let rgba = palette::rgb::Srgba::from_components((rgba.r, rgba.g, rgba.b, rgba.a));
  19    let hsla = palette::Hsla::from_color(rgba);
  20
  21    let hsla = gpui::hsla(
  22        hsla.hue.into_positive_degrees() / 360.,
  23        hsla.saturation,
  24        hsla.lightness,
  25        hsla.alpha,
  26    );
  27
  28    Ok(hsla)
  29}
  30
  31#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema)]
  32#[serde(rename_all = "snake_case")]
  33pub enum AppearanceContent {
  34    Light,
  35    Dark,
  36}
  37
  38/// The background appearance of the window.
  39#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema)]
  40#[serde(rename_all = "snake_case")]
  41pub enum WindowBackgroundContent {
  42    Opaque,
  43    Transparent,
  44    Blurred,
  45}
  46
  47impl From<WindowBackgroundContent> for WindowBackgroundAppearance {
  48    fn from(value: WindowBackgroundContent) -> Self {
  49        match value {
  50            WindowBackgroundContent::Opaque => WindowBackgroundAppearance::Opaque,
  51            WindowBackgroundContent::Transparent => WindowBackgroundAppearance::Transparent,
  52            WindowBackgroundContent::Blurred => WindowBackgroundAppearance::Blurred,
  53        }
  54    }
  55}
  56
  57/// The content of a serialized theme family.
  58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
  59pub struct ThemeFamilyContent {
  60    pub name: String,
  61    pub author: String,
  62    pub themes: Vec<ThemeContent>,
  63}
  64
  65/// The content of a serialized theme.
  66#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
  67pub struct ThemeContent {
  68    pub name: String,
  69    pub appearance: AppearanceContent,
  70    pub style: ThemeStyleContent,
  71}
  72
  73/// The content of a serialized theme.
  74#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
  75#[serde(default)]
  76pub struct ThemeStyleContent {
  77    #[serde(default, rename = "background.appearance")]
  78    pub window_background_appearance: Option<WindowBackgroundContent>,
  79
  80    #[serde(default)]
  81    pub accents: Vec<AccentContent>,
  82
  83    #[serde(flatten, default)]
  84    pub colors: ThemeColorsContent,
  85
  86    #[serde(flatten, default)]
  87    pub status: StatusColorsContent,
  88
  89    #[serde(default)]
  90    pub players: Vec<PlayerColorContent>,
  91
  92    /// The styles for syntax nodes.
  93    #[serde(default)]
  94    pub syntax: IndexMap<String, HighlightStyleContent>,
  95}
  96
  97impl ThemeStyleContent {
  98    /// Returns a [`ThemeColorsRefinement`] based on the colors in the [`ThemeContent`].
  99    #[inline(always)]
 100    pub fn theme_colors_refinement(&self) -> ThemeColorsRefinement {
 101        self.colors.theme_colors_refinement()
 102    }
 103
 104    /// Returns a [`StatusColorsRefinement`] based on the colors in the [`ThemeContent`].
 105    #[inline(always)]
 106    pub fn status_colors_refinement(&self) -> StatusColorsRefinement {
 107        self.status.status_colors_refinement()
 108    }
 109
 110    /// Returns the syntax style overrides in the [`ThemeContent`].
 111    pub fn syntax_overrides(&self) -> Vec<(String, HighlightStyle)> {
 112        self.syntax
 113            .iter()
 114            .map(|(key, style)| {
 115                (
 116                    key.clone(),
 117                    HighlightStyle {
 118                        color: style
 119                            .color
 120                            .as_ref()
 121                            .and_then(|color| try_parse_color(color).ok()),
 122                        background_color: style
 123                            .background_color
 124                            .as_ref()
 125                            .and_then(|color| try_parse_color(color).ok()),
 126                        font_style: style.font_style.map(FontStyle::from),
 127                        font_weight: style.font_weight.map(FontWeight::from),
 128                        ..Default::default()
 129                    },
 130                )
 131            })
 132            .collect()
 133    }
 134}
 135
 136#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
 137#[serde(default)]
 138pub struct ThemeColorsContent {
 139    /// Border color. Used for most borders, is usually a high contrast color.
 140    #[serde(rename = "border")]
 141    pub border: Option<String>,
 142
 143    /// Border color. Used for deemphasized borders, like a visual divider between two sections
 144    #[serde(rename = "border.variant")]
 145    pub border_variant: Option<String>,
 146
 147    /// Border color. Used for focused elements, like keyboard focused list item.
 148    #[serde(rename = "border.focused")]
 149    pub border_focused: Option<String>,
 150
 151    /// Border color. Used for selected elements, like an active search filter or selected checkbox.
 152    #[serde(rename = "border.selected")]
 153    pub border_selected: Option<String>,
 154
 155    /// Border color. Used for transparent borders. Used for placeholder borders when an element gains a border on state change.
 156    #[serde(rename = "border.transparent")]
 157    pub border_transparent: Option<String>,
 158
 159    /// Border color. Used for disabled elements, like a disabled input or button.
 160    #[serde(rename = "border.disabled")]
 161    pub border_disabled: Option<String>,
 162
 163    /// Background color. Used for elevated surfaces, like a context menu, popup, or dialog.
 164    #[serde(rename = "elevated_surface.background")]
 165    pub elevated_surface_background: Option<String>,
 166
 167    /// Background Color. Used for grounded surfaces like a panel or tab.
 168    #[serde(rename = "surface.background")]
 169    pub surface_background: Option<String>,
 170
 171    /// Background Color. Used for the app background and blank panels or windows.
 172    #[serde(rename = "background")]
 173    pub background: Option<String>,
 174
 175    /// Background Color. Used for the background of an element that should have a different background than the surface it's on.
 176    ///
 177    /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
 178    ///
 179    /// For an element that should have the same background as the surface it's on, use `ghost_element_background`.
 180    #[serde(rename = "element.background")]
 181    pub element_background: Option<String>,
 182
 183    /// Background Color. Used for the hover state of an element that should have a different background than the surface it's on.
 184    ///
 185    /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
 186    #[serde(rename = "element.hover")]
 187    pub element_hover: Option<String>,
 188
 189    /// Background Color. Used for the active state of an element that should have a different background than the surface it's on.
 190    ///
 191    /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressd.
 192    #[serde(rename = "element.active")]
 193    pub element_active: Option<String>,
 194
 195    /// Background Color. Used for the selected state of an element that should have a different background than the surface it's on.
 196    ///
 197    /// Selected states are triggered by the element being selected (or "activated") by the user.
 198    ///
 199    /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
 200    #[serde(rename = "element.selected")]
 201    pub element_selected: Option<String>,
 202
 203    /// Background Color. Used for the disabled state of an element that should have a different background than the surface it's on.
 204    ///
 205    /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
 206    #[serde(rename = "element.disabled")]
 207    pub element_disabled: Option<String>,
 208
 209    /// Background Color. Used for the area that shows where a dragged element will be dropped.
 210    #[serde(rename = "drop_target.background")]
 211    pub drop_target_background: Option<String>,
 212
 213    /// Used for the background of a ghost element that should have the same background as the surface it's on.
 214    ///
 215    /// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
 216    ///
 217    /// For an element that should have a different background than the surface it's on, use `element_background`.
 218    #[serde(rename = "ghost_element.background")]
 219    pub ghost_element_background: Option<String>,
 220
 221    /// Background Color. Used for the hover state of a ghost element that should have the same background as the surface it's on.
 222    ///
 223    /// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
 224    #[serde(rename = "ghost_element.hover")]
 225    pub ghost_element_hover: Option<String>,
 226
 227    /// Background Color. Used for the active state of a ghost element that should have the same background as the surface it's on.
 228    ///
 229    /// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressd.
 230    #[serde(rename = "ghost_element.active")]
 231    pub ghost_element_active: Option<String>,
 232
 233    /// Background Color. Used for the selected state of a ghost element that should have the same background as the surface it's on.
 234    ///
 235    /// Selected states are triggered by the element being selected (or "activated") by the user.
 236    ///
 237    /// This could include a selected checkbox, a toggleable button that is toggled on, etc.
 238    #[serde(rename = "ghost_element.selected")]
 239    pub ghost_element_selected: Option<String>,
 240
 241    /// Background Color. Used for the disabled state of a ghost element that should have the same background as the surface it's on.
 242    ///
 243    /// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
 244    #[serde(rename = "ghost_element.disabled")]
 245    pub ghost_element_disabled: Option<String>,
 246
 247    /// Text Color. Default text color used for most text.
 248    #[serde(rename = "text")]
 249    pub text: Option<String>,
 250
 251    /// Text Color. Color of muted or deemphasized text. It is a subdued version of the standard text color.
 252    #[serde(rename = "text.muted")]
 253    pub text_muted: Option<String>,
 254
 255    /// Text Color. Color of the placeholder text typically shown in input fields to guide the user to enter valid data.
 256    #[serde(rename = "text.placeholder")]
 257    pub text_placeholder: Option<String>,
 258
 259    /// Text Color. Color used for text denoting disabled elements. Typically, the color is faded or grayed out to emphasize the disabled state.
 260    #[serde(rename = "text.disabled")]
 261    pub text_disabled: Option<String>,
 262
 263    /// Text Color. Color used for emphasis or highlighting certain text, like an active filter or a matched character in a search.
 264    #[serde(rename = "text.accent")]
 265    pub text_accent: Option<String>,
 266
 267    /// Fill Color. Used for the default fill color of an icon.
 268    #[serde(rename = "icon")]
 269    pub icon: Option<String>,
 270
 271    /// Fill Color. Used for the muted or deemphasized fill color of an icon.
 272    ///
 273    /// This might be used to show an icon in an inactive pane, or to demphasize a series of icons to give them less visual weight.
 274    #[serde(rename = "icon.muted")]
 275    pub icon_muted: Option<String>,
 276
 277    /// Fill Color. Used for the disabled fill color of an icon.
 278    ///
 279    /// Disabled states are shown when a user cannot interact with an element, like a icon button.
 280    #[serde(rename = "icon.disabled")]
 281    pub icon_disabled: Option<String>,
 282
 283    /// Fill Color. Used for the placeholder fill color of an icon.
 284    ///
 285    /// This might be used to show an icon in an input that disappears when the user enters text.
 286    #[serde(rename = "icon.placeholder")]
 287    pub icon_placeholder: Option<String>,
 288
 289    /// Fill Color. Used for the accent fill color of an icon.
 290    ///
 291    /// This might be used to show when a toggleable icon button is selected.
 292    #[serde(rename = "icon.accent")]
 293    pub icon_accent: Option<String>,
 294
 295    #[serde(rename = "status_bar.background")]
 296    pub status_bar_background: Option<String>,
 297
 298    #[serde(rename = "title_bar.background")]
 299    pub title_bar_background: Option<String>,
 300
 301    #[serde(rename = "title_bar.inactive_background")]
 302    pub title_bar_inactive_background: Option<String>,
 303
 304    #[serde(rename = "toolbar.background")]
 305    pub toolbar_background: Option<String>,
 306
 307    #[serde(rename = "tab_bar.background")]
 308    pub tab_bar_background: Option<String>,
 309
 310    #[serde(rename = "tab.inactive_background")]
 311    pub tab_inactive_background: Option<String>,
 312
 313    #[serde(rename = "tab.active_background")]
 314    pub tab_active_background: Option<String>,
 315
 316    #[serde(rename = "search.match_background")]
 317    pub search_match_background: Option<String>,
 318
 319    #[serde(rename = "panel.background")]
 320    pub panel_background: Option<String>,
 321
 322    #[serde(rename = "panel.focused_border")]
 323    pub panel_focused_border: Option<String>,
 324
 325    #[serde(rename = "pane.focused_border")]
 326    pub pane_focused_border: Option<String>,
 327
 328    #[serde(rename = "pane_group.border")]
 329    pub pane_group_border: Option<String>,
 330
 331    /// The deprecated version of `scrollbar.thumb.background`.
 332    ///
 333    /// Don't use this field.
 334    #[serde(rename = "scrollbar_thumb.background", skip_serializing)]
 335    #[schemars(skip)]
 336    pub deprecated_scrollbar_thumb_background: Option<String>,
 337
 338    /// The color of the scrollbar thumb.
 339    #[serde(rename = "scrollbar.thumb.background")]
 340    pub scrollbar_thumb_background: Option<String>,
 341
 342    /// The color of the scrollbar thumb when hovered over.
 343    #[serde(rename = "scrollbar.thumb.hover_background")]
 344    pub scrollbar_thumb_hover_background: Option<String>,
 345
 346    /// The border color of the scrollbar thumb.
 347    #[serde(rename = "scrollbar.thumb.border")]
 348    pub scrollbar_thumb_border: Option<String>,
 349
 350    /// The background color of the scrollbar track.
 351    #[serde(rename = "scrollbar.track.background")]
 352    pub scrollbar_track_background: Option<String>,
 353
 354    /// The border color of the scrollbar track.
 355    #[serde(rename = "scrollbar.track.border")]
 356    pub scrollbar_track_border: Option<String>,
 357
 358    #[serde(rename = "editor.foreground")]
 359    pub editor_foreground: Option<String>,
 360
 361    #[serde(rename = "editor.background")]
 362    pub editor_background: Option<String>,
 363
 364    #[serde(rename = "editor.gutter.background")]
 365    pub editor_gutter_background: Option<String>,
 366
 367    #[serde(rename = "editor.subheader.background")]
 368    pub editor_subheader_background: Option<String>,
 369
 370    #[serde(rename = "editor.active_line.background")]
 371    pub editor_active_line_background: Option<String>,
 372
 373    #[serde(rename = "editor.highlighted_line.background")]
 374    pub editor_highlighted_line_background: Option<String>,
 375
 376    /// Text Color. Used for the text of the line number in the editor gutter.
 377    #[serde(rename = "editor.line_number")]
 378    pub editor_line_number: Option<String>,
 379
 380    /// Text Color. Used for the text of the line number in the editor gutter when the line is highlighted.
 381    #[serde(rename = "editor.active_line_number")]
 382    pub editor_active_line_number: Option<String>,
 383
 384    /// Text Color. Used to mark invisible characters in the editor.
 385    ///
 386    /// Example: spaces, tabs, carriage returns, etc.
 387    #[serde(rename = "editor.invisible")]
 388    pub editor_invisible: Option<String>,
 389
 390    #[serde(rename = "editor.wrap_guide")]
 391    pub editor_wrap_guide: Option<String>,
 392
 393    #[serde(rename = "editor.active_wrap_guide")]
 394    pub editor_active_wrap_guide: Option<String>,
 395
 396    #[serde(rename = "editor.indent_guide")]
 397    pub editor_indent_guide: Option<String>,
 398
 399    #[serde(rename = "editor.indent_guide_active")]
 400    pub editor_indent_guide_active: Option<String>,
 401
 402    /// Read-access of a symbol, like reading a variable.
 403    ///
 404    /// A document highlight is a range inside a text document which deserves
 405    /// special attention. Usually a document highlight is visualized by changing
 406    /// the background color of its range.
 407    #[serde(rename = "editor.document_highlight.read_background")]
 408    pub editor_document_highlight_read_background: Option<String>,
 409
 410    /// Read-access of a symbol, like reading a variable.
 411    ///
 412    /// A document highlight is a range inside a text document which deserves
 413    /// special attention. Usually a document highlight is visualized by changing
 414    /// the background color of its range.
 415    #[serde(rename = "editor.document_highlight.write_background")]
 416    pub editor_document_highlight_write_background: Option<String>,
 417
 418    /// Highlighted brackets background color.
 419    ///
 420    /// Matching brackets in the cursor scope are highlighted with this background color.
 421    #[serde(rename = "editor.document_highlight.bracket_background")]
 422    pub editor_document_highlight_bracket_background: Option<String>,
 423
 424    /// Terminal background color.
 425    #[serde(rename = "terminal.background")]
 426    pub terminal_background: Option<String>,
 427
 428    /// Terminal foreground color.
 429    #[serde(rename = "terminal.foreground")]
 430    pub terminal_foreground: Option<String>,
 431
 432    /// Terminal ANSI background color.
 433    #[serde(rename = "terminal.ansi.background")]
 434    pub terminal_ansi_background: Option<String>,
 435
 436    /// Bright terminal foreground color.
 437    #[serde(rename = "terminal.bright_foreground")]
 438    pub terminal_bright_foreground: Option<String>,
 439
 440    /// Dim terminal foreground color.
 441    #[serde(rename = "terminal.dim_foreground")]
 442    pub terminal_dim_foreground: Option<String>,
 443
 444    /// Black ANSI terminal color.
 445    #[serde(rename = "terminal.ansi.black")]
 446    pub terminal_ansi_black: Option<String>,
 447
 448    /// Bright black ANSI terminal color.
 449    #[serde(rename = "terminal.ansi.bright_black")]
 450    pub terminal_ansi_bright_black: Option<String>,
 451
 452    /// Dim black ANSI terminal color.
 453    #[serde(rename = "terminal.ansi.dim_black")]
 454    pub terminal_ansi_dim_black: Option<String>,
 455
 456    /// Red ANSI terminal color.
 457    #[serde(rename = "terminal.ansi.red")]
 458    pub terminal_ansi_red: Option<String>,
 459
 460    /// Bright red ANSI terminal color.
 461    #[serde(rename = "terminal.ansi.bright_red")]
 462    pub terminal_ansi_bright_red: Option<String>,
 463
 464    /// Dim red ANSI terminal color.
 465    #[serde(rename = "terminal.ansi.dim_red")]
 466    pub terminal_ansi_dim_red: Option<String>,
 467
 468    /// Green ANSI terminal color.
 469    #[serde(rename = "terminal.ansi.green")]
 470    pub terminal_ansi_green: Option<String>,
 471
 472    /// Bright green ANSI terminal color.
 473    #[serde(rename = "terminal.ansi.bright_green")]
 474    pub terminal_ansi_bright_green: Option<String>,
 475
 476    /// Dim green ANSI terminal color.
 477    #[serde(rename = "terminal.ansi.dim_green")]
 478    pub terminal_ansi_dim_green: Option<String>,
 479
 480    /// Yellow ANSI terminal color.
 481    #[serde(rename = "terminal.ansi.yellow")]
 482    pub terminal_ansi_yellow: Option<String>,
 483
 484    /// Bright yellow ANSI terminal color.
 485    #[serde(rename = "terminal.ansi.bright_yellow")]
 486    pub terminal_ansi_bright_yellow: Option<String>,
 487
 488    /// Dim yellow ANSI terminal color.
 489    #[serde(rename = "terminal.ansi.dim_yellow")]
 490    pub terminal_ansi_dim_yellow: Option<String>,
 491
 492    /// Blue ANSI terminal color.
 493    #[serde(rename = "terminal.ansi.blue")]
 494    pub terminal_ansi_blue: Option<String>,
 495
 496    /// Bright blue ANSI terminal color.
 497    #[serde(rename = "terminal.ansi.bright_blue")]
 498    pub terminal_ansi_bright_blue: Option<String>,
 499
 500    /// Dim blue ANSI terminal color.
 501    #[serde(rename = "terminal.ansi.dim_blue")]
 502    pub terminal_ansi_dim_blue: Option<String>,
 503
 504    /// Magenta ANSI terminal color.
 505    #[serde(rename = "terminal.ansi.magenta")]
 506    pub terminal_ansi_magenta: Option<String>,
 507
 508    /// Bright magenta ANSI terminal color.
 509    #[serde(rename = "terminal.ansi.bright_magenta")]
 510    pub terminal_ansi_bright_magenta: Option<String>,
 511
 512    /// Dim magenta ANSI terminal color.
 513    #[serde(rename = "terminal.ansi.dim_magenta")]
 514    pub terminal_ansi_dim_magenta: Option<String>,
 515
 516    /// Cyan ANSI terminal color.
 517    #[serde(rename = "terminal.ansi.cyan")]
 518    pub terminal_ansi_cyan: Option<String>,
 519
 520    /// Bright cyan ANSI terminal color.
 521    #[serde(rename = "terminal.ansi.bright_cyan")]
 522    pub terminal_ansi_bright_cyan: Option<String>,
 523
 524    /// Dim cyan ANSI terminal color.
 525    #[serde(rename = "terminal.ansi.dim_cyan")]
 526    pub terminal_ansi_dim_cyan: Option<String>,
 527
 528    /// White ANSI terminal color.
 529    #[serde(rename = "terminal.ansi.white")]
 530    pub terminal_ansi_white: Option<String>,
 531
 532    /// Bright white ANSI terminal color.
 533    #[serde(rename = "terminal.ansi.bright_white")]
 534    pub terminal_ansi_bright_white: Option<String>,
 535
 536    /// Dim white ANSI terminal color.
 537    #[serde(rename = "terminal.ansi.dim_white")]
 538    pub terminal_ansi_dim_white: Option<String>,
 539
 540    #[serde(rename = "link_text.hover")]
 541    pub link_text_hover: Option<String>,
 542}
 543
 544impl ThemeColorsContent {
 545    /// Returns a [`ThemeColorsRefinement`] based on the colors in the [`ThemeColorsContent`].
 546    pub fn theme_colors_refinement(&self) -> ThemeColorsRefinement {
 547        let border = self
 548            .border
 549            .as_ref()
 550            .and_then(|color| try_parse_color(color).ok());
 551        let editor_document_highlight_read_background = self
 552            .editor_document_highlight_read_background
 553            .as_ref()
 554            .and_then(|color| try_parse_color(color).ok());
 555        ThemeColorsRefinement {
 556            border,
 557            border_variant: self
 558                .border_variant
 559                .as_ref()
 560                .and_then(|color| try_parse_color(color).ok()),
 561            border_focused: self
 562                .border_focused
 563                .as_ref()
 564                .and_then(|color| try_parse_color(color).ok()),
 565            border_selected: self
 566                .border_selected
 567                .as_ref()
 568                .and_then(|color| try_parse_color(color).ok()),
 569            border_transparent: self
 570                .border_transparent
 571                .as_ref()
 572                .and_then(|color| try_parse_color(color).ok()),
 573            border_disabled: self
 574                .border_disabled
 575                .as_ref()
 576                .and_then(|color| try_parse_color(color).ok()),
 577            elevated_surface_background: self
 578                .elevated_surface_background
 579                .as_ref()
 580                .and_then(|color| try_parse_color(color).ok()),
 581            surface_background: self
 582                .surface_background
 583                .as_ref()
 584                .and_then(|color| try_parse_color(color).ok()),
 585            background: self
 586                .background
 587                .as_ref()
 588                .and_then(|color| try_parse_color(color).ok()),
 589            element_background: self
 590                .element_background
 591                .as_ref()
 592                .and_then(|color| try_parse_color(color).ok()),
 593            element_hover: self
 594                .element_hover
 595                .as_ref()
 596                .and_then(|color| try_parse_color(color).ok()),
 597            element_active: self
 598                .element_active
 599                .as_ref()
 600                .and_then(|color| try_parse_color(color).ok()),
 601            element_selected: self
 602                .element_selected
 603                .as_ref()
 604                .and_then(|color| try_parse_color(color).ok()),
 605            element_disabled: self
 606                .element_disabled
 607                .as_ref()
 608                .and_then(|color| try_parse_color(color).ok()),
 609            drop_target_background: self
 610                .drop_target_background
 611                .as_ref()
 612                .and_then(|color| try_parse_color(color).ok()),
 613            ghost_element_background: self
 614                .ghost_element_background
 615                .as_ref()
 616                .and_then(|color| try_parse_color(color).ok()),
 617            ghost_element_hover: self
 618                .ghost_element_hover
 619                .as_ref()
 620                .and_then(|color| try_parse_color(color).ok()),
 621            ghost_element_active: self
 622                .ghost_element_active
 623                .as_ref()
 624                .and_then(|color| try_parse_color(color).ok()),
 625            ghost_element_selected: self
 626                .ghost_element_selected
 627                .as_ref()
 628                .and_then(|color| try_parse_color(color).ok()),
 629            ghost_element_disabled: self
 630                .ghost_element_disabled
 631                .as_ref()
 632                .and_then(|color| try_parse_color(color).ok()),
 633            text: self
 634                .text
 635                .as_ref()
 636                .and_then(|color| try_parse_color(color).ok()),
 637            text_muted: self
 638                .text_muted
 639                .as_ref()
 640                .and_then(|color| try_parse_color(color).ok()),
 641            text_placeholder: self
 642                .text_placeholder
 643                .as_ref()
 644                .and_then(|color| try_parse_color(color).ok()),
 645            text_disabled: self
 646                .text_disabled
 647                .as_ref()
 648                .and_then(|color| try_parse_color(color).ok()),
 649            text_accent: self
 650                .text_accent
 651                .as_ref()
 652                .and_then(|color| try_parse_color(color).ok()),
 653            icon: self
 654                .icon
 655                .as_ref()
 656                .and_then(|color| try_parse_color(color).ok()),
 657            icon_muted: self
 658                .icon_muted
 659                .as_ref()
 660                .and_then(|color| try_parse_color(color).ok()),
 661            icon_disabled: self
 662                .icon_disabled
 663                .as_ref()
 664                .and_then(|color| try_parse_color(color).ok()),
 665            icon_placeholder: self
 666                .icon_placeholder
 667                .as_ref()
 668                .and_then(|color| try_parse_color(color).ok()),
 669            icon_accent: self
 670                .icon_accent
 671                .as_ref()
 672                .and_then(|color| try_parse_color(color).ok()),
 673            status_bar_background: self
 674                .status_bar_background
 675                .as_ref()
 676                .and_then(|color| try_parse_color(color).ok()),
 677            title_bar_background: self
 678                .title_bar_background
 679                .as_ref()
 680                .and_then(|color| try_parse_color(color).ok()),
 681            title_bar_inactive_background: self
 682                .title_bar_inactive_background
 683                .as_ref()
 684                .and_then(|color| try_parse_color(color).ok()),
 685            toolbar_background: self
 686                .toolbar_background
 687                .as_ref()
 688                .and_then(|color| try_parse_color(color).ok()),
 689            tab_bar_background: self
 690                .tab_bar_background
 691                .as_ref()
 692                .and_then(|color| try_parse_color(color).ok()),
 693            tab_inactive_background: self
 694                .tab_inactive_background
 695                .as_ref()
 696                .and_then(|color| try_parse_color(color).ok()),
 697            tab_active_background: self
 698                .tab_active_background
 699                .as_ref()
 700                .and_then(|color| try_parse_color(color).ok()),
 701            search_match_background: self
 702                .search_match_background
 703                .as_ref()
 704                .and_then(|color| try_parse_color(color).ok()),
 705            panel_background: self
 706                .panel_background
 707                .as_ref()
 708                .and_then(|color| try_parse_color(color).ok()),
 709            panel_focused_border: self
 710                .panel_focused_border
 711                .as_ref()
 712                .and_then(|color| try_parse_color(color).ok()),
 713            pane_focused_border: self
 714                .pane_focused_border
 715                .as_ref()
 716                .and_then(|color| try_parse_color(color).ok()),
 717            pane_group_border: self
 718                .pane_group_border
 719                .as_ref()
 720                .and_then(|color| try_parse_color(color).ok())
 721                .or(border),
 722            scrollbar_thumb_background: self
 723                .scrollbar_thumb_background
 724                .as_ref()
 725                .and_then(|color| try_parse_color(color).ok())
 726                .or_else(|| {
 727                    self.deprecated_scrollbar_thumb_background
 728                        .as_ref()
 729                        .and_then(|color| try_parse_color(color).ok())
 730                }),
 731            scrollbar_thumb_hover_background: self
 732                .scrollbar_thumb_hover_background
 733                .as_ref()
 734                .and_then(|color| try_parse_color(color).ok()),
 735            scrollbar_thumb_border: self
 736                .scrollbar_thumb_border
 737                .as_ref()
 738                .and_then(|color| try_parse_color(color).ok()),
 739            scrollbar_track_background: self
 740                .scrollbar_track_background
 741                .as_ref()
 742                .and_then(|color| try_parse_color(color).ok()),
 743            scrollbar_track_border: self
 744                .scrollbar_track_border
 745                .as_ref()
 746                .and_then(|color| try_parse_color(color).ok()),
 747            editor_foreground: self
 748                .editor_foreground
 749                .as_ref()
 750                .and_then(|color| try_parse_color(color).ok()),
 751            editor_background: self
 752                .editor_background
 753                .as_ref()
 754                .and_then(|color| try_parse_color(color).ok()),
 755            editor_gutter_background: self
 756                .editor_gutter_background
 757                .as_ref()
 758                .and_then(|color| try_parse_color(color).ok()),
 759            editor_subheader_background: self
 760                .editor_subheader_background
 761                .as_ref()
 762                .and_then(|color| try_parse_color(color).ok()),
 763            editor_active_line_background: self
 764                .editor_active_line_background
 765                .as_ref()
 766                .and_then(|color| try_parse_color(color).ok()),
 767            editor_highlighted_line_background: self
 768                .editor_highlighted_line_background
 769                .as_ref()
 770                .and_then(|color| try_parse_color(color).ok()),
 771            editor_line_number: self
 772                .editor_line_number
 773                .as_ref()
 774                .and_then(|color| try_parse_color(color).ok()),
 775            editor_active_line_number: self
 776                .editor_active_line_number
 777                .as_ref()
 778                .and_then(|color| try_parse_color(color).ok()),
 779            editor_invisible: self
 780                .editor_invisible
 781                .as_ref()
 782                .and_then(|color| try_parse_color(color).ok()),
 783            editor_wrap_guide: self
 784                .editor_wrap_guide
 785                .as_ref()
 786                .and_then(|color| try_parse_color(color).ok()),
 787            editor_active_wrap_guide: self
 788                .editor_active_wrap_guide
 789                .as_ref()
 790                .and_then(|color| try_parse_color(color).ok()),
 791            editor_indent_guide: self
 792                .editor_indent_guide
 793                .as_ref()
 794                .and_then(|color| try_parse_color(color).ok()),
 795            editor_indent_guide_active: self
 796                .editor_indent_guide_active
 797                .as_ref()
 798                .and_then(|color| try_parse_color(color).ok()),
 799            editor_document_highlight_read_background,
 800            editor_document_highlight_write_background: self
 801                .editor_document_highlight_write_background
 802                .as_ref()
 803                .and_then(|color| try_parse_color(color).ok()),
 804            editor_document_highlight_bracket_background: self
 805                .editor_document_highlight_bracket_background
 806                .as_ref()
 807                .and_then(|color| try_parse_color(color).ok())
 808                // Fall back to `editor.document_highlight.read_background`, for backwards compatibility.
 809                .or(editor_document_highlight_read_background),
 810            terminal_background: self
 811                .terminal_background
 812                .as_ref()
 813                .and_then(|color| try_parse_color(color).ok()),
 814            terminal_ansi_background: self
 815                .terminal_ansi_background
 816                .as_ref()
 817                .and_then(|color| try_parse_color(color).ok()),
 818            terminal_foreground: self
 819                .terminal_foreground
 820                .as_ref()
 821                .and_then(|color| try_parse_color(color).ok()),
 822            terminal_bright_foreground: self
 823                .terminal_bright_foreground
 824                .as_ref()
 825                .and_then(|color| try_parse_color(color).ok()),
 826            terminal_dim_foreground: self
 827                .terminal_dim_foreground
 828                .as_ref()
 829                .and_then(|color| try_parse_color(color).ok()),
 830            terminal_ansi_black: self
 831                .terminal_ansi_black
 832                .as_ref()
 833                .and_then(|color| try_parse_color(color).ok()),
 834            terminal_ansi_bright_black: self
 835                .terminal_ansi_bright_black
 836                .as_ref()
 837                .and_then(|color| try_parse_color(color).ok()),
 838            terminal_ansi_dim_black: self
 839                .terminal_ansi_dim_black
 840                .as_ref()
 841                .and_then(|color| try_parse_color(color).ok()),
 842            terminal_ansi_red: self
 843                .terminal_ansi_red
 844                .as_ref()
 845                .and_then(|color| try_parse_color(color).ok()),
 846            terminal_ansi_bright_red: self
 847                .terminal_ansi_bright_red
 848                .as_ref()
 849                .and_then(|color| try_parse_color(color).ok()),
 850            terminal_ansi_dim_red: self
 851                .terminal_ansi_dim_red
 852                .as_ref()
 853                .and_then(|color| try_parse_color(color).ok()),
 854            terminal_ansi_green: self
 855                .terminal_ansi_green
 856                .as_ref()
 857                .and_then(|color| try_parse_color(color).ok()),
 858            terminal_ansi_bright_green: self
 859                .terminal_ansi_bright_green
 860                .as_ref()
 861                .and_then(|color| try_parse_color(color).ok()),
 862            terminal_ansi_dim_green: self
 863                .terminal_ansi_dim_green
 864                .as_ref()
 865                .and_then(|color| try_parse_color(color).ok()),
 866            terminal_ansi_yellow: self
 867                .terminal_ansi_yellow
 868                .as_ref()
 869                .and_then(|color| try_parse_color(color).ok()),
 870            terminal_ansi_bright_yellow: self
 871                .terminal_ansi_bright_yellow
 872                .as_ref()
 873                .and_then(|color| try_parse_color(color).ok()),
 874            terminal_ansi_dim_yellow: self
 875                .terminal_ansi_dim_yellow
 876                .as_ref()
 877                .and_then(|color| try_parse_color(color).ok()),
 878            terminal_ansi_blue: self
 879                .terminal_ansi_blue
 880                .as_ref()
 881                .and_then(|color| try_parse_color(color).ok()),
 882            terminal_ansi_bright_blue: self
 883                .terminal_ansi_bright_blue
 884                .as_ref()
 885                .and_then(|color| try_parse_color(color).ok()),
 886            terminal_ansi_dim_blue: self
 887                .terminal_ansi_dim_blue
 888                .as_ref()
 889                .and_then(|color| try_parse_color(color).ok()),
 890            terminal_ansi_magenta: self
 891                .terminal_ansi_magenta
 892                .as_ref()
 893                .and_then(|color| try_parse_color(color).ok()),
 894            terminal_ansi_bright_magenta: self
 895                .terminal_ansi_bright_magenta
 896                .as_ref()
 897                .and_then(|color| try_parse_color(color).ok()),
 898            terminal_ansi_dim_magenta: self
 899                .terminal_ansi_dim_magenta
 900                .as_ref()
 901                .and_then(|color| try_parse_color(color).ok()),
 902            terminal_ansi_cyan: self
 903                .terminal_ansi_cyan
 904                .as_ref()
 905                .and_then(|color| try_parse_color(color).ok()),
 906            terminal_ansi_bright_cyan: self
 907                .terminal_ansi_bright_cyan
 908                .as_ref()
 909                .and_then(|color| try_parse_color(color).ok()),
 910            terminal_ansi_dim_cyan: self
 911                .terminal_ansi_dim_cyan
 912                .as_ref()
 913                .and_then(|color| try_parse_color(color).ok()),
 914            terminal_ansi_white: self
 915                .terminal_ansi_white
 916                .as_ref()
 917                .and_then(|color| try_parse_color(color).ok()),
 918            terminal_ansi_bright_white: self
 919                .terminal_ansi_bright_white
 920                .as_ref()
 921                .and_then(|color| try_parse_color(color).ok()),
 922            terminal_ansi_dim_white: self
 923                .terminal_ansi_dim_white
 924                .as_ref()
 925                .and_then(|color| try_parse_color(color).ok()),
 926            link_text_hover: self
 927                .link_text_hover
 928                .as_ref()
 929                .and_then(|color| try_parse_color(color).ok()),
 930        }
 931    }
 932}
 933
 934#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
 935#[serde(default)]
 936pub struct StatusColorsContent {
 937    /// Indicates some kind of conflict, like a file changed on disk while it was open, or
 938    /// merge conflicts in a Git repository.
 939    #[serde(rename = "conflict")]
 940    pub conflict: Option<String>,
 941
 942    #[serde(rename = "conflict.background")]
 943    pub conflict_background: Option<String>,
 944
 945    #[serde(rename = "conflict.border")]
 946    pub conflict_border: Option<String>,
 947
 948    /// Indicates something new, like a new file added to a Git repository.
 949    #[serde(rename = "created")]
 950    pub created: Option<String>,
 951
 952    #[serde(rename = "created.background")]
 953    pub created_background: Option<String>,
 954
 955    #[serde(rename = "created.border")]
 956    pub created_border: Option<String>,
 957
 958    /// Indicates that something no longer exists, like a deleted file.
 959    #[serde(rename = "deleted")]
 960    pub deleted: Option<String>,
 961
 962    #[serde(rename = "deleted.background")]
 963    pub deleted_background: Option<String>,
 964
 965    #[serde(rename = "deleted.border")]
 966    pub deleted_border: Option<String>,
 967
 968    /// Indicates a system error, a failed operation or a diagnostic error.
 969    #[serde(rename = "error")]
 970    pub error: Option<String>,
 971
 972    #[serde(rename = "error.background")]
 973    pub error_background: Option<String>,
 974
 975    #[serde(rename = "error.border")]
 976    pub error_border: Option<String>,
 977
 978    /// Represents a hidden status, such as a file being hidden in a file tree.
 979    #[serde(rename = "hidden")]
 980    pub hidden: Option<String>,
 981
 982    #[serde(rename = "hidden.background")]
 983    pub hidden_background: Option<String>,
 984
 985    #[serde(rename = "hidden.border")]
 986    pub hidden_border: Option<String>,
 987
 988    /// Indicates a hint or some kind of additional information.
 989    #[serde(rename = "hint")]
 990    pub hint: Option<String>,
 991
 992    #[serde(rename = "hint.background")]
 993    pub hint_background: Option<String>,
 994
 995    #[serde(rename = "hint.border")]
 996    pub hint_border: Option<String>,
 997
 998    /// Indicates that something is deliberately ignored, such as a file or operation ignored by Git.
 999    #[serde(rename = "ignored")]
1000    pub ignored: Option<String>,
1001
1002    #[serde(rename = "ignored.background")]
1003    pub ignored_background: Option<String>,
1004
1005    #[serde(rename = "ignored.border")]
1006    pub ignored_border: Option<String>,
1007
1008    /// Represents informational status updates or messages.
1009    #[serde(rename = "info")]
1010    pub info: Option<String>,
1011
1012    #[serde(rename = "info.background")]
1013    pub info_background: Option<String>,
1014
1015    #[serde(rename = "info.border")]
1016    pub info_border: Option<String>,
1017
1018    /// Indicates a changed or altered status, like a file that has been edited.
1019    #[serde(rename = "modified")]
1020    pub modified: Option<String>,
1021
1022    #[serde(rename = "modified.background")]
1023    pub modified_background: Option<String>,
1024
1025    #[serde(rename = "modified.border")]
1026    pub modified_border: Option<String>,
1027
1028    /// Indicates something that is predicted, like automatic code completion, or generated code.
1029    #[serde(rename = "predictive")]
1030    pub predictive: Option<String>,
1031
1032    #[serde(rename = "predictive.background")]
1033    pub predictive_background: Option<String>,
1034
1035    #[serde(rename = "predictive.border")]
1036    pub predictive_border: Option<String>,
1037
1038    /// Represents a renamed status, such as a file that has been renamed.
1039    #[serde(rename = "renamed")]
1040    pub renamed: Option<String>,
1041
1042    #[serde(rename = "renamed.background")]
1043    pub renamed_background: Option<String>,
1044
1045    #[serde(rename = "renamed.border")]
1046    pub renamed_border: Option<String>,
1047
1048    /// Indicates a successful operation or task completion.
1049    #[serde(rename = "success")]
1050    pub success: Option<String>,
1051
1052    #[serde(rename = "success.background")]
1053    pub success_background: Option<String>,
1054
1055    #[serde(rename = "success.border")]
1056    pub success_border: Option<String>,
1057
1058    /// Indicates some kind of unreachable status, like a block of code that can never be reached.
1059    #[serde(rename = "unreachable")]
1060    pub unreachable: Option<String>,
1061
1062    #[serde(rename = "unreachable.background")]
1063    pub unreachable_background: Option<String>,
1064
1065    #[serde(rename = "unreachable.border")]
1066    pub unreachable_border: Option<String>,
1067
1068    /// Represents a warning status, like an operation that is about to fail.
1069    #[serde(rename = "warning")]
1070    pub warning: Option<String>,
1071
1072    #[serde(rename = "warning.background")]
1073    pub warning_background: Option<String>,
1074
1075    #[serde(rename = "warning.border")]
1076    pub warning_border: Option<String>,
1077}
1078
1079impl StatusColorsContent {
1080    /// Returns a [`StatusColorsRefinement`] based on the colors in the [`StatusColorsContent`].
1081    pub fn status_colors_refinement(&self) -> StatusColorsRefinement {
1082        StatusColorsRefinement {
1083            conflict: self
1084                .conflict
1085                .as_ref()
1086                .and_then(|color| try_parse_color(color).ok()),
1087            conflict_background: self
1088                .conflict_background
1089                .as_ref()
1090                .and_then(|color| try_parse_color(color).ok()),
1091            conflict_border: self
1092                .conflict_border
1093                .as_ref()
1094                .and_then(|color| try_parse_color(color).ok()),
1095            created: self
1096                .created
1097                .as_ref()
1098                .and_then(|color| try_parse_color(color).ok()),
1099            created_background: self
1100                .created_background
1101                .as_ref()
1102                .and_then(|color| try_parse_color(color).ok()),
1103            created_border: self
1104                .created_border
1105                .as_ref()
1106                .and_then(|color| try_parse_color(color).ok()),
1107            deleted: self
1108                .deleted
1109                .as_ref()
1110                .and_then(|color| try_parse_color(color).ok()),
1111            deleted_background: self
1112                .deleted_background
1113                .as_ref()
1114                .and_then(|color| try_parse_color(color).ok()),
1115            deleted_border: self
1116                .deleted_border
1117                .as_ref()
1118                .and_then(|color| try_parse_color(color).ok()),
1119            error: self
1120                .error
1121                .as_ref()
1122                .and_then(|color| try_parse_color(color).ok()),
1123            error_background: self
1124                .error_background
1125                .as_ref()
1126                .and_then(|color| try_parse_color(color).ok()),
1127            error_border: self
1128                .error_border
1129                .as_ref()
1130                .and_then(|color| try_parse_color(color).ok()),
1131            hidden: self
1132                .hidden
1133                .as_ref()
1134                .and_then(|color| try_parse_color(color).ok()),
1135            hidden_background: self
1136                .hidden_background
1137                .as_ref()
1138                .and_then(|color| try_parse_color(color).ok()),
1139            hidden_border: self
1140                .hidden_border
1141                .as_ref()
1142                .and_then(|color| try_parse_color(color).ok()),
1143            hint: self
1144                .hint
1145                .as_ref()
1146                .and_then(|color| try_parse_color(color).ok()),
1147            hint_background: self
1148                .hint_background
1149                .as_ref()
1150                .and_then(|color| try_parse_color(color).ok()),
1151            hint_border: self
1152                .hint_border
1153                .as_ref()
1154                .and_then(|color| try_parse_color(color).ok()),
1155            ignored: self
1156                .ignored
1157                .as_ref()
1158                .and_then(|color| try_parse_color(color).ok()),
1159            ignored_background: self
1160                .ignored_background
1161                .as_ref()
1162                .and_then(|color| try_parse_color(color).ok()),
1163            ignored_border: self
1164                .ignored_border
1165                .as_ref()
1166                .and_then(|color| try_parse_color(color).ok()),
1167            info: self
1168                .info
1169                .as_ref()
1170                .and_then(|color| try_parse_color(color).ok()),
1171            info_background: self
1172                .info_background
1173                .as_ref()
1174                .and_then(|color| try_parse_color(color).ok()),
1175            info_border: self
1176                .info_border
1177                .as_ref()
1178                .and_then(|color| try_parse_color(color).ok()),
1179            modified: self
1180                .modified
1181                .as_ref()
1182                .and_then(|color| try_parse_color(color).ok()),
1183            modified_background: self
1184                .modified_background
1185                .as_ref()
1186                .and_then(|color| try_parse_color(color).ok()),
1187            modified_border: self
1188                .modified_border
1189                .as_ref()
1190                .and_then(|color| try_parse_color(color).ok()),
1191            predictive: self
1192                .predictive
1193                .as_ref()
1194                .and_then(|color| try_parse_color(color).ok()),
1195            predictive_background: self
1196                .predictive_background
1197                .as_ref()
1198                .and_then(|color| try_parse_color(color).ok()),
1199            predictive_border: self
1200                .predictive_border
1201                .as_ref()
1202                .and_then(|color| try_parse_color(color).ok()),
1203            renamed: self
1204                .renamed
1205                .as_ref()
1206                .and_then(|color| try_parse_color(color).ok()),
1207            renamed_background: self
1208                .renamed_background
1209                .as_ref()
1210                .and_then(|color| try_parse_color(color).ok()),
1211            renamed_border: self
1212                .renamed_border
1213                .as_ref()
1214                .and_then(|color| try_parse_color(color).ok()),
1215            success: self
1216                .success
1217                .as_ref()
1218                .and_then(|color| try_parse_color(color).ok()),
1219            success_background: self
1220                .success_background
1221                .as_ref()
1222                .and_then(|color| try_parse_color(color).ok()),
1223            success_border: self
1224                .success_border
1225                .as_ref()
1226                .and_then(|color| try_parse_color(color).ok()),
1227            unreachable: self
1228                .unreachable
1229                .as_ref()
1230                .and_then(|color| try_parse_color(color).ok()),
1231            unreachable_background: self
1232                .unreachable_background
1233                .as_ref()
1234                .and_then(|color| try_parse_color(color).ok()),
1235            unreachable_border: self
1236                .unreachable_border
1237                .as_ref()
1238                .and_then(|color| try_parse_color(color).ok()),
1239            warning: self
1240                .warning
1241                .as_ref()
1242                .and_then(|color| try_parse_color(color).ok()),
1243            warning_background: self
1244                .warning_background
1245                .as_ref()
1246                .and_then(|color| try_parse_color(color).ok()),
1247            warning_border: self
1248                .warning_border
1249                .as_ref()
1250                .and_then(|color| try_parse_color(color).ok()),
1251        }
1252    }
1253}
1254
1255#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1256pub struct AccentContent(pub Option<String>);
1257
1258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1259pub struct PlayerColorContent {
1260    pub cursor: Option<String>,
1261    pub background: Option<String>,
1262    pub selection: Option<String>,
1263}
1264
1265#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
1266#[serde(rename_all = "snake_case")]
1267pub enum FontStyleContent {
1268    Normal,
1269    Italic,
1270    Oblique,
1271}
1272
1273impl From<FontStyleContent> for FontStyle {
1274    fn from(value: FontStyleContent) -> Self {
1275        match value {
1276            FontStyleContent::Normal => FontStyle::Normal,
1277            FontStyleContent::Italic => FontStyle::Italic,
1278            FontStyleContent::Oblique => FontStyle::Oblique,
1279        }
1280    }
1281}
1282
1283#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
1284#[repr(u16)]
1285pub enum FontWeightContent {
1286    Thin = 100,
1287    ExtraLight = 200,
1288    Light = 300,
1289    Normal = 400,
1290    Medium = 500,
1291    Semibold = 600,
1292    Bold = 700,
1293    ExtraBold = 800,
1294    Black = 900,
1295}
1296
1297impl JsonSchema for FontWeightContent {
1298    fn schema_name() -> String {
1299        "FontWeightContent".to_owned()
1300    }
1301
1302    fn is_referenceable() -> bool {
1303        false
1304    }
1305
1306    fn json_schema(_: &mut SchemaGenerator) -> Schema {
1307        SchemaObject {
1308            enum_values: Some(vec![
1309                100.into(),
1310                200.into(),
1311                300.into(),
1312                400.into(),
1313                500.into(),
1314                600.into(),
1315                700.into(),
1316                800.into(),
1317                900.into(),
1318            ]),
1319            ..Default::default()
1320        }
1321        .into()
1322    }
1323}
1324
1325impl From<FontWeightContent> for FontWeight {
1326    fn from(value: FontWeightContent) -> Self {
1327        match value {
1328            FontWeightContent::Thin => FontWeight::THIN,
1329            FontWeightContent::ExtraLight => FontWeight::EXTRA_LIGHT,
1330            FontWeightContent::Light => FontWeight::LIGHT,
1331            FontWeightContent::Normal => FontWeight::NORMAL,
1332            FontWeightContent::Medium => FontWeight::MEDIUM,
1333            FontWeightContent::Semibold => FontWeight::SEMIBOLD,
1334            FontWeightContent::Bold => FontWeight::BOLD,
1335            FontWeightContent::ExtraBold => FontWeight::EXTRA_BOLD,
1336            FontWeightContent::Black => FontWeight::BLACK,
1337        }
1338    }
1339}
1340
1341#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
1342#[serde(default)]
1343pub struct HighlightStyleContent {
1344    pub color: Option<String>,
1345
1346    #[serde(deserialize_with = "treat_error_as_none")]
1347    pub background_color: Option<String>,
1348
1349    #[serde(deserialize_with = "treat_error_as_none")]
1350    pub font_style: Option<FontStyleContent>,
1351
1352    #[serde(deserialize_with = "treat_error_as_none")]
1353    pub font_weight: Option<FontWeightContent>,
1354}
1355
1356impl HighlightStyleContent {
1357    pub fn is_empty(&self) -> bool {
1358        self.color.is_none()
1359            && self.background_color.is_none()
1360            && self.font_style.is_none()
1361            && self.font_weight.is_none()
1362    }
1363}
1364
1365fn treat_error_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
1366where
1367    T: Deserialize<'de>,
1368    D: Deserializer<'de>,
1369{
1370    let value: Value = Deserialize::deserialize(deserializer)?;
1371    Ok(T::deserialize(value).ok())
1372}