1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4#![warn(missing_docs)]
5#![warn(clippy::print_stderr)]
6#![warn(clippy::print_stdout)]
7
8pub mod palette;
9
10use anstyle::RgbColor as Rgb;
11
12pub const fn color_to_rgb(color: anstyle::Color, palette: palette::Palette) -> anstyle::RgbColor {
17 match color {
18 anstyle::Color::Ansi(color) => ansi_to_rgb(color, palette),
19 anstyle::Color::Ansi256(color) => xterm_to_rgb(color, palette),
20 anstyle::Color::Rgb(color) => color,
21 }
22}
23
24pub const fn color_to_xterm(color: anstyle::Color) -> anstyle::Ansi256Color {
29 match color {
30 anstyle::Color::Ansi(color) => anstyle::Ansi256Color::from_ansi(color),
31 anstyle::Color::Ansi256(color) => color,
32 anstyle::Color::Rgb(color) => rgb_to_xterm(color),
33 }
34}
35
36pub const fn color_to_ansi(color: anstyle::Color, palette: palette::Palette) -> anstyle::AnsiColor {
41 match color {
42 anstyle::Color::Ansi(color) => color,
43 anstyle::Color::Ansi256(color) => xterm_to_ansi(color, palette),
44 anstyle::Color::Rgb(color) => rgb_to_ansi(color, palette),
45 }
46}
47
48pub const fn ansi_to_rgb(
53 color: anstyle::AnsiColor,
54 palette: palette::Palette,
55) -> anstyle::RgbColor {
56 palette.rgb_from_ansi(color)
57}
58
59pub const fn xterm_to_rgb(
64 color: anstyle::Ansi256Color,
65 palette: palette::Palette,
66) -> anstyle::RgbColor {
67 match palette.rgb_from_index(color.0) {
68 Some(rgb) => rgb,
69 None => XTERM_COLORS[color.0 as usize],
70 }
71}
72
73pub const fn xterm_to_ansi(
78 color: anstyle::Ansi256Color,
79 palette: palette::Palette,
80) -> anstyle::AnsiColor {
81 match color.0 {
82 0 => anstyle::AnsiColor::Black,
83 1 => anstyle::AnsiColor::Red,
84 2 => anstyle::AnsiColor::Green,
85 3 => anstyle::AnsiColor::Yellow,
86 4 => anstyle::AnsiColor::Blue,
87 5 => anstyle::AnsiColor::Magenta,
88 6 => anstyle::AnsiColor::Cyan,
89 7 => anstyle::AnsiColor::White,
90 8 => anstyle::AnsiColor::BrightBlack,
91 9 => anstyle::AnsiColor::BrightRed,
92 10 => anstyle::AnsiColor::BrightGreen,
93 11 => anstyle::AnsiColor::BrightYellow,
94 12 => anstyle::AnsiColor::BrightBlue,
95 13 => anstyle::AnsiColor::BrightMagenta,
96 14 => anstyle::AnsiColor::BrightCyan,
97 15 => anstyle::AnsiColor::BrightWhite,
98 _ => {
99 let rgb = XTERM_COLORS[color.0 as usize];
100 palette.find_match(rgb)
101 }
102 }
103}
104
105pub const fn rgb_to_ansi(
110 color: anstyle::RgbColor,
111 palette: palette::Palette,
112) -> anstyle::AnsiColor {
113 palette.find_match(color)
114}
115
116pub const fn rgb_to_xterm(color: anstyle::RgbColor) -> anstyle::Ansi256Color {
118 let index = find_xterm_match(color);
120 anstyle::Ansi256Color(index as u8)
121}
122
123const fn find_xterm_match(color: anstyle::RgbColor) -> usize {
124 let mut best_index = 16;
125 let mut best_distance = distance(color, XTERM_COLORS[best_index]);
126
127 let mut index = best_index + 1;
128 while index < XTERM_COLORS.len() {
129 let distance = distance(color, XTERM_COLORS[index]);
130 if distance < best_distance {
131 best_index = index;
132 best_distance = distance;
133 }
134
135 index += 1;
136 }
137
138 best_index
139}
140
141pub(crate) const fn distance(c1: anstyle::RgbColor, c2: anstyle::RgbColor) -> u32 {
143 let c1_r = c1.r() as i32;
144 let c1_g = c1.g() as i32;
145 let c1_b = c1.b() as i32;
146 let c2_r = c2.r() as i32;
147 let c2_g = c2.g() as i32;
148 let c2_b = c2.b() as i32;
149
150 let r_sum = c1_r + c2_r;
151 let r_delta = c1_r - c2_r;
152 let g_delta = c1_g - c2_g;
153 let b_delta = c1_b - c2_b;
154
155 let r = (2 * 512 + r_sum) * r_delta * r_delta;
156 let g = 4 * g_delta * g_delta * (1 << 8);
157 let b = (2 * 767 - r_sum) * b_delta * b_delta;
158
159 (r + g + b) as u32
160}
161
162const XTERM_COLORS: [anstyle::RgbColor; 256] = [
163 Rgb(0, 0, 0),
165 Rgb(0, 0, 0),
166 Rgb(0, 0, 0),
167 Rgb(0, 0, 0),
168 Rgb(0, 0, 0),
169 Rgb(0, 0, 0),
170 Rgb(0, 0, 0),
171 Rgb(0, 0, 0),
172 Rgb(0, 0, 0),
173 Rgb(0, 0, 0),
174 Rgb(0, 0, 0),
175 Rgb(0, 0, 0),
176 Rgb(0, 0, 0),
177 Rgb(0, 0, 0),
178 Rgb(0, 0, 0),
179 Rgb(0, 0, 0),
180 Rgb(0, 0, 0),
183 Rgb(0, 0, 95),
184 Rgb(0, 0, 135),
185 Rgb(0, 0, 175),
186 Rgb(0, 0, 215),
187 Rgb(0, 0, 255),
188 Rgb(0, 95, 0),
189 Rgb(0, 95, 95),
190 Rgb(0, 95, 135),
191 Rgb(0, 95, 175),
192 Rgb(0, 95, 215),
193 Rgb(0, 95, 255),
194 Rgb(0, 135, 0),
195 Rgb(0, 135, 95),
196 Rgb(0, 135, 135),
197 Rgb(0, 135, 175),
198 Rgb(0, 135, 215),
199 Rgb(0, 135, 255),
200 Rgb(0, 175, 0),
201 Rgb(0, 175, 95),
202 Rgb(0, 175, 135),
203 Rgb(0, 175, 175),
204 Rgb(0, 175, 215),
205 Rgb(0, 175, 255),
206 Rgb(0, 215, 0),
207 Rgb(0, 215, 95),
208 Rgb(0, 215, 135),
209 Rgb(0, 215, 175),
210 Rgb(0, 215, 215),
211 Rgb(0, 215, 255),
212 Rgb(0, 255, 0),
213 Rgb(0, 255, 95),
214 Rgb(0, 255, 135),
215 Rgb(0, 255, 175),
216 Rgb(0, 255, 215),
217 Rgb(0, 255, 255),
218 Rgb(95, 0, 0),
219 Rgb(95, 0, 95),
220 Rgb(95, 0, 135),
221 Rgb(95, 0, 175),
222 Rgb(95, 0, 215),
223 Rgb(95, 0, 255),
224 Rgb(95, 95, 0),
225 Rgb(95, 95, 95),
226 Rgb(95, 95, 135),
227 Rgb(95, 95, 175),
228 Rgb(95, 95, 215),
229 Rgb(95, 95, 255),
230 Rgb(95, 135, 0),
231 Rgb(95, 135, 95),
232 Rgb(95, 135, 135),
233 Rgb(95, 135, 175),
234 Rgb(95, 135, 215),
235 Rgb(95, 135, 255),
236 Rgb(95, 175, 0),
237 Rgb(95, 175, 95),
238 Rgb(95, 175, 135),
239 Rgb(95, 175, 175),
240 Rgb(95, 175, 215),
241 Rgb(95, 175, 255),
242 Rgb(95, 215, 0),
243 Rgb(95, 215, 95),
244 Rgb(95, 215, 135),
245 Rgb(95, 215, 175),
246 Rgb(95, 215, 215),
247 Rgb(95, 215, 255),
248 Rgb(95, 255, 0),
249 Rgb(95, 255, 95),
250 Rgb(95, 255, 135),
251 Rgb(95, 255, 175),
252 Rgb(95, 255, 215),
253 Rgb(95, 255, 255),
254 Rgb(135, 0, 0),
255 Rgb(135, 0, 95),
256 Rgb(135, 0, 135),
257 Rgb(135, 0, 175),
258 Rgb(135, 0, 215),
259 Rgb(135, 0, 255),
260 Rgb(135, 95, 0),
261 Rgb(135, 95, 95),
262 Rgb(135, 95, 135),
263 Rgb(135, 95, 175),
264 Rgb(135, 95, 215),
265 Rgb(135, 95, 255),
266 Rgb(135, 135, 0),
267 Rgb(135, 135, 95),
268 Rgb(135, 135, 135),
269 Rgb(135, 135, 175),
270 Rgb(135, 135, 215),
271 Rgb(135, 135, 255),
272 Rgb(135, 175, 0),
273 Rgb(135, 175, 95),
274 Rgb(135, 175, 135),
275 Rgb(135, 175, 175),
276 Rgb(135, 175, 215),
277 Rgb(135, 175, 255),
278 Rgb(135, 215, 0),
279 Rgb(135, 215, 95),
280 Rgb(135, 215, 135),
281 Rgb(135, 215, 175),
282 Rgb(135, 215, 215),
283 Rgb(135, 215, 255),
284 Rgb(135, 255, 0),
285 Rgb(135, 255, 95),
286 Rgb(135, 255, 135),
287 Rgb(135, 255, 175),
288 Rgb(135, 255, 215),
289 Rgb(135, 255, 255),
290 Rgb(175, 0, 0),
291 Rgb(175, 0, 95),
292 Rgb(175, 0, 135),
293 Rgb(175, 0, 175),
294 Rgb(175, 0, 215),
295 Rgb(175, 0, 255),
296 Rgb(175, 95, 0),
297 Rgb(175, 95, 95),
298 Rgb(175, 95, 135),
299 Rgb(175, 95, 175),
300 Rgb(175, 95, 215),
301 Rgb(175, 95, 255),
302 Rgb(175, 135, 0),
303 Rgb(175, 135, 95),
304 Rgb(175, 135, 135),
305 Rgb(175, 135, 175),
306 Rgb(175, 135, 215),
307 Rgb(175, 135, 255),
308 Rgb(175, 175, 0),
309 Rgb(175, 175, 95),
310 Rgb(175, 175, 135),
311 Rgb(175, 175, 175),
312 Rgb(175, 175, 215),
313 Rgb(175, 175, 255),
314 Rgb(175, 215, 0),
315 Rgb(175, 215, 95),
316 Rgb(175, 215, 135),
317 Rgb(175, 215, 175),
318 Rgb(175, 215, 215),
319 Rgb(175, 215, 255),
320 Rgb(175, 255, 0),
321 Rgb(175, 255, 95),
322 Rgb(175, 255, 135),
323 Rgb(175, 255, 175),
324 Rgb(175, 255, 215),
325 Rgb(175, 255, 255),
326 Rgb(215, 0, 0),
327 Rgb(215, 0, 95),
328 Rgb(215, 0, 135),
329 Rgb(215, 0, 175),
330 Rgb(215, 0, 215),
331 Rgb(215, 0, 255),
332 Rgb(215, 95, 0),
333 Rgb(215, 95, 95),
334 Rgb(215, 95, 135),
335 Rgb(215, 95, 175),
336 Rgb(215, 95, 215),
337 Rgb(215, 95, 255),
338 Rgb(215, 135, 0),
339 Rgb(215, 135, 95),
340 Rgb(215, 135, 135),
341 Rgb(215, 135, 175),
342 Rgb(215, 135, 215),
343 Rgb(215, 135, 255),
344 Rgb(215, 175, 0),
345 Rgb(215, 175, 95),
346 Rgb(215, 175, 135),
347 Rgb(215, 175, 175),
348 Rgb(215, 175, 215),
349 Rgb(215, 175, 255),
350 Rgb(215, 215, 0),
351 Rgb(215, 215, 95),
352 Rgb(215, 215, 135),
353 Rgb(215, 215, 175),
354 Rgb(215, 215, 215),
355 Rgb(215, 215, 255),
356 Rgb(215, 255, 0),
357 Rgb(215, 255, 95),
358 Rgb(215, 255, 135),
359 Rgb(215, 255, 175),
360 Rgb(215, 255, 215),
361 Rgb(215, 255, 255),
362 Rgb(255, 0, 0),
363 Rgb(255, 0, 95),
364 Rgb(255, 0, 135),
365 Rgb(255, 0, 175),
366 Rgb(255, 0, 215),
367 Rgb(255, 0, 255),
368 Rgb(255, 95, 0),
369 Rgb(255, 95, 95),
370 Rgb(255, 95, 135),
371 Rgb(255, 95, 175),
372 Rgb(255, 95, 215),
373 Rgb(255, 95, 255),
374 Rgb(255, 135, 0),
375 Rgb(255, 135, 95),
376 Rgb(255, 135, 135),
377 Rgb(255, 135, 175),
378 Rgb(255, 135, 215),
379 Rgb(255, 135, 255),
380 Rgb(255, 175, 0),
381 Rgb(255, 175, 95),
382 Rgb(255, 175, 135),
383 Rgb(255, 175, 175),
384 Rgb(255, 175, 215),
385 Rgb(255, 175, 255),
386 Rgb(255, 215, 0),
387 Rgb(255, 215, 95),
388 Rgb(255, 215, 135),
389 Rgb(255, 215, 175),
390 Rgb(255, 215, 215),
391 Rgb(255, 215, 255),
392 Rgb(255, 255, 0),
393 Rgb(255, 255, 95),
394 Rgb(255, 255, 135),
395 Rgb(255, 255, 175),
396 Rgb(255, 255, 215),
397 Rgb(255, 255, 255),
398 Rgb(8, 8, 8),
401 Rgb(18, 18, 18),
402 Rgb(28, 28, 28),
403 Rgb(38, 38, 38),
404 Rgb(48, 48, 48),
405 Rgb(58, 58, 58),
406 Rgb(68, 68, 68),
407 Rgb(78, 78, 78),
408 Rgb(88, 88, 88),
409 Rgb(98, 98, 98),
410 Rgb(108, 108, 108),
411 Rgb(118, 118, 118),
412 Rgb(128, 128, 128),
413 Rgb(138, 138, 138),
414 Rgb(148, 148, 148),
415 Rgb(158, 158, 158),
416 Rgb(168, 168, 168),
417 Rgb(178, 178, 178),
418 Rgb(188, 188, 188),
419 Rgb(198, 198, 198),
420 Rgb(208, 208, 208),
421 Rgb(218, 218, 218),
422 Rgb(228, 228, 228),
423 Rgb(238, 238, 238),
424];
425
426#[doc = include_str!("../README.md")]
427#[cfg(doctest)]
428pub struct ReadmeDoctests;