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::{JsonSchema, JsonSchema_repr};
   8use serde::{Deserialize, Deserializer, Serialize};
   9use serde_json::Value;
  10use serde_repr::{Deserialize_repr, Serialize_repr};
  11
  12use crate::{StatusColorsRefinement, ThemeColorsRefinement};
  13
  14pub(crate) fn try_parse_color(color: &str) -> Result<Hsla> {
  15    let rgba = gpui::Rgba::try_from(color)?;
  16    let rgba = palette::rgb::Srgba::from_components((rgba.r, rgba.g, rgba.b, rgba.a));
  17    let hsla = palette::Hsla::from_color(rgba);
  18
  19    let hsla = gpui::hsla(
  20        hsla.hue.into_positive_degrees() / 360.,
  21        hsla.saturation,
  22        hsla.lightness,
  23        hsla.alpha,
  24    );
  25
  26    Ok(hsla)
  27}
  28
  29fn ensure_non_opaque(color: Hsla) -> Hsla {
  30    const MAXIMUM_OPACITY: f32 = 0.7;
  31    if color.a <= MAXIMUM_OPACITY {
  32        color
  33    } else {
  34        Hsla {
  35            a: MAXIMUM_OPACITY,
  36            ..color
  37        }
  38    }
  39}
  40
  41fn ensure_opaque(color: Hsla) -> Hsla {
  42    Hsla { a: 1.0, ..color }
  43}
  44
  45#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema)]
  46#[serde(rename_all = "snake_case")]
  47pub enum AppearanceContent {
  48    Light,
  49    Dark,
  50}
  51
  52/// The background appearance of the window.
  53#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, JsonSchema)]
  54#[serde(rename_all = "snake_case")]
  55pub enum WindowBackgroundContent {
  56    Opaque,
  57    Transparent,
  58    Blurred,
  59}
  60
  61impl From<WindowBackgroundContent> for WindowBackgroundAppearance {
  62    fn from(value: WindowBackgroundContent) -> Self {
  63        match value {
  64            WindowBackgroundContent::Opaque => WindowBackgroundAppearance::Opaque,
  65            WindowBackgroundContent::Transparent => WindowBackgroundAppearance::Transparent,
  66            WindowBackgroundContent::Blurred => WindowBackgroundAppearance::Blurred,
  67        }
  68    }
  69}
  70
  71/// The content of a serialized theme family.
  72#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
  73pub struct ThemeFamilyContent {
  74    pub name: String,
  75    pub author: String,
  76    pub themes: Vec<ThemeContent>,
  77}
  78
  79/// The content of a serialized theme.
  80#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
  81pub struct ThemeContent {
  82    pub name: String,
  83    pub appearance: AppearanceContent,
  84    pub style: ThemeStyleContent,
  85}
  86
  87/// The content of a serialized theme.
  88#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
  89#[serde(default)]
  90pub struct ThemeStyleContent {
  91    #[serde(default, rename = "background.appearance")]
  92    pub window_background_appearance: Option<WindowBackgroundContent>,
  93
  94    #[serde(default)]
  95    pub accents: Vec<AccentContent>,
  96
  97    #[serde(flatten, default)]
  98    pub colors: ThemeColorsContent,
  99
 100    #[serde(flatten, default)]
 101    pub status: StatusColorsContent,
 102
 103    #[serde(default)]
 104    pub players: Vec<PlayerColorContent>,
 105
 106    /// The styles for syntax nodes.
 107    #[serde(default)]
 108    pub syntax: IndexMap<String, HighlightStyleContent>,
 109}
 110
 111impl ThemeStyleContent {
 112    /// Returns a [`ThemeColorsRefinement`] based on the colors in the [`ThemeContent`].
 113    #[inline(always)]
 114    pub fn theme_colors_refinement(&self) -> ThemeColorsRefinement {
 115        self.colors
 116            .theme_colors_refinement(&self.status_colors_refinement())
 117    }
 118
 119    /// Returns a [`StatusColorsRefinement`] based on the colors in the [`ThemeContent`].
 120    #[inline(always)]
 121    pub fn status_colors_refinement(&self) -> StatusColorsRefinement {
 122        self.status.status_colors_refinement()
 123    }
 124
 125    /// Returns the syntax style overrides in the [`ThemeContent`].
 126    pub fn syntax_overrides(&self) -> Vec<(String, HighlightStyle)> {
 127        self.syntax
 128            .iter()
 129            .map(|(key, style)| {
 130                (
 131                    key.clone(),
 132                    HighlightStyle {
 133                        color: style
 134                            .color
 135                            .as_ref()
 136                            .and_then(|color| try_parse_color(color).ok()),
 137                        background_color: style
 138                            .background_color
 139                            .as_ref()
 140                            .and_then(|color| try_parse_color(color).ok()),
 141                        font_style: style.font_style.map(FontStyle::from),
 142                        font_weight: style.font_weight.map(FontWeight::from),
 143                        ..Default::default()
 144                    },
 145                )
 146            })
 147            .collect()
 148    }
 149}
 150
 151pub(crate) fn try_parse_color(color: &str) -> Result<Hsla> {
 152    let rgba = gpui::Rgba::try_from(color)?;
 153    let rgba = palette::rgb::Srgba::from_components((rgba.r, rgba.g, rgba.b, rgba.a));
 154    let hsla = palette::Hsla::from_color(rgba);
 155
 156    let hsla = gpui::hsla(
 157        hsla.hue.into_positive_degrees() / 360.,
 158        hsla.saturation,
 159        hsla.lightness,
 160        hsla.alpha,
 161    );
 162
 163    Ok(hsla)
 164}
 165
 166impl ThemeColorsContent {
 167    /// Returns a [`ThemeColorsRefinement`] based on the colors in the [`ThemeColorsContent`].
 168    pub fn theme_colors_refinement(
 169        &self,
 170        status_colors: &StatusColorsRefinement,
 171    ) -> ThemeColorsRefinement {
 172        let border = self
 173            .border
 174            .as_ref()
 175            .and_then(|color| try_parse_color(color).ok());
 176        let editor_document_highlight_read_background = self
 177            .editor_document_highlight_read_background
 178            .as_ref()
 179            .and_then(|color| try_parse_color(color).ok());
 180        let scrollbar_thumb_background = self
 181            .scrollbar_thumb_background
 182            .as_ref()
 183            .and_then(|color| try_parse_color(color).ok())
 184            .or_else(|| {
 185                self.deprecated_scrollbar_thumb_background
 186                    .as_ref()
 187                    .and_then(|color| try_parse_color(color).ok())
 188            });
 189        let scrollbar_thumb_hover_background = self
 190            .scrollbar_thumb_hover_background
 191            .as_ref()
 192            .and_then(|color| try_parse_color(color).ok());
 193        let scrollbar_thumb_active_background = self
 194            .scrollbar_thumb_active_background
 195            .as_ref()
 196            .and_then(|color| try_parse_color(color).ok())
 197            .or(scrollbar_thumb_background);
 198        let scrollbar_thumb_border = self
 199            .scrollbar_thumb_border
 200            .as_ref()
 201            .and_then(|color| try_parse_color(color).ok());
 202        let element_hover = self
 203            .element_hover
 204            .as_ref()
 205            .and_then(|color| try_parse_color(color).ok());
 206        let panel_background = self
 207            .panel_background
 208            .as_ref()
 209            .and_then(|color| try_parse_color(color).ok());
 210        ThemeColorsRefinement {
 211            border,
 212            border_variant: self
 213                .border_variant
 214                .as_ref()
 215                .and_then(|color| try_parse_color(color).ok()),
 216            border_focused: self
 217                .border_focused
 218                .as_ref()
 219                .and_then(|color| try_parse_color(color).ok()),
 220            border_selected: self
 221                .border_selected
 222                .as_ref()
 223                .and_then(|color| try_parse_color(color).ok()),
 224            border_transparent: self
 225                .border_transparent
 226                .as_ref()
 227                .and_then(|color| try_parse_color(color).ok()),
 228            border_disabled: self
 229                .border_disabled
 230                .as_ref()
 231                .and_then(|color| try_parse_color(color).ok()),
 232            elevated_surface_background: self
 233                .elevated_surface_background
 234                .as_ref()
 235                .and_then(|color| try_parse_color(color).ok()),
 236            surface_background: self
 237                .surface_background
 238                .as_ref()
 239                .and_then(|color| try_parse_color(color).ok()),
 240            background: self
 241                .background
 242                .as_ref()
 243                .and_then(|color| try_parse_color(color).ok()),
 244            element_background: self
 245                .element_background
 246                .as_ref()
 247                .and_then(|color| try_parse_color(color).ok()),
 248            element_hover,
 249            element_active: self
 250                .element_active
 251                .as_ref()
 252                .and_then(|color| try_parse_color(color).ok()),
 253            element_selected: self
 254                .element_selected
 255                .as_ref()
 256                .and_then(|color| try_parse_color(color).ok()),
 257            element_disabled: self
 258                .element_disabled
 259                .as_ref()
 260                .and_then(|color| try_parse_color(color).ok()),
 261            element_selection_background: self
 262                .element_selection_background
 263                .as_ref()
 264                .and_then(|color| try_parse_color(color).ok()),
 265            drop_target_background: self
 266                .drop_target_background
 267                .as_ref()
 268                .and_then(|color| try_parse_color(color).ok()),
 269            drop_target_border: self
 270                .drop_target_border
 271                .as_ref()
 272                .and_then(|color| try_parse_color(color).ok()),
 273            ghost_element_background: self
 274                .ghost_element_background
 275                .as_ref()
 276                .and_then(|color| try_parse_color(color).ok()),
 277            ghost_element_hover: self
 278                .ghost_element_hover
 279                .as_ref()
 280                .and_then(|color| try_parse_color(color).ok()),
 281            ghost_element_active: self
 282                .ghost_element_active
 283                .as_ref()
 284                .and_then(|color| try_parse_color(color).ok()),
 285            ghost_element_selected: self
 286                .ghost_element_selected
 287                .as_ref()
 288                .and_then(|color| try_parse_color(color).ok()),
 289            ghost_element_disabled: self
 290                .ghost_element_disabled
 291                .as_ref()
 292                .and_then(|color| try_parse_color(color).ok()),
 293            text: self
 294                .text
 295                .as_ref()
 296                .and_then(|color| try_parse_color(color).ok()),
 297            text_muted: self
 298                .text_muted
 299                .as_ref()
 300                .and_then(|color| try_parse_color(color).ok()),
 301            text_placeholder: self
 302                .text_placeholder
 303                .as_ref()
 304                .and_then(|color| try_parse_color(color).ok()),
 305            text_disabled: self
 306                .text_disabled
 307                .as_ref()
 308                .and_then(|color| try_parse_color(color).ok()),
 309            text_accent: self
 310                .text_accent
 311                .as_ref()
 312                .and_then(|color| try_parse_color(color).ok()),
 313            icon: self
 314                .icon
 315                .as_ref()
 316                .and_then(|color| try_parse_color(color).ok()),
 317            icon_muted: self
 318                .icon_muted
 319                .as_ref()
 320                .and_then(|color| try_parse_color(color).ok()),
 321            icon_disabled: self
 322                .icon_disabled
 323                .as_ref()
 324                .and_then(|color| try_parse_color(color).ok()),
 325            icon_placeholder: self
 326                .icon_placeholder
 327                .as_ref()
 328                .and_then(|color| try_parse_color(color).ok()),
 329            icon_accent: self
 330                .icon_accent
 331                .as_ref()
 332                .and_then(|color| try_parse_color(color).ok()),
 333            debugger_accent: self
 334                .debugger_accent
 335                .as_ref()
 336                .and_then(|color| try_parse_color(color).ok()),
 337            status_bar_background: self
 338                .status_bar_background
 339                .as_ref()
 340                .and_then(|color| try_parse_color(color).ok()),
 341            title_bar_background: self
 342                .title_bar_background
 343                .as_ref()
 344                .and_then(|color| try_parse_color(color).ok()),
 345            title_bar_inactive_background: self
 346                .title_bar_inactive_background
 347                .as_ref()
 348                .and_then(|color| try_parse_color(color).ok()),
 349            toolbar_background: self
 350                .toolbar_background
 351                .as_ref()
 352                .and_then(|color| try_parse_color(color).ok()),
 353            tab_bar_background: self
 354                .tab_bar_background
 355                .as_ref()
 356                .and_then(|color| try_parse_color(color).ok()),
 357            tab_inactive_background: self
 358                .tab_inactive_background
 359                .as_ref()
 360                .and_then(|color| try_parse_color(color).ok()),
 361            tab_active_background: self
 362                .tab_active_background
 363                .as_ref()
 364                .and_then(|color| try_parse_color(color).ok()),
 365            search_match_background: self
 366                .search_match_background
 367                .as_ref()
 368                .and_then(|color| try_parse_color(color).ok()),
 369            panel_background,
 370            panel_focused_border: self
 371                .panel_focused_border
 372                .as_ref()
 373                .and_then(|color| try_parse_color(color).ok()),
 374            panel_indent_guide: self
 375                .panel_indent_guide
 376                .as_ref()
 377                .and_then(|color| try_parse_color(color).ok()),
 378            panel_indent_guide_hover: self
 379                .panel_indent_guide_hover
 380                .as_ref()
 381                .and_then(|color| try_parse_color(color).ok()),
 382            panel_indent_guide_active: self
 383                .panel_indent_guide_active
 384                .as_ref()
 385                .and_then(|color| try_parse_color(color).ok()),
 386            panel_overlay_background: self
 387                .panel_overlay_background
 388                .as_ref()
 389                .and_then(|color| try_parse_color(color).ok())
 390                .or(panel_background.map(ensure_opaque)),
 391            panel_overlay_hover: self
 392                .panel_overlay_hover
 393                .as_ref()
 394                .and_then(|color| try_parse_color(color).ok())
 395                .or(panel_background
 396                    .zip(element_hover)
 397                    .map(|(panel_bg, hover_bg)| panel_bg.blend(hover_bg))
 398                    .map(ensure_opaque)),
 399            pane_focused_border: self
 400                .pane_focused_border
 401                .as_ref()
 402                .and_then(|color| try_parse_color(color).ok()),
 403            pane_group_border: self
 404                .pane_group_border
 405                .as_ref()
 406                .and_then(|color| try_parse_color(color).ok())
 407                .or(border),
 408            scrollbar_thumb_background,
 409            scrollbar_thumb_hover_background,
 410            scrollbar_thumb_active_background,
 411            scrollbar_thumb_border,
 412            scrollbar_track_background: self
 413                .scrollbar_track_background
 414                .as_ref()
 415                .and_then(|color| try_parse_color(color).ok()),
 416            scrollbar_track_border: self
 417                .scrollbar_track_border
 418                .as_ref()
 419                .and_then(|color| try_parse_color(color).ok()),
 420            minimap_thumb_background: self
 421                .minimap_thumb_background
 422                .as_ref()
 423                .and_then(|color| try_parse_color(color).ok())
 424                .or(scrollbar_thumb_background.map(ensure_non_opaque)),
 425            minimap_thumb_hover_background: self
 426                .minimap_thumb_hover_background
 427                .as_ref()
 428                .and_then(|color| try_parse_color(color).ok())
 429                .or(scrollbar_thumb_hover_background.map(ensure_non_opaque)),
 430            minimap_thumb_active_background: self
 431                .minimap_thumb_active_background
 432                .as_ref()
 433                .and_then(|color| try_parse_color(color).ok())
 434                .or(scrollbar_thumb_active_background.map(ensure_non_opaque)),
 435            minimap_thumb_border: self
 436                .minimap_thumb_border
 437                .as_ref()
 438                .and_then(|color| try_parse_color(color).ok())
 439                .or(scrollbar_thumb_border),
 440            editor_foreground: self
 441                .editor_foreground
 442                .as_ref()
 443                .and_then(|color| try_parse_color(color).ok()),
 444            editor_background: self
 445                .editor_background
 446                .as_ref()
 447                .and_then(|color| try_parse_color(color).ok()),
 448            editor_gutter_background: self
 449                .editor_gutter_background
 450                .as_ref()
 451                .and_then(|color| try_parse_color(color).ok()),
 452            editor_subheader_background: self
 453                .editor_subheader_background
 454                .as_ref()
 455                .and_then(|color| try_parse_color(color).ok()),
 456            editor_active_line_background: self
 457                .editor_active_line_background
 458                .as_ref()
 459                .and_then(|color| try_parse_color(color).ok()),
 460            editor_highlighted_line_background: self
 461                .editor_highlighted_line_background
 462                .as_ref()
 463                .and_then(|color| try_parse_color(color).ok()),
 464            editor_debugger_active_line_background: self
 465                .editor_debugger_active_line_background
 466                .as_ref()
 467                .and_then(|color| try_parse_color(color).ok()),
 468            editor_line_number: self
 469                .editor_line_number
 470                .as_ref()
 471                .and_then(|color| try_parse_color(color).ok()),
 472            editor_hover_line_number: self
 473                .editor_hover_line_number
 474                .as_ref()
 475                .and_then(|color| try_parse_color(color).ok()),
 476            editor_active_line_number: self
 477                .editor_active_line_number
 478                .as_ref()
 479                .and_then(|color| try_parse_color(color).ok()),
 480            editor_invisible: self
 481                .editor_invisible
 482                .as_ref()
 483                .and_then(|color| try_parse_color(color).ok()),
 484            editor_wrap_guide: self
 485                .editor_wrap_guide
 486                .as_ref()
 487                .and_then(|color| try_parse_color(color).ok()),
 488            editor_active_wrap_guide: self
 489                .editor_active_wrap_guide
 490                .as_ref()
 491                .and_then(|color| try_parse_color(color).ok()),
 492            editor_indent_guide: self
 493                .editor_indent_guide
 494                .as_ref()
 495                .and_then(|color| try_parse_color(color).ok()),
 496            editor_indent_guide_active: self
 497                .editor_indent_guide_active
 498                .as_ref()
 499                .and_then(|color| try_parse_color(color).ok()),
 500            editor_document_highlight_read_background,
 501            editor_document_highlight_write_background: self
 502                .editor_document_highlight_write_background
 503                .as_ref()
 504                .and_then(|color| try_parse_color(color).ok()),
 505            editor_document_highlight_bracket_background: self
 506                .editor_document_highlight_bracket_background
 507                .as_ref()
 508                .and_then(|color| try_parse_color(color).ok())
 509                // Fall back to `editor.document_highlight.read_background`, for backwards compatibility.
 510                .or(editor_document_highlight_read_background),
 511            terminal_background: self
 512                .terminal_background
 513                .as_ref()
 514                .and_then(|color| try_parse_color(color).ok()),
 515            terminal_ansi_background: self
 516                .terminal_ansi_background
 517                .as_ref()
 518                .and_then(|color| try_parse_color(color).ok()),
 519            terminal_foreground: self
 520                .terminal_foreground
 521                .as_ref()
 522                .and_then(|color| try_parse_color(color).ok()),
 523            terminal_bright_foreground: self
 524                .terminal_bright_foreground
 525                .as_ref()
 526                .and_then(|color| try_parse_color(color).ok()),
 527            terminal_dim_foreground: self
 528                .terminal_dim_foreground
 529                .as_ref()
 530                .and_then(|color| try_parse_color(color).ok()),
 531            terminal_ansi_black: self
 532                .terminal_ansi_black
 533                .as_ref()
 534                .and_then(|color| try_parse_color(color).ok()),
 535            terminal_ansi_bright_black: self
 536                .terminal_ansi_bright_black
 537                .as_ref()
 538                .and_then(|color| try_parse_color(color).ok()),
 539            terminal_ansi_dim_black: self
 540                .terminal_ansi_dim_black
 541                .as_ref()
 542                .and_then(|color| try_parse_color(color).ok()),
 543            terminal_ansi_red: self
 544                .terminal_ansi_red
 545                .as_ref()
 546                .and_then(|color| try_parse_color(color).ok()),
 547            terminal_ansi_bright_red: self
 548                .terminal_ansi_bright_red
 549                .as_ref()
 550                .and_then(|color| try_parse_color(color).ok()),
 551            terminal_ansi_dim_red: self
 552                .terminal_ansi_dim_red
 553                .as_ref()
 554                .and_then(|color| try_parse_color(color).ok()),
 555            terminal_ansi_green: self
 556                .terminal_ansi_green
 557                .as_ref()
 558                .and_then(|color| try_parse_color(color).ok()),
 559            terminal_ansi_bright_green: self
 560                .terminal_ansi_bright_green
 561                .as_ref()
 562                .and_then(|color| try_parse_color(color).ok()),
 563            terminal_ansi_dim_green: self
 564                .terminal_ansi_dim_green
 565                .as_ref()
 566                .and_then(|color| try_parse_color(color).ok()),
 567            terminal_ansi_yellow: self
 568                .terminal_ansi_yellow
 569                .as_ref()
 570                .and_then(|color| try_parse_color(color).ok()),
 571            terminal_ansi_bright_yellow: self
 572                .terminal_ansi_bright_yellow
 573                .as_ref()
 574                .and_then(|color| try_parse_color(color).ok()),
 575            terminal_ansi_dim_yellow: self
 576                .terminal_ansi_dim_yellow
 577                .as_ref()
 578                .and_then(|color| try_parse_color(color).ok()),
 579            terminal_ansi_blue: self
 580                .terminal_ansi_blue
 581                .as_ref()
 582                .and_then(|color| try_parse_color(color).ok()),
 583            terminal_ansi_bright_blue: self
 584                .terminal_ansi_bright_blue
 585                .as_ref()
 586                .and_then(|color| try_parse_color(color).ok()),
 587            terminal_ansi_dim_blue: self
 588                .terminal_ansi_dim_blue
 589                .as_ref()
 590                .and_then(|color| try_parse_color(color).ok()),
 591            terminal_ansi_magenta: self
 592                .terminal_ansi_magenta
 593                .as_ref()
 594                .and_then(|color| try_parse_color(color).ok()),
 595            terminal_ansi_bright_magenta: self
 596                .terminal_ansi_bright_magenta
 597                .as_ref()
 598                .and_then(|color| try_parse_color(color).ok()),
 599            terminal_ansi_dim_magenta: self
 600                .terminal_ansi_dim_magenta
 601                .as_ref()
 602                .and_then(|color| try_parse_color(color).ok()),
 603            terminal_ansi_cyan: self
 604                .terminal_ansi_cyan
 605                .as_ref()
 606                .and_then(|color| try_parse_color(color).ok()),
 607            terminal_ansi_bright_cyan: self
 608                .terminal_ansi_bright_cyan
 609                .as_ref()
 610                .and_then(|color| try_parse_color(color).ok()),
 611            terminal_ansi_dim_cyan: self
 612                .terminal_ansi_dim_cyan
 613                .as_ref()
 614                .and_then(|color| try_parse_color(color).ok()),
 615            terminal_ansi_white: self
 616                .terminal_ansi_white
 617                .as_ref()
 618                .and_then(|color| try_parse_color(color).ok()),
 619            terminal_ansi_bright_white: self
 620                .terminal_ansi_bright_white
 621                .as_ref()
 622                .and_then(|color| try_parse_color(color).ok()),
 623            terminal_ansi_dim_white: self
 624                .terminal_ansi_dim_white
 625                .as_ref()
 626                .and_then(|color| try_parse_color(color).ok()),
 627            link_text_hover: self
 628                .link_text_hover
 629                .as_ref()
 630                .and_then(|color| try_parse_color(color).ok()),
 631            version_control_added: self
 632                .version_control_added
 633                .as_ref()
 634                .and_then(|color| try_parse_color(color).ok())
 635                // Fall back to `created`, for backwards compatibility.
 636                .or(status_colors.created),
 637            version_control_deleted: self
 638                .version_control_deleted
 639                .as_ref()
 640                .and_then(|color| try_parse_color(color).ok())
 641                // Fall back to `deleted`, for backwards compatibility.
 642                .or(status_colors.deleted),
 643            version_control_modified: self
 644                .version_control_modified
 645                .as_ref()
 646                .and_then(|color| try_parse_color(color).ok())
 647                // Fall back to `modified`, for backwards compatibility.
 648                .or(status_colors.modified),
 649            version_control_renamed: self
 650                .version_control_renamed
 651                .as_ref()
 652                .and_then(|color| try_parse_color(color).ok())
 653                // Fall back to `modified`, for backwards compatibility.
 654                .or(status_colors.modified),
 655            version_control_conflict: self
 656                .version_control_conflict
 657                .as_ref()
 658                .and_then(|color| try_parse_color(color).ok())
 659                // Fall back to `ignored`, for backwards compatibility.
 660                .or(status_colors.ignored),
 661            version_control_ignored: self
 662                .version_control_ignored
 663                .as_ref()
 664                .and_then(|color| try_parse_color(color).ok())
 665                // Fall back to `conflict`, for backwards compatibility.
 666                .or(status_colors.ignored),
 667            #[allow(deprecated)]
 668            version_control_conflict_marker_ours: self
 669                .version_control_conflict_marker_ours
 670                .as_ref()
 671                .or(self.version_control_conflict_ours_background.as_ref())
 672                .and_then(|color| try_parse_color(color).ok()),
 673            #[allow(deprecated)]
 674            version_control_conflict_marker_theirs: self
 675                .version_control_conflict_marker_theirs
 676                .as_ref()
 677                .or(self.version_control_conflict_theirs_background.as_ref())
 678                .and_then(|color| try_parse_color(color).ok()),
 679        }
 680    }
 681}
 682
 683#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
 684#[serde(default)]
 685pub struct StatusColorsContent {
 686    /// Indicates some kind of conflict, like a file changed on disk while it was open, or
 687    /// merge conflicts in a Git repository.
 688    #[serde(rename = "conflict")]
 689    pub conflict: Option<String>,
 690
 691    #[serde(rename = "conflict.background")]
 692    pub conflict_background: Option<String>,
 693
 694    #[serde(rename = "conflict.border")]
 695    pub conflict_border: Option<String>,
 696
 697    /// Indicates something new, like a new file added to a Git repository.
 698    #[serde(rename = "created")]
 699    pub created: Option<String>,
 700
 701    #[serde(rename = "created.background")]
 702    pub created_background: Option<String>,
 703
 704    #[serde(rename = "created.border")]
 705    pub created_border: Option<String>,
 706
 707    /// Indicates that something no longer exists, like a deleted file.
 708    #[serde(rename = "deleted")]
 709    pub deleted: Option<String>,
 710
 711    #[serde(rename = "deleted.background")]
 712    pub deleted_background: Option<String>,
 713
 714    #[serde(rename = "deleted.border")]
 715    pub deleted_border: Option<String>,
 716
 717    /// Indicates a system error, a failed operation or a diagnostic error.
 718    #[serde(rename = "error")]
 719    pub error: Option<String>,
 720
 721    #[serde(rename = "error.background")]
 722    pub error_background: Option<String>,
 723
 724    #[serde(rename = "error.border")]
 725    pub error_border: Option<String>,
 726
 727    /// Represents a hidden status, such as a file being hidden in a file tree.
 728    #[serde(rename = "hidden")]
 729    pub hidden: Option<String>,
 730
 731    #[serde(rename = "hidden.background")]
 732    pub hidden_background: Option<String>,
 733
 734    #[serde(rename = "hidden.border")]
 735    pub hidden_border: Option<String>,
 736
 737    /// Indicates a hint or some kind of additional information.
 738    #[serde(rename = "hint")]
 739    pub hint: Option<String>,
 740
 741    #[serde(rename = "hint.background")]
 742    pub hint_background: Option<String>,
 743
 744    #[serde(rename = "hint.border")]
 745    pub hint_border: Option<String>,
 746
 747    /// Indicates that something is deliberately ignored, such as a file or operation ignored by Git.
 748    #[serde(rename = "ignored")]
 749    pub ignored: Option<String>,
 750
 751    #[serde(rename = "ignored.background")]
 752    pub ignored_background: Option<String>,
 753
 754    #[serde(rename = "ignored.border")]
 755    pub ignored_border: Option<String>,
 756
 757    /// Represents informational status updates or messages.
 758    #[serde(rename = "info")]
 759    pub info: Option<String>,
 760
 761    #[serde(rename = "info.background")]
 762    pub info_background: Option<String>,
 763
 764    #[serde(rename = "info.border")]
 765    pub info_border: Option<String>,
 766
 767    /// Indicates a changed or altered status, like a file that has been edited.
 768    #[serde(rename = "modified")]
 769    pub modified: Option<String>,
 770
 771    #[serde(rename = "modified.background")]
 772    pub modified_background: Option<String>,
 773
 774    #[serde(rename = "modified.border")]
 775    pub modified_border: Option<String>,
 776
 777    /// Indicates something that is predicted, like automatic code completion, or generated code.
 778    #[serde(rename = "predictive")]
 779    pub predictive: Option<String>,
 780
 781    #[serde(rename = "predictive.background")]
 782    pub predictive_background: Option<String>,
 783
 784    #[serde(rename = "predictive.border")]
 785    pub predictive_border: Option<String>,
 786
 787    /// Represents a renamed status, such as a file that has been renamed.
 788    #[serde(rename = "renamed")]
 789    pub renamed: Option<String>,
 790
 791    #[serde(rename = "renamed.background")]
 792    pub renamed_background: Option<String>,
 793
 794    #[serde(rename = "renamed.border")]
 795    pub renamed_border: Option<String>,
 796
 797    /// Indicates a successful operation or task completion.
 798    #[serde(rename = "success")]
 799    pub success: Option<String>,
 800
 801    #[serde(rename = "success.background")]
 802    pub success_background: Option<String>,
 803
 804    #[serde(rename = "success.border")]
 805    pub success_border: Option<String>,
 806
 807    /// Indicates some kind of unreachable status, like a block of code that can never be reached.
 808    #[serde(rename = "unreachable")]
 809    pub unreachable: Option<String>,
 810
 811    #[serde(rename = "unreachable.background")]
 812    pub unreachable_background: Option<String>,
 813
 814    #[serde(rename = "unreachable.border")]
 815    pub unreachable_border: Option<String>,
 816
 817    /// Represents a warning status, like an operation that is about to fail.
 818    #[serde(rename = "warning")]
 819    pub warning: Option<String>,
 820
 821    #[serde(rename = "warning.background")]
 822    pub warning_background: Option<String>,
 823
 824    #[serde(rename = "warning.border")]
 825    pub warning_border: Option<String>,
 826}
 827
 828impl StatusColorsContent {
 829    /// Returns a [`StatusColorsRefinement`] based on the colors in the [`StatusColorsContent`].
 830    pub fn status_colors_refinement(&self) -> StatusColorsRefinement {
 831        StatusColorsRefinement {
 832            conflict: self
 833                .conflict
 834                .as_ref()
 835                .and_then(|color| try_parse_color(color).ok()),
 836            conflict_background: self
 837                .conflict_background
 838                .as_ref()
 839                .and_then(|color| try_parse_color(color).ok()),
 840            conflict_border: self
 841                .conflict_border
 842                .as_ref()
 843                .and_then(|color| try_parse_color(color).ok()),
 844            created: self
 845                .created
 846                .as_ref()
 847                .and_then(|color| try_parse_color(color).ok()),
 848            created_background: self
 849                .created_background
 850                .as_ref()
 851                .and_then(|color| try_parse_color(color).ok()),
 852            created_border: self
 853                .created_border
 854                .as_ref()
 855                .and_then(|color| try_parse_color(color).ok()),
 856            deleted: self
 857                .deleted
 858                .as_ref()
 859                .and_then(|color| try_parse_color(color).ok()),
 860            deleted_background: self
 861                .deleted_background
 862                .as_ref()
 863                .and_then(|color| try_parse_color(color).ok()),
 864            deleted_border: self
 865                .deleted_border
 866                .as_ref()
 867                .and_then(|color| try_parse_color(color).ok()),
 868            error: self
 869                .error
 870                .as_ref()
 871                .and_then(|color| try_parse_color(color).ok()),
 872            error_background: self
 873                .error_background
 874                .as_ref()
 875                .and_then(|color| try_parse_color(color).ok()),
 876            error_border: self
 877                .error_border
 878                .as_ref()
 879                .and_then(|color| try_parse_color(color).ok()),
 880            hidden: self
 881                .hidden
 882                .as_ref()
 883                .and_then(|color| try_parse_color(color).ok()),
 884            hidden_background: self
 885                .hidden_background
 886                .as_ref()
 887                .and_then(|color| try_parse_color(color).ok()),
 888            hidden_border: self
 889                .hidden_border
 890                .as_ref()
 891                .and_then(|color| try_parse_color(color).ok()),
 892            hint: self
 893                .hint
 894                .as_ref()
 895                .and_then(|color| try_parse_color(color).ok()),
 896            hint_background: self
 897                .hint_background
 898                .as_ref()
 899                .and_then(|color| try_parse_color(color).ok()),
 900            hint_border: self
 901                .hint_border
 902                .as_ref()
 903                .and_then(|color| try_parse_color(color).ok()),
 904            ignored: self
 905                .ignored
 906                .as_ref()
 907                .and_then(|color| try_parse_color(color).ok()),
 908            ignored_background: self
 909                .ignored_background
 910                .as_ref()
 911                .and_then(|color| try_parse_color(color).ok()),
 912            ignored_border: self
 913                .ignored_border
 914                .as_ref()
 915                .and_then(|color| try_parse_color(color).ok()),
 916            info: self
 917                .info
 918                .as_ref()
 919                .and_then(|color| try_parse_color(color).ok()),
 920            info_background: self
 921                .info_background
 922                .as_ref()
 923                .and_then(|color| try_parse_color(color).ok()),
 924            info_border: self
 925                .info_border
 926                .as_ref()
 927                .and_then(|color| try_parse_color(color).ok()),
 928            modified: self
 929                .modified
 930                .as_ref()
 931                .and_then(|color| try_parse_color(color).ok()),
 932            modified_background: self
 933                .modified_background
 934                .as_ref()
 935                .and_then(|color| try_parse_color(color).ok()),
 936            modified_border: self
 937                .modified_border
 938                .as_ref()
 939                .and_then(|color| try_parse_color(color).ok()),
 940            predictive: self
 941                .predictive
 942                .as_ref()
 943                .and_then(|color| try_parse_color(color).ok()),
 944            predictive_background: self
 945                .predictive_background
 946                .as_ref()
 947                .and_then(|color| try_parse_color(color).ok()),
 948            predictive_border: self
 949                .predictive_border
 950                .as_ref()
 951                .and_then(|color| try_parse_color(color).ok()),
 952            renamed: self
 953                .renamed
 954                .as_ref()
 955                .and_then(|color| try_parse_color(color).ok()),
 956            renamed_background: self
 957                .renamed_background
 958                .as_ref()
 959                .and_then(|color| try_parse_color(color).ok()),
 960            renamed_border: self
 961                .renamed_border
 962                .as_ref()
 963                .and_then(|color| try_parse_color(color).ok()),
 964            success: self
 965                .success
 966                .as_ref()
 967                .and_then(|color| try_parse_color(color).ok()),
 968            success_background: self
 969                .success_background
 970                .as_ref()
 971                .and_then(|color| try_parse_color(color).ok()),
 972            success_border: self
 973                .success_border
 974                .as_ref()
 975                .and_then(|color| try_parse_color(color).ok()),
 976            unreachable: self
 977                .unreachable
 978                .as_ref()
 979                .and_then(|color| try_parse_color(color).ok()),
 980            unreachable_background: self
 981                .unreachable_background
 982                .as_ref()
 983                .and_then(|color| try_parse_color(color).ok()),
 984            unreachable_border: self
 985                .unreachable_border
 986                .as_ref()
 987                .and_then(|color| try_parse_color(color).ok()),
 988            warning: self
 989                .warning
 990                .as_ref()
 991                .and_then(|color| try_parse_color(color).ok()),
 992            warning_background: self
 993                .warning_background
 994                .as_ref()
 995                .and_then(|color| try_parse_color(color).ok()),
 996            warning_border: self
 997                .warning_border
 998                .as_ref()
 999                .and_then(|color| try_parse_color(color).ok()),
1000        }
1001    }
1002}
1003
1004#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
1005pub struct AccentContent(pub Option<String>);
1006
1007#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
1008pub struct PlayerColorContent {
1009    pub cursor: Option<String>,
1010    pub background: Option<String>,
1011    pub selection: Option<String>,
1012}
1013
1014#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
1015#[serde(rename_all = "snake_case")]
1016pub enum FontStyleContent {
1017    Normal,
1018    Italic,
1019    Oblique,
1020}
1021
1022impl From<FontStyleContent> for FontStyle {
1023    fn from(value: FontStyleContent) -> Self {
1024        match value {
1025            FontStyleContent::Normal => FontStyle::Normal,
1026            FontStyleContent::Italic => FontStyle::Italic,
1027            FontStyleContent::Oblique => FontStyle::Oblique,
1028        }
1029    }
1030}
1031
1032#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, JsonSchema_repr, PartialEq)]
1033#[repr(u16)]
1034pub enum FontWeightContent {
1035    Thin = 100,
1036    ExtraLight = 200,
1037    Light = 300,
1038    Normal = 400,
1039    Medium = 500,
1040    Semibold = 600,
1041    Bold = 700,
1042    ExtraBold = 800,
1043    Black = 900,
1044}
1045
1046impl From<FontWeightContent> for FontWeight {
1047    fn from(value: FontWeightContent) -> Self {
1048        match value {
1049            FontWeightContent::Thin => FontWeight::THIN,
1050            FontWeightContent::ExtraLight => FontWeight::EXTRA_LIGHT,
1051            FontWeightContent::Light => FontWeight::LIGHT,
1052            FontWeightContent::Normal => FontWeight::NORMAL,
1053            FontWeightContent::Medium => FontWeight::MEDIUM,
1054            FontWeightContent::Semibold => FontWeight::SEMIBOLD,
1055            FontWeightContent::Bold => FontWeight::BOLD,
1056            FontWeightContent::ExtraBold => FontWeight::EXTRA_BOLD,
1057            FontWeightContent::Black => FontWeight::BLACK,
1058        }
1059    }
1060}