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 +++++++++++--------------------------------------- 1 file changed, 82 insertions(+), 285 deletions(-) (limited to 'src/blocking') 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) } } -- cgit v1.2.3-54-g00ecf