dinglebit_terminal/
escape_sequence.rs

1//! Escape Sequence for the terminal.
2//!
3//! There are a variety of escape sequences (see [ANSI escape
4//! codes](http://ascii-table.com/ansi-escape-sequences.php)) for the
5//! terminal but we currently have only implemented "Set Graphics
6//! Mode". More can be added to the enum as needed.
7//!
8//! # Examples
9//!
10//! ```
11//! # #[macro_use]
12//! # use dinglebit_terminal::escape_sequence::EscapeSequence;
13//! # use dinglebit_terminal::consts::*;
14//! # fn main() {
15//!     let s = EscapeSequence::SetGraphicsMode(vec![OP_BOLD, FG_BLACK, BG_WHITE]).to_string();
16//!     assert_eq!(s, "\x1b[1;30;47m");
17//! # }
18//! ```
19
20use std::fmt;
21
22/// An escape sequence for the terminal.
23pub enum EscapeSequence {
24    /// Change the foreground, background, and attributes of terminal
25    /// text using the given values.
26    ///
27    /// # Examples
28    ///
29    /// ```
30    /// # #[macro_use]
31    /// # use dinglebit_terminal::escape_sequence::EscapeSequence;
32    /// # use dinglebit_terminal::consts::*;
33    /// # fn main() {
34    ///     let s = EscapeSequence::SetGraphicsMode(vec![OP_BOLD, FG_BLACK, BG_WHITE]).to_string();
35    ///     assert_eq!(s, "\x1b[1;30;47m");
36    /// # }
37    /// ```
38    SetGraphicsMode(Vec<u8>),
39}
40
41impl fmt::Display for EscapeSequence {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            EscapeSequence::SetGraphicsMode(v) => {
45                // This seems "faster" per an article I found, but we
46                // could also just map/collect/join to a string.
47                let mut s = String::with_capacity(100);
48                if v.len() > 0 {
49                    s.push_str(v[0].to_string().as_str());
50                    for i in v[1..].into_iter() {
51                        s.push_str(";");
52                        s.push_str(i.to_string().as_str());
53                    }
54                }
55                write!(f, "{}", format!("\x1b[{}m", s))
56            }
57        }
58    }
59}
60
61/// Create a reset escape sequence for the graphics mode.
62///
63/// # Examples
64///
65/// ```
66/// # #[macro_use]
67/// # use dinglebit_terminal::reset;
68/// # fn main() {
69///     let s = reset!().to_string();
70///     assert_eq!(s, "\x1b[0m");
71/// # }
72/// ```
73#[macro_export]
74macro_rules! reset {
75    () => {
76        $crate::escape_sequence::EscapeSequence::SetGraphicsMode(vec![$crate::consts::OP_RESET])
77    };
78}
79
80/// Create a SetGraphicsMode using the given vector.
81///
82/// # Examples
83///
84/// ```
85/// # #[macro_use]
86/// # use dinglebit_terminal::sgm;
87/// # use dinglebit_terminal::consts::*;
88/// # fn main() {
89///     let s = sgm!(vec![OP_BOLD, FG_BLACK, BG_WHITE]).to_string();
90///     assert_eq!(s, "\x1b[1;30;47m");
91/// # }
92/// ```
93#[macro_export]
94macro_rules! sgm {
95    ($e:expr) => {
96        $crate::escape_sequence::EscapeSequence::SetGraphicsMode(($e))
97    };
98}
99
100#[cfg(test)]
101mod tests {
102    pub use super::*;
103    pub use crate::consts::*;
104
105    #[test]
106    fn display() {
107        let s = sgm!(vec![OP_BOLD, FG_BLACK, BG_WHITE]);
108        assert_eq!("test: \x1b[1;30;47m", format!("test: {}", s));
109    }
110}