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