1 | /// An example how to use the ANSI escape sequence parser. |
2 | use std::io::{Read, Result, Write}; |
3 | |
4 | use anes::{ |
5 | self, execute, |
6 | parser::{KeyCode, Parser, Sequence}, |
7 | queue, |
8 | }; |
9 | use libc::termios as Termios; |
10 | |
11 | const HELP: &str = r#"ANES parser example |
12 | |
13 | * Hit `Esc` to quit |
14 | * Hit 'c' to ask for cursor position |
15 | * Use your mouse or type anything |
16 | "# ; |
17 | |
18 | fn main() -> Result<()> { |
19 | let mut w = std::io::stdout(); |
20 | queue!( |
21 | w, |
22 | anes::SwitchBufferToAlternate, |
23 | anes::HideCursor, |
24 | anes::EnableMouseEvents |
25 | )?; |
26 | for line in HELP.split(' \n' ) { |
27 | queue!(w, line, anes::MoveCursorToNextLine(1))?; |
28 | } |
29 | w.flush()?; |
30 | |
31 | let saved_attributes = get_termios()?; |
32 | let mut attributes = saved_attributes; |
33 | make_raw(&mut attributes); |
34 | set_termios(attributes)?; |
35 | |
36 | let mut stdin = std::io::stdin(); |
37 | let mut stdin_buffer = [0u8; 1024]; |
38 | let mut parser = Parser::default(); |
39 | |
40 | loop { |
41 | if let Ok(size) = stdin.read(&mut stdin_buffer) { |
42 | parser.advance(&stdin_buffer[..size], false); |
43 | |
44 | let mut break_outer_loop = false; |
45 | |
46 | while let Some(sequence) = parser.next() { |
47 | match sequence { |
48 | Sequence::Key(KeyCode::Esc, _) => { |
49 | break_outer_loop = true; |
50 | break; |
51 | } |
52 | Sequence::Key(KeyCode::Char('c' ), _) => { |
53 | execute!(w, anes::ReportCursorPosition)? |
54 | } |
55 | _ => execute!( |
56 | w, |
57 | anes::ClearLine::Left, |
58 | anes::MoveCursorToColumn(1), |
59 | format!("{:?}" , sequence), |
60 | )?, |
61 | } |
62 | } |
63 | |
64 | if break_outer_loop { |
65 | break; |
66 | } |
67 | } |
68 | } |
69 | |
70 | set_termios(saved_attributes)?; |
71 | |
72 | execute!( |
73 | w, |
74 | anes::DisableMouseEvents, |
75 | anes::ShowCursor, |
76 | anes::SwitchBufferToNormal |
77 | )?; |
78 | Ok(()) |
79 | } |
80 | |
81 | // |
82 | // RAW mode |
83 | // |
84 | |
85 | fn get_termios() -> Result<Termios> { |
86 | unsafe { |
87 | let mut termios = std::mem::zeroed(); |
88 | if libc::tcgetattr(libc::STDIN_FILENO, &mut termios) != -1 { |
89 | Ok(termios) |
90 | } else { |
91 | Err(std::io::Error::last_os_error()) |
92 | } |
93 | } |
94 | } |
95 | |
96 | fn set_termios(termios: Termios) -> Result<()> { |
97 | if unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &termios) } != -1 { |
98 | Ok(()) |
99 | } else { |
100 | Err(std::io::Error::last_os_error()) |
101 | } |
102 | } |
103 | |
104 | fn make_raw(termios: &mut Termios) { |
105 | unsafe { libc::cfmakeraw(termios) } |
106 | } |
107 | |