From 9885f5ca8db5060f95066b16f68f69c1a858cf0f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 12 Mar 2021 00:33:26 -0500 Subject: refactor input implementations to share some code --- src/blocking/input.rs | 367 +++++++++++-------------------------------------- src/input.rs | 374 ++++++++++++-------------------------------------- src/lib.rs | 20 +-- src/private.rs | 339 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 507 insertions(+), 593 deletions(-) create mode 100644 src/private.rs diff --git a/src/blocking/input.rs b/src/blocking/input.rs index bdc916b..fc173f0 100644 --- a/src/blocking/input.rs +++ b/src/blocking/input.rs @@ -3,6 +3,8 @@ use crate::error::*; use std::io::Read as _; use std::os::unix::io::AsRawFd as _; +use crate::private::InputImpl as _; + pub struct RawGuard { termios: nix::sys::termios::Termios, cleaned_up: bool, @@ -60,6 +62,56 @@ pub struct Input { parse_single: bool, } +impl crate::private::InputImpl for Input { + fn buf(&self) -> &[u8] { + &self.buf[self.pos..] + } + + fn buf_mut(&mut self) -> &mut [u8] { + &mut self.buf[self.pos..] + } + + fn buf_mut_vec(&mut self) -> &mut Vec { + &mut self.buf + } + + fn consume(&mut self, n: usize) { + self.pos += n; + } + + fn unconsume(&mut self, n: usize) { + self.pos -= n; + } + + fn buf_is_empty(&self) -> bool { + self.pos >= self.buf.len() + } + + fn buf_at_beginning(&self) -> bool { + self.pos == 0 + } + + fn should_parse_utf8(&self) -> bool { + self.parse_utf8 + } + + fn should_parse_ctrl(&self) -> bool { + self.parse_ctrl + } + + fn should_parse_meta(&self) -> bool { + self.parse_meta + } + + fn should_parse_special_keys(&self) -> bool { + self.parse_special_keys + } + + fn should_parse_single(&self) -> bool { + self.parse_single + } +} + #[allow(clippy::new_without_default)] impl Input { pub fn new() -> Result<(Self, RawGuard)> { @@ -99,305 +151,32 @@ impl Input { } pub fn read_key(&mut self) -> Result> { + self.fill_buf()?; + if self.parse_single { self.read_single_key() } else { - self.maybe_fill_buf()?; - if self.parse_utf8 { - let prefix: Vec<_> = self - .buf - .iter() - .copied() - .skip(self.pos) - .take_while(|&c| matches!(c, 32..=126 | 128..=255)) - .collect(); - if !prefix.is_empty() { - self.pos += prefix.len(); - match std::string::String::from_utf8(prefix) { - Ok(s) => return Ok(Some(crate::Key::String(s))), - Err(e) => { - return Ok(Some(crate::Key::Bytes( - e.into_bytes(), - ))) - } - } - } - } - - let prefix: Vec<_> = self - .buf - .iter() - .copied() - .skip(self.pos) - .take_while(|&c| match c { - 0 => true, - 1..=26 => !self.parse_ctrl, - 27 => !self.parse_meta && !self.parse_special_keys, - 28..=31 => true, - 32..=126 => true, - 127 => !self.parse_special_keys, - 128..=255 => true, - }) - .collect(); - if !prefix.is_empty() { - self.pos += prefix.len(); - return Ok(Some(crate::Key::Bytes(prefix))); - } - - self.read_single_key().map(|key| { - if let Some(crate::Key::Byte(c)) = key { - Some(crate::Key::Bytes(vec![c])) - } else { - key - } - }) - } - } - - fn read_single_key(&mut self) -> Result> { - match self.getc(true)? { - Some(0) => Ok(Some(crate::Key::Byte(0))), - Some(c @ 1..=26) => { - if self.parse_ctrl { - Ok(Some(crate::Key::Ctrl(b'a' + c - 1))) - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - Some(27) => { - if self.parse_meta || self.parse_special_keys { - self.read_escape_sequence() - } else { - Ok(Some(crate::Key::Byte(27))) - } - } - Some(c @ 28..=31) => Ok(Some(crate::Key::Byte(c))), - Some(c @ 32..=126) => { - if self.parse_utf8 { - Ok(Some(crate::Key::Char(c as char))) - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - Some(127) => { - if self.parse_special_keys { - Ok(Some(crate::Key::Backspace)) - } else { - Ok(Some(crate::Key::Byte(127))) - } - } - Some(c @ 128..=255) => { - if self.parse_utf8 { - self.read_utf8_char(c) - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - None => Ok(None), - } - } - - fn read_escape_sequence(&mut self) -> Result> { - let mut seen = vec![b'\x1b']; - - macro_rules! fail { - () => {{ - for &c in seen.iter().skip(1).rev() { - self.ungetc(c); - } - if self.parse_special_keys { - return Ok(Some(crate::Key::Escape)); - } else { - return Ok(Some(crate::Key::Byte(27))); - } - }}; - } - macro_rules! next_byte { - () => { - match self.getc(false)? { - Some(c) => c, - None => { - fail!() - } - } - }; - } - - enum EscapeState { - Escape, - CSI(Vec), - CKM, - } - - let mut state = EscapeState::Escape; - loop { - let c = next_byte!(); - seen.push(c); - match state { - EscapeState::Escape => match c { - b'[' => { - if self.parse_special_keys { - state = EscapeState::CSI(vec![]); - } else { - fail!() - } - } - b'O' => { - if self.parse_special_keys { - state = EscapeState::CKM; - } else { - fail!() - } - } - b' '..=b'N' | b'P'..=b'Z' | b'\\'..=b'~' => { - if self.parse_meta { - return Ok(Some(crate::Key::Meta(c))); - } else { - fail!() - } - } - _ => fail!(), - }, - EscapeState::CSI(ref mut param) => match c { - b'A' => return Ok(Some(crate::Key::Up)), - b'B' => return Ok(Some(crate::Key::Down)), - b'C' => return Ok(Some(crate::Key::Right)), - b'D' => return Ok(Some(crate::Key::Left)), - b'H' => return Ok(Some(crate::Key::Home)), - b'F' => return Ok(Some(crate::Key::End)), - b'0'..=b'9' => param.push(c), - b'~' => match param.as_slice() { - [b'2'] => return Ok(Some(crate::Key::Insert)), - [b'3'] => return Ok(Some(crate::Key::Delete)), - [b'5'] => return Ok(Some(crate::Key::PageUp)), - [b'6'] => return Ok(Some(crate::Key::PageDown)), - [b'1', b'5'] => return Ok(Some(crate::Key::F(5))), - [b'1', b'7'] => return Ok(Some(crate::Key::F(6))), - [b'1', b'8'] => return Ok(Some(crate::Key::F(7))), - [b'1', b'9'] => return Ok(Some(crate::Key::F(8))), - [b'2', b'0'] => return Ok(Some(crate::Key::F(9))), - [b'2', b'1'] => return Ok(Some(crate::Key::F(10))), - [b'2', b'3'] => return Ok(Some(crate::Key::F(11))), - [b'2', b'4'] => return Ok(Some(crate::Key::F(12))), - [b'2', b'5'] => return Ok(Some(crate::Key::F(13))), - [b'2', b'6'] => return Ok(Some(crate::Key::F(14))), - [b'2', b'8'] => return Ok(Some(crate::Key::F(15))), - [b'2', b'9'] => return Ok(Some(crate::Key::F(16))), - [b'3', b'1'] => return Ok(Some(crate::Key::F(17))), - [b'3', b'2'] => return Ok(Some(crate::Key::F(18))), - [b'3', b'3'] => return Ok(Some(crate::Key::F(19))), - [b'3', b'4'] => return Ok(Some(crate::Key::F(20))), - _ => fail!(), - }, - _ => fail!(), - }, - EscapeState::CKM => match c { - b'A' => return Ok(Some(crate::Key::KeypadUp)), - b'B' => return Ok(Some(crate::Key::KeypadDown)), - b'C' => return Ok(Some(crate::Key::KeypadRight)), - b'D' => return Ok(Some(crate::Key::KeypadLeft)), - b'P' => return Ok(Some(crate::Key::F(1))), - b'Q' => return Ok(Some(crate::Key::F(2))), - b'R' => return Ok(Some(crate::Key::F(3))), - b'S' => return Ok(Some(crate::Key::F(4))), - _ => fail!(), - }, - } - } - } - - fn read_utf8_char(&mut self, initial: u8) -> Result> { - let mut buf = vec![initial]; - - macro_rules! fail { - () => {{ - for &c in buf.iter().skip(1).rev() { - self.ungetc(c); - } - return Ok(Some(crate::Key::Byte(initial))); - }}; - } - macro_rules! next_byte { - () => { - match self.getc(true)? { - Some(c) => { - if (0b1000_0000..=0b1011_1111).contains(&c) { - c - } else { - fail!() - } - } - None => return Ok(None), - } - }; - } - - match initial { - 0b0000_0000..=0b0111_1111 => {} - 0b1100_0000..=0b1101_1111 => { - buf.push(next_byte!()); - } - 0b1110_0000..=0b1110_1111 => { - buf.push(next_byte!()); - buf.push(next_byte!()); + if let Some(s) = self.try_read_string()? { + return Ok(Some(s)); } - 0b1111_0000..=0b1111_0111 => { - buf.push(next_byte!()); - buf.push(next_byte!()); - buf.push(next_byte!()); - } - _ => fail!(), - } - match std::string::String::from_utf8(buf) { - // unwrap is fine because buf always contains at least the initial - // character, and we have already done the parsing to ensure that - // it contains a valid utf8 character before getting here - Ok(s) => Ok(Some(crate::Key::Char(s.chars().next().unwrap()))), - Err(e) => { - buf = e.into_bytes(); - fail!() + if let Some(s) = self.try_read_bytes()? { + return Ok(Some(s)); } - } - } - fn getc(&mut self, fill: bool) -> Result> { - if fill { - if !self.maybe_fill_buf()? { - return Ok(None); + if let Some(key) = self.read_single_key()? { + return Ok(Some(self.normalize_to_bytes(key))); } - } else { - if self.buf_is_empty() { - return Ok(None); - } - } - let c = self.buf[self.pos]; - self.pos += 1; - Ok(Some(c)) - } - fn ungetc(&mut self, c: u8) { - if self.pos == 0 { - self.buf.insert(0, c); - } else { - self.pos -= 1; - self.buf[self.pos] = c; + Ok(None) } } - fn maybe_fill_buf(&mut self) -> Result { - if self.buf_is_empty() { - self.fill_buf() - } else { - Ok(true) + fn fill_buf(&mut self) -> Result { + if !self.buf_is_empty() { + return Ok(true); } - } - - fn buf_is_empty(&self) -> bool { - self.pos >= self.buf.len() - } - fn fill_buf(&mut self) -> Result { self.buf.resize(4096, 0); self.pos = 0; let bytes = read_stdin(&mut self.buf)?; @@ -405,6 +184,24 @@ impl Input { return Ok(false); } self.buf.truncate(bytes); + + if self.parse_utf8 { + let mut extra = self.find_truncated_utf8(); + if extra > 0 { + let mut cur = self.buf.len(); + self.buf.resize(4096 + extra, 0); + while extra > 0 { + let bytes = read_stdin(&mut self.buf[cur..])?; + if bytes == 0 { + return Ok(false); + } + cur += bytes; + extra = extra.saturating_sub(bytes); + } + self.buf.truncate(cur); + } + } + Ok(true) } } diff --git a/src/input.rs b/src/input.rs index a324c85..7a87c8c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -3,6 +3,8 @@ use crate::error::*; use futures_lite::io::AsyncReadExt as _; use std::os::unix::io::AsRawFd as _; +use crate::private::InputImpl as _; + pub struct RawGuard { termios: nix::sys::termios::Termios, cleaned_up: bool, @@ -73,6 +75,56 @@ pub struct Input { parse_single: bool, } +impl super::private::InputImpl for Input { + fn buf(&self) -> &[u8] { + &self.buf[self.pos..] + } + + fn buf_mut(&mut self) -> &mut [u8] { + &mut self.buf[self.pos..] + } + + fn buf_mut_vec(&mut self) -> &mut Vec { + &mut self.buf + } + + fn consume(&mut self, n: usize) { + self.pos += n; + } + + fn unconsume(&mut self, n: usize) { + self.pos -= n; + } + + fn buf_is_empty(&self) -> bool { + self.pos >= self.buf.len() + } + + fn buf_at_beginning(&self) -> bool { + self.pos == 0 + } + + fn should_parse_utf8(&self) -> bool { + self.parse_utf8 + } + + fn should_parse_ctrl(&self) -> bool { + self.parse_ctrl + } + + fn should_parse_meta(&self) -> bool { + self.parse_meta + } + + fn should_parse_special_keys(&self) -> bool { + self.parse_special_keys + } + + fn should_parse_single(&self) -> bool { + self.parse_single + } +} + #[allow(clippy::new_without_default)] impl Input { pub async fn new() -> Result<(Self, RawGuard)> { @@ -113,308 +165,32 @@ impl Input { } pub async fn read_key(&mut self) -> Result> { + self.fill_buf().await?; + if self.parse_single { - self.read_single_key().await + self.read_single_key() } else { - self.maybe_fill_buf().await?; - if self.parse_utf8 { - let prefix: Vec<_> = self - .buf - .iter() - .copied() - .skip(self.pos) - .take_while(|&c| matches!(c, 32..=126 | 128..=255)) - .collect(); - if !prefix.is_empty() { - self.pos += prefix.len(); - match std::string::String::from_utf8(prefix) { - Ok(s) => return Ok(Some(crate::Key::String(s))), - Err(e) => { - return Ok(Some(crate::Key::Bytes( - e.into_bytes(), - ))) - } - } - } - } - - let prefix: Vec<_> = self - .buf - .iter() - .copied() - .skip(self.pos) - .take_while(|&c| match c { - 0 => true, - 1..=26 => !self.parse_ctrl, - 27 => !self.parse_meta && !self.parse_special_keys, - 28..=31 => true, - 32..=126 => true, - 127 => !self.parse_special_keys, - 128..=255 => true, - }) - .collect(); - if !prefix.is_empty() { - self.pos += prefix.len(); - return Ok(Some(crate::Key::Bytes(prefix))); - } - - self.read_single_key().await.map(|key| { - if let Some(crate::Key::Byte(c)) = key { - Some(crate::Key::Bytes(vec![c])) - } else { - key - } - }) - } - } - - async fn read_single_key(&mut self) -> Result> { - match self.getc(true).await? { - Some(0) => Ok(Some(crate::Key::Byte(0))), - Some(c @ 1..=26) => { - if self.parse_ctrl { - Ok(Some(crate::Key::Ctrl(b'a' + c - 1))) - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - Some(27) => { - if self.parse_meta || self.parse_special_keys { - self.read_escape_sequence().await - } else { - Ok(Some(crate::Key::Byte(27))) - } - } - Some(c @ 28..=31) => Ok(Some(crate::Key::Byte(c))), - Some(c @ 32..=126) => { - if self.parse_utf8 { - Ok(Some(crate::Key::Char(c as char))) - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - Some(127) => { - if self.parse_special_keys { - Ok(Some(crate::Key::Backspace)) - } else { - Ok(Some(crate::Key::Byte(127))) - } - } - Some(c @ 128..=255) => { - if self.parse_utf8 { - self.read_utf8_char(c).await - } else { - Ok(Some(crate::Key::Byte(c))) - } - } - None => Ok(None), - } - } - - async fn read_escape_sequence(&mut self) -> Result> { - let mut seen = vec![b'\x1b']; - - macro_rules! fail { - () => {{ - for &c in seen.iter().skip(1).rev() { - self.ungetc(c); - } - if self.parse_special_keys { - return Ok(Some(crate::Key::Escape)); - } else { - return Ok(Some(crate::Key::Byte(27))); - } - }}; - } - macro_rules! next_byte { - () => { - match self.getc(false).await? { - Some(c) => c, - None => { - fail!() - } - } - }; - } - - enum EscapeState { - Escape, - CSI(Vec), - CKM, - } - - let mut state = EscapeState::Escape; - loop { - let c = next_byte!(); - seen.push(c); - match state { - EscapeState::Escape => match c { - b'[' => { - if self.parse_special_keys { - state = EscapeState::CSI(vec![]); - } else { - fail!() - } - } - b'O' => { - if self.parse_special_keys { - state = EscapeState::CKM; - } else { - fail!() - } - } - b' '..=b'N' | b'P'..=b'Z' | b'\\'..=b'~' => { - if self.parse_meta { - return Ok(Some(crate::Key::Meta(c))); - } else { - fail!() - } - } - _ => fail!(), - }, - EscapeState::CSI(ref mut param) => match c { - b'A' => return Ok(Some(crate::Key::Up)), - b'B' => return Ok(Some(crate::Key::Down)), - b'C' => return Ok(Some(crate::Key::Right)), - b'D' => return Ok(Some(crate::Key::Left)), - b'H' => return Ok(Some(crate::Key::Home)), - b'F' => return Ok(Some(crate::Key::End)), - b'0'..=b'9' => param.push(c), - b'~' => match param.as_slice() { - [b'2'] => return Ok(Some(crate::Key::Insert)), - [b'3'] => return Ok(Some(crate::Key::Delete)), - [b'5'] => return Ok(Some(crate::Key::PageUp)), - [b'6'] => return Ok(Some(crate::Key::PageDown)), - [b'1', b'5'] => return Ok(Some(crate::Key::F(5))), - [b'1', b'7'] => return Ok(Some(crate::Key::F(6))), - [b'1', b'8'] => return Ok(Some(crate::Key::F(7))), - [b'1', b'9'] => return Ok(Some(crate::Key::F(8))), - [b'2', b'0'] => return Ok(Some(crate::Key::F(9))), - [b'2', b'1'] => return Ok(Some(crate::Key::F(10))), - [b'2', b'3'] => return Ok(Some(crate::Key::F(11))), - [b'2', b'4'] => return Ok(Some(crate::Key::F(12))), - [b'2', b'5'] => return Ok(Some(crate::Key::F(13))), - [b'2', b'6'] => return Ok(Some(crate::Key::F(14))), - [b'2', b'8'] => return Ok(Some(crate::Key::F(15))), - [b'2', b'9'] => return Ok(Some(crate::Key::F(16))), - [b'3', b'1'] => return Ok(Some(crate::Key::F(17))), - [b'3', b'2'] => return Ok(Some(crate::Key::F(18))), - [b'3', b'3'] => return Ok(Some(crate::Key::F(19))), - [b'3', b'4'] => return Ok(Some(crate::Key::F(20))), - _ => fail!(), - }, - _ => fail!(), - }, - EscapeState::CKM => match c { - b'A' => return Ok(Some(crate::Key::KeypadUp)), - b'B' => return Ok(Some(crate::Key::KeypadDown)), - b'C' => return Ok(Some(crate::Key::KeypadRight)), - b'D' => return Ok(Some(crate::Key::KeypadLeft)), - b'P' => return Ok(Some(crate::Key::F(1))), - b'Q' => return Ok(Some(crate::Key::F(2))), - b'R' => return Ok(Some(crate::Key::F(3))), - b'S' => return Ok(Some(crate::Key::F(4))), - _ => fail!(), - }, - } - } - } - - async fn read_utf8_char( - &mut self, - initial: u8, - ) -> Result> { - let mut buf = vec![initial]; - - macro_rules! fail { - () => {{ - for &c in buf.iter().skip(1).rev() { - self.ungetc(c); - } - return Ok(Some(crate::Key::Byte(initial))); - }}; - } - macro_rules! next_byte { - () => { - match self.getc(true).await? { - Some(c) => { - if (0b1000_0000..=0b1011_1111).contains(&c) { - c - } else { - fail!() - } - } - None => return Ok(None), - } - }; - } - - match initial { - 0b0000_0000..=0b0111_1111 => {} - 0b1100_0000..=0b1101_1111 => { - buf.push(next_byte!()); - } - 0b1110_0000..=0b1110_1111 => { - buf.push(next_byte!()); - buf.push(next_byte!()); + if let Some(s) = self.try_read_string()? { + return Ok(Some(s)); } - 0b1111_0000..=0b1111_0111 => { - buf.push(next_byte!()); - buf.push(next_byte!()); - buf.push(next_byte!()); - } - _ => fail!(), - } - match std::string::String::from_utf8(buf) { - // unwrap is fine because buf always contains at least the initial - // character, and we have already done the parsing to ensure that - // it contains a valid utf8 character before getting here - Ok(s) => Ok(Some(crate::Key::Char(s.chars().next().unwrap()))), - Err(e) => { - buf = e.into_bytes(); - fail!() + if let Some(s) = self.try_read_bytes()? { + return Ok(Some(s)); } - } - } - async fn getc(&mut self, fill: bool) -> Result> { - if fill { - if !self.maybe_fill_buf().await? { - return Ok(None); + if let Some(key) = self.read_single_key()? { + return Ok(Some(self.normalize_to_bytes(key))); } - } else { - if self.buf_is_empty() { - return Ok(None); - } - } - let c = self.buf[self.pos]; - self.pos += 1; - Ok(Some(c)) - } - fn ungetc(&mut self, c: u8) { - if self.pos == 0 { - self.buf.insert(0, c); - } else { - self.pos -= 1; - self.buf[self.pos] = c; + Ok(None) } } - async fn maybe_fill_buf(&mut self) -> Result { - if self.buf_is_empty() { - self.fill_buf().await - } else { - Ok(true) + async fn fill_buf(&mut self) -> Result { + if !self.buf_is_empty() { + return Ok(true); } - } - - fn buf_is_empty(&self) -> bool { - self.pos >= self.buf.len() - } - async fn fill_buf(&mut self) -> Result { self.buf.resize(4096, 0); self.pos = 0; let bytes = read_stdin(&mut self.stdin, &mut self.buf).await?; @@ -422,6 +198,26 @@ impl Input { return Ok(false); } self.buf.truncate(bytes); + + if self.parse_utf8 { + let mut extra = self.find_truncated_utf8(); + if extra > 0 { + let mut cur = self.buf.len(); + self.buf.resize(4096 + extra, 0); + while extra > 0 { + let bytes = + read_stdin(&mut self.stdin, &mut self.buf[cur..]) + .await?; + if bytes == 0 { + return Ok(false); + } + cur += bytes; + extra = extra.saturating_sub(bytes); + } + self.buf.truncate(cur); + } + } + Ok(true) } } diff --git a/src/lib.rs b/src/lib.rs index e4abf7b..79caedc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ mod error; pub use error::{Error, Result}; mod key; pub use key::Key; +mod private; #[cfg(feature = "async")] mod output; @@ -20,25 +21,6 @@ pub use input::{Input, RawGuard}; const INIT: &[u8] = b"\x1b7\x1b[?47h\x1b[2J\x1b[H\x1b[?25h"; const DEINIT: &[u8] = b"\x1b[?47l\x1b8\x1b[?25h"; -mod private { - pub trait TextmodeImpl { - fn cur(&self) -> &vt100::Parser; - fn cur_mut(&mut self) -> &mut vt100::Parser; - fn next(&self) -> &vt100::Parser; - fn next_mut(&mut self) -> &mut vt100::Parser; - - fn write_u16(&mut self, i: u16) { - // unwrap is fine because vt100::Parser::write can never fail - itoa::write(self.next_mut(), i).unwrap(); - } - - fn write_u8(&mut self, i: u8) { - // unwrap is fine because vt100::Parser::write can never fail - itoa::write(self.next_mut(), i).unwrap(); - } - } -} - pub trait Textmode: private::TextmodeImpl { fn screen(&self) -> &vt100::Screen { self.next().screen() diff --git a/src/private.rs b/src/private.rs new file mode 100644 index 0000000..a925a27 --- /dev/null +++ b/src/private.rs @@ -0,0 +1,339 @@ +pub trait TextmodeImpl { + fn cur(&self) -> &vt100::Parser; + fn cur_mut(&mut self) -> &mut vt100::Parser; + fn next(&self) -> &vt100::Parser; + fn next_mut(&mut self) -> &mut vt100::Parser; + + fn write_u16(&mut self, i: u16) { + // unwrap is fine because vt100::Parser::write can never fail + itoa::write(self.next_mut(), i).unwrap(); + } + + fn write_u8(&mut self, i: u8) { + // unwrap is fine because vt100::Parser::write can never fail + itoa::write(self.next_mut(), i).unwrap(); + } +} + +pub trait InputImpl { + fn buf(&self) -> &[u8]; + fn buf_mut(&mut self) -> &mut [u8]; + fn buf_mut_vec(&mut self) -> &mut Vec; + fn consume(&mut self, n: usize); + fn unconsume(&mut self, n: usize); + fn buf_is_empty(&self) -> bool; + fn buf_at_beginning(&self) -> bool; + + fn should_parse_utf8(&self) -> bool; + fn should_parse_ctrl(&self) -> bool; + fn should_parse_meta(&self) -> bool; + fn should_parse_special_keys(&self) -> bool; + fn should_parse_single(&self) -> bool; + + fn try_read_string(&mut self) -> crate::Result> { + if !self.should_parse_utf8() { + return Ok(None); + } + + let prefix: Vec<_> = self + .buf() + .iter() + .copied() + .take_while(|&c| matches!(c, 32..=126 | 128..=255)) + .collect(); + if !prefix.is_empty() { + self.consume(prefix.len()); + match std::string::String::from_utf8(prefix) { + Ok(s) => return Ok(Some(crate::Key::String(s))), + Err(e) => return Ok(Some(crate::Key::Bytes(e.into_bytes()))), + } + } + + Ok(None) + } + + fn try_read_bytes(&mut self) -> crate::Result> { + let prefix: Vec<_> = self + .buf() + .iter() + .copied() + .take_while(|&c| match c { + 0 => true, + 1..=26 => !self.should_parse_ctrl(), + 27 => { + !self.should_parse_meta() + && !self.should_parse_special_keys() + } + 28..=31 => true, + 32..=126 => true, + 127 => !self.should_parse_special_keys(), + 128..=255 => true, + }) + .collect(); + if !prefix.is_empty() { + self.consume(prefix.len()); + return Ok(Some(crate::Key::Bytes(prefix))); + } + + Ok(None) + } + + fn normalize_to_bytes(&self, key: crate::Key) -> crate::Key { + if let crate::Key::Byte(c) = key { + crate::Key::Bytes(vec![c]) + } else { + key + } + } + + fn read_single_key(&mut self) -> crate::Result> { + match self.getc() { + Some(0) => Ok(Some(crate::Key::Byte(0))), + Some(c @ 1..=26) => { + if self.should_parse_ctrl() { + Ok(Some(crate::Key::Ctrl(b'a' + c - 1))) + } else { + Ok(Some(crate::Key::Byte(c))) + } + } + Some(27) => { + if self.should_parse_meta() + || self.should_parse_special_keys() + { + self.read_escape_sequence() + } else { + Ok(Some(crate::Key::Byte(27))) + } + } + Some(c @ 28..=31) => Ok(Some(crate::Key::Byte(c))), + Some(c @ 32..=126) => { + if self.should_parse_utf8() { + Ok(Some(crate::Key::Char(c as char))) + } else { + Ok(Some(crate::Key::Byte(c))) + } + } + Some(127) => { + if self.should_parse_special_keys() { + Ok(Some(crate::Key::Backspace)) + } else { + Ok(Some(crate::Key::Byte(127))) + } + } + Some(c @ 128..=255) => { + if self.should_parse_utf8() { + self.read_utf8_char(c) + } else { + Ok(Some(crate::Key::Byte(c))) + } + } + None => Ok(None), + } + } + + fn read_escape_sequence(&mut self) -> crate::Result> { + let mut seen = vec![b'\x1b']; + + macro_rules! fail { + () => {{ + for &c in seen.iter().skip(1).rev() { + self.ungetc(c); + } + if self.should_parse_special_keys() { + return Ok(Some(crate::Key::Escape)); + } else { + return Ok(Some(crate::Key::Byte(27))); + } + }}; + } + macro_rules! next_byte { + () => { + match self.getc() { + Some(c) => c, + None => { + fail!() + } + } + }; + } + + enum EscapeState { + Escape, + CSI(Vec), + CKM, + } + + let mut state = EscapeState::Escape; + loop { + let c = next_byte!(); + seen.push(c); + match state { + EscapeState::Escape => match c { + b'[' => { + if self.should_parse_special_keys() { + state = EscapeState::CSI(vec![]); + } else { + fail!() + } + } + b'O' => { + if self.should_parse_special_keys() { + state = EscapeState::CKM; + } else { + fail!() + } + } + b' '..=b'N' | b'P'..=b'Z' | b'\\'..=b'~' => { + if self.should_parse_meta() { + return Ok(Some(crate::Key::Meta(c))); + } else { + fail!() + } + } + _ => fail!(), + }, + EscapeState::CSI(ref mut param) => match c { + b'A' => return Ok(Some(crate::Key::Up)), + b'B' => return Ok(Some(crate::Key::Down)), + b'C' => return Ok(Some(crate::Key::Right)), + b'D' => return Ok(Some(crate::Key::Left)), + b'H' => return Ok(Some(crate::Key::Home)), + b'F' => return Ok(Some(crate::Key::End)), + b'0'..=b'9' => param.push(c), + b'~' => match param.as_slice() { + [b'2'] => return Ok(Some(crate::Key::Insert)), + [b'3'] => return Ok(Some(crate::Key::Delete)), + [b'5'] => return Ok(Some(crate::Key::PageUp)), + [b'6'] => return Ok(Some(crate::Key::PageDown)), + [b'1', b'5'] => return Ok(Some(crate::Key::F(5))), + [b'1', b'7'] => return Ok(Some(crate::Key::F(6))), + [b'1', b'8'] => return Ok(Some(crate::Key::F(7))), + [b'1', b'9'] => return Ok(Some(crate::Key::F(8))), + [b'2', b'0'] => return Ok(Some(crate::Key::F(9))), + [b'2', b'1'] => return Ok(Some(crate::Key::F(10))), + [b'2', b'3'] => return Ok(Some(crate::Key::F(11))), + [b'2', b'4'] => return Ok(Some(crate::Key::F(12))), + [b'2', b'5'] => return Ok(Some(crate::Key::F(13))), + [b'2', b'6'] => return Ok(Some(crate::Key::F(14))), + [b'2', b'8'] => return Ok(Some(crate::Key::F(15))), + [b'2', b'9'] => return Ok(Some(crate::Key::F(16))), + [b'3', b'1'] => return Ok(Some(crate::Key::F(17))), + [b'3', b'2'] => return Ok(Some(crate::Key::F(18))), + [b'3', b'3'] => return Ok(Some(crate::Key::F(19))), + [b'3', b'4'] => return Ok(Some(crate::Key::F(20))), + _ => fail!(), + }, + _ => fail!(), + }, + EscapeState::CKM => match c { + b'A' => return Ok(Some(crate::Key::KeypadUp)), + b'B' => return Ok(Some(crate::Key::KeypadDown)), + b'C' => return Ok(Some(crate::Key::KeypadRight)), + b'D' => return Ok(Some(crate::Key::KeypadLeft)), + b'P' => return Ok(Some(crate::Key::F(1))), + b'Q' => return Ok(Some(crate::Key::F(2))), + b'R' => return Ok(Some(crate::Key::F(3))), + b'S' => return Ok(Some(crate::Key::F(4))), + _ => fail!(), + }, + } + } + } + + fn read_utf8_char( + &mut self, + initial: u8, + ) -> crate::Result> { + let mut buf = vec![initial]; + + macro_rules! fail { + () => {{ + for &c in buf.iter().skip(1).rev() { + self.ungetc(c); + } + return Ok(Some(crate::Key::Byte(initial))); + }}; + } + macro_rules! next_byte { + () => { + match self.getc() { + Some(c) => { + if (0b1000_0000..=0b1011_1111).contains(&c) { + c + } else { + fail!() + } + } + None => return Ok(None), + } + }; + } + + match initial { + 0b0000_0000..=0b0111_1111 => {} + 0b1100_0000..=0b1101_1111 => { + buf.push(next_byte!()); + } + 0b1110_0000..=0b1110_1111 => { + buf.push(next_byte!()); + buf.push(next_byte!()); + } + 0b1111_0000..=0b1111_0111 => { + buf.push(next_byte!()); + buf.push(next_byte!()); + buf.push(next_byte!()); + } + _ => fail!(), + } + + match std::string::String::from_utf8(buf) { + // unwrap is fine because buf always contains at least the + // initial character, and we have already done the parsing to + // ensure that it contains a valid utf8 character before + // getting here + Ok(s) => Ok(Some(crate::Key::Char(s.chars().next().unwrap()))), + Err(e) => { + buf = e.into_bytes(); + fail!() + } + } + } + + fn getc(&mut self) -> Option { + if self.buf_is_empty() { + return None; + } + let c = self.buf()[0]; + self.consume(1); + Some(c) + } + + fn ungetc(&mut self, c: u8) { + if self.buf_at_beginning() { + self.buf_mut_vec().insert(0, c); + } else { + self.unconsume(1); + self.buf_mut()[0] = c; + } + } + + fn find_truncated_utf8(&self) -> usize { + for i in 0..4 { + match self.buf()[self.buf().len() - 1 - i] { + 0b0000_0000..=0b0111_1111 => return 0, + 0b1100_0000..=0b1101_1111 => { + return 1usize.saturating_sub(i); + } + 0b1110_0000..=0b1110_1111 => { + return 2usize.saturating_sub(i); + } + 0b1111_0000..=0b1111_0111 => { + return 3usize.saturating_sub(i); + } + 0b1000_0000..=0b1011_1111 => {} + _ => return 0, + } + } + 0 + } +} -- cgit v1.2.3-54-g00ecf