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}