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}