blob: be87b2986eaacf77fef02c234188802f0eae1379 [file] [log] [blame] [edit]
//! An ANSI escape sequence parser module.
//!
//! **This module is not available with default features. You have to enable `parser` feature
//! if you'd like to use it.**
//!
//! # Parser
//!
//! The ANSI escape sequence parser parses input data in two steps:
//!
//! * transforms input data into valid characters, generic csi & escape sequences, throws away invalid data,
//! * give them meaning, throws away sequences without known meaning.
//!
//! ## First step
//!
//! State machine implementation for the first step is inspired by the
//! [A parser for DEC’s ANSI-compatible video terminals](https://vt100.net/emu/dec_ansi_parser) article
//! and the [vte](https://crates.io/crates/vte) crate. The goal of this step is to transform an input
//! data into characters, generic csi & escape sequences, validate them and throw away malformed input.
//!
//! An example of valid csi sequence: `b"\x1B[20;10R"`. Output of the first step will be:
//!
//! * valid csi sequence
//! * with two parameters `[20, 10]`
//! * and the final character `R`.
//!
//! ## Second step
//!
//! An input of this step is output of the first one. We know that the final character `R` represents
//! cursor position and two parameters should be provided. They were provided, we can give it a
//! meaning and return `Sequence::CursorPosition(10, 20)`.
//!
//! All sequences without known meaning are discarded.
//!
//! ## Implementation
//!
//! Both steps are considered as an implementation detail and there's no plan to make them
//! publicly available.
//!
//! The `parser` module provides the [`Parser`](struct.Parser.html) structure you can feed with
//! the [`advance`](struct.Parser.html#method.advance) method. It also implements the standard
//! library `Iterator<Item = Sequence>` trait which allows you to consume valid sequences with
//! known meaning via the `next()` method. Check the [`Sequence`](enum.Sequence.html) enum to learn
//! what this module can parse.
use std::collections::VecDeque;
use engine::{Engine, Provide};
pub use types::{KeyCode, KeyModifiers, Mouse, MouseButton, Sequence};
mod engine;
mod parsers;
pub(crate) mod types;
/// An ANSI escape sequence parser.
///
/// `Parser` implements the `Iterator<Item = Sequence>` trait, thus you can use the
/// `next()` method to consume all valid sequences with known meaning.
///
/// # Examples
///
/// Parse cursor position:
///
/// ```
/// use anes::parser::{Parser, Sequence};
///
/// let mut parser = Parser::default();
/// parser.advance(b"\x1B[20;10R", false);
///
/// assert_eq!(Some(Sequence::CursorPosition(10, 20)), parser.next());
/// assert!(parser.next().is_none());
/// ```
///
/// Parse keyboard event:
///
/// ```
/// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence};
///
/// let mut parser = Parser::default();
/// parser.advance("𐌼a".as_bytes(), false);
///
/// assert_eq!(Some(Sequence::Key(KeyCode::Char('𐌼'), KeyModifiers::empty())), parser.next());
/// assert_eq!(Some(Sequence::Key(KeyCode::Char('a'), KeyModifiers::empty())), parser.next());
/// assert!(parser.next().is_none());
/// ```
#[derive(Default)]
pub struct Parser {
engine: Engine,
provider: SequenceProvider,
}
impl Parser {
/// Advances parser state machine with additional input data.
///
/// # Arguments
///
/// * `buffer` - input data (stdin in raw mode, etc.)
/// * `more` - more input data available right now
///
/// It's crucial to provide correct `more` value in order to receive `KeyCode::Esc` events
/// as soon as possible.
///
/// # Examples
///
/// Esc key:
///
/// ```
/// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence};
///
/// let mut parser = Parser::default();
/// // User pressed Esc key & nothing else which means that there's no additional input available
/// // aka no possible escape sequence = `KeyCode::Esc` dispatched.
/// parser.advance(&[0x1b], false);
///
/// assert_eq!(Some(Sequence::Key(KeyCode::Esc, KeyModifiers::empty())), parser.next());
/// assert!(parser.next().is_none());
/// ```
///
/// Possible escape sequence:
///
/// ```
/// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence};
///
/// let mut parser = Parser::default();
/// // User pressed F1 = b"\x1BOP"
///
/// // Every escape sequence starts with Esc (0x1b). There's more input available
/// // aka possible escape sequence = `KeyCode::Esc` isn't dispatched even when the parser
/// // doesn't know rest of the sequence.
/// parser.advance(&[0x1b], true);
/// assert!(parser.next().is_none());
///
/// // Advance parser with rest of the sequence
/// parser.advance(&[b'O', b'P'], false);
/// assert_eq!(Some(Sequence::Key(KeyCode::F(1), KeyModifiers::empty())), parser.next());
/// assert!(parser.next().is_none());
/// ```
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) {
// eprintln!("dispatch_char: {}", ch);
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' {
// Exception
//
// Esc O - dispatched as an escape sequence followed by single character (P-S) representing
// F1-F4 keys. We store Esc O flag only which is then used in the dispatch_char method.
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());
}
}