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}