better_term/
lib.rs

1pub mod input;
2
3#[cfg(feature = "fancy")]
4pub mod fancy;
5
6#[cfg(feature = "output")]
7use std::fmt::Display;
8#[cfg(feature = "output")]
9use std::fmt;
10
11/// Default ansi colors
12/// # Example
13/// ```
14/// use better_term::Color;
15///
16/// // prints Hello, world! in green and red
17/// println!("{}Hello, {}world!", Color::BrightGreen, Color::BrightRed);
18/// ```
19#[cfg(feature = "output")]
20#[derive(PartialEq, Clone, Copy)]
21pub enum Color {
22    Black,
23    Red,
24    Green,
25    Yellow,
26    Blue,
27    Purple,
28    Cyan,
29    White,
30    BrightBlack,
31    BrightRed,
32    BrightGreen,
33    BrightYellow,
34    BrightBlue,
35    BrightPurple,
36    BrightCyan,
37    BrightWhite,
38    Fixed(u8),
39    RGB(u8,u8,u8),
40    Hex(u32),
41    Default,
42}
43
44impl Color {
45    /// Convert color to a style with the foreground set to this color
46    pub fn to_style_fg(self) -> Style {
47        Style::new().fg(self)
48    }
49    /// Convert color to a style with the background set to this color
50    pub fn to_style_bg(self) -> Style {
51        Style::new().bg(self)
52    }
53
54    /// convert a hexadecimal value to an RGB color value (hex example: 0x000000 for black)
55    pub fn hex_to_rgb(hex: u32) -> Color {
56        Color::RGB(((hex >> (16u8)) & 0xFF) as u8, ((hex >> (8u8)) & 0xFF) as u8, ((hex) & 0xFF) as u8)
57    }
58
59    /// Convert to the ansi value within a string (for output with the ansi char)
60    pub fn as_fg(&self) -> String {
61        match *self {
62            Color::Black  => String::from("30"),
63            Color::Red    => String::from("31"),
64            Color::Green  => String::from("32"),
65            Color::Yellow => String::from("33"),
66            Color::Blue   => String::from("34"),
67            Color::Purple => String::from("35"),
68            Color::Cyan   => String::from("36"),
69            Color::White  => String::from("37"),
70            Color::BrightBlack  => String::from("90"),
71            Color::BrightRed    => String::from("91"),
72            Color::BrightGreen  => String::from("92"),
73            Color::BrightYellow => String::from("93"),
74            Color::BrightBlue   => String::from("94"),
75            Color::BrightPurple => String::from("95"),
76            Color::BrightCyan   => String::from("96"),
77            Color::BrightWhite  => String::from("97"),
78            Color::Fixed(u) => format!("38;5;{}", &u),
79            Color::RGB(r,g,b) => format!("38;2;{};{};{}", &r,&g,&b),
80            Color::Hex(hex) => Color::hex_to_rgb(hex).as_fg(),
81            Color::Default => String::from("37"),
82        }
83    }
84    /// Convert to the ansi value within a string (for output with the ansi char
85    pub fn as_bg(&self) -> String {
86        match *self {
87            Color::Black  => String::from("40"),
88            Color::Red    => String::from("41"),
89            Color::Green  => String::from("42"),
90            Color::Yellow => String::from("43"),
91            Color::Blue   => String::from("44"),
92            Color::Purple => String::from("45"),
93            Color::Cyan   => String::from("46"),
94            Color::White  => String::from("47"),
95            Color::BrightBlack  => String::from("100"),
96            Color::BrightRed    => String::from("101"),
97            Color::BrightGreen  => String::from("102"),
98            Color::BrightYellow => String::from("103"),
99            Color::BrightBlue   => String::from("104"),
100            Color::BrightPurple => String::from("105"),
101            Color::BrightCyan   => String::from("106"),
102            Color::BrightWhite  => String::from("107"),
103            Color::Fixed(u) => format!("48;5;{}", &u).to_string(),
104            Color::RGB(r,g,b) => format!("48;2;{};{};{}", &r,&g,&b).to_string(),
105            Color::Hex(hex) => Color::hex_to_rgb(hex).as_bg(),
106            Color::Default => String::from("40"),
107        }
108    }
109}
110
111impl Display for Color {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        self.to_style_fg().fmt(f)
114    }
115}
116
117/// A way to style output, by setting flags within this struct and then outputting it with ("... {} ...", style)
118///
119/// # Example
120/// ```
121/// use better_term::Style;
122///
123/// // prints out Hello world! underlined and bold
124/// let style = Style::default().underline().bold();
125///
126/// println!("{}Hello, world!", style);
127/// ```
128#[cfg(feature = "output")]
129#[derive(PartialEq, Clone, Copy)]
130pub struct Style {
131    fg: Option<Color>,
132    bg: Option<Color>,
133    overwrite: bool,
134    bold: bool,
135    dim: bool,
136    italic: bool,
137    underline: bool,
138    blink: bool,
139    invert: bool,
140    hide: bool,
141    strikethrough: bool,
142}
143
144impl Style {
145    /// Creates a new Style with default values
146    pub fn new() -> Style {
147        Style::default()
148    }
149
150    /// Resets all styles and makes a new style
151    pub fn reset() -> Style {
152        Style::default().overwrite()
153    }
154
155    /// sets the foreground
156    pub fn fg(self, c: Color) -> Style {
157        Style { fg: Some(c), .. self }
158    }
159
160    /// clears the foreground
161    pub fn clear_fg(self) -> Style {
162        Style { fg: None, .. self }
163    }
164
165    /// sets a new background
166    pub fn bg(self, c: Color) -> Style {
167        Style { bg: Some(c), .. self }
168    }
169
170    /// clear the background
171    pub fn clear_bg(self) -> Style {
172        Style { bg: None, .. self }
173    }
174
175    /// this will overwrite previous styles with default values
176    pub fn overwrite(self) -> Style {
177        Style { overwrite: true, .. self }
178    }
179
180    /// Set the output to bold
181    pub fn bold(self) -> Style {
182        Style { bold: true, .. self }
183    }
184
185    /// Set the output to be dim
186    pub fn dim(self) -> Style {
187        Style { dim: true, .. self }
188    }
189
190    /// Set the output to be italic
191    pub fn italic(self) -> Style {
192        Style { italic: true, .. self }
193    }
194
195    /// Set the output to be underlined
196    pub fn underline(self) -> Style {
197        Style { underline: true, .. self }
198    }
199
200    /// Set the output to blink
201    /// This is not supported in most terminals
202    pub fn blink(self) -> Style {
203        Style { blink: true, .. self }
204    }
205
206    /// Inverts the current colors (bg and fg) through ansi (does not change fg and bg values)
207    pub fn invert(self) -> Style {
208        Style { invert: true, .. self }
209    }
210
211    /// hides the text (it's still there, just hidden.)
212    pub fn hide(self) -> Style {
213        Style { hide: true, .. self }
214    }
215
216    /// sets the text to be strike-through
217    pub fn strikethrough(self) -> Style {
218        Style { strikethrough: true, .. self }
219    }
220
221    #[doc(hidden)]
222    fn gen(&self) -> String {
223        let mut s = String::from("\x1b[");
224        let mut has_written = false;
225
226        {
227            let mut write_c = |c| {
228                if has_written { s += ";"; }
229                has_written = true;
230                s += c;
231            };
232
233            if self.overwrite { write_c("0") }
234
235            if self.bold          { write_c("1"); }
236            if self.dim           { write_c("2"); }
237            if self.italic        { write_c("3"); }
238            if self.underline     { write_c("4"); }
239            if self.blink         { write_c("5"); }
240            if self.invert        { write_c("7"); }
241            if self.hide          { write_c("8"); }
242            if self.strikethrough { write_c("9"); }
243        }
244
245        if let Some(bg) = self.bg {
246            if has_written { s += ";"; }
247            has_written = true;
248            s += bg.as_bg().as_str();
249        }
250
251        if let Some(fg) = self.fg {
252            if has_written { s += ";"; }
253            s += fg.as_fg().as_str();
254        }
255
256        s += "m";
257
258        s
259    }
260}
261
262impl Default for Style {
263    /// Get the default values for a Style
264    /// This will not overwrite anything other than what is set by previous styles
265    fn default() -> Self {
266        Style {
267            fg: None,
268            bg: None,
269            overwrite: false,
270            bold: false,
271            dim: false,
272            italic: false,
273            underline: false,
274            blink: false,
275            invert: false,
276            hide: false,
277            strikethrough: false,
278        }
279    }
280}
281
282impl Display for Style {
283    #[doc(hidden)]
284    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285        write!(f, "{}", self.gen())
286    }
287}
288
289/// this will reset all colors and styles in the console for future output
290///
291/// # Example:
292/// ```
293/// use better_term::{Color, flush_styles};
294///
295/// // this will print in rainbow colors
296/// println!("{}This is red!", Color::Red);
297///
298/// // clear all colors and styles from the terminal to ensure the next output is normal
299/// flush_styles();
300/// println!("This is normal!");
301/// ```
302pub fn flush_styles() {
303    print!("{}", Style::default());
304}