syntastica_core/style.rs
1//! Defines the [`Style`] and [`Color`] types used by
2//! [`ResolvedTheme`](crate::theme::ResolvedTheme)s.
3
4use std::hash::{Hash, Hasher};
5
6use palette::Srgb;
7
8/// A non-transparent color with red, green, and blue values between 0 and 255.
9///
10/// The type is an alias to [`palette::Srgb<u8>`], so there are many ways of obtaining instances of
11/// this type. For example, you could add a dependency an `palette` with the
12/// <span class="stab portability"><code>named</code></span> feature enabled, to access a list of
13/// predefined colors in the `palette::named` module.
14pub type Color = Srgb<u8>;
15
16/// Defines how to style a region of text.
17///
18/// Besides a main foreground [`Color`], an optional background color and the following four
19/// booleans can be set:
20///
21/// - `underline`
22/// - `strikethrough`
23/// - `italic`
24/// - `bold`
25///
26/// # Instantiation
27///
28/// A [`Style`] can mainly be created in three ways:
29///
30/// - Using [`Style::new`] to specify the colors and all boolean flags explicitly.
31/// - Using [`Style::color_only`] to specify the foreground color's red, green, and blue values and
32/// keep all booleans disabled.
33/// - Using the [`From<Color>`](#impl-From<Color>-for-Style) implementation to create a [`Style`]
34/// with the given [`Color`] and all booleans disabled.
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct Style {
38 color: Color,
39 bg: Option<Color>,
40 underline: bool,
41 strikethrough: bool,
42 italic: bool,
43 bold: bool,
44}
45
46impl Style {
47 /// Create a new [`Style`].
48 pub fn new(
49 color: Color,
50 bg: Option<Color>,
51 underline: bool,
52 strikethrough: bool,
53 italic: bool,
54 bold: bool,
55 ) -> Self {
56 Self {
57 color,
58 bg,
59 underline,
60 strikethrough,
61 italic,
62 bold,
63 }
64 }
65
66 /// Create a new [`Style`] with only foreground color information attached.
67 ///
68 /// The function does not accept a [`Color`] instance, but instead takes the red, green, and
69 /// blue values separately to create a new color. To create a color-only [`Style`] from an
70 /// existing [`Color`] instance, use the [`From<Color>`](#impl-From<Color>-for-Style)
71 /// implementation.
72 pub fn color_only(red: u8, green: u8, blue: u8) -> Self {
73 Self::new(
74 Color::new(red, green, blue),
75 None,
76 false,
77 false,
78 false,
79 false,
80 )
81 }
82
83 /// Get this [`Style`]'s foreground [`Color`].
84 pub fn color(&self) -> Color {
85 self.color
86 }
87
88 /// Get this [`Style`]'s background [`Color`].
89 pub fn bg(&self) -> Option<Color> {
90 self.bg
91 }
92
93 /// Whether this [`Style`] is underlined.
94 pub fn underline(&self) -> bool {
95 self.underline
96 }
97
98 /// Whether this [`Style`] is strikethrough.
99 pub fn strikethrough(&self) -> bool {
100 self.strikethrough
101 }
102
103 /// Whether this [`Style`] is italic.
104 pub fn italic(&self) -> bool {
105 self.italic
106 }
107
108 /// Whether this [`Style`] is bold.
109 pub fn bold(&self) -> bool {
110 self.bold
111 }
112}
113
114impl From<Color> for Style {
115 fn from(color: Color) -> Self {
116 Self::new(color, None, false, false, false, false)
117 }
118}
119
120// palette's `Srgb` type does not implement `Hash`, but because we use `u8` as the generic type
121// argument, we can implement it on `Style` manually
122impl Hash for Style {
123 fn hash<H: Hasher>(&self, state: &mut H) {
124 Hash::hash(&self.color.red, state);
125 Hash::hash(&self.color.green, state);
126 Hash::hash(&self.color.blue, state);
127 Hash::hash(&self.color.standard, state);
128
129 if let Some(color) = self.bg {
130 Hash::hash(&true, state);
131 Hash::hash(&color.red, state);
132 Hash::hash(&color.green, state);
133 Hash::hash(&color.blue, state);
134 Hash::hash(&color.standard, state);
135 } else {
136 Hash::hash(&false, state);
137 }
138
139 Hash::hash(&self.underline, state);
140 Hash::hash(&self.strikethrough, state);
141 Hash::hash(&self.italic, state);
142 Hash::hash(&self.bold, state);
143 }
144}