diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ansi/mod.rs | 124 |
1 files changed, 13 insertions, 111 deletions
diff --git a/src/ansi/mod.rs b/src/ansi/mod.rs index cbdcbe6..020713a 100644 --- a/src/ansi/mod.rs +++ b/src/ansi/mod.rs @@ -1,25 +1,4 @@ -use std::{collections::BTreeMap, io::Read, os::unix::ffi::OsStrExt, sync::RwLock}; - -use crate::cursor::Direction; - -pub enum KeyboardInput { - Eof, - Key(u8), - CtrlA, - CtrlB, - CtrlC, - CtrlE, - CtrlD, - CtrlL, - CtrlR, - Arrow(Direction), - CtrlArrow(Direction), - DeleteLeft, - DeleteRight, - CtrlDeleteRight, - Home, - End, -} +use std::{collections::BTreeMap, io::Read, sync::RwLock}; fn read1() -> Option<u8> { let mut buf = [0]; @@ -29,95 +8,8 @@ fn read1() -> Option<u8> { } } -fn byte_to_dir(b: u8) -> Option<Direction> { - use Direction::*; - match b { - b'A' => Some(Up), - b'B' => Some(Down), - b'C' => Some(Right), - b'D' => Some(Left), - _ => None, - } -} - -fn read_escape(debug: bool) -> KeyboardInput { - use Direction::*; - use KeyboardInput::*; - - let mut seq = vec![match read1() { - Some(x) => x, - None => return Eof, - }]; - - if seq[0] == b'[' { - // still more - while { - let last = seq[seq.len() - 1]; - !(0x40..=0x7E).contains(&last) || seq.len() == 1 - } { - seq.push(match read1() { - Some(x) => x, - None => return Eof, - }); - } - - if debug { - println!("escape: {}", seq.escape_ascii()); - } - - match seq[1] { - b'3' => { - if seq.len() > 2 && seq[2] == b'~' { - DeleteRight - } else { - todo!("unhandled: {}", seq.escape_ascii()); - } - } - b'H' => Home, - b'F' => End, - b'd' => CtrlDeleteRight, - - // Ctrl Arrow - b'1' => { - if seq[1..].starts_with(b"1;5") { - if seq.len() == 4 { - todo!("idk what this is."); - } - match seq[4] { - b'A' => CtrlArrow(Up), - b'B' => CtrlArrow(Down), - b'C' => CtrlArrow(Right), - b'D' => CtrlArrow(Left), - _ => todo!("unhandled {}", seq.escape_ascii()), - } - } else { - todo!("unhandled {}", seq[1..].escape_ascii()) - } - } - - x => { - if let Some(dir) = byte_to_dir(x) { - Arrow(dir) - } else { - todo!("escape characters {}", seq[1..].escape_ascii()) - } - } - } - } else { - if debug { - println!("escape: {}", seq.escape_ascii()); - } - match seq[0] { - b'd' => CtrlDeleteRight, - x => todo!("unhandled escape code: ESC {x}"), - } - } -} - pub fn read(debug: bool) -> Option<KbInput<'static>> { - let trie = EscapeTrie::from(ti()); - let trie = Box::leak(Box::new(trie)); // TODO don't leak memory, this is only temporary - let mut reader = EscapingStdinReader::new(trie); + let mut reader = EscapingStdinReader::new(et()); loop { let Some(b) = read1() else { break None; @@ -216,6 +108,7 @@ pub struct Escape<'a> { use terminfo_lean::parse::Terminfo; static TERMINFO: RwLock<Option<&'static Terminfo<'static>>> = RwLock::new(None); +static ESCAPE_TRIE: RwLock<Option<&'static EscapeTrie>> = RwLock::new(None); fn parse_terminfo() -> Result<Terminfo<'static>, ()> { let term = std::env::var_os("TERM").unwrap_or_else(|| "xterm".into()); @@ -244,15 +137,24 @@ pub fn setup() { println!("using backup terminfo (might not be correct for this terminal)"); parse_terminfo_backup() }); - let ti = Box::leak(Box::new(ti)); + let ti: &'static _ = Box::leak(Box::new(ti)); + TERMINFO.clear_poison(); *TERMINFO.write().unwrap() = Some(ti); + + let et = Box::leak(Box::new(EscapeTrie::from(ti))); + ESCAPE_TRIE.clear_poison(); + *ESCAPE_TRIE.write().unwrap() = Some(et); } pub fn ti() -> &'static Terminfo<'static> { TERMINFO.read().unwrap().unwrap() } +fn et() -> &'static EscapeTrie { + ESCAPE_TRIE.read().unwrap().unwrap() +} + fn is_parametrized(x: &[u8]) -> bool { let mut pct = false; for &b in x { |
