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