summaryrefslogtreecommitdiffstats
path: root/vendor/anes/src/parser.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
commit023939b627b7dc93b01471f7d41fb8553ddb4ffa (patch)
tree60fc59477c605c72b0a1051409062ddecc43f877 /vendor/anes/src/parser.rs
parentAdding debian version 1.72.1+dfsg1-1. (diff)
downloadrustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.tar.xz
rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/anes/src/parser.rs')
-rw-r--r--vendor/anes/src/parser.rs252
1 files changed, 252 insertions, 0 deletions
diff --git a/vendor/anes/src/parser.rs b/vendor/anes/src/parser.rs
new file mode 100644
index 000000000..be87b2986
--- /dev/null
+++ b/vendor/anes/src/parser.rs
@@ -0,0 +1,252 @@
+//! 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());
+ }
+}