1pub mod cursor;
21mod sys;
22
23use crate::key::KeyIterator;
25use crate::term::cursor::Cursor;
26use std::fmt::Debug;
27use std::io::{self, Error, Read, Stdin, Write};
28use std::sync::mpsc;
29use std::thread;
30use sys::{get_attr, set_attr, set_raw, Termios};
31
32pub enum TermMode {
34 Cannonical,
35 Raw,
36}
37
38pub struct Terminal<'a, T: Write> {
40 pub rel_size: (u16, u16),
41 pub pix_size: (u16, u16),
42 pub stdout: &'a mut T, pub x_pos: u16,
44 pub y_pos: u16,
45 pub cursor_mode: Cursor,
46 pub screen_num: u8,
47 pub mode: TermMode,
48 prev_ios: Termios,
49}
50
51impl<T: Write> Debug for Terminal<'_, T> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("Terminal")
54 .field("Relative Size", &(self.rel_size))
55 .field("Pixels Size", &(self.pix_size))
56 .field("x_pos, y_pos", &(self.x_pos, self.y_pos))
57 .field("Cursor Mode", &self.cursor_mode)
58 .finish()
59 }
60}
61
62impl<T: Write> Drop for Terminal<'_, T> {
63 fn drop(&mut self) {
64 set_attr(&mut self.prev_ios);
65 self.mode = TermMode::Cannonical;
66 self.screen_num = 0;
67 write!(self.stdout, "\u{001b}[?1049l").unwrap();
68 }
69}
70
71impl<'a, T: Write> Terminal<'a, T> {
72 pub fn new(stdout: &'a mut T) -> Result<Terminal<T>, Error> {
73 let (rel_size, pix_size) = sys::term_size();
74
75 Ok(Terminal {
76 rel_size,
77 pix_size,
78 stdout,
79 x_pos: 0,
80 y_pos: 0,
81 cursor_mode: Cursor::Default,
82 screen_num: 0,
83 mode: TermMode::Cannonical,
84 prev_ios: get_attr(),
85 })
86 }
87
88 pub fn print(&mut self, x: &str) -> io::Result<()> {
89 write!(self.stdout, "{}", x)
90 }
91
92 pub fn size_did_change(&mut self) -> bool {
93 let (rel_size, pix_size) = sys::term_size();
94
95 if rel_size == (self.rel_size) {
96 false
97 } else {
98 self.rel_size = rel_size;
99 self.pix_size = pix_size;
100 true
101 }
102 }
103
104 pub fn enter_raw_mode(&mut self) -> io::Result<()> {
105 let mut ios = get_attr();
106
107 set_raw(&mut ios);
108
109 set_attr(&mut ios);
110 self.mode = TermMode::Raw;
111
112 Ok(())
113 }
114
115 pub fn keys(&self, stdin: Stdin) -> KeyIterator {
117 let rx = async_stdin(stdin);
118
119 KeyIterator::from(rx)
120 }
121
122 pub fn switch_screen(&mut self) -> io::Result<()> {
123 self.screen_num = 1;
124 write!(self.stdout, "\u{001b}[?1049h")
125 }
126
127 pub fn switch_main(&mut self) -> io::Result<()> {
128 self.screen_num = 0;
129 write!(self.stdout, "\u{001b}[?1049l")
130 }
131
132 pub fn get_size(&self) -> (u16, u16) {
133 self.rel_size
134 }
135
136 pub fn get_position(&self) -> (u16, u16) {
137 (self.x_pos, self.y_pos)
138 }
139}
140
141fn async_stdin(d: Stdin) -> mpsc::Receiver<Result<u8, Error>> {
142 let (tx, rx) = mpsc::channel();
143
144 thread::spawn(move || {
145 for b in d.bytes() {
146 tx.send(b).unwrap();
147 }
148 });
149
150 rx
151}
152
153impl<T: Write> Terminal<'_, T> {
155 pub fn set_cursor_to(&mut self, x_pos: u16, y_pos: u16) -> io::Result<()> {
156 if x_pos <= self.rel_size.0 && y_pos <= self.rel_size.1 {
157 let result = write!(self.stdout, "\u{001b}[{};{}f", y_pos, x_pos)?;
158 self.stdout.flush().unwrap();
159 self.x_pos = x_pos;
160 self.y_pos = y_pos;
161 Ok(result)
162 } else {
163 panic!("Cursor set to out of bounds");
164 }
165 }
166
167 pub fn get_cursor(&self) -> io::Result<(u16, u16)> {
168 Ok((self.x_pos, self.y_pos))
169 }
170
171 pub fn show_cursor(&mut self) -> io::Result<()> {
172 self.cursor_mode = Cursor::Default;
173 let result = write!(self.stdout, "\u{001b}[?25h")?;
174 self.stdout.flush().unwrap();
175 Ok(result)
176 }
177
178 pub fn hide_cursor(&mut self) -> io::Result<()> {
179 self.cursor_mode = Cursor::Hidden;
180 let result = write!(self.stdout, "\u{001b}[?25l")?;
181 self.stdout.flush().unwrap();
182 Ok(result)
183 }
184
185 pub fn blinking_block(&mut self) -> io::Result<()> {
186 self.cursor_mode = Cursor::BlinkingBlock;
187 let result = write!(self.stdout, "\u{001b}[1 q")?;
188 self.stdout.flush().unwrap();
189 Ok(result)
190 }
191
192 pub fn steady_block(&mut self) -> io::Result<()> {
193 self.cursor_mode = Cursor::Block;
194 let result = write!(self.stdout, "\u{001b}[2 q")?;
195 self.stdout.flush().unwrap();
196 Ok(result)
197 }
198
199 pub fn blinking_underline(&mut self) -> io::Result<()> {
200 self.cursor_mode = Cursor::BlinkingUnderline;
201 let result = write!(self.stdout, "\u{001b}[3 q")?;
202 self.stdout.flush().unwrap();
203 Ok(result)
204 }
205
206 pub fn steady_underline(&mut self) -> io::Result<()> {
207 self.cursor_mode = Cursor::Underline;
208 let result = write!(self.stdout, "\u{001b}[4 q")?;
209 self.stdout.flush().unwrap();
210 Ok(result)
211 }
212
213 pub fn blinking_bar(&mut self) -> io::Result<()> {
214 self.cursor_mode = Cursor::BlinkingBar;
215 let result = write!(self.stdout, "\u{001b}[5 q")?;
216 self.stdout.flush().unwrap();
217 Ok(result)
218 }
219
220 pub fn steady_bar(&mut self) -> io::Result<()> {
221 self.cursor_mode = Cursor::Bar;
222 let result = write!(self.stdout, "\u{001b}[6 q")?;
223 self.stdout.flush().unwrap();
224 Ok(result)
225 }
226
227 pub fn reset_cursor(&mut self) -> io::Result<()> {
228 self.cursor_mode = Cursor::Default;
229 let result = write!(self.stdout, "\u{001b}[0 q")?;
230 self.stdout.flush().unwrap();
231 Ok(result)
232 }
233}
234
235impl<T: Write> Terminal<'_, T> {
236 pub fn clear_screen(&mut self) -> io::Result<()> {
237 let result = write!(self.stdout, "\u{001b}[2J")?;
238 self.stdout.flush().unwrap();
239 Ok(result)
240 }
241
242 pub fn clear_below_cursor(&mut self) -> io::Result<()> {
243 let result = write!(self.stdout, "\u{001b}[0J")?;
244 self.stdout.flush().unwrap();
245 Ok(result)
246 }
247
248 pub fn clear_above_cursor(&mut self) -> io::Result<()> {
249 let result = write!(self.stdout, "\u{001b}[1J")?;
250 self.stdout.flush().unwrap();
251 Ok(result)
252 }
253
254 pub fn clear_line(&mut self) -> io::Result<()> {
255 let result = write!(self.stdout, "\u{001b}[K")?;
256 self.stdout.flush().unwrap();
257 Ok(result)
258 }
259}