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}