grid_printer/
style.rs

1//! The style module provides an API to customize the style settings
2//! for a GridPrinter instance, such as the font foreground color, the font
3//! background color, and the font text style (bold, italic, strike-through, etc.).
4//!
5//! # Example
6//! ```rust
7//! use grid_printer::GridPrinter;
8//! use grid_printer::style::{Fg, Bg, Sgr, StyleOpt};
9//! use std::error::Error;
10//! 
11//! fn main() -> Result<(), Box<dyn Error>> {
12//! 
13//!     let grid = vec![
14//!         vec![1, 2, 3, 4, ],
15//!         vec![5, 6, 7, 8, ],
16//!         vec![9, 10, 11, 12, ],
17//!     ];
18//! 
19//!     let rows = grid.len();
20//!     let cols = grid[0].len();
21//!     
22//!     let printer = GridPrinter::builder(rows, cols)
23//!         .col_style(0, StyleOpt::new().fg(Fg::Magenta))?
24//!         .col_style(1, StyleOpt::new().fg(Fg::Black).bg(Bg::BrightYellow))?
25//!         .col_style(2, StyleOpt::new().sgr(Sgr::StrikeThrough))?
26//!         .col_style(3, StyleOpt::new().fg(Fg::Cyan))?
27//!         .build();
28//!     printer.print(&grid);
29//! 
30//!     Ok(())
31//! }
32//! ```
33//! # Output
34//! <div style="background-color:#2A2A2A">
35//! <span style="color:magenta">1</span>    <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>   <span style="color:black;background-color:yellow">2</span>      <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>     <span style="text-decoration:line-through">3</span>   <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>     <span style="color:cyan;text-decoration:italic">4</span><br/>
36//! <span style="color:magenta">5</span>    <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>   <span style="color:black;background-color:yellow">6</span>      <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>     <span style="text-decoration:line-through">7</span>   <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>     <span style="color:cyan;text-decoration:italic">8</span><br/>
37//! <span style="color:magenta">9</span>    <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>   <span style="color:black;background-color:yellow">10</span>     <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>                 <span style="text-decoration:line-through">11</span>  <span>&nbsp;&nbsp;&nbsp;</span>           <span style="color:cyan;text-decoration:italic">12</span><br/>
38//! </div>
39
40
41/// A struct providing optional customization of the foreground color, background
42/// color, and text style of a GridPrinter column.
43#[derive(Debug, Clone, PartialEq)]
44pub struct StyleOpt {
45    pub fg: Option<Fg>,
46    pub bg: Option<Bg>, 
47    pub sgr: Option<Sgr>,
48}
49
50impl StyleOpt {
51
52    /// Create a new StyleOpt with no specified style options. 
53    pub fn new() -> Self {
54        Self::default()
55    }
56
57    /// Set the foreground color.
58    pub fn fg(self, fg: Fg) -> Self {
59        Self { fg: Some(fg), ..self }
60    }
61    
62    /// Set the background color.
63    pub fn bg(self, bg: Bg) -> Self {
64        Self { bg: Some(bg), ..self }
65    }
66
67    /// Set the Select Graphic Rendition.
68    pub fn sgr(self, sgr: Sgr) -> Self {
69        Self { sgr: Some(sgr), ..self }
70    }
71}
72
73impl Default for StyleOpt {
74    fn default() -> StyleOpt {
75        Self { fg: None, bg: None, sgr: None }
76    }
77}
78
79// pub fn reset() -> &'static str {
80//     "\x1b[1;0m"
81// }
82
83
84/// A function which will print a given &str `s` in accordance to the StylOpt `opt`.
85pub fn stylize(s: &str, opt: &StyleOpt) -> String {
86    format!("{fg}{bg}{sgr}{text}{reset}",
87        fg = match opt.fg.as_ref() {
88            None => "",
89            Some(fg) => fg.escape_code(),
90        },
91        bg = match opt.bg.as_ref() {
92            None => "",
93            Some(bg) => bg.escape_code(),
94        },
95        sgr = match opt.sgr.as_ref() {
96            None => "",
97            Some(sgr) => sgr.escape_code(),
98        },
99        text = s,
100        // Note: Using Fg::Reset vs. Bg::Reset makes no difference 
101        reset = Fg::Reset.escape_code(),
102    )
103}
104
105/// An enumeration of foreground color options.
106#[derive(Debug, Clone, PartialEq)]
107pub enum Fg {
108    Black,
109    Red,
110    Green,
111    Yellow,
112    Blue,
113    Magenta,
114    Cyan,
115    White,
116    BrightBlack,
117    BrightRed,
118    BrightGreen,
119    BrightYellow,
120    BrightBlue,
121    BrightMagenta,
122    BrightCyan,
123    BrightWhite,
124    Reset,
125}
126
127impl Fg {
128
129    /// A fucntion which will produce the ASCII escape code for a given Fg.
130    pub fn escape_code(&self) -> &'static str {
131        match self {
132            Self::Black           => "\x1b[1;30m",
133            Self::Red             => "\x1b[1;31m",
134            Self::Green           => "\x1b[1;32m",
135            Self::Yellow          => "\x1b[1;33m",
136            Self::Blue            => "\x1b[1;34m",
137            Self::Magenta         => "\x1b[1;35m",
138            Self::Cyan            => "\x1b[1;36m",
139            Self::White           => "\x1b[1;37m",
140            Self::BrightBlack     => "\x1b[1;90m",
141            Self::BrightRed       => "\x1b[1;91m",
142            Self::BrightGreen     => "\x1b[1;92m",
143            Self::BrightYellow    => "\x1b[1;93m",
144            Self::BrightBlue      => "\x1b[1;94m",
145            Self::BrightMagenta   => "\x1b[1;95m",
146            Self::BrightCyan      => "\x1b[1;96m",
147            Self::BrightWhite     => "\x1b[1;97m",
148            Self::Reset           => "\x1b[1;0m",
149        }
150    }
151}
152
153/// An enumeration of background color options.
154#[derive(Debug, Clone, PartialEq)]
155pub enum Bg {
156    Black,
157    Red,
158    Green,
159    Yellow,
160    Blue,
161    Magenta,
162    Cyan,
163    White,
164    BrightBlack,
165    BrightRed,
166    BrightGreen,
167    BrightYellow,
168    BrightBlue,
169    BrightMagenta,
170    BrightCyan,
171    BrightWhite,
172    Reset,
173}
174
175impl Bg {
176    /// A fucntion which will produce the ASCII escape code for a given Bg.
177    pub fn escape_code(&self) -> &'static str {
178        match self {
179            Self::Black          => "\x1b[1;40m",
180            Self::Red            => "\x1b[1;41m",
181            Self::Green          => "\x1b[1;42m",
182            Self::Yellow         => "\x1b[1;43m",
183            Self::Blue           => "\x1b[1;44m",
184            Self::Magenta        => "\x1b[1;45m",
185            Self::Cyan           => "\x1b[1;46m",
186            Self::White          => "\x1b[1;47m",
187            Self::BrightBlack    => "\x1b[1;100m",
188            Self::BrightRed      => "\x1b[1;101m",
189            Self::BrightGreen    => "\x1b[1;102m",
190            Self::BrightYellow   => "\x1b[1;103m",
191            Self::BrightBlue     => "\x1b[1;104m",
192            Self::BrightMagenta  => "\x1b[1;105m",
193            Self::BrightCyan     => "\x1b[1;106m",
194            Self::BrightWhite    => "\x1b[1;107m",
195            Self::Reset          => "\x1b[1;0m",
196        }
197    }
198}
199
200/*
201 * Dont work:
202 * - slowblink
203 *
204 * */
205
206/// Select Graphic Renditions, i.e. an enumeration of text style options, such
207/// as bold, italic, etc.
208///
209/// This list was obtained from the following source: 
210/// * [Select Graphic Rendition](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters)
211///
212/// The total list of Select Graphic Renditions were trimmed down to those
213/// styles which have general, wide support.
214#[derive(Debug, Clone, PartialEq)]
215pub enum Sgr {
216    Bold,
217    Faint,
218    Italic,
219    Underline,
220    StrikeThrough,
221    Reset,
222}
223
224impl Sgr {
225    /// A fucntion which will produce the ASCII escape code for a given Sgr.
226    pub fn escape_code(&self) -> &'static str {
227        match self {
228            Self::Bold          => "\x1b[1;1m",
229            Self::Faint         => "\x1b[1;2m",
230            Self::Italic        => "\x1b[1;3m",
231            Self::Underline     => "\x1b[1;4m",
232            Self::StrikeThrough => "\x1b[1;9m",
233            Self::Reset         => "\x1b[1;0m",
234        }
235
236    }
237}