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    CUU(u16),
10
11    CUD(u16),
13
14    CUF(u16),
16
17    CUB(u16),
19
20    CNL(u16),
22
23    CPL(u16),
25
26    CHA(u16),
28
29    CUP(u16, u16),
31
32    ED(u16),
35
36    EL(u16),
38
39    #[allow(dead_code)]
41    SM(Mode),
42
43    #[allow(dead_code)]
45    RM(Mode),
46
47    #[allow(dead_code)]
49    PSM(PrivateMode),
50
51    #[allow(dead_code)]
53    PRM(PrivateMode),
54
55    SGR(&'a [SGR]),
57
58    LxULColor(Color),
60
61    LxDimColor(Color),
63
64    LxDefColor,
66
67    LxScreenBlankTimeout(u16),
69
70    LxBellFrequency(u16),
72
73    LxBellDuration(u16),
75
76    LxActivateConsole(u8),
78
79    LxUnblankScreen,
81
82    LxVESAPowerdownInterval(u16),
84
85    LxActivatePreviousConsole,
87
88    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}