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> </span> <span style="color:black;background-color:yellow">2</span> <span> </span> <span style="text-decoration:line-through">3</span> <span> </span> <span style="color:cyan;text-decoration:italic">4</span><br/>
36//! <span style="color:magenta">5</span> <span> </span> <span style="color:black;background-color:yellow">6</span> <span> </span> <span style="text-decoration:line-through">7</span> <span> </span> <span style="color:cyan;text-decoration:italic">8</span><br/>
37//! <span style="color:magenta">9</span> <span> </span> <span style="color:black;background-color:yellow">10</span> <span> </span> <span style="text-decoration:line-through">11</span> <span> </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}