1use async::async_stdin_until;
4use numtoa::NumToA;
5use raw::CONTROL_SEQUENCE_TIMEOUT;
6use std::fmt;
7use std::io::{self, Error, ErrorKind, Read, Write};
8use std::ops;
9use std::time::{Duration, SystemTime};
10
11derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
12derive_csi_sequence!("Show the cursor.", Show, "?25h");
13
14derive_csi_sequence!("Restore the cursor.", Restore, "u");
15derive_csi_sequence!("Save the cursor.", Save, "s");
16
17derive_csi_sequence!(
18 "Change the cursor style to blinking block",
19 BlinkingBlock,
20 "\x31 q"
21);
22derive_csi_sequence!(
23 "Change the cursor style to steady block",
24 SteadyBlock,
25 "\x32 q"
26);
27derive_csi_sequence!(
28 "Change the cursor style to blinking underline",
29 BlinkingUnderline,
30 "\x33 q"
31);
32derive_csi_sequence!(
33 "Change the cursor style to steady underline",
34 SteadyUnderline,
35 "\x34 q"
36);
37derive_csi_sequence!(
38 "Change the cursor style to blinking bar",
39 BlinkingBar,
40 "\x35 q"
41);
42derive_csi_sequence!("Change the cursor style to steady bar", SteadyBar, "\x36 q");
43
44#[derive(Copy, Clone, PartialEq, Eq)]
62pub struct Goto(pub u16, pub u16);
63
64impl From<Goto> for String {
65 fn from(this: Goto) -> String {
66 let (mut x, mut y) = ([0u8; 20], [0u8; 20]);
67 [
68 "\x1B[",
69 this.1.numtoa_str(10, &mut x),
70 ";",
71 this.0.numtoa_str(10, &mut y),
72 "H",
73 ]
74 .concat()
75 }
76}
77
78impl Default for Goto {
79 fn default() -> Goto {
80 Goto(1, 1)
81 }
82}
83
84impl fmt::Display for Goto {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 debug_assert!(self != &Goto(0, 0), "Goto is one-based.");
87 write!(f, "\x1B[{};{}H", self.1, self.0)
88 }
89}
90
91#[derive(Copy, Clone, PartialEq, Eq)]
93pub struct Left(pub u16);
94
95impl From<Left> for String {
96 fn from(this: Left) -> String {
97 let mut buf = [0u8; 20];
98 ["\x1B[", this.0.numtoa_str(10, &mut buf), "D"].concat()
99 }
100}
101
102impl fmt::Display for Left {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 write!(f, "\x1B[{}D", self.0)
105 }
106}
107
108#[derive(Copy, Clone, PartialEq, Eq)]
110pub struct Right(pub u16);
111
112impl From<Right> for String {
113 fn from(this: Right) -> String {
114 let mut buf = [0u8; 20];
115 ["\x1B[", this.0.numtoa_str(10, &mut buf), "C"].concat()
116 }
117}
118
119impl fmt::Display for Right {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 write!(f, "\x1B[{}C", self.0)
122 }
123}
124
125#[derive(Copy, Clone, PartialEq, Eq)]
127pub struct Up(pub u16);
128
129impl From<Up> for String {
130 fn from(this: Up) -> String {
131 let mut buf = [0u8; 20];
132 ["\x1B[", this.0.numtoa_str(10, &mut buf), "A"].concat()
133 }
134}
135
136impl fmt::Display for Up {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(f, "\x1B[{}A", self.0)
139 }
140}
141
142#[derive(Copy, Clone, PartialEq, Eq)]
144pub struct Down(pub u16);
145
146impl From<Down> for String {
147 fn from(this: Down) -> String {
148 let mut buf = [0u8; 20];
149 ["\x1B[", this.0.numtoa_str(10, &mut buf), "B"].concat()
150 }
151}
152
153impl fmt::Display for Down {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 write!(f, "\x1B[{}B", self.0)
156 }
157}
158
159pub trait DetectCursorPos {
161 fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
163}
164
165impl<W: Write> DetectCursorPos for W {
166 fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
167 let delimiter = b'R';
168 let mut stdin = async_stdin_until(delimiter);
169
170 write!(self, "\x1B[6n")?;
173 self.flush()?;
174
175 let mut buf: [u8; 1] = [0];
176 let mut read_chars = Vec::new();
177
178 let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
179 let now = SystemTime::now();
180
181 while buf[0] != delimiter && now.elapsed().unwrap() < timeout {
183 if stdin.read(&mut buf)? > 0 {
184 read_chars.push(buf[0]);
185 }
186 }
187
188 if read_chars.is_empty() {
189 return Err(Error::new(
190 ErrorKind::Other,
191 "Cursor position detection timed out.",
192 ));
193 }
194
195 read_chars.pop(); let read_str = String::from_utf8(read_chars).unwrap();
199 let beg = read_str.rfind('[').unwrap();
200 let coords: String = read_str.chars().skip(beg + 1).collect();
201 let mut nums = coords.split(';');
202
203 let cy = nums.next().unwrap().parse::<u16>().unwrap();
204 let cx = nums.next().unwrap().parse::<u16>().unwrap();
205
206 Ok((cx, cy))
207 }
208}
209
210pub struct HideCursor<W: Write> {
213 output: W,
215}
216
217impl<W: Write> HideCursor<W> {
218 pub fn from(mut output: W) -> Self {
220 write!(output, "{}", Hide).expect("hide the cursor");
221 HideCursor { output: output }
222 }
223}
224
225impl<W: Write> Drop for HideCursor<W> {
226 fn drop(&mut self) {
227 write!(self, "{}", Show).expect("show the cursor");
228 }
229}
230
231impl<W: Write> ops::Deref for HideCursor<W> {
232 type Target = W;
233
234 fn deref(&self) -> &W {
235 &self.output
236 }
237}
238
239impl<W: Write> ops::DerefMut for HideCursor<W> {
240 fn deref_mut(&mut self) -> &mut W {
241 &mut self.output
242 }
243}
244
245impl<W: Write> Write for HideCursor<W> {
246 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
247 self.output.write(buf)
248 }
249
250 fn flush(&mut self) -> io::Result<()> {
251 self.output.flush()
252 }
253}