1use std::{error, fmt, str::FromStr};
4
5use anstyle::RgbColor;
6use serde::{Deserialize, Serialize};
7
8use super::data::serde_color;
9
10#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
14pub struct Palette {
15 pub colors: TermColors,
17 pub intense_colors: TermColors,
19}
20
21impl Default for Palette {
23 fn default() -> Self {
24 Self::gjm8()
25 }
26}
27
28impl Palette {
29 const fn dracula() -> Self {
30 Self {
31 colors: TermColors {
32 black: RgbColor(0x28, 0x29, 0x36),
33 red: RgbColor(0xea, 0x51, 0xb2),
34 green: RgbColor(0xeb, 0xff, 0x87),
35 yellow: RgbColor(0x00, 0xf7, 0x69),
36 blue: RgbColor(0x62, 0xd6, 0xe8),
37 magenta: RgbColor(0xb4, 0x5b, 0xcf),
38 cyan: RgbColor(0xa1, 0xef, 0xe4),
39 white: RgbColor(0xe9, 0xe9, 0xf4),
40 },
41 intense_colors: TermColors {
42 black: RgbColor(0x62, 0x64, 0x83),
43 red: RgbColor(0xb4, 0x5b, 0xcf),
44 green: RgbColor(0x3a, 0x3c, 0x4e),
45 yellow: RgbColor(0x4d, 0x4f, 0x68),
46 blue: RgbColor(0x62, 0xd6, 0xe8),
47 magenta: RgbColor(0xf1, 0xf2, 0xf8),
48 cyan: RgbColor(0x00, 0xf7, 0x69),
49 white: RgbColor(0xf7, 0xf7, 0xfb),
50 },
51 }
52 }
53
54 const fn powershell() -> Self {
55 Self {
56 colors: TermColors {
57 black: RgbColor(0x0c, 0x0c, 0x0c),
58 red: RgbColor(0xc5, 0x0f, 0x1f),
59 green: RgbColor(0x13, 0xa1, 0x0e),
60 yellow: RgbColor(0xc1, 0x9c, 0x00),
61 blue: RgbColor(0x00, 0x37, 0xda),
62 magenta: RgbColor(0x88, 0x17, 0x98),
63 cyan: RgbColor(0x3a, 0x96, 0xdd),
64 white: RgbColor(0xcc, 0xcc, 0xcc),
65 },
66 intense_colors: TermColors {
67 black: RgbColor(0x76, 0x76, 0x76),
68 red: RgbColor(0xe7, 0x48, 0x56),
69 green: RgbColor(0x16, 0xc6, 0x0c),
70 yellow: RgbColor(0xf9, 0xf1, 0xa5),
71 blue: RgbColor(0x3b, 0x78, 0xff),
72 magenta: RgbColor(0xb4, 0x00, 0x9e),
73 cyan: RgbColor(0x61, 0xd6, 0xd6),
74 white: RgbColor(0xf2, 0xf2, 0xf2),
75 },
76 }
77 }
78
79 const fn xterm() -> Self {
80 Self {
81 colors: TermColors {
82 black: RgbColor(0, 0, 0),
83 red: RgbColor(0xcd, 0, 0),
84 green: RgbColor(0, 0xcd, 0),
85 yellow: RgbColor(0xcd, 0xcd, 0),
86 blue: RgbColor(0, 0, 0xee),
87 magenta: RgbColor(0xcd, 0, 0xcd),
88 cyan: RgbColor(0, 0xcd, 0xcd),
89 white: RgbColor(0xe5, 0xe5, 0xe5),
90 },
91 intense_colors: TermColors {
92 black: RgbColor(0x7f, 0x7f, 0x7f),
93 red: RgbColor(0xff, 0, 0),
94 green: RgbColor(0, 0xff, 0),
95 yellow: RgbColor(0xff, 0xff, 0),
96 blue: RgbColor(0x5c, 0x5c, 0xff),
97 magenta: RgbColor(0xff, 0, 0xff),
98 cyan: RgbColor(0, 0xff, 0xff),
99 white: RgbColor(0xff, 0xff, 0xff),
100 },
101 }
102 }
103
104 const fn ubuntu() -> Self {
105 Self {
106 colors: TermColors {
107 black: RgbColor(0x01, 0x01, 0x01),
108 red: RgbColor(0xde, 0x38, 0x2b),
109 green: RgbColor(0x38, 0xb5, 0x4a),
110 yellow: RgbColor(0xff, 0xc7, 0x06),
111 blue: RgbColor(0, 0x6f, 0xb8),
112 magenta: RgbColor(0x76, 0x26, 0x71),
113 cyan: RgbColor(0x2c, 0xb5, 0xe9),
114 white: RgbColor(0xcc, 0xcc, 0xcc),
115 },
116 intense_colors: TermColors {
117 black: RgbColor(0x80, 0x80, 0x80),
118 red: RgbColor(0xff, 0, 0),
119 green: RgbColor(0, 0xff, 0),
120 yellow: RgbColor(0xff, 0xff, 0),
121 blue: RgbColor(0, 0, 0xff),
122 magenta: RgbColor(0xff, 0, 0xff),
123 cyan: RgbColor(0, 0xff, 0xff),
124 white: RgbColor(0xff, 0xff, 0xff),
125 },
126 }
127 }
128
129 const fn gjm8() -> Self {
130 Self {
131 colors: TermColors {
132 black: RgbColor(0x1c, 0x1c, 0x1c),
133 red: RgbColor(0xff, 0x00, 0x5b),
134 green: RgbColor(0xce, 0xe3, 0x18),
135 yellow: RgbColor(0xff, 0xe7, 0x55),
136 blue: RgbColor(0x04, 0x8a, 0xc7),
137 magenta: RgbColor(0x83, 0x3c, 0x9f),
138 cyan: RgbColor(0x0a, 0xc1, 0xcd),
139 white: RgbColor(0xe5, 0xe5, 0xe5),
140 },
141 intense_colors: TermColors {
142 black: RgbColor(0x66, 0x66, 0x66),
143 red: RgbColor(0xff, 0x00, 0xa0),
144 green: RgbColor(0xcc, 0xff, 0x00),
145 yellow: RgbColor(0xff, 0x9f, 0x00),
146 blue: RgbColor(0x48, 0xc6, 0xff),
147 magenta: RgbColor(0xbe, 0x67, 0xe1),
148 cyan: RgbColor(0x63, 0xe7, 0xf0),
149 white: RgbColor(0xf3, 0xf3, 0xf3),
150 },
151 }
152 }
153}
154
155#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
159pub struct TermColors {
160 #[serde(with = "serde_color")]
162 pub black: RgbColor,
163 #[serde(with = "serde_color")]
165 pub red: RgbColor,
166 #[serde(with = "serde_color")]
168 pub green: RgbColor,
169 #[serde(with = "serde_color")]
171 pub yellow: RgbColor,
172 #[serde(with = "serde_color")]
174 pub blue: RgbColor,
175 #[serde(with = "serde_color")]
177 pub magenta: RgbColor,
178 #[serde(with = "serde_color")]
180 pub cyan: RgbColor,
181 #[serde(with = "serde_color")]
183 pub white: RgbColor,
184}
185
186#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
188#[non_exhaustive]
189pub enum NamedPalette {
190 Dracula,
192 PowerShell,
194 Xterm,
196 Ubuntu,
198 #[default]
200 Gjm8,
201}
202
203impl From<NamedPalette> for Palette {
204 fn from(value: NamedPalette) -> Self {
205 match value {
206 NamedPalette::Dracula => Self::dracula(),
207 NamedPalette::PowerShell => Self::powershell(),
208 NamedPalette::Xterm => Self::xterm(),
209 NamedPalette::Ubuntu => Self::ubuntu(),
210 NamedPalette::Gjm8 => Self::gjm8(),
211 }
212 }
213}
214
215impl FromStr for NamedPalette {
216 type Err = NamedPaletteParseError;
217
218 fn from_str(s: &str) -> Result<Self, Self::Err> {
219 match s {
220 "dracula" => Ok(Self::Dracula),
221 "powershell" => Ok(Self::PowerShell),
222 "xterm" => Ok(Self::Xterm),
223 "ubuntu" => Ok(Self::Ubuntu),
224 "gjm8" => Ok(Self::Gjm8),
225 _ => Err(NamedPaletteParseError(())),
226 }
227 }
228}
229
230#[derive(Debug)]
232pub struct NamedPaletteParseError(());
233
234impl fmt::Display for NamedPaletteParseError {
235 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
236 formatter.write_str(
237 "Invalid palette name; allowed names are `dracula`, `powershell`, `xterm`, \
238 `ubuntu` and `gjm8`",
239 )
240 }
241}
242
243impl error::Error for NamedPaletteParseError {}