console_utils/styled.rs
1//! Style Utilities
2//!
3//! This module provides functions for coloring text using ANSI escape code sequences.
4//! It allows setting foreground and background colors, as well as applying bold, italic,
5//! underline, blink, reverse and strikethrough formatting.
6
7use std::fmt;
8
9/// Represents all colors the text/background can be.
10#[derive(Debug, Clone, Copy)]
11pub enum Color {
12 /// Black color.
13 Black,
14 /// Red color.
15 Red,
16 /// Green color.
17 Green,
18 /// Yellow color.
19 Yellow,
20 /// Blue color.
21 Blue,
22 /// Magenta color.
23 Magenta,
24 /// Cyan color.
25 Cyan,
26 /// White color.
27 White,
28 /// Bright Black color.
29 BrightBlack,
30 /// Bright Red color.
31 BrightRed,
32 /// Bright Green color.
33 BrightGreen,
34 /// Bright Yellow color.
35 BrightYellow,
36 /// Bright Blue color.
37 BrightBlue,
38 /// Bright Magenta color.
39 BrightMagenta,
40 /// Bright Cyan color.
41 BrightCyan,
42 /// Bright White color.
43 BrightWhite,
44 /// An ANSI color of your choice.
45 ANSI(u8),
46}
47
48impl Color {
49 /// Converts a color to its ANSI foreground variant.
50 fn fg_code(self) -> u8 {
51 match self {
52 Color::Black => 30,
53 Color::Red => 31,
54 Color::Green => 32,
55 Color::Yellow => 33,
56 Color::Blue => 34,
57 Color::Magenta => 35,
58 Color::Cyan => 36,
59 Color::White => 37,
60 Color::BrightBlack => 90,
61 Color::BrightRed => 91,
62 Color::BrightGreen => 92,
63 Color::BrightYellow => 93,
64 Color::BrightBlue => 94,
65 Color::BrightMagenta => 95,
66 Color::BrightCyan => 96,
67 Color::BrightWhite => 97,
68 Color::ANSI(c) => c,
69 }
70 }
71
72 /// Converts a color to its ANSI background variant.
73 fn bg_code(self) -> u8 {
74 self.fg_code() + 10
75 }
76}
77
78/// Represents a piece of text with optional color and formatting.
79pub struct StyledText<'a> {
80 text: &'a str,
81 fg: Option<Color>,
82 bg: Option<Color>,
83 bold: bool,
84 italic: bool,
85 underline: bool,
86 blink: bool,
87 reverse: bool,
88 strikethrough: bool,
89}
90
91impl<'a> StyledText<'a> {
92 /// Creates a new `StyledText` instance with default settings.
93 ///
94 /// # Arguments
95 /// * `text` - The string slice representing the text.
96 ///
97 /// # Returns
98 /// A `StyledText` instance with no colors or formatting applied.
99 pub fn new(text: &'a str) -> Self {
100 Self {
101 text,
102 fg: None,
103 bg: None,
104 bold: false,
105 italic: false,
106 underline: false,
107 blink: false,
108 reverse: false,
109 strikethrough: false,
110 }
111 }
112
113 /// Sets the foreground color of the text.
114 ///
115 /// # Arguments
116 /// * `color` - A `Color` enum variant representing the desired foreground color.
117 ///
118 /// # Returns
119 /// The modified `StyledText` instance.
120 pub fn fg(mut self, color: Color) -> Self {
121 self.fg = Some(color);
122 self
123 }
124
125 /// Sets the background color of the text.
126 ///
127 /// # Arguments
128 /// * `color` - A `Color` enum variant representing the desired background color.
129 ///
130 /// # Returns
131 /// The modified `StyledText` instance.
132 pub fn bg(mut self, color: Color) -> Self {
133 self.bg = Some(color);
134 self
135 }
136
137 /// Enables bold formatting for the text.
138 ///
139 /// # Returns
140 /// The modified `StyledText` instance with bold formatting applied.
141 pub fn bold(mut self) -> Self {
142 self.bold = true;
143 self
144 }
145
146 /// Enables italic formatting for the text.
147 ///
148 /// # Returns
149 /// The modified `StyledText` instance with italic formatting applied.
150 pub fn italic(mut self) -> Self {
151 self.italic = true;
152 self
153 }
154
155 /// Enables underline formatting for the text.
156 ///
157 /// # Returns
158 /// The modified `StyledText` instance with underline formatting applied.
159 pub fn underline(mut self) -> Self {
160 self.underline = true;
161 self
162 }
163
164 /// Enables blink effect for the text.
165 ///
166 /// # Returns
167 /// The modified `StyledText` instance with blinking enabled.
168 pub fn blink(mut self) -> Self {
169 self.blink = true;
170 self
171 }
172
173 /// Enables reverse video (inverts foreground and background colors).
174 ///
175 /// # Returns
176 /// The modified `StyledText` instance with inverted colors.
177 pub fn reverse(mut self) -> Self {
178 self.reverse = true;
179 self
180 }
181
182 /// Enables strikethrough formatting for the text.
183 ///
184 /// # Returns
185 /// The modified `StyledText` instance with strikethrough applied.
186 pub fn strikethrough(mut self) -> Self {
187 self.strikethrough = true;
188 self
189 }
190
191 /// Converts the colored text into a formatted ANSI escape sequence string.
192 ///
193 /// # Returns
194 /// A `String` containing the ANSI-formatted text.
195 pub fn format_sequence(&'a self) -> String {
196 let mut codes = Vec::new();
197 if let Some(fg) = self.fg {
198 codes.push(fg.fg_code());
199 }
200 if let Some(bg) = self.bg {
201 codes.push(bg.bg_code());
202 }
203 if self.bold {
204 codes.push(1);
205 }
206 if self.italic {
207 codes.push(3);
208 }
209 if self.underline {
210 codes.push(4);
211 }
212 if self.blink {
213 codes.push(5);
214 }
215 if self.reverse {
216 codes.push(7);
217 }
218 if self.strikethrough {
219 codes.push(9);
220 }
221
222 let codes_str = codes
223 .iter()
224 .map(|c| c.to_string())
225 .collect::<Vec<_>>()
226 .join(";");
227
228 if !codes.is_empty() {
229 format!("\x1B[{}m{}\x1B[0m", codes_str, self.text)
230 } else {
231 self.text.to_string()
232 }
233 }
234}
235
236/// Implements the `Display` trait for `StyledText`, allowing it to be printed directly.
237impl fmt::Display for StyledText<'_> {
238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239 write!(f, "{}", self.format_sequence())
240 }
241}