dinglebit_terminal/
style.rs

1//! Apply a style to terminal text using the "Set Graphics Mode"
2//! escape sequence.
3//!
4//! The easiest way to use this is to use the style! macro.
5//!
6//! ```
7//! # #[macro_use]
8//! use dinglebit_terminal::style;
9//! fn main() {
10//!     let s = style!("{}, {}!", "Hello", "world")
11//!                 .black()
12//!                 .underline()
13//!                 .to_string();
14//!     assert_eq!(s, "\x1b[30;4mHello, world!\x1b[0m");
15//! }
16//! ```
17
18use crate::consts::*;
19use std::fmt;
20
21/// format! the given values and create a Style that can then be used
22/// to style the text.
23///
24/// # Examples
25///
26/// ```
27/// # #[macro_use]
28/// # use dinglebit_terminal::style;
29/// # fn main() {
30///     let s = style!("{}, {}!", "Hello", "world")
31///                 .black()
32///                 .underline()
33///                 .to_string();
34///     assert_eq!(s, "\x1b[30;4mHello, world!\x1b[0m");
35/// # }
36/// ```
37#[macro_export]
38macro_rules! style {
39    ($($arg:tt)*) => ($crate::style::Style::new(format!($($arg)*)))
40}
41
42/// A Stylized text that can be output to a terminal.
43///
44/// # Examples
45///
46/// ```
47/// # #[macro_use]
48/// # use dinglebit_terminal::style::Style;
49/// # fn main() {
50///     let s = Style::new(format!("{}, {}!", "Hello", "world"))
51///                 .black()
52///                 .underline()
53///                 .to_string();
54///     assert_eq!(s, "\x1b[30;4mHello, world!\x1b[0m");
55/// # }
56/// ```
57pub struct Style {
58    text: String,
59    values: Vec<u8>,
60}
61
62impl Style {
63    /// Create a new style whose text is the given text.
64    pub fn new(text: String) -> Self {
65        Self {
66            text: text,
67            values: Vec::new(),
68        }
69    }
70
71    /// Apply a bold value to the escape sequence.
72    pub fn bold(&mut self) -> &mut Self {
73        self.values.push(OP_BOLD);
74        self
75    }
76
77    /// Apply a faint value to the escape sequence.
78    pub fn faint(&mut self) -> &mut Self {
79        self.values.push(OP_FAINT);
80        self
81    }
82
83    /// Apply an italic value to the escape sequence.
84    pub fn italic(&mut self) -> &mut Self {
85        self.values.push(OP_ITALIC);
86        self
87    }
88
89    /// Apply an underline value to the escape sequence.
90    pub fn underline(&mut self) -> &mut Self {
91        self.values.push(OP_UNDERLINE);
92        self
93    }
94
95    /// Apply a slow blink value to the escape sequence.
96    pub fn slow_blink(&mut self) -> &mut Self {
97        self.values.push(OP_SLOW_BLINK);
98        self
99    }
100
101    /// Apply a fast blink value to the escape sequence.
102    pub fn fast_blink(&mut self) -> &mut Self {
103        self.values.push(OP_FAST_BLINK);
104        self
105    }
106
107    /// Apply a reverse value to the escape sequence.
108    pub fn reverse(&mut self) -> &mut Self {
109        self.values.push(OP_REVERSE);
110        self
111    }
112
113    /// Apply a conceal value to the escape sequence.
114    pub fn conceal(&mut self) -> &mut Self {
115        self.values.push(OP_CONCEAL);
116        self
117    }
118
119    /// Apply a strikethrough value to the escape sequence.
120    pub fn strikethrough(&mut self) -> &mut Self {
121        self.values.push(OP_STRIKETHROUGH);
122        self
123    }
124
125    /// Apply the foreground color black value to the escape sequence.
126    pub fn black(&mut self) -> &mut Self {
127        self.values.push(FG_BLACK);
128        self
129    }
130
131    /// Apply the foreground color red value to the escape sequence.
132    pub fn red(&mut self) -> &mut Self {
133        self.values.push(FG_RED);
134        self
135    }
136
137    /// Apply the foreground color green value to the escape sequence.
138    pub fn green(&mut self) -> &mut Self {
139        self.values.push(FG_GREEN);
140        self
141    }
142
143    /// Apply the foreground color yellow value to the escape
144    /// sequence.
145    pub fn yellow(&mut self) -> &mut Self {
146        self.values.push(FG_YELLOW);
147        self
148    }
149
150    /// Apply the foreground color blue value to the escape sequence.
151    pub fn blue(&mut self) -> &mut Self {
152        self.values.push(FG_BLUE);
153        self
154    }
155
156    /// Apply the foreground color magenta value to the escape
157    /// sequence.
158    pub fn magenta(&mut self) -> &mut Self {
159        self.values.push(FG_MAGENTA);
160        self
161    }
162
163    /// Apply the foreground color cyan value to the escape sequence.
164    pub fn cyan(&mut self) -> &mut Self {
165        self.values.push(FG_CYAN);
166        self
167    }
168
169    /// Apply the foreground color white value to the escape sequence.
170    pub fn white(&mut self) -> &mut Self {
171        self.values.push(FG_WHITE);
172        self
173    }
174
175    /// Apply the foreground color gray value to the escape sequence.
176    pub fn gray(&mut self) -> &mut Self {
177        self.values.push(FG_GRAY);
178        self
179    }
180
181    /// Apply the foreground color bright red value to the escape
182    /// sequence.
183    pub fn bright_red(&mut self) -> &mut Self {
184        self.values.push(FG_BRIGHT_RED);
185        self
186    }
187
188    /// Apply the foreground color bright green value to the escape
189    /// sequence.
190    pub fn bright_green(&mut self) -> &mut Self {
191        self.values.push(FG_BRIGHT_GREEN);
192        self
193    }
194
195    /// Apply the foreground color bright yellow value to the escape
196    /// sequence.
197    pub fn bright_yellow(&mut self) -> &mut Self {
198        self.values.push(FG_BRIGHT_YELLOW);
199        self
200    }
201
202    /// Apply the foreground color bright blue value to the escape
203    /// sequence.
204    pub fn bright_blue(&mut self) -> &mut Self {
205        self.values.push(FG_BRIGHT_BLUE);
206        self
207    }
208
209    /// Apply the foreground color bright magenta value to the escape
210    /// sequence.
211    pub fn bright_magenta(&mut self) -> &mut Self {
212        self.values.push(FG_BRIGHT_MAGENTA);
213        self
214    }
215
216    /// Apply the foreground color bright cyan value to the escape
217    /// sequence.
218    pub fn bright_cyan(&mut self) -> &mut Self {
219        self.values.push(FG_BRIGHT_CYAN);
220        self
221    }
222
223    /// Apply the foreground color bright white value to the escape
224    /// sequence.
225    pub fn bright_white(&mut self) -> &mut Self {
226        self.values.push(FG_BRIGHT_WHITE);
227        self
228    }
229
230    /// Apply the background color black value to the escape sequence.
231    pub fn bg_black(&mut self) -> &mut Self {
232        self.values.push(BG_BLACK);
233        self
234    }
235
236    /// Apply the background color red value to the escape sequence.
237    pub fn bg_red(&mut self) -> &mut Self {
238        self.values.push(BG_RED);
239        self
240    }
241
242    /// Apply the background color green value to the escape sequence.
243    pub fn bg_green(&mut self) -> &mut Self {
244        self.values.push(BG_GREEN);
245        self
246    }
247
248    /// Apply the background color yellow value to the escape
249    /// sequence.
250    pub fn bg_yellow(&mut self) -> &mut Self {
251        self.values.push(BG_YELLOW);
252        self
253    }
254
255    /// Apply the background color blue value to the escape sequence.
256    pub fn bg_blue(&mut self) -> &mut Self {
257        self.values.push(BG_BLUE);
258        self
259    }
260
261    /// Apply the background color magenta value to the escape
262    /// sequence.
263    pub fn bg_magenta(&mut self) -> &mut Self {
264        self.values.push(BG_MAGENTA);
265        self
266    }
267
268    /// Apply the background color cyan value to the escape sequence.
269    pub fn bg_cyan(&mut self) -> &mut Self {
270        self.values.push(BG_CYAN);
271        self
272    }
273
274    /// Apply the background color white value to the escape sequence.
275    pub fn bg_white(&mut self) -> &mut Self {
276        self.values.push(BG_WHITE);
277        self
278    }
279
280    /// Apply the background color gray value to the escape sequence.
281    pub fn bg_gray(&mut self) -> &mut Self {
282        self.values.push(BG_GRAY);
283        self
284    }
285
286    /// Apply the background color bright red value to the escape
287    /// sequence.
288    pub fn bg_bright_red(&mut self) -> &mut Self {
289        self.values.push(BG_BRIGHT_RED);
290        self
291    }
292
293    /// Apply the background color bright green value to the escape
294    /// sequence.
295    pub fn bg_bright_green(&mut self) -> &mut Self {
296        self.values.push(BG_BRIGHT_GREEN);
297        self
298    }
299
300    /// Apply the background color bright yellow value to the escape
301    /// sequence.
302    pub fn bg_bright_yellow(&mut self) -> &mut Self {
303        self.values.push(BG_BRIGHT_YELLOW);
304        self
305    }
306
307    /// Apply the background color bright blue value to the escape
308    /// sequence.
309    pub fn bg_bright_blue(&mut self) -> &mut Self {
310        self.values.push(BG_BRIGHT_BLUE);
311        self
312    }
313
314    /// Apply the background color bright magenta value to the escape
315    /// sequence.
316    pub fn bg_bright_magenta(&mut self) -> &mut Self {
317        self.values.push(BG_BRIGHT_MAGENTA);
318        self
319    }
320
321    /// Apply the background color bright cyan value to the escape
322    /// sequence.
323    pub fn bg_bright_cyan(&mut self) -> &mut Self {
324        self.values.push(BG_BRIGHT_CYAN);
325        self
326    }
327
328    /// Apply the background color bright white value to the escape
329    /// sequence.
330    pub fn bg_bright_white(&mut self) -> &mut Self {
331        self.values.push(BG_BRIGHT_WHITE);
332        self
333    }
334}
335
336impl fmt::Display for Style {
337    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338        write!(f, "{}{}{}", sgm!(self.values.clone()), self.text, reset!())
339    }
340}
341
342#[cfg(test)]
343mod tests {
344    pub use super::*;
345    pub use crate::consts::*;
346
347    macro_rules! style_test {
348        ( $( $name:ident: $exp:expr ),* ) => {
349            $(
350                #[test]
351                fn $name() {
352                    let mut s = Style::new("test".to_string());
353                    s.$name();
354                    assert_eq!($exp, s.values);
355                }
356            )*
357        }
358    }
359
360    style_test! {
361        bold: vec![OP_BOLD],
362        faint: vec![OP_FAINT],
363        italic: vec![OP_ITALIC],
364        underline: vec![OP_UNDERLINE],
365        slow_blink: vec![OP_SLOW_BLINK],
366        fast_blink: vec![OP_FAST_BLINK],
367        reverse: vec![OP_REVERSE],
368        conceal: vec![OP_CONCEAL],
369        strikethrough: vec![OP_STRIKETHROUGH],
370        black: vec![FG_BLACK],
371        red: vec![FG_RED],
372        green: vec![FG_GREEN],
373        yellow: vec![FG_YELLOW],
374        blue: vec![FG_BLUE],
375        magenta: vec![FG_MAGENTA],
376        cyan: vec![FG_CYAN],
377        white: vec![FG_WHITE],
378        gray: vec![FG_GRAY],
379        bright_red: vec![FG_BRIGHT_RED],
380        bright_green: vec![FG_BRIGHT_GREEN],
381        bright_yellow: vec![FG_BRIGHT_YELLOW],
382        bright_blue: vec![FG_BRIGHT_BLUE],
383        bright_magenta: vec![FG_BRIGHT_MAGENTA],
384        bright_cyan: vec![FG_BRIGHT_CYAN],
385        bright_white: vec![FG_BRIGHT_WHITE],
386        bg_black: vec![BG_BLACK],
387        bg_red: vec![BG_RED],
388        bg_green: vec![BG_GREEN],
389        bg_yellow: vec![BG_YELLOW],
390        bg_blue: vec![BG_BLUE],
391        bg_magenta: vec![BG_MAGENTA],
392        bg_cyan: vec![BG_CYAN],
393        bg_white: vec![BG_WHITE],
394        bg_gray: vec![BG_GRAY],
395        bg_bright_red: vec![BG_BRIGHT_RED],
396        bg_bright_green: vec![BG_BRIGHT_GREEN],
397        bg_bright_yellow: vec![BG_BRIGHT_YELLOW],
398        bg_bright_blue: vec![BG_BRIGHT_BLUE],
399        bg_bright_magenta: vec![BG_BRIGHT_MAGENTA],
400        bg_bright_cyan: vec![BG_BRIGHT_CYAN],
401        bg_bright_white: vec![BG_BRIGHT_WHITE]
402    }
403
404    #[test]
405    fn multi_style() {
406        let mut s = style!("test");
407        s.bold().underline().red().bg_green();
408        assert_eq!(s.values, vec![OP_BOLD, OP_UNDERLINE, FG_RED, BG_GREEN]);
409        assert_eq!(
410            format!(
411                "\x1b[{};{};{};{}mtest\x1b[0m",
412                OP_BOLD, OP_UNDERLINE, FG_RED, BG_GREEN
413            ),
414            s.to_string()
415        );
416    }
417}