term_model/term/
color.rs
1use std::fmt;
2use std::ops::{Index, IndexMut, Mul};
3use std::str::FromStr;
4
5use log::{error, trace};
6use serde::de::Visitor;
7use serde::{Deserialize, Deserializer, Serialize};
8
9use crate::ansi;
10use crate::config::Colors;
11
12pub const COUNT: usize = 269;
13
14pub const RED: Rgb = Rgb { r: 0xff, g: 0x0, b: 0x0 };
15pub const YELLOW: Rgb = Rgb { r: 0xff, g: 0xff, b: 0x0 };
16
17#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Serialize)]
18pub struct Rgb {
19 pub r: u8,
20 pub g: u8,
21 pub b: u8,
22}
23
24impl Mul<f32> for Rgb {
26 type Output = Rgb;
27
28 fn mul(self, rhs: f32) -> Rgb {
29 let result = Rgb {
30 r: (f32::from(self.r) * rhs).max(0.0).min(255.0) as u8,
31 g: (f32::from(self.g) * rhs).max(0.0).min(255.0) as u8,
32 b: (f32::from(self.b) * rhs).max(0.0).min(255.0) as u8,
33 };
34
35 trace!("Scaling RGB by {} from {:?} to {:?}", rhs, self, result);
36
37 result
38 }
39}
40
41impl<'de> Deserialize<'de> for Rgb {
46 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
47 where
48 D: Deserializer<'de>,
49 {
50 struct RgbVisitor;
51
52 #[derive(Deserialize)]
54 struct RgbDerivedDeser {
55 r: u8,
56 g: u8,
57 b: u8,
58 }
59
60 impl<'a> Visitor<'a> for RgbVisitor {
61 type Value = Rgb;
62
63 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.write_str("hex color like 0xff00ff")
65 }
66
67 fn visit_str<E>(self, value: &str) -> ::std::result::Result<Rgb, E>
68 where
69 E: ::serde::de::Error,
70 {
71 Rgb::from_str(&value[..])
72 .map_err(|_| E::custom("failed to parse rgb; expected hex color like 0xff00ff"))
73 }
74 }
75
76 let value = serde_json::Value::deserialize(deserializer)?;
78
79 if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) {
81 return Ok(Rgb { r, g, b });
82 }
83
84 match value.deserialize_str(RgbVisitor) {
86 Ok(rgb) => Ok(rgb),
87 Err(err) => {
88 error!("Problem with config: {}; using color #000000", err);
89 Ok(Rgb::default())
90 }
91 }
92 }
93}
94
95impl FromStr for Rgb {
96 type Err = ();
97
98 fn from_str(s: &str) -> ::std::result::Result<Rgb, ()> {
99 let mut chars = s.chars();
100 let mut rgb = Rgb::default();
101
102 macro_rules! component {
103 ($($c:ident),*) => {
104 $(
105 match chars.next().and_then(|c| c.to_digit(16)) {
106 Some(val) => rgb.$c = (val as u8) << 4,
107 None => return Err(())
108 }
109
110 match chars.next().and_then(|c| c.to_digit(16)) {
111 Some(val) => rgb.$c |= val as u8,
112 None => return Err(())
113 }
114 )*
115 }
116 }
117
118 match chars.next() {
119 Some('0') => {
120 if chars.next() != Some('x') {
121 return Err(());
122 }
123 }
124 Some('#') => (),
125 _ => return Err(()),
126 }
127
128 component!(r, g, b);
129
130 Ok(rgb)
131 }
132}
133
134#[derive(Copy, Clone)]
142pub struct List([Rgb; COUNT]);
143
144impl<'a> From<&'a Colors> for List {
145 fn from(colors: &Colors) -> List {
146 let mut list = List([Rgb::default(); COUNT]);
148
149 list.fill_named(colors);
150 list.fill_cube(colors);
151 list.fill_gray_ramp(colors);
152
153 list
154 }
155}
156
157impl List {
158 pub fn fill_named(&mut self, colors: &Colors) {
159 self[ansi::NamedColor::Black] = colors.normal().black;
161 self[ansi::NamedColor::Red] = colors.normal().red;
162 self[ansi::NamedColor::Green] = colors.normal().green;
163 self[ansi::NamedColor::Yellow] = colors.normal().yellow;
164 self[ansi::NamedColor::Blue] = colors.normal().blue;
165 self[ansi::NamedColor::Magenta] = colors.normal().magenta;
166 self[ansi::NamedColor::Cyan] = colors.normal().cyan;
167 self[ansi::NamedColor::White] = colors.normal().white;
168
169 self[ansi::NamedColor::BrightBlack] = colors.bright().black;
171 self[ansi::NamedColor::BrightRed] = colors.bright().red;
172 self[ansi::NamedColor::BrightGreen] = colors.bright().green;
173 self[ansi::NamedColor::BrightYellow] = colors.bright().yellow;
174 self[ansi::NamedColor::BrightBlue] = colors.bright().blue;
175 self[ansi::NamedColor::BrightMagenta] = colors.bright().magenta;
176 self[ansi::NamedColor::BrightCyan] = colors.bright().cyan;
177 self[ansi::NamedColor::BrightWhite] = colors.bright().white;
178 self[ansi::NamedColor::BrightForeground] =
179 colors.primary.bright_foreground.unwrap_or(colors.primary.foreground);
180
181 self[ansi::NamedColor::Foreground] = colors.primary.foreground;
183 self[ansi::NamedColor::Background] = colors.primary.background;
184
185 self[ansi::NamedColor::Cursor] = colors.cursor.cursor.unwrap_or_else(Rgb::default);
187
188 self[ansi::NamedColor::DimForeground] =
190 colors.primary.dim_foreground.unwrap_or(colors.primary.foreground * 0.66);
191 match colors.dim {
192 Some(ref dim) => {
193 trace!("Using config-provided dim colors");
194 self[ansi::NamedColor::DimBlack] = dim.black;
195 self[ansi::NamedColor::DimRed] = dim.red;
196 self[ansi::NamedColor::DimGreen] = dim.green;
197 self[ansi::NamedColor::DimYellow] = dim.yellow;
198 self[ansi::NamedColor::DimBlue] = dim.blue;
199 self[ansi::NamedColor::DimMagenta] = dim.magenta;
200 self[ansi::NamedColor::DimCyan] = dim.cyan;
201 self[ansi::NamedColor::DimWhite] = dim.white;
202 }
203 None => {
204 trace!("Deriving dim colors from normal colors");
205 self[ansi::NamedColor::DimBlack] = colors.normal().black * 0.66;
206 self[ansi::NamedColor::DimRed] = colors.normal().red * 0.66;
207 self[ansi::NamedColor::DimGreen] = colors.normal().green * 0.66;
208 self[ansi::NamedColor::DimYellow] = colors.normal().yellow * 0.66;
209 self[ansi::NamedColor::DimBlue] = colors.normal().blue * 0.66;
210 self[ansi::NamedColor::DimMagenta] = colors.normal().magenta * 0.66;
211 self[ansi::NamedColor::DimCyan] = colors.normal().cyan * 0.66;
212 self[ansi::NamedColor::DimWhite] = colors.normal().white * 0.66;
213 }
214 }
215 }
216
217 pub fn fill_cube(&mut self, colors: &Colors) {
218 let mut index: usize = 16;
219 for r in 0..6 {
221 for g in 0..6 {
222 for b in 0..6 {
223 if let Some(indexed_color) =
225 colors.indexed_colors.iter().find(|ic| ic.index == index as u8)
226 {
227 self[index] = indexed_color.color;
228 } else {
229 self[index] = Rgb {
230 r: if r == 0 { 0 } else { r * 40 + 55 },
231 b: if b == 0 { 0 } else { b * 40 + 55 },
232 g: if g == 0 { 0 } else { g * 40 + 55 },
233 };
234 }
235 index += 1;
236 }
237 }
238 }
239
240 debug_assert!(index == 232);
241 }
242
243 pub fn fill_gray_ramp(&mut self, colors: &Colors) {
244 let mut index: usize = 232;
245
246 for i in 0..24 {
247 let color_index = 16 + 216 + i;
249
250 if let Some(indexed_color) =
252 colors.indexed_colors.iter().find(|ic| ic.index == color_index)
253 {
254 self[index] = indexed_color.color;
255 index += 1;
256 continue;
257 }
258
259 let value = i * 10 + 8;
260 self[index] = Rgb { r: value, g: value, b: value };
261 index += 1;
262 }
263
264 debug_assert!(index == 256);
265 }
266}
267
268impl fmt::Debug for List {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 f.write_str("List[..]")
271 }
272}
273
274impl Index<ansi::NamedColor> for List {
275 type Output = Rgb;
276
277 #[inline]
278 fn index(&self, idx: ansi::NamedColor) -> &Self::Output {
279 &self.0[idx as usize]
280 }
281}
282
283impl IndexMut<ansi::NamedColor> for List {
284 #[inline]
285 fn index_mut(&mut self, idx: ansi::NamedColor) -> &mut Self::Output {
286 &mut self.0[idx as usize]
287 }
288}
289
290impl Index<usize> for List {
291 type Output = Rgb;
292
293 #[inline]
294 fn index(&self, idx: usize) -> &Self::Output {
295 &self.0[idx]
296 }
297}
298
299impl IndexMut<usize> for List {
300 #[inline]
301 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
302 &mut self.0[idx]
303 }
304}
305
306impl Index<u8> for List {
307 type Output = Rgb;
308
309 #[inline]
310 fn index(&self, idx: u8) -> &Self::Output {
311 &self.0[idx as usize]
312 }
313}
314
315impl IndexMut<u8> for List {
316 #[inline]
317 fn index_mut(&mut self, idx: u8) -> &mut Self::Output {
318 &mut self.0[idx as usize]
319 }
320}