vte/
lib.rs

1//! Parser for implementing virtual terminal emulators
2//!
3//! [`Parser`] is implemented according to [Paul Williams' ANSI parser
4//! state machine]. The state machine doesn't assign meaning to the parsed data
5//! and is thus not itself sufficient for writing a terminal emulator. Instead,
6//! it is expected that an implementation of [`Perform`] is provided which does
7//! something useful with the parsed data. The [`Parser`] handles the book
8//! keeping, and the [`Perform`] gets to simply handle actions.
9//!
10//! # Examples
11//!
12//! For an example of using the [`Parser`] please see the examples folder. The example included
13//! there simply logs all the actions [`Perform`] does. One quick thing to see it in action is to
14//! pipe `vim` into it
15//!
16//! ```sh
17//! cargo build --release --example parselog
18//! vim | target/release/examples/parselog
19//! ```
20//!
21//! Just type `:q` to exit.
22//!
23//! # Differences from original state machine description
24//!
25//! * UTF-8 Support for Input
26//! * OSC Strings can be terminated by 0x07
27//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they no longer work in
28//!   all states.
29//!
30//! [`Parser`]: struct.Parser.html
31//! [`Perform`]: trait.Perform.html
32//! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser
33#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]
34#![cfg_attr(all(feature = "nightly", test), feature(test))]
35#![cfg_attr(feature = "no_std", no_std)]
36
37use core::mem::MaybeUninit;
38
39#[cfg(feature = "no_std")]
40use arrayvec::ArrayVec;
41use utf8parse as utf8;
42
43mod definitions;
44mod params;
45mod table;
46
47#[cfg(feature = "ansi")]
48pub mod ansi;
49pub use params::{Params, ParamsIter};
50
51use definitions::{unpack, Action, State};
52
53const MAX_INTERMEDIATES: usize = 2;
54const MAX_OSC_PARAMS: usize = 16;
55#[cfg(any(feature = "no_std", test))]
56const MAX_OSC_RAW: usize = 1024;
57
58struct VtUtf8Receiver<'a, P: Perform>(&'a mut P, &'a mut State);
59
60impl<'a, P: Perform> utf8::Receiver for VtUtf8Receiver<'a, P> {
61    fn codepoint(&mut self, c: char) {
62        self.0.print(c);
63        *self.1 = State::Ground;
64    }
65
66    fn invalid_sequence(&mut self) {
67        self.0.print('�');
68        *self.1 = State::Ground;
69    }
70}
71
72/// Parser for raw _VTE_ protocol which delegates actions to a [`Perform`]
73///
74/// [`Perform`]: trait.Perform.html
75#[derive(Default)]
76pub struct Parser {
77    state: State,
78    intermediates: [u8; MAX_INTERMEDIATES],
79    intermediate_idx: usize,
80    params: Params,
81    param: u16,
82    #[cfg(feature = "no_std")]
83    osc_raw: ArrayVec<u8, MAX_OSC_RAW>,
84    #[cfg(not(feature = "no_std"))]
85    osc_raw: Vec<u8>,
86    osc_params: [(usize, usize); MAX_OSC_PARAMS],
87    osc_num_params: usize,
88    ignoring: bool,
89    utf8_parser: utf8::Parser,
90}
91
92impl Parser {
93    /// Create a new Parser
94    pub fn new() -> Parser {
95        Parser::default()
96    }
97
98    #[inline]
99    fn params(&self) -> &Params {
100        &self.params
101    }
102
103    #[inline]
104    fn intermediates(&self) -> &[u8] {
105        &self.intermediates[..self.intermediate_idx]
106    }
107
108    /// Advance the parser state
109    ///
110    /// Requires a [`Perform`] in case `byte` triggers an action
111    ///
112    /// [`Perform`]: trait.Perform.html
113    #[inline]
114    pub fn advance<P: Perform>(&mut self, performer: &mut P, byte: u8) {
115        // Utf8 characters are handled out-of-band.
116        if let State::Utf8 = self.state {
117            self.process_utf8(performer, byte);
118            return;
119        }
120
121        // Handle state changes in the anywhere state before evaluating changes
122        // for current state.
123        let mut change = table::STATE_CHANGES[State::Anywhere as usize][byte as usize];
124
125        if change == 0 {
126            change = table::STATE_CHANGES[self.state as usize][byte as usize];
127        }
128
129        // Unpack into a state and action
130        let (state, action) = unpack(change);
131
132        self.perform_state_change(performer, state, action, byte);
133    }
134
135    #[inline]
136    fn process_utf8<P>(&mut self, performer: &mut P, byte: u8)
137    where
138        P: Perform,
139    {
140        let mut receiver = VtUtf8Receiver(performer, &mut self.state);
141        let utf8_parser = &mut self.utf8_parser;
142        utf8_parser.advance(&mut receiver, byte);
143    }
144
145    #[inline]
146    fn perform_state_change<P>(&mut self, performer: &mut P, state: State, action: Action, byte: u8)
147    where
148        P: Perform,
149    {
150        macro_rules! maybe_action {
151            ($action:expr, $arg:expr) => {
152                match $action {
153                    Action::None => (),
154                    action => {
155                        self.perform_action(performer, action, $arg);
156                    },
157                }
158            };
159        }
160
161        match state {
162            State::Anywhere => {
163                // Just run the action
164                self.perform_action(performer, action, byte);
165            },
166            state => {
167                match self.state {
168                    State::DcsPassthrough => {
169                        self.perform_action(performer, Action::Unhook, byte);
170                    },
171                    State::OscString => {
172                        self.perform_action(performer, Action::OscEnd, byte);
173                    },
174                    _ => (),
175                }
176
177                maybe_action!(action, byte);
178
179                match state {
180                    State::CsiEntry | State::DcsEntry | State::Escape => {
181                        self.perform_action(performer, Action::Clear, byte);
182                    },
183                    State::DcsPassthrough => {
184                        self.perform_action(performer, Action::Hook, byte);
185                    },
186                    State::OscString => {
187                        self.perform_action(performer, Action::OscStart, byte);
188                    },
189                    _ => (),
190                }
191
192                // Assume the new state
193                self.state = state;
194            },
195        }
196    }
197
198    /// Separate method for osc_dispatch that borrows self as read-only
199    ///
200    /// The aliasing is needed here for multiple slices into self.osc_raw
201    #[inline]
202    fn osc_dispatch<P: Perform>(&self, performer: &mut P, byte: u8) {
203        let mut slices: [MaybeUninit<&[u8]>; MAX_OSC_PARAMS] =
204            unsafe { MaybeUninit::uninit().assume_init() };
205
206        for (i, slice) in slices.iter_mut().enumerate().take(self.osc_num_params) {
207            let indices = self.osc_params[i];
208            *slice = MaybeUninit::new(&self.osc_raw[indices.0..indices.1]);
209        }
210
211        unsafe {
212            let num_params = self.osc_num_params;
213            let params = &slices[..num_params] as *const [MaybeUninit<&[u8]>] as *const [&[u8]];
214            performer.osc_dispatch(&*params, byte == 0x07);
215        }
216    }
217
218    #[inline]
219    fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) {
220        match action {
221            Action::Print => performer.print(byte as char),
222            Action::Execute => performer.execute(byte),
223            Action::Hook => {
224                if self.params.is_full() {
225                    self.ignoring = true;
226                } else {
227                    self.params.push(self.param);
228                }
229
230                performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char);
231            },
232            Action::Put => performer.put(byte),
233            Action::OscStart => {
234                self.osc_raw.clear();
235                self.osc_num_params = 0;
236            },
237            Action::OscPut => {
238                #[cfg(feature = "no_std")]
239                {
240                    if self.osc_raw.is_full() {
241                        return;
242                    }
243                }
244
245                let idx = self.osc_raw.len();
246
247                // Param separator
248                if byte == b';' {
249                    let param_idx = self.osc_num_params;
250                    match param_idx {
251                        // Only process up to MAX_OSC_PARAMS
252                        MAX_OSC_PARAMS => return,
253
254                        // First param is special - 0 to current byte index
255                        0 => {
256                            self.osc_params[param_idx] = (0, idx);
257                        },
258
259                        // All other params depend on previous indexing
260                        _ => {
261                            let prev = self.osc_params[param_idx - 1];
262                            let begin = prev.1;
263                            self.osc_params[param_idx] = (begin, idx);
264                        },
265                    }
266
267                    self.osc_num_params += 1;
268                } else {
269                    self.osc_raw.push(byte);
270                }
271            },
272            Action::OscEnd => {
273                let param_idx = self.osc_num_params;
274                let idx = self.osc_raw.len();
275
276                match param_idx {
277                    // Finish last parameter if not already maxed
278                    MAX_OSC_PARAMS => (),
279
280                    // First param is special - 0 to current byte index
281                    0 => {
282                        self.osc_params[param_idx] = (0, idx);
283                        self.osc_num_params += 1;
284                    },
285
286                    // All other params depend on previous indexing
287                    _ => {
288                        let prev = self.osc_params[param_idx - 1];
289                        let begin = prev.1;
290                        self.osc_params[param_idx] = (begin, idx);
291                        self.osc_num_params += 1;
292                    },
293                }
294                self.osc_dispatch(performer, byte);
295            },
296            Action::Unhook => performer.unhook(),
297            Action::CsiDispatch => {
298                if self.params.is_full() {
299                    self.ignoring = true;
300                } else {
301                    self.params.push(self.param);
302                }
303
304                performer.csi_dispatch(
305                    self.params(),
306                    self.intermediates(),
307                    self.ignoring,
308                    byte as char,
309                );
310            },
311            Action::EscDispatch => {
312                performer.esc_dispatch(self.intermediates(), self.ignoring, byte);
313            },
314            Action::Collect => {
315                if self.intermediate_idx == MAX_INTERMEDIATES {
316                    self.ignoring = true;
317                } else {
318                    self.intermediates[self.intermediate_idx] = byte;
319                    self.intermediate_idx += 1;
320                }
321            },
322            Action::Param => {
323                if self.params.is_full() {
324                    self.ignoring = true;
325                    return;
326                }
327
328                if byte == b';' {
329                    self.params.push(self.param);
330                    self.param = 0;
331                } else if byte == b':' {
332                    self.params.extend(self.param);
333                    self.param = 0;
334                } else {
335                    // Continue collecting bytes into param
336                    self.param = self.param.saturating_mul(10);
337                    self.param = self.param.saturating_add((byte - b'0') as u16);
338                }
339            },
340            Action::Clear => {
341                // Reset everything on ESC/CSI/DCS entry
342                self.intermediate_idx = 0;
343                self.ignoring = false;
344                self.param = 0;
345
346                self.params.clear();
347            },
348            Action::BeginUtf8 => self.process_utf8(performer, byte),
349            Action::Ignore => (),
350            Action::None => (),
351        }
352    }
353}
354
355/// Performs actions requested by the Parser
356///
357/// Actions in this case mean, for example, handling a CSI escape sequence describing cursor
358/// movement, or simply printing characters to the screen.
359///
360/// The methods on this type correspond to actions described in
361/// http://vt100.net/emu/dec_ansi_parser. I've done my best to describe them in
362/// a useful way in my own words for completeness, but the site should be
363/// referenced if something isn't clear. If the site disappears at some point in
364/// the future, consider checking archive.org.
365pub trait Perform {
366    /// Draw a character to the screen and update states.
367    fn print(&mut self, _c: char) {}
368
369    /// Execute a C0 or C1 control function.
370    fn execute(&mut self, _byte: u8) {}
371
372    /// Invoked when a final character arrives in first part of device control string.
373    ///
374    /// The control function should be determined from the private marker, final character, and
375    /// execute with a parameter list. A handler should be selected for remaining characters in the
376    /// string; the handler function should subsequently be called by `put` for every character in
377    /// the control string.
378    ///
379    /// The `ignore` flag indicates that more than two intermediates arrived and
380    /// subsequent characters were ignored.
381    fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _action: char) {}
382
383    /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls
384    /// will also be passed to the handler.
385    fn put(&mut self, _byte: u8) {}
386
387    /// Called when a device control string is terminated.
388    ///
389    /// The previously selected handler should be notified that the DCS has
390    /// terminated.
391    fn unhook(&mut self) {}
392
393    /// Dispatch an operating system command.
394    fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}
395
396    /// A final character has arrived for a CSI sequence
397    ///
398    /// The `ignore` flag indicates that either more than two intermediates arrived
399    /// or the number of parameters exceeded the maximum supported length,
400    /// and subsequent characters were ignored.
401    fn csi_dispatch(
402        &mut self,
403        _params: &Params,
404        _intermediates: &[u8],
405        _ignore: bool,
406        _action: char,
407    ) {
408    }
409
410    /// The final character of an escape sequence has arrived.
411    ///
412    /// The `ignore` flag indicates that more than two intermediates arrived and
413    /// subsequent characters were ignored.
414    fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}
415}
416
417#[cfg(all(test, feature = "no_std"))]
418#[macro_use]
419extern crate std;
420
421#[cfg(test)]
422mod tests {
423    use super::*;
424
425    use std::vec::Vec;
426
427    static OSC_BYTES: &[u8] = &[
428        0x1b, 0x5d, // Begin OSC
429        b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd',
430        b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', b'd', b'e', b'/', b'a', b'l', b'a',
431        b'c', b'r', b'i', b't', b't', b'y', 0x07, // End OSC
432    ];
433
434    #[derive(Default)]
435    struct Dispatcher {
436        dispatched: Vec<Sequence>,
437    }
438
439    #[derive(Debug, PartialEq, Eq)]
440    enum Sequence {
441        Osc(Vec<Vec<u8>>, bool),
442        Csi(Vec<Vec<u16>>, Vec<u8>, bool, char),
443        Esc(Vec<u8>, bool, u8),
444        DcsHook(Vec<Vec<u16>>, Vec<u8>, bool, char),
445        DcsPut(u8),
446        DcsUnhook,
447    }
448
449    impl Perform for Dispatcher {
450        fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
451            let params = params.iter().map(|p| p.to_vec()).collect();
452            self.dispatched.push(Sequence::Osc(params, bell_terminated));
453        }
454
455        fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
456            let params = params.iter().map(|subparam| subparam.to_vec()).collect();
457            let intermediates = intermediates.to_vec();
458            self.dispatched.push(Sequence::Csi(params, intermediates, ignore, c));
459        }
460
461        fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
462            let intermediates = intermediates.to_vec();
463            self.dispatched.push(Sequence::Esc(intermediates, ignore, byte));
464        }
465
466        fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
467            let params = params.iter().map(|subparam| subparam.to_vec()).collect();
468            let intermediates = intermediates.to_vec();
469            self.dispatched.push(Sequence::DcsHook(params, intermediates, ignore, c));
470        }
471
472        fn put(&mut self, byte: u8) {
473            self.dispatched.push(Sequence::DcsPut(byte));
474        }
475
476        fn unhook(&mut self) {
477            self.dispatched.push(Sequence::DcsUnhook);
478        }
479    }
480
481    #[test]
482    fn parse_osc() {
483        let mut dispatcher = Dispatcher::default();
484        let mut parser = Parser::new();
485
486        for byte in OSC_BYTES {
487            parser.advance(&mut dispatcher, *byte);
488        }
489
490        assert_eq!(dispatcher.dispatched.len(), 1);
491        match &dispatcher.dispatched[0] {
492            Sequence::Osc(params, _) => {
493                assert_eq!(params.len(), 2);
494                assert_eq!(params[0], &OSC_BYTES[2..3]);
495                assert_eq!(params[1], &OSC_BYTES[4..(OSC_BYTES.len() - 1)]);
496            },
497            _ => panic!("expected osc sequence"),
498        }
499    }
500
501    #[test]
502    fn parse_empty_osc() {
503        let mut dispatcher = Dispatcher::default();
504        let mut parser = Parser::new();
505
506        for byte in &[0x1b, 0x5d, 0x07] {
507            parser.advance(&mut dispatcher, *byte);
508        }
509
510        assert_eq!(dispatcher.dispatched.len(), 1);
511        match &dispatcher.dispatched[0] {
512            Sequence::Osc(..) => (),
513            _ => panic!("expected osc sequence"),
514        }
515    }
516
517    #[test]
518    fn parse_osc_max_params() {
519        let params = ";".repeat(params::MAX_PARAMS + 1);
520        let input = format!("\x1b]{}\x1b", &params[..]).into_bytes();
521        let mut dispatcher = Dispatcher::default();
522        let mut parser = Parser::new();
523
524        for byte in input {
525            parser.advance(&mut dispatcher, byte);
526        }
527
528        assert_eq!(dispatcher.dispatched.len(), 1);
529        match &dispatcher.dispatched[0] {
530            Sequence::Osc(params, _) => {
531                assert_eq!(params.len(), MAX_OSC_PARAMS);
532                assert!(params.iter().all(Vec::is_empty));
533            },
534            _ => panic!("expected osc sequence"),
535        }
536    }
537
538    #[test]
539    fn osc_bell_terminated() {
540        static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07";
541        let mut dispatcher = Dispatcher::default();
542        let mut parser = Parser::new();
543
544        for byte in INPUT {
545            parser.advance(&mut dispatcher, *byte);
546        }
547
548        assert_eq!(dispatcher.dispatched.len(), 1);
549        match &dispatcher.dispatched[0] {
550            Sequence::Osc(_, true) => (),
551            _ => panic!("expected osc with bell terminator"),
552        }
553    }
554
555    #[test]
556    fn osc_c0_st_terminated() {
557        static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\";
558        let mut dispatcher = Dispatcher::default();
559        let mut parser = Parser::new();
560
561        for byte in INPUT {
562            parser.advance(&mut dispatcher, *byte);
563        }
564
565        assert_eq!(dispatcher.dispatched.len(), 2);
566        match &dispatcher.dispatched[0] {
567            Sequence::Osc(_, false) => (),
568            _ => panic!("expected osc with ST terminator"),
569        }
570    }
571
572    #[test]
573    fn parse_osc_with_utf8_arguments() {
574        static INPUT: &[u8] = &[
575            0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0xc2, 0xaf, 0x5c,
576            0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26,
577            0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07,
578        ];
579        let mut dispatcher = Dispatcher::default();
580        let mut parser = Parser::new();
581
582        for byte in INPUT {
583            parser.advance(&mut dispatcher, *byte);
584        }
585
586        assert_eq!(dispatcher.dispatched.len(), 1);
587        match &dispatcher.dispatched[0] {
588            Sequence::Osc(params, _) => {
589                assert_eq!(params[0], &[b'2']);
590                assert_eq!(params[1], &INPUT[5..(INPUT.len() - 1)]);
591            },
592            _ => panic!("expected osc sequence"),
593        }
594    }
595
596    #[test]
597    fn osc_containing_string_terminator() {
598        static INPUT: &[u8] = b"\x1b]2;\xe6\x9c\xab\x1b\\";
599        let mut dispatcher = Dispatcher::default();
600        let mut parser = Parser::new();
601
602        for byte in INPUT {
603            parser.advance(&mut dispatcher, *byte);
604        }
605
606        assert_eq!(dispatcher.dispatched.len(), 2);
607        match &dispatcher.dispatched[0] {
608            Sequence::Osc(params, _) => {
609                assert_eq!(params[1], &INPUT[4..(INPUT.len() - 2)]);
610            },
611            _ => panic!("expected osc sequence"),
612        }
613    }
614
615    #[test]
616    fn exceed_max_buffer_size() {
617        static NUM_BYTES: usize = MAX_OSC_RAW + 100;
618        static INPUT_START: &[u8] = &[0x1b, b']', b'5', b'2', b';', b's'];
619        static INPUT_END: &[u8] = &[b'\x07'];
620
621        let mut dispatcher = Dispatcher::default();
622        let mut parser = Parser::new();
623
624        // Create valid OSC escape
625        for byte in INPUT_START {
626            parser.advance(&mut dispatcher, *byte);
627        }
628
629        // Exceed max buffer size
630        for _ in 0..NUM_BYTES {
631            parser.advance(&mut dispatcher, b'a');
632        }
633
634        // Terminate escape for dispatch
635        for byte in INPUT_END {
636            parser.advance(&mut dispatcher, *byte);
637        }
638
639        assert_eq!(dispatcher.dispatched.len(), 1);
640        match &dispatcher.dispatched[0] {
641            Sequence::Osc(params, _) => {
642                assert_eq!(params.len(), 2);
643                assert_eq!(params[0], b"52");
644
645                #[cfg(not(feature = "no_std"))]
646                assert_eq!(params[1].len(), NUM_BYTES + INPUT_END.len());
647
648                #[cfg(feature = "no_std")]
649                assert_eq!(params[1].len(), MAX_OSC_RAW - params[0].len());
650            },
651            _ => panic!("expected osc sequence"),
652        }
653    }
654
655    #[test]
656    fn parse_csi_max_params() {
657        // This will build a list of repeating '1;'s
658        // The length is MAX_PARAMS - 1 because the last semicolon is interpreted
659        // as an implicit zero, making the total number of parameters MAX_PARAMS
660        let params = "1;".repeat(params::MAX_PARAMS - 1);
661        let input = format!("\x1b[{}p", &params[..]).into_bytes();
662
663        let mut dispatcher = Dispatcher::default();
664        let mut parser = Parser::new();
665
666        for byte in input {
667            parser.advance(&mut dispatcher, byte);
668        }
669
670        assert_eq!(dispatcher.dispatched.len(), 1);
671        match &dispatcher.dispatched[0] {
672            Sequence::Csi(params, _, ignore, _) => {
673                assert_eq!(params.len(), params::MAX_PARAMS);
674                assert!(!ignore);
675            },
676            _ => panic!("expected csi sequence"),
677        }
678    }
679
680    #[test]
681    fn parse_csi_params_ignore_long_params() {
682        // This will build a list of repeating '1;'s
683        // The length is MAX_PARAMS because the last semicolon is interpreted
684        // as an implicit zero, making the total number of parameters MAX_PARAMS + 1
685        let params = "1;".repeat(params::MAX_PARAMS);
686        let input = format!("\x1b[{}p", &params[..]).into_bytes();
687
688        let mut dispatcher = Dispatcher::default();
689        let mut parser = Parser::new();
690
691        for byte in input {
692            parser.advance(&mut dispatcher, byte);
693        }
694
695        assert_eq!(dispatcher.dispatched.len(), 1);
696        match &dispatcher.dispatched[0] {
697            Sequence::Csi(params, _, ignore, _) => {
698                assert_eq!(params.len(), params::MAX_PARAMS);
699                assert!(ignore);
700            },
701            _ => panic!("expected csi sequence"),
702        }
703    }
704
705    #[test]
706    fn parse_csi_params_trailing_semicolon() {
707        let mut dispatcher = Dispatcher::default();
708        let mut parser = Parser::new();
709
710        for byte in b"\x1b[4;m" {
711            parser.advance(&mut dispatcher, *byte);
712        }
713
714        assert_eq!(dispatcher.dispatched.len(), 1);
715        match &dispatcher.dispatched[0] {
716            Sequence::Csi(params, ..) => assert_eq!(params, &[[4], [0]]),
717            _ => panic!("expected csi sequence"),
718        }
719    }
720
721    #[test]
722    fn parse_csi_params_leading_semicolon() {
723        // Create dispatcher and check state
724        let mut dispatcher = Dispatcher::default();
725        let mut parser = Parser::new();
726
727        for byte in b"\x1b[;4m" {
728            parser.advance(&mut dispatcher, *byte);
729        }
730
731        assert_eq!(dispatcher.dispatched.len(), 1);
732        match &dispatcher.dispatched[0] {
733            Sequence::Csi(params, ..) => assert_eq!(params, &[[0], [4]]),
734            _ => panic!("expected csi sequence"),
735        }
736    }
737
738    #[test]
739    fn parse_long_csi_param() {
740        // The important part is the parameter, which is (i64::MAX + 1)
741        static INPUT: &[u8] = b"\x1b[9223372036854775808m";
742        let mut dispatcher = Dispatcher::default();
743        let mut parser = Parser::new();
744
745        for byte in INPUT {
746            parser.advance(&mut dispatcher, *byte);
747        }
748
749        assert_eq!(dispatcher.dispatched.len(), 1);
750        match &dispatcher.dispatched[0] {
751            Sequence::Csi(params, ..) => assert_eq!(params, &[[std::u16::MAX as u16]]),
752            _ => panic!("expected csi sequence"),
753        }
754    }
755
756    #[test]
757    fn csi_reset() {
758        static INPUT: &[u8] = b"\x1b[3;1\x1b[?1049h";
759        let mut dispatcher = Dispatcher::default();
760        let mut parser = Parser::new();
761
762        for byte in INPUT {
763            parser.advance(&mut dispatcher, *byte);
764        }
765
766        assert_eq!(dispatcher.dispatched.len(), 1);
767        match &dispatcher.dispatched[0] {
768            Sequence::Csi(params, intermediates, ignore, _) => {
769                assert_eq!(intermediates, &[b'?']);
770                assert_eq!(params, &[[1049]]);
771                assert!(!ignore);
772            },
773            _ => panic!("expected csi sequence"),
774        }
775    }
776
777    #[test]
778    fn csi_subparameters() {
779        static INPUT: &[u8] = b"\x1b[38:2:255:0:255;1m";
780        let mut dispatcher = Dispatcher::default();
781        let mut parser = Parser::new();
782
783        for byte in INPUT {
784            parser.advance(&mut dispatcher, *byte);
785        }
786
787        assert_eq!(dispatcher.dispatched.len(), 1);
788        match &dispatcher.dispatched[0] {
789            Sequence::Csi(params, intermediates, ignore, _) => {
790                assert_eq!(params, &[vec![38, 2, 255, 0, 255], vec![1]]);
791                assert_eq!(intermediates, &[]);
792                assert!(!ignore);
793            },
794            _ => panic!("expected csi sequence"),
795        }
796    }
797
798    #[test]
799    fn parse_dcs_max_params() {
800        let params = "1;".repeat(params::MAX_PARAMS + 1);
801        let input = format!("\x1bP{}p", &params[..]).into_bytes();
802        let mut dispatcher = Dispatcher::default();
803        let mut parser = Parser::new();
804
805        for byte in input {
806            parser.advance(&mut dispatcher, byte);
807        }
808
809        assert_eq!(dispatcher.dispatched.len(), 1);
810        match &dispatcher.dispatched[0] {
811            Sequence::DcsHook(params, _, ignore, _) => {
812                assert_eq!(params.len(), params::MAX_PARAMS);
813                assert!(params.iter().all(|param| param == &[1]));
814                assert!(ignore);
815            },
816            _ => panic!("expected dcs sequence"),
817        }
818    }
819
820    #[test]
821    fn dcs_reset() {
822        static INPUT: &[u8] = b"\x1b[3;1\x1bP1$tx\x9c";
823        let mut dispatcher = Dispatcher::default();
824        let mut parser = Parser::new();
825
826        for byte in INPUT {
827            parser.advance(&mut dispatcher, *byte);
828        }
829
830        assert_eq!(dispatcher.dispatched.len(), 3);
831        match &dispatcher.dispatched[0] {
832            Sequence::DcsHook(params, intermediates, ignore, _) => {
833                assert_eq!(intermediates, &[b'$']);
834                assert_eq!(params, &[[1]]);
835                assert!(!ignore);
836            },
837            _ => panic!("expected dcs sequence"),
838        }
839        assert_eq!(dispatcher.dispatched[1], Sequence::DcsPut(b'x'));
840        assert_eq!(dispatcher.dispatched[2], Sequence::DcsUnhook);
841    }
842
843    #[test]
844    fn parse_dcs() {
845        static INPUT: &[u8] = b"\x1bP0;1|17/ab\x9c";
846        let mut dispatcher = Dispatcher::default();
847        let mut parser = Parser::new();
848
849        for byte in INPUT {
850            parser.advance(&mut dispatcher, *byte);
851        }
852
853        assert_eq!(dispatcher.dispatched.len(), 7);
854        match &dispatcher.dispatched[0] {
855            Sequence::DcsHook(params, _, _, c) => {
856                assert_eq!(params, &[[0], [1]]);
857                assert_eq!(c, &'|');
858            },
859            _ => panic!("expected dcs sequence"),
860        }
861        for (i, byte) in b"17/ab".iter().enumerate() {
862            assert_eq!(dispatcher.dispatched[1 + i], Sequence::DcsPut(*byte));
863        }
864        assert_eq!(dispatcher.dispatched[6], Sequence::DcsUnhook);
865    }
866
867    #[test]
868    fn intermediate_reset_on_dcs_exit() {
869        static INPUT: &[u8] = b"\x1bP=1sZZZ\x1b+\x5c";
870        let mut dispatcher = Dispatcher::default();
871        let mut parser = Parser::new();
872
873        for byte in INPUT {
874            parser.advance(&mut dispatcher, *byte);
875        }
876
877        assert_eq!(dispatcher.dispatched.len(), 6);
878        match &dispatcher.dispatched[5] {
879            Sequence::Esc(intermediates, ..) => assert_eq!(intermediates, &[b'+']),
880            _ => panic!("expected esc sequence"),
881        }
882    }
883
884    #[test]
885    fn esc_reset() {
886        static INPUT: &[u8] = b"\x1b[3;1\x1b(A";
887        let mut dispatcher = Dispatcher::default();
888        let mut parser = Parser::new();
889
890        for byte in INPUT {
891            parser.advance(&mut dispatcher, *byte);
892        }
893
894        assert_eq!(dispatcher.dispatched.len(), 1);
895        match &dispatcher.dispatched[0] {
896            Sequence::Esc(intermediates, ignore, byte) => {
897                assert_eq!(intermediates, &[b'(']);
898                assert_eq!(*byte, b'A');
899                assert!(!ignore);
900            },
901            _ => panic!("expected esc sequence"),
902        }
903    }
904
905    #[test]
906    fn params_buffer_filled_with_subparam() {
907        static INPUT: &[u8] = b"\x1b[::::::::::::::::::::::::::::::::x\x1b";
908        let mut dispatcher = Dispatcher::default();
909        let mut parser = Parser::new();
910
911        for byte in INPUT {
912            parser.advance(&mut dispatcher, *byte);
913        }
914
915        assert_eq!(dispatcher.dispatched.len(), 1);
916        match &dispatcher.dispatched[0] {
917            Sequence::Csi(params, intermediates, ignore, c) => {
918                assert_eq!(intermediates, &[]);
919                assert_eq!(params, &[[0; 32]]);
920                assert_eq!(c, &'x');
921                assert!(ignore);
922            },
923            _ => panic!("expected csi sequence"),
924        }
925    }
926}
927
928#[cfg(all(feature = "nightly", test))]
929mod bench {
930    extern crate std;
931    extern crate test;
932
933    use super::*;
934
935    use test::{black_box, Bencher};
936
937    static VTE_DEMO: &[u8] = include_bytes!("../tests/demo.vte");
938
939    struct BenchDispatcher;
940    impl Perform for BenchDispatcher {
941        fn print(&mut self, c: char) {
942            black_box(c);
943        }
944
945        fn execute(&mut self, byte: u8) {
946            black_box(byte);
947        }
948
949        fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
950            black_box((params, intermediates, ignore, c));
951        }
952
953        fn put(&mut self, byte: u8) {
954            black_box(byte);
955        }
956
957        fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
958            black_box((params, bell_terminated));
959        }
960
961        fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
962            black_box((params, intermediates, ignore, c));
963        }
964
965        fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
966            black_box((intermediates, ignore, byte));
967        }
968    }
969
970    #[bench]
971    fn testfile(b: &mut Bencher) {
972        b.iter(|| {
973            let mut dispatcher = BenchDispatcher;
974            let mut parser = Parser::new();
975
976            for byte in VTE_DEMO {
977                parser.advance(&mut dispatcher, *byte);
978            }
979        });
980    }
981
982    #[bench]
983    fn state_changes(b: &mut Bencher) {
984        let input = b"\x1b]2;X\x1b\\ \x1b[0m \x1bP0@\x1b\\";
985        b.iter(|| {
986            let mut dispatcher = BenchDispatcher;
987            let mut parser = Parser::new();
988
989            for _ in 0..1_000 {
990                for byte in input {
991                    parser.advance(&mut dispatcher, *byte);
992                }
993            }
994        });
995    }
996}