1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct Rgb {
10 pub r: u8,
11 pub g: u8,
12 pub b: u8,
13}
14
15impl Rgb {
16 #[must_use]
17 pub const fn new(r: u8, g: u8, b: u8) -> Self {
18 Self { r, g, b }
19 }
20
21 #[must_use]
22 pub const fn from_hex(hex: u32) -> Self {
23 Self {
24 r: ((hex >> 16) & 0xFF) as u8,
25 g: ((hex >> 8) & 0xFF) as u8,
26 b: (hex & 0xFF) as u8,
27 }
28 }
29
30 #[must_use]
31 pub fn to_hex(self) -> String {
32 format!("#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
33 }
34
35 #[must_use]
37 pub fn fg_ansi(self) -> String {
38 format!("\x1b[38;2;{};{};{}m", self.r, self.g, self.b)
39 }
40
41 #[must_use]
43 pub fn bg_ansi(self) -> String {
44 format!("\x1b[48;2;{};{};{}m", self.r, self.g, self.b)
45 }
46}
47
48pub const ANSI_RESET: &str = "\x1b[0m";
50
51#[allow(non_snake_case)]
53pub struct Nord;
54
55impl Nord {
56 pub const NORD0: Rgb = Rgb::new(0x2E, 0x34, 0x40);
58 pub const NORD1: Rgb = Rgb::new(0x3B, 0x42, 0x52);
59 pub const NORD2: Rgb = Rgb::new(0x43, 0x4C, 0x5E);
60 pub const NORD3: Rgb = Rgb::new(0x4C, 0x56, 0x6A);
61 pub const NORD4: Rgb = Rgb::new(0xD8, 0xDE, 0xE9);
63 pub const NORD5: Rgb = Rgb::new(0xE5, 0xE9, 0xF0);
64 pub const NORD6: Rgb = Rgb::new(0xEC, 0xEF, 0xF4);
65 pub const NORD7: Rgb = Rgb::new(0x8F, 0xBC, 0xBB);
67 pub const NORD8: Rgb = Rgb::new(0x88, 0xC0, 0xD0);
68 pub const NORD9: Rgb = Rgb::new(0x81, 0xA1, 0xC1);
69 pub const NORD10: Rgb = Rgb::new(0x5E, 0x81, 0xAC);
70 pub const NORD11: Rgb = Rgb::new(0xBF, 0x61, 0x6A); pub const NORD12: Rgb = Rgb::new(0xD0, 0x87, 0x70); pub const NORD13: Rgb = Rgb::new(0xEB, 0xCB, 0x8B); pub const NORD14: Rgb = Rgb::new(0xA3, 0xBE, 0x8C); pub const NORD15: Rgb = Rgb::new(0xB4, 0x8E, 0xAD); }
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn hex_round_trip() {
84 let c = Rgb::from_hex(0x5E_81_AC);
85 assert_eq!(c.to_hex(), "#5E81AC");
86 }
87
88 #[test]
89 fn palette_table_matches_rgb_new_byte_slots() {
90 assert_eq!(Nord::NORD0, Rgb::new(0x2E, 0x34, 0x40));
104 assert_eq!(Nord::NORD6, Rgb::new(0xEC, 0xEF, 0xF4));
105 assert_eq!(Nord::NORD10, Rgb::new(0x5E, 0x81, 0xAC));
106 assert_eq!(Nord::NORD11, Rgb::new(0xBF, 0x61, 0x6A));
107 }
108
109 #[test]
110 fn ansi_fg_shape() {
111 let c = Nord::NORD11;
112 let s = c.fg_ansi();
113 assert!(s.starts_with("\x1b[38;2;"));
114 }
115}