1use anyhow::Result;
2use crossterm::{
3 cursor,
4 event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
5 execute,
6 terminal::{self, ClearType},
7};
8use std::io::{self, Write};
9
10pub struct Terminal {
11 size: (u16, u16),
12}
13
14impl Terminal {
15 pub fn new() -> Result<Self> {
16 let size = terminal::size()?;
17 Ok(Self { size })
18 }
19
20 pub fn enter_raw_mode() -> Result<()> {
21 terminal::enable_raw_mode()?;
22 execute!(io::stdout(), terminal::EnterAlternateScreen)?;
23 Ok(())
24 }
25
26 pub fn exit_raw_mode() -> Result<()> {
27 execute!(io::stdout(), terminal::LeaveAlternateScreen)?;
28 terminal::disable_raw_mode()?;
29 Ok(())
30 }
31
32 pub fn clear_screen() -> Result<()> {
33 execute!(io::stdout(), terminal::Clear(ClearType::All))?;
34 Ok(())
35 }
36
37 pub fn size(&self) -> (u16, u16) {
38 self.size
39 }
40
41 #[allow(dead_code)]
42 pub fn update_size(&mut self) -> Result<()> {
43 self.size = terminal::size()?;
44 Ok(())
45 }
46
47 #[allow(dead_code)]
48 pub fn flush() -> Result<()> {
49 io::stdout().flush()?;
50 Ok(())
51 }
52
53 pub fn read_key() -> Result<KeyEvent> {
54 loop {
55 let event = event::read()?;
56
57 match event {
58 Event::Key(key_event) => {
59 if key_event.kind == KeyEventKind::Press
61 || key_event.kind == KeyEventKind::Repeat
62 {
63 return Ok(key_event);
64 }
65 }
66 Event::Resize(_cols, _rows) => {
67 return Ok(KeyEvent::new(KeyCode::F(21), KeyModifiers::NONE));
69 }
70 Event::Paste(_text) => {
71 return Ok(KeyEvent::new(KeyCode::F(20), KeyModifiers::NONE));
75 }
76 _ => {
77 }
79 }
80 }
81 }
82
83 #[allow(dead_code)]
84 pub fn set_cursor_position(x: u16, y: u16) -> Result<()> {
85 execute!(io::stdout(), cursor::MoveTo(x, y))?;
86 Ok(())
87 }
88
89 #[allow(dead_code)]
90 pub fn hide_cursor() -> Result<()> {
91 execute!(io::stdout(), cursor::Hide)?;
92 Ok(())
93 }
94
95 pub fn show_cursor() -> Result<()> {
96 execute!(io::stdout(), cursor::Show)?;
97 Ok(())
98 }
99}
100
101impl Drop for Terminal {
102 fn drop(&mut self) {
103 let _ = Self::exit_raw_mode();
104 let _ = Self::show_cursor();
105 }
106}