1pub fn style(text: &str, code: &str, enabled: bool) -> String {
12 if enabled {
13 format!("\x1b[{code}m{text}\x1b[0m")
14 } else {
15 text.to_string()
16 }
17}
18
19pub fn green(text: &str, enabled: bool) -> String {
21 style(text, "32", enabled)
22}
23
24pub fn red(text: &str, enabled: bool) -> String {
26 style(text, "31", enabled)
27}
28
29pub fn yellow(text: &str, enabled: bool) -> String {
31 style(text, "33", enabled)
32}
33
34pub fn bold(text: &str, enabled: bool) -> String {
36 style(text, "1", enabled)
37}
38
39pub fn dim(text: &str, enabled: bool) -> String {
41 style(text, "2", enabled)
42}
43
44pub mod aurora {
53 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
56 pub struct Token {
57 pub hex: (u8, u8, u8),
58 pub ansi256: u8,
59 }
60
61 pub const ACCENT: Token = Token {
62 hex: (0x29, 0xb6, 0xf6),
63 ansi256: 39,
64 };
65 pub const TERTIARY: Token = Token {
66 hex: (0x67, 0xcb, 0xfa),
67 ansi256: 81,
68 };
69 pub const PRIMARY: Token = Token {
70 hex: (0xe6, 0xf4, 0xfb),
71 ansi256: 255,
72 };
73 pub const MUTED: Token = Token {
74 hex: (0xa7, 0xbc, 0xc9),
75 ansi256: 250,
76 };
77 pub const SERVICE_NAME: Token = Token {
78 hex: (0xf9, 0xa8, 0xc4),
79 ansi256: 217,
80 };
81 pub const VIOLET: Token = Token {
82 hex: (0xa7, 0x8b, 0xfa),
83 ansi256: 141,
84 };
85 pub const BORDER: Token = Token {
86 hex: (0x1d, 0x3d, 0x4e),
87 ansi256: 239,
88 };
89 pub const INFO: Token = Token {
90 hex: (0x72, 0xc8, 0xf5),
91 ansi256: 117,
92 };
93 pub const SUCCESS: Token = Token {
94 hex: (0x7d, 0xd3, 0xc7),
95 ansi256: 115,
96 };
97 pub const WARN: Token = Token {
98 hex: (0xc6, 0xa3, 0x6b),
99 ansi256: 180,
100 };
101 pub const ERROR: Token = Token {
102 hex: (0xc7, 0x84, 0x90),
103 ansi256: 174,
104 };
105 pub const NEUTRAL: Token = Token {
106 hex: (0x91, 0xa8, 0xb6),
107 ansi256: 109,
108 };
109}
110
111pub fn truecolor_fg(text: &str, token: aurora::Token, enabled: bool) -> String {
114 if enabled {
115 let (r, g, b) = token.hex;
116 format!("\x1b[38;2;{r};{g};{b}m{text}\x1b[0m")
117 } else {
118 text.to_string()
119 }
120}
121
122pub fn ansi256_fg(text: &str, token: aurora::Token, enabled: bool) -> String {
126 if enabled {
127 format!("\x1b[38;5;{}m{text}\x1b[0m", token.ansi256)
128 } else {
129 text.to_string()
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn style_wraps_when_enabled() {
139 assert_eq!(green("ok", true), "\x1b[32mok\x1b[0m");
140 assert_eq!(red("bad", true), "\x1b[31mbad\x1b[0m");
141 assert_eq!(yellow("hint", true), "\x1b[33mhint\x1b[0m");
142 assert_eq!(bold("hi", true), "\x1b[1mhi\x1b[0m");
143 assert_eq!(dim("lo", true), "\x1b[2mlo\x1b[0m");
144 }
145
146 #[test]
147 fn style_passes_through_when_disabled() {
148 assert_eq!(green("ok", false), "ok");
149 assert_eq!(red("bad", false), "bad");
150 assert_eq!(yellow("hint", false), "hint");
151 assert_eq!(bold("hi", false), "hi");
152 assert_eq!(dim("lo", false), "lo");
153 }
154
155 #[test]
156 fn truecolor_and_ansi256_wrap_when_enabled() {
157 assert_eq!(
158 truecolor_fg("x", aurora::ACCENT, true),
159 "\x1b[38;2;41;182;246mx\x1b[0m"
160 );
161 assert_eq!(
162 ansi256_fg("x", aurora::ACCENT, true),
163 "\x1b[38;5;39mx\x1b[0m"
164 );
165 assert_eq!(truecolor_fg("x", aurora::ACCENT, false), "x");
166 assert_eq!(ansi256_fg("x", aurora::ACCENT, false), "x");
167 }
168}