use std::collections::VecDeque;
use engine::{Engine, Provide};
pub use types::{KeyCode, KeyModifiers, Mouse, MouseButton, Sequence};
mod engine;
mod parsers;
pub(crate) mod types;
#[derive(Default)]
pub struct Parser {
engine: Engine,
provider: SequenceProvider,
}
impl Parser {
pub fn advance(&mut self, buffer: &[u8], more: bool) {
let len = buffer.len();
for (idx, byte) in buffer.iter().enumerate() {
self.engine
.advance(&mut self.provider, *byte, idx < len - 1 || more);
}
}
}
impl Iterator for Parser {
type Item = Sequence;
fn next(&mut self) -> Option<Self::Item> {
self.provider.next()
}
}
#[derive(Default)]
struct SequenceProvider {
esc_o: bool,
seqs: VecDeque<Sequence>,
}
impl Iterator for SequenceProvider {
type Item = Sequence;
fn next(&mut self) -> Option<Self::Item> {
self.seqs.pop_front()
}
}
impl Provide for SequenceProvider {
fn provide_char(&mut self, ch: char) {
if let Some(seq) = parsers::parse_char(ch, self.esc_o) {
self.seqs.push_back(seq);
}
self.esc_o = false;
}
fn provide_esc_sequence(&mut self, ch: char) {
if ch == 'O' {
self.esc_o = true;
} else {
self.esc_o = false;
if let Some(seq) = parsers::parse_esc_sequence(ch) {
self.seqs.push_back(seq);
}
}
}
fn provide_csi_sequence(&mut self, parameters: &[u64], ignored_count: usize, ch: char) {
if let Some(seq) = parsers::parse_csi_sequence(parameters, ignored_count, ch) {
self.seqs.push_back(seq);
}
self.esc_o = false;
}
}
#[cfg(test)]
mod tests {
use super::Parser;
#[test]
fn dispatch_char() {
let mut parser = Parser::default();
parser.advance(&[b'a'], false);
assert!(parser.next().is_some());
}
#[test]
fn dispatch_esc_sequence() {
let mut parser = Parser::default();
parser.advance(&[b'\x1B'], true);
assert!(parser.next().is_none());
parser.advance(&[b'a'], false);
assert!(parser.next().is_some());
}
#[test]
fn does_not_dispatch_esc_sequence_with_upper_case_o() {
let mut parser = Parser::default();
parser.advance(&[b'\x1B'], true);
assert!(parser.next().is_none());
parser.advance(&[b'O'], true);
assert!(parser.next().is_none());
}
#[test]
fn dispatch_esc_with_upper_case_o_followed_by_char_as_single_sequence() {
let mut parser = Parser::default();
parser.advance(&[b'\x1B'], true);
assert!(parser.next().is_none());
parser.advance(&[b'O'], true);
assert!(parser.next().is_none());
parser.advance(&[b'P'], false);
assert!(parser.next().is_some());
assert!(parser.next().is_none());
}
#[test]
fn dispatch_csi_sequence() {
let mut parser = Parser::default();
parser.advance(&[b'\x1B'], true);
assert!(parser.next().is_none());
parser.advance(&[b'['], true);
assert!(parser.next().is_none());
parser.advance(&[b'D'], false);
assert!(parser.next().is_some());
}
}