console_codes/
csi.rs

1use crate::mode::Mode;
2use crate::privmode::PrivateMode;
3use crate::color::Color;
4use crate::sgr::SGR;
5
6#[derive(Debug, Clone, Copy, Eq, PartialEq)]
7pub enum CSI<'a> {
8    /// CUrsor Up
9    CUU(u16),
10
11    /// CUrsor Down
12    CUD(u16),
13
14    /// CUrsor Forward
15    CUF(u16),
16
17    /// CUrsor Backward
18    CUB(u16),
19
20    /// CUrsor Next line
21    CNL(u16),
22
23    /// CUrsor Preceding line
24    CPL(u16),
25
26    /// Cursor cHaracter Absolute
27    CHA(u16),
28
29    /// CUrsor Position
30    CUP(u16, u16),
31
32    /// Erase Display; 0: from cursor to end of display; 1: from start to cursor; 2: whole display;
33    /// 3: whole display including scrollback
34    ED(u16),
35
36    /// Erase Line; 0: from cursor to end of line; 1: from start of line to cursor; 2: whole line
37    EL(u16),
38
39    /// Set Mode
40    #[allow(dead_code)]
41    SM(Mode),
42
43    /// Reset Mode
44    #[allow(dead_code)]
45    RM(Mode),
46
47    /// Private Set Mode
48    #[allow(dead_code)]
49    PSM(PrivateMode),
50
51    /// Private Reset Mode
52    #[allow(dead_code)]
53    PRM(PrivateMode),
54
55    /// Set Graphics Rendition
56    SGR(&'a [SGR]),
57
58    /// Set underline color
59    LxULColor(Color),
60
61    /// Set dim color
62    LxDimColor(Color),
63
64    /// Make the current color pair the default attributes
65    LxDefColor,
66
67    /// Set screen blank timeout to n minutes
68    LxScreenBlankTimeout(u16),
69
70    /// Set bell frequency in Hz
71    LxBellFrequency(u16),
72
73    /// Set bell duration in msec
74    LxBellDuration(u16),
75
76    /// Bring specified console to the front
77    LxActivateConsole(u8),
78
79    /// Unblank the screen
80    LxUnblankScreen,
81
82    /// Set VESA powerdown interval in minutes
83    LxVESAPowerdownInterval(u16),
84
85    /// Bring the previous console to the front
86    LxActivatePreviousConsole,
87
88    /// Set cursor blink interval in milliseconds
89    LxSetCursorBlinkInterval(u16),
90}
91
92fn csi(attr: &[u16], ch: char) -> String {
93    format!("\x1b[{}{}", attr.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(";"), ch)
94}
95
96fn decpm(p: u16, ch: char) -> String {
97    format!("\x1b[?{}{}", p, ch)
98}
99
100fn sgr(attr: &[SGR]) -> Vec<u16> {
101    attr.iter()
102        .flat_map::<Vec<u16>, _>(|a| (*a).into())
103        .collect()
104}
105
106impl<'a> std::fmt::Display for CSI<'a> {
107    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
108        write!(f, "{}", match *self {
109            CSI::CUU(n)                         => csi(&[n], 'A'),
110            CSI::CUD(n)                         => csi(&[n], 'B'),
111            CSI::CUF(n)                         => csi(&[n], 'C'),
112            CSI::CUB(n)                         => csi(&[n], 'D'),
113            CSI::CNL(n)                         => csi(&[n], 'E'),
114            CSI::CPL(n)                         => csi(&[n], 'F'),
115            CSI::CHA(n)                         => csi(&[n], 'G'),
116            CSI::CUP(r, c)                      => csi(&[r, c], 'H'),
117            CSI::ED(m) if m <= 3                => csi(&[m], 'J'),
118            CSI::ED(x)                          => panic!("illegal ED mode {}", x),
119            CSI::EL(m) if m <= 2                => csi(&[m], 'K'),
120            CSI::EL(x)                          => panic!("illegal EL mode {}", x),
121            CSI::SM(m)                          => csi(&[m.into()], 'h'),
122            CSI::RM(m)                          => csi(&[m.into()], 'l'),
123            CSI::PSM(m)                         => decpm(m.into(), 'h'),
124            CSI::PRM(m)                         => decpm(m.into(), 'l'),
125            CSI::SGR(attr)                      => csi(&sgr(attr), 'm'),
126            CSI::LxULColor(c)                   => csi(&[1, c.into()], ']'),
127            CSI::LxDimColor(c)                  => csi(&[2, c.into()], ']'),
128            CSI::LxDefColor                     => csi(&[8], ']'),
129            CSI::LxScreenBlankTimeout(n)        => csi(&[9, n], ']'),
130            CSI::LxBellFrequency(n)             => csi(&[10, n], ']'),
131            CSI::LxBellDuration(t)              => csi(&[11, t], ']'),
132            CSI::LxActivateConsole(n)           => csi(&[12, n as u16], ']'),
133            CSI::LxUnblankScreen                => csi(&[13], ']'),
134            CSI::LxVESAPowerdownInterval(n)     => csi(&[14, n], ']'),
135            CSI::LxActivatePreviousConsole      => csi(&[15], ']'),
136            CSI::LxSetCursorBlinkInterval(n)    => csi(&[16, n], ']'),
137        })
138    }
139}
140
141#[cfg(test)]
142mod test {
143    use super::CSI;
144    use crate::sgr::SGR;
145    use crate::color::Color;
146
147    #[test]
148    fn test_eq() {
149        let a = CSI::CUU(3);
150        let b = CSI::CUU(3);
151        assert!(a == b);
152    }
153
154    #[test]
155    fn test_neq() {
156        let a = CSI::CUU(3);
157        let b = CSI::CUD(3);
158        assert!(a != b);
159    }
160
161    #[test]
162    fn test_clone() {
163        let a = CSI::CUU(3);
164        let b = a.clone();
165        assert!(a == b);
166    }
167
168    #[test]
169    fn test_copy() {
170        let a = CSI::SGR(&[SGR::FG(Color::Red)]);
171        let b = a;
172        assert!(a == b);
173    }
174}