1use nu_ansi_term::{Color as AnsiColor, Style};
2use std::fmt;
3
4#[derive(Clone, Debug)]
5pub struct Tint {
6 style: Style,
7}
8
9impl Tint {
10 fn new(style: Style) -> Self {
11 Self { style }
12 }
13
14 pub fn red() -> Self {
16 Self::new(AnsiColor::Red.normal())
17 }
18 pub fn green() -> Self {
19 Self::new(AnsiColor::Green.normal())
20 }
21 pub fn yellow() -> Self {
22 Self::new(AnsiColor::Yellow.normal())
23 }
24 pub fn blue() -> Self {
25 Self::new(AnsiColor::Blue.normal())
26 }
27 pub fn purple() -> Self {
28 Self::new(AnsiColor::Purple.normal())
29 }
30 pub fn cyan() -> Self {
31 Self::new(AnsiColor::Cyan.normal())
32 }
33 pub fn white() -> Self {
34 Self::new(AnsiColor::White.normal())
35 }
36 pub fn black() -> Self {
37 Self::new(AnsiColor::Black.normal())
38 }
39
40 pub fn bright_red() -> Self {
42 Self::new(AnsiColor::LightRed.normal())
43 }
44 pub fn bright_green() -> Self {
45 Self::new(AnsiColor::LightGreen.normal())
46 }
47 pub fn bright_yellow() -> Self {
48 Self::new(AnsiColor::LightYellow.normal())
49 }
50 pub fn bright_blue() -> Self {
51 Self::new(AnsiColor::LightBlue.normal())
52 }
53 pub fn bright_purple() -> Self {
54 Self::new(AnsiColor::LightPurple.normal())
55 }
56 pub fn bright_cyan() -> Self {
57 Self::new(AnsiColor::LightCyan.normal())
58 }
59
60 pub fn bold(mut self) -> Self {
62 self.style = self.style.bold();
63 self
64 }
65 pub fn dimmed(mut self) -> Self {
66 self.style = self.style.dimmed();
67 self
68 }
69 pub fn italic(mut self) -> Self {
70 self.style = self.style.italic();
71 self
72 }
73 pub fn underline(mut self) -> Self {
74 self.style = self.style.underline();
75 self
76 }
77 pub fn strikethrough(mut self) -> Self {
78 self.style = self.style.strikethrough();
79 self
80 }
81
82 pub fn bg_red(mut self) -> Self {
84 self.style = self.style.on(AnsiColor::Red);
85 self
86 }
87 pub fn bg_green(mut self) -> Self {
88 self.style = self.style.on(AnsiColor::Green);
89 self
90 }
91 pub fn bg_yellow(mut self) -> Self {
92 self.style = self.style.on(AnsiColor::Yellow);
93 self
94 }
95 pub fn bg_blue(mut self) -> Self {
96 self.style = self.style.on(AnsiColor::Blue);
97 self
98 }
99 pub fn bg_purple(mut self) -> Self {
100 self.style = self.style.on(AnsiColor::Purple);
101 self
102 }
103 pub fn bg_cyan(mut self) -> Self {
104 self.style = self.style.on(AnsiColor::Cyan);
105 self
106 }
107 pub fn bg_white(mut self) -> Self {
108 self.style = self.style.on(AnsiColor::White);
109 self
110 }
111 pub fn bg_black(mut self) -> Self {
112 self.style = self.style.on(AnsiColor::Black);
113 self
114 }
115
116 pub fn color(n: u8) -> Self {
118 Self::new(AnsiColor::Fixed(n).normal())
119 }
120 pub fn bg_color(mut self, n: u8) -> Self {
121 self.style = self.style.on(AnsiColor::Fixed(n));
122 self
123 }
124
125 pub fn rgb(r: u8, g: u8, b: u8) -> Self {
127 Self::new(AnsiColor::Rgb(r, g, b).normal())
128 }
129 pub fn bg_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
130 self.style = self.style.on(AnsiColor::Rgb(r, g, b));
131 self
132 }
133
134 pub fn paint(&self, text: &str) -> String {
136 self.style.paint(text).to_string()
137 }
138}
139
140impl fmt::Display for Tint {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 write!(f, "{:?}", self.style)
143 }
144}
145
146pub fn supports_color() -> bool {
148 std::io::IsTerminal::is_terminal(&std::io::stderr())
149}
150
151pub fn supports_color_stdout() -> bool {
154 std::io::IsTerminal::is_terminal(&std::io::stdout())
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn basic_colors() {
163 let s = Tint::red().paint("error");
164 assert!(s.contains("error"));
165
166 let s = Tint::green().paint("success");
167 assert!(s.contains("success"));
168 }
169
170 #[test]
171 fn chained_styles() {
172 let s = Tint::red().bold().underline().paint("important");
173 assert!(s.contains("important"));
174 }
175
176 #[test]
177 fn background_colors() {
178 let s = Tint::white().bg_red().paint("alert");
179 assert!(s.contains("alert"));
180 }
181
182 #[test]
183 fn ansi256_color() {
184 let s = Tint::color(208).paint("orange");
185 assert!(s.contains("orange"));
186 }
187
188 #[test]
189 fn rgb_color() {
190 let s = Tint::rgb(255, 128, 0).paint("custom");
191 assert!(s.contains("custom"));
192 }
193
194 #[test]
195 fn style_reuse() {
196 let header = Tint::cyan().bold();
197 let a = header.paint("Title A");
198 let b = header.paint("Title B");
199 assert!(a.contains("Title A"));
200 assert!(b.contains("Title B"));
201 }
202}