termion/
cursor.rs
1use std::fmt;
4use std::ops;
5use std::io::{self, Write, Error, ErrorKind, Read};
6use async::async_stdin_until;
7use std::time::{SystemTime, Duration};
8use raw::CONTROL_SEQUENCE_TIMEOUT;
9use numtoa::NumToA;
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
17#[derive(Copy, Clone, PartialEq, Eq)]
35pub struct Goto(pub u16, pub u16);
36
37impl From<Goto> for String {
38 fn from(this: Goto) -> String {
39 let (mut x, mut y) = ([0u8; 20], [0u8; 20]);
40 ["\x1B[", this.1.numtoa_str(10, &mut x), ";", this.0.numtoa_str(10, &mut y), "H"].concat()
41 }
42}
43
44impl Default for Goto {
45 fn default() -> Goto {
46 Goto(1, 1)
47 }
48}
49
50impl fmt::Display for Goto {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 debug_assert!(self != &Goto(0, 0), "Goto is one-based.");
53 f.write_str(&String::from(*self))
54 }
55}
56
57#[derive(Copy, Clone, PartialEq, Eq)]
59pub struct Left(pub u16);
60
61impl From<Left> for String {
62 fn from(this: Left) -> String {
63 let mut buf = [0u8; 20];
64 ["\x1B[", this.0.numtoa_str(10, &mut buf), "D"].concat()
65 }
66}
67
68impl fmt::Display for Left {
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 f.write_str(&String::from(*self))
71 }
72}
73
74#[derive(Copy, Clone, PartialEq, Eq)]
76pub struct Right(pub u16);
77
78impl From<Right> for String {
79 fn from(this: Right) -> String {
80 let mut buf = [0u8; 20];
81 ["\x1B[", this.0.numtoa_str(10, &mut buf), "C"].concat()
82 }
83}
84
85impl fmt::Display for Right {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 f.write_str(&String::from(*self))
88 }
89}
90
91#[derive(Copy, Clone, PartialEq, Eq)]
93pub struct Up(pub u16);
94
95impl From<Up> for String {
96 fn from(this: Up) -> String {
97 let mut buf = [0u8; 20];
98 ["\x1B[", this.0.numtoa_str(10, &mut buf), "A"].concat()
99 }
100}
101
102impl fmt::Display for Up {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 f.write_str(&String::from(*self))
105 }
106}
107
108#[derive(Copy, Clone, PartialEq, Eq)]
110pub struct Down(pub u16);
111
112impl From<Down> for String {
113 fn from(this: Down) -> String {
114 let mut buf = [0u8; 20];
115 ["\x1B[", this.0.numtoa_str(10, &mut buf), "B"].concat()
116 }
117}
118
119impl fmt::Display for Down {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 f.write_str(&String::from(*self))
122 }
123}
124
125pub trait DetectCursorPos {
127 fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
129}
130
131impl<W: Write> DetectCursorPos for W {
132 fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
133 let delimiter = b'R';
134 let mut stdin = async_stdin_until(delimiter);
135
136 write!(self, "\x1B[6n")?;
139 self.flush()?;
140
141 let mut buf: [u8; 1] = [0];
142 let mut read_chars = Vec::new();
143
144 let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
145 let now = SystemTime::now();
146
147 while buf[0] != delimiter && now.elapsed().unwrap() < timeout {
149 if stdin.read(&mut buf)? > 0 {
150 read_chars.push(buf[0]);
151 }
152 }
153
154 if read_chars.is_empty() {
155 return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out."));
156 }
157
158 read_chars.pop(); let read_str = String::from_utf8(read_chars).unwrap();
162 let beg = read_str.rfind('[').unwrap();
163 let coords: String = read_str.chars().skip(beg + 1).collect();
164 let mut nums = coords.split(';');
165
166 let cy = nums.next()
167 .unwrap()
168 .parse::<u16>()
169 .unwrap();
170 let cx = nums.next()
171 .unwrap()
172 .parse::<u16>()
173 .unwrap();
174
175 Ok((cx, cy))
176 }
177}
178
179pub struct HideCursor<W: Write> {
182 output: W,
184}
185
186impl<W: Write> HideCursor<W> {
187 pub fn from(mut output: W) -> Self {
189 write!(output, "{}", Hide).expect("hide the cursor");
190 HideCursor { output: output }
191 }
192}
193
194impl<W: Write> Drop for HideCursor<W> {
195 fn drop(&mut self) {
196 write!(self, "{}", Show).expect("show the cursor");
197 }
198}
199
200impl<W: Write> ops::Deref for HideCursor<W> {
201 type Target = W;
202
203 fn deref(&self) -> &W {
204 &self.output
205 }
206}
207
208impl<W: Write> ops::DerefMut for HideCursor<W> {
209 fn deref_mut(&mut self) -> &mut W {
210 &mut self.output
211 }
212}
213
214impl<W: Write> Write for HideCursor<W> {
215 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
216 self.output.write(buf)
217 }
218
219 fn flush(&mut self) -> io::Result<()> {
220 self.output.flush()
221 }
222}