1pub mod ascii;
42pub mod capture;
43pub mod event;
44pub mod iter;
45pub mod signature;
46
47use smallvec::SmallVec;
48
49use ascii::AsciiControl;
50use event::{CSI, DCS, Esc, EscInvalid, SS2, SS3, VTEvent, VTIntermediate};
51
52const ESC: u8 = AsciiControl::Esc as _;
53const BEL: u8 = AsciiControl::Bel as _;
54const DEL: u8 = AsciiControl::Del as _;
55const CAN: u8 = AsciiControl::Can as _;
56const SUB: u8 = AsciiControl::Sub as _;
57const CSI: u8 = b'[';
58const OSC: u8 = b']';
59const SS2: u8 = b'N';
60const SS3: u8 = b'O';
61const DCS: u8 = b'P';
62const APC: u8 = b'_';
63const PM: u8 = b'^';
64const SOS: u8 = b'X';
65const ST_FINAL: u8 = b'\\';
66
67use crate::event::{Param, ParamBuf, Params};
68
69#[allow(private_bounds)]
71pub trait VTEventCallback: VTEventCallbackMaybeAbortable<()> {
72 fn event(&mut self, event: VTEvent<'_>) -> ();
73}
74
75impl<T: FnMut(VTEvent<'_>)> VTEventCallback for T {
76 #[inline(always)]
77 fn event(&mut self, event: VTEvent<'_>) -> () {
78 self(event)
79 }
80}
81
82impl<T: VTEventCallback> VTEventCallbackMaybeAbortable<()> for T {
83 #[inline(always)]
84 fn event(&mut self, event: VTEvent<'_>) -> () {
85 VTEventCallback::event(self, event)
86 }
87}
88
89#[allow(private_bounds)]
92pub trait VTEventCallbackAbortable: VTEventCallbackMaybeAbortable<bool> {
93 fn event(&mut self, event: VTEvent<'_>) -> bool;
94}
95
96impl<T: VTEventCallbackAbortable> VTEventCallbackMaybeAbortable<bool> for T {
97 #[inline(always)]
98 fn event(&mut self, event: VTEvent<'_>) -> bool {
99 VTEventCallbackAbortable::event(self, event)
100 }
101}
102
103impl<T: FnMut(VTEvent<'_>) -> bool> VTEventCallbackAbortable for T {
104 #[inline(always)]
105 fn event(&mut self, event: VTEvent<'_>) -> bool {
106 self(event)
107 }
108}
109
110trait VTEventCallbackMaybeAbortable<R: MaybeAbortable> {
111 fn event<'e>(&mut self, event: VTEvent<'e>) -> R;
112}
113
114enum VTAction<'a> {
116 None,
119 Event(VTEvent<'a>),
122 End(VTEnd),
124 Buffer(VTEmit),
127 Hold(VTEmit),
130 Cancel(VTEmit),
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, Eq)]
135enum VTEmit {
136 Ground,
138 Dcs,
140 Osc,
142}
143
144#[derive(Debug, Copy, Clone, PartialEq, Eq)]
145enum VTEnd {
146 Dcs,
148 Osc { used_bel: bool },
150}
151
152#[inline]
153const fn is_c0(b: u8) -> bool {
154 b <= 0x1F && b != b'\r' && b != b'\n' && b != b'\t'
156}
157#[inline]
158fn is_printable(b: u8) -> bool {
159 (0x20..=0x7E).contains(&b)
160}
161#[inline]
162fn is_intermediate(b: u8) -> bool {
163 (0x20..=0x2F).contains(&b)
165}
166#[inline]
167const fn is_final(b: u8) -> bool {
168 b >= 0x40 && b <= 0x7E
169}
170#[inline]
171fn is_digit(b: u8) -> bool {
172 b.is_ascii_digit()
173}
174#[inline]
175fn is_priv(b: u8) -> bool {
176 matches!(b, b'<' | b'=' | b'>' | b'?')
177}
178
179macro_rules! byte_predicate {
180 (|$p:ident| $body:block) => {{
181 let mut out: [bool; 256] = [false; 256];
182 let mut i = 0;
183 while i < 256 {
184 let $p: u8 = i as u8;
185 out[i] = $body;
186 i += 1;
187 }
188 out
189 }};
190}
191
192const ENDS_CSI: [bool; 256] =
193 byte_predicate!(|b| { is_final(b) || b == ESC || b == CAN || b == SUB });
194
195const ENDS_GROUND: [bool; 256] = byte_predicate!(|b| { is_c0(b) || b == DEL });
196
197#[derive(Debug, Copy, Clone, PartialEq, Eq)]
198enum State {
199 Ground,
200 Escape,
201 EscInt,
202 EscSs2,
203 EscSs3,
204 CsiEntry,
205 CsiParam,
206 CsiInt,
207 CsiIgnore,
208 DcsEntry,
209 DcsParam,
210 DcsInt,
211 DcsIgnore,
212 DcsIgnoreEsc,
213 DcsPassthrough,
214 DcsEsc,
215 OscString,
216 OscEsc,
217 SosPmApcString,
218 SpaEsc,
219}
220
221pub const VT_PARSER_INTEREST_NONE: u8 = 0;
223pub const VT_PARSER_INTEREST_CSI: u8 = 1 << 0;
225pub const VT_PARSER_INTEREST_DCS: u8 = 1 << 1;
227pub const VT_PARSER_INTEREST_OSC: u8 = 1 << 2;
229pub const VT_PARSER_INTEREST_ESCAPE_RECOVERY: u8 = 1 << 4;
231pub const VT_PARSER_INTEREST_OTHER: u8 = 1 << 5;
233
234pub const VT_PARSER_INTEREST_ALL: u8 = VT_PARSER_INTEREST_CSI
236 | VT_PARSER_INTEREST_DCS
237 | VT_PARSER_INTEREST_OSC
238 | VT_PARSER_INTEREST_ESCAPE_RECOVERY
239 | VT_PARSER_INTEREST_OTHER;
240
241pub const VT_PARSER_INTEREST_DEFAULT: u8 = VT_PARSER_INTEREST_CSI
243 | VT_PARSER_INTEREST_DCS
244 | VT_PARSER_INTEREST_OSC
245 | VT_PARSER_INTEREST_OTHER;
246
247#[must_use]
248trait MaybeAbortable {
249 fn abort(self) -> bool;
250}
251
252impl MaybeAbortable for bool {
253 #[inline(always)]
254 fn abort(self) -> bool {
255 !self
256 }
257}
258
259impl MaybeAbortable for () {
260 #[inline(always)]
261 fn abort(self) -> bool {
262 false
263 }
264}
265
266pub struct VTPushParser<const INTEREST: u8 = VT_PARSER_INTEREST_DEFAULT> {
271 st: State,
272
273 ints: VTIntermediate,
275 params: Params,
276 cur_param: Param,
277 priv_prefix: Option<u8>,
278 held_byte: Option<u8>,
279}
280
281impl Default for VTPushParser {
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287impl VTPushParser {
288 pub const fn new() -> Self {
289 VTPushParser::new_with()
290 }
291
292 pub fn decode_buffer<'a>(input: &'a [u8], mut cb: impl for<'b> FnMut(VTEvent<'b>)) {
294 let mut parser = VTPushParser::new();
295 parser.feed_with(input, &mut cb);
296 }
297
298 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
299 VTPushParser::new_with()
300 }
301}
302
303macro_rules! invalid {
305 ($self:ident .priv_prefix, $self_:ident .ints, $b:expr) => {
306 if let Some(p) = $self.priv_prefix {
307 if $self.ints.len() == 0 {
308 VTEvent::EscInvalid(EscInvalid::Two(p, $b))
309 } else if $self.ints.len() == 1 {
310 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $b))
311 } else {
312 VTEvent::EscInvalid(EscInvalid::Four(
313 p,
314 $self.ints.data[0],
315 $self.ints.data[1],
316 $b,
317 ))
318 }
319 } else {
320 if $self.ints.len() == 0 {
321 VTEvent::EscInvalid(EscInvalid::One($b))
322 } else if $self.ints.len() == 1 {
323 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
324 } else {
325 VTEvent::EscInvalid(EscInvalid::Three(
326 $self.ints.data[0],
327 $self.ints.data[1],
328 $b,
329 ))
330 }
331 }
332 };
333 ($self:ident .priv_prefix, $self_:ident .ints) => {
334 if let Some(p) = $self.priv_prefix {
335 if $self.ints.len() == 0 {
336 VTEvent::EscInvalid(EscInvalid::One(p))
337 } else if $self.ints.len() == 1 {
338 VTEvent::EscInvalid(EscInvalid::Two(p, $self.ints.data[0]))
339 } else {
340 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $self.ints.data[1]))
341 }
342 } else {
343 if $self.ints.len() == 0 {
344 VTEvent::C0(0x1b)
346 } else if $self.ints.len() == 1 {
347 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
348 } else {
349 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
350 }
351 }
352 };
353 ($a:expr) => {
354 VTEvent::EscInvalid(EscInvalid::One($a))
355 };
356 ($a:expr, $b:expr) => {
357 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
358 };
359}
360
361impl<const INTEREST: u8> VTPushParser<INTEREST> {
362 const fn new_with() -> Self {
363 Self {
364 st: State::Ground,
365 ints: VTIntermediate::empty(),
366 params: SmallVec::new_const(),
367 cur_param: SmallVec::new_const(),
368 priv_prefix: None,
369 held_byte: None,
370 }
371 }
372
373 #[inline]
417 pub fn feed_with<'this, 'input, F: VTEventCallback>(
418 &'this mut self,
419 input: &'input [u8],
420 mut cb: F,
421 ) {
422 self.feed_with_internal(input, &mut cb);
423 }
424
425 #[inline]
438 pub fn feed_with_abortable<'this, 'input, F: VTEventCallbackAbortable>(
439 &'this mut self,
440 input: &'input [u8],
441 mut cb: F,
442 ) -> usize {
443 self.feed_with_internal(input, &mut cb)
444 }
445
446 #[inline(always)]
447 fn feed_with_internal<'this, 'input, R: MaybeAbortable, F: VTEventCallbackMaybeAbortable<R>>(
448 &'this mut self,
449 input: &'input [u8],
450 cb: &mut F,
451 ) -> usize {
452 if input.is_empty() {
453 return 0;
454 }
455
456 #[derive(Debug)]
457 struct FeedState {
458 buffer_idx: usize,
459 current_emit: Option<VTEmit>,
460 hold: bool,
461 }
462
463 let mut state = FeedState {
464 buffer_idx: 0,
465 current_emit: None,
466 hold: self.held_byte.is_some(),
467 };
468
469 macro_rules! emit {
470 ($state:ident, $i:expr, $cb:expr, $end:expr, $used_bel:expr) => {
471 let hold = std::mem::take(&mut $state.hold);
472 if let Some(emit) = $state.current_emit.take() {
473 let i = $i;
474 let range = $state.buffer_idx..(i - hold as usize);
475 if $end {
476 if match emit {
477 VTEmit::Ground => unreachable!(),
478 VTEmit::Dcs => $cb.event(VTEvent::DcsEnd(&input[range])),
479 VTEmit::Osc => $cb.event(VTEvent::OscEnd {
480 data: &input[range],
481 used_bel: $used_bel,
482 }),
483 }
484 .abort()
485 {
486 return i + 1;
487 }
488 } else if range.len() > 0 {
489 if match emit {
490 VTEmit::Ground => $cb.event(VTEvent::Raw(&input[range])),
491 VTEmit::Dcs => $cb.event(VTEvent::DcsData(&input[range])),
492 VTEmit::Osc => $cb.event(VTEvent::OscData(&input[range])),
493 }
494 .abort()
495 {
496 return i + 1;
497 }
498 }
499 }
500 };
501 }
502
503 let mut held_byte = self.held_byte.take();
504 let mut i = 0;
505
506 while i < input.len() {
507 if self.st == State::Ground {
509 let start = i;
510 loop {
511 if i >= input.len() {
512 cb.event(VTEvent::Raw(&input[start..]));
513 return input.len();
514 }
515 if ENDS_GROUND[input[i] as usize] {
516 break;
517 }
518 i += 1;
519 }
520
521 if start != i && cb.event(VTEvent::Raw(&input[start..i])).abort() {
522 return i;
523 }
524
525 if input[i] == ESC {
526 self.clear_hdr_collectors();
527 self.st = State::Escape;
528 i += 1;
529 continue;
530 }
531 }
532
533 if self.st == State::CsiIgnore {
535 loop {
536 if i >= input.len() {
537 return input.len();
538 }
539 if ENDS_CSI[input[i] as usize] {
540 break;
541 }
542 i += 1;
543 }
544
545 if input[i] == ESC {
546 self.st = State::Escape;
547 } else {
548 self.st = State::Ground;
549 }
550 i += 1;
551 continue;
552 }
553
554 let action = self.push_with(input[i]);
555
556 match action {
557 VTAction::None => {
558 if let Some(emit) = state.current_emit {
559 let range = state.buffer_idx..(i - state.hold as usize);
561 if !range.is_empty()
562 && match emit {
563 VTEmit::Ground => cb.event(VTEvent::Raw(&input[range])),
564 VTEmit::Dcs => cb.event(VTEvent::DcsData(&input[range])),
565 VTEmit::Osc => cb.event(VTEvent::OscData(&input[range])),
566 }
567 .abort()
568 {
569 if state.hold {
570 self.held_byte = Some(0x1b);
571 }
572 return i + 1;
573 }
574 if state.hold {
575 held_byte = Some(0x1b);
576 }
577 state.current_emit = None;
578 }
579 }
580 VTAction::Event(e) => {
581 if cb.event(e).abort() {
582 return i + 1;
583 }
584 }
585 VTAction::End(VTEnd::Dcs) => {
586 held_byte = None;
587 emit!(state, i, cb, true, false);
588 }
589 VTAction::End(VTEnd::Osc { used_bel }) => {
590 held_byte = None;
591 emit!(state, i, cb, true, used_bel);
592 }
593 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
594 if state.current_emit.is_none()
595 && let Some(h) = held_byte.take()
596 && match emit {
597 VTEmit::Ground => cb.event(VTEvent::Raw(&[h])),
598 VTEmit::Dcs => cb.event(VTEvent::DcsData(&[h])),
599 VTEmit::Osc => cb.event(VTEvent::OscData(&[h])),
600 }
601 .abort()
602 {
603 if matches!(action, VTAction::Hold(_)) {
604 self.held_byte = Some(0x1b);
605 return 1;
606 }
607 return 0;
608 }
609
610 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
611
612 state.hold = matches!(action, VTAction::Hold(_));
613 if state.current_emit.is_none() {
614 state.buffer_idx = i;
615 state.current_emit = Some(emit);
616 }
617 }
618 VTAction::Cancel(emit) => {
619 state.current_emit = None;
620 state.hold = false;
621 if match emit {
622 VTEmit::Ground => unreachable!(),
623 VTEmit::Dcs => cb.event(VTEvent::DcsCancel),
624 VTEmit::Osc => cb.event(VTEvent::OscCancel),
625 }
626 .abort()
627 {
628 return i + 1;
629 }
630 }
631 };
632 i += 1;
633 }
634
635 if state.hold {
637 self.held_byte = Some(0x1b);
638 }
639
640 if let Some(emit) = state.current_emit.take() {
641 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
642 if !range.is_empty() {
643 match emit {
644 VTEmit::Ground => cb.event(VTEvent::Raw(range)),
645 VTEmit::Dcs => cb.event(VTEvent::DcsData(range)),
646 VTEmit::Osc => cb.event(VTEvent::OscData(range)),
647 };
648 }
649 };
650
651 input.len()
653 }
654
655 pub fn is_ground(&self) -> bool {
657 self.st == State::Ground
658 }
659
660 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
664 match self.st {
665 State::Escape => {
666 self.st = State::Ground;
667 Some(VTEvent::C0(ESC))
668 }
669 State::EscInt => {
670 self.st = State::Ground;
671 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
672 None
673 } else {
674 Some(invalid!(self.priv_prefix, self.ints))
675 }
676 }
677 State::EscSs2 | State::EscSs3 => {
678 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
679 self.st = State::Ground;
680 None
681 } else {
682 let c = match self.st {
683 State::EscSs2 => SS2,
684 State::EscSs3 => SS3,
685 _ => unreachable!(),
686 };
687 self.st = State::Ground;
688 Some(invalid!(c))
689 }
690 }
691 _ => None,
692 }
693 }
694
695 fn push_with(&mut self, b: u8) -> VTAction {
696 use State::*;
697 match self.st {
698 Ground => self.on_ground(b),
699 Escape => self.on_escape(b),
700 EscInt => self.on_esc_int(b),
701 EscSs2 => self.on_esc_ss2(b),
702 EscSs3 => self.on_esc_ss3(b),
703
704 CsiEntry => self.on_csi_entry(b),
705 CsiParam => self.on_csi_param(b),
706 CsiInt => self.on_csi_int(b),
707 CsiIgnore => self.on_csi_ignore(b),
708
709 DcsEntry => self.on_dcs_entry(b),
710 DcsParam => self.on_dcs_param(b),
711 DcsInt => self.on_dcs_int(b),
712 DcsIgnore => self.on_dcs_ignore(b),
713 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
714 DcsPassthrough => self.on_dcs_pass(b),
715 DcsEsc => self.on_dcs_esc(b),
716
717 OscString => self.on_osc_string(b),
718 OscEsc => self.on_osc_esc(b),
719
720 SosPmApcString => self.on_spa_string(b),
721 SpaEsc => self.on_spa_esc(b),
722 }
723 }
724
725 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
726 self.reset_collectors();
727 self.st = State::Ground;
728
729 }
731
732 fn clear_hdr_collectors(&mut self) {
737 self.ints.clear();
738 self.params.clear();
739 self.cur_param.clear();
740 self.priv_prefix = None;
741 }
742
743 fn reset_collectors(&mut self) {
744 self.clear_hdr_collectors();
745 }
746
747 fn next_param(&mut self) {
748 self.params.push(std::mem::take(&mut self.cur_param));
749 }
750
751 fn finish_params_if_any(&mut self) {
752 if !self.cur_param.is_empty() || !self.params.is_empty() {
753 self.next_param();
754 }
755 }
756
757 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
758 self.finish_params_if_any();
759
760 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
762 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
763
764 let privp = self.priv_prefix.take();
765 VTAction::Event(VTEvent::Csi(CSI {
766 private: privp,
767 params: ParamBuf {
768 params: &self.params,
769 },
770 intermediates: self.ints,
771 final_byte,
772 }))
773 }
774
775 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
776 self.finish_params_if_any();
777
778 let privp = self.priv_prefix.take();
779 VTAction::Event(VTEvent::DcsStart(DCS {
780 private: privp,
781 params: ParamBuf {
782 params: &self.params,
783 },
784 intermediates: self.ints,
785 final_byte,
786 }))
787 }
788
789 fn on_ground(&mut self, b: u8) -> VTAction {
794 match b {
795 ESC => {
796 self.clear_hdr_collectors();
797 self.st = State::Escape;
798 VTAction::None
799 }
800 DEL => VTAction::Event(VTEvent::C0(DEL)),
801 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
802 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
803 _ => VTAction::Buffer(VTEmit::Ground), }
805 }
806
807 fn on_escape(&mut self, b: u8) -> VTAction {
808 use State::*;
809 match b {
810 CAN | SUB => {
811 self.st = Ground;
812 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
813 VTAction::None
814 } else {
815 VTAction::Event(invalid!(b))
816 }
817 }
818 DEL => {
821 self.st = Ground;
822 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
823 VTAction::None
824 } else {
825 VTAction::Event(invalid!(b))
826 }
827 }
828 c if is_intermediate(c) => {
829 if self.ints.push(c) {
830 self.st = EscInt;
831 } else {
832 self.st = Ground;
833 }
834 VTAction::None
835 }
836 b'?' => {
838 self.priv_prefix = Some(b);
839 self.st = EscInt;
840 VTAction::None
841 }
842 c if is_priv(c) => {
844 self.st = Ground;
845 VTAction::Event(VTEvent::Esc(Esc {
846 intermediates: VTIntermediate::empty(),
847 private: None,
848 final_byte: b,
849 }))
850 }
851 CSI => {
852 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
853 self.st = CsiIgnore;
854 } else {
855 self.st = CsiEntry;
856 }
857 VTAction::None
858 }
859 DCS => {
860 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
861 self.st = DcsIgnore;
862 } else {
863 self.st = DcsEntry;
864 }
865 VTAction::None
866 }
867 OSC => {
868 self.st = OscString;
869 VTAction::Event(VTEvent::OscStart)
870 }
871 SS2 => {
872 self.st = EscSs2;
873 VTAction::None
874 }
875 SS3 => {
876 self.st = EscSs3;
877 VTAction::None
878 }
879 SOS | PM | APC => {
880 self.st = State::SosPmApcString;
881 VTAction::None
882 }
883 c if is_final(c) || is_digit(c) => {
884 self.st = Ground;
885 VTAction::Event(VTEvent::Esc(Esc {
886 intermediates: self.ints,
887 private: self.priv_prefix.take(),
888 final_byte: c,
889 }))
890 }
891 ESC => {
892 VTAction::Event(VTEvent::C0(ESC))
894 }
895 _ => {
896 self.st = Ground;
897 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
898 VTAction::None
899 } else {
900 VTAction::Event(invalid!(b))
901 }
902 }
903 }
904 }
905
906 fn on_esc_int(&mut self, b: u8) -> VTAction {
907 use State::*;
908 match b {
909 CAN | SUB => {
910 self.st = Ground;
911 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
912 VTAction::None
913 } else {
914 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
915 }
916 }
917 DEL => {
920 self.st = Ground;
921 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
922 VTAction::None
923 } else {
924 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
925 }
926 }
927 c if is_intermediate(c) => {
928 if !self.ints.push(c) {
929 self.st = Ground;
930 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
931 VTAction::None
932 } else {
933 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
934 }
935 } else {
936 VTAction::None
937 }
938 }
939 c if is_final(c) || is_digit(c) => {
940 self.st = Ground;
941 VTAction::Event(VTEvent::Esc(Esc {
942 intermediates: self.ints,
943 private: self.priv_prefix.take(),
944 final_byte: c,
945 }))
946 }
947 ESC => {
950 self.st = Escape;
951 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
952 VTAction::None
953 } else {
954 VTAction::Event(invalid!(self.priv_prefix, self.ints))
955 }
956 }
957 c => {
958 self.st = Ground;
959 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
960 VTAction::None
961 } else {
962 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
963 }
964 }
965 }
966 }
967
968 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
969 use State::*;
970 self.st = Ground;
971 match b {
972 CAN | SUB => {
973 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
974 VTAction::None
975 } else {
976 VTAction::Event(invalid!(SS2, b))
977 }
978 }
979 ESC => {
982 self.st = Escape;
983 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
984 VTAction::None
985 } else {
986 VTAction::Event(invalid!(SS2))
987 }
988 }
989 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
990 }
991 }
992
993 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
994 use State::*;
995 self.st = Ground;
996 match b {
997 CAN | SUB => {
998 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
999 VTAction::None
1000 } else {
1001 VTAction::Event(invalid!(SS3, b))
1002 }
1003 }
1004 ESC => {
1007 self.st = Escape;
1008 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
1009 VTAction::None
1010 } else {
1011 VTAction::Event(invalid!(SS3))
1012 }
1013 }
1014 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
1015 }
1016 }
1017
1018 fn on_csi_entry(&mut self, b: u8) -> VTAction {
1020 use State::*;
1021 match b {
1022 CAN | SUB => {
1023 self.st = Ground;
1024 VTAction::None
1025 }
1026 DEL => VTAction::None,
1027 ESC => {
1028 self.st = Escape;
1029 VTAction::None
1030 }
1031 c if is_priv(c) => {
1032 self.priv_prefix = Some(c);
1033 self.st = CsiParam;
1034 VTAction::None
1035 }
1036 d if is_digit(d) => {
1037 self.cur_param.push(d);
1038 self.st = CsiParam;
1039 VTAction::None
1040 }
1041 b';' => {
1042 self.next_param();
1043 self.st = CsiParam;
1044 VTAction::None
1045 }
1046 b':' => {
1047 self.cur_param.push(b':');
1048 self.st = CsiParam;
1049 VTAction::None
1050 }
1051 c if is_intermediate(c) => {
1052 if self.ints.push(c) {
1053 self.st = CsiInt;
1054 } else {
1055 self.st = Ground;
1056 }
1057 VTAction::None
1058 }
1059 c if is_final(c) => {
1060 self.st = Ground;
1061 self.emit_csi(c)
1062 }
1063 _ => {
1064 self.st = CsiIgnore;
1065 VTAction::None
1066 }
1067 }
1068 }
1069
1070 fn on_csi_param(&mut self, b: u8) -> VTAction {
1071 use State::*;
1072 match b {
1073 CAN | SUB => {
1074 self.st = Ground;
1075 VTAction::None
1076 }
1077 DEL => VTAction::None,
1078 ESC => {
1079 self.st = Escape;
1080 VTAction::None
1081 }
1082 d if is_digit(d) => {
1083 self.cur_param.push(d);
1084 VTAction::None
1085 }
1086 b';' => {
1087 self.next_param();
1088 VTAction::None
1089 }
1090 b':' => {
1091 self.cur_param.push(b':');
1092 VTAction::None
1093 }
1094 c if is_intermediate(c) => {
1095 if self.ints.push(c) {
1096 self.st = CsiInt;
1097 } else {
1098 self.st = Ground;
1099 }
1100 VTAction::None
1101 }
1102 c if is_final(c) => {
1103 self.st = Ground;
1104 self.emit_csi(c)
1105 }
1106 _ => {
1107 self.st = CsiIgnore;
1108 VTAction::None
1109 }
1110 }
1111 }
1112
1113 fn on_csi_int(&mut self, b: u8) -> VTAction {
1114 use State::*;
1115 match b {
1116 CAN | SUB => {
1117 self.st = Ground;
1118 VTAction::None
1119 }
1120 DEL => VTAction::None,
1121 ESC => {
1122 self.st = Escape;
1123 VTAction::None
1124 }
1125 c if is_intermediate(c) => {
1126 if self.ints.push(c) {
1127 self.st = CsiInt;
1128 } else {
1129 self.st = Ground;
1130 }
1131 VTAction::None
1132 }
1133 c if is_final(c) => {
1134 self.st = Ground;
1135 self.emit_csi(c)
1136 }
1137 _ => {
1138 self.st = CsiIgnore;
1139 VTAction::None
1140 }
1141 }
1142 }
1143
1144 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1145 use State::*;
1146 match b {
1147 CAN | SUB => {
1148 self.st = Ground;
1149 VTAction::None
1150 }
1151 DEL => VTAction::None,
1152 ESC => {
1153 self.st = Escape;
1154 VTAction::None
1155 }
1156 c if is_final(c) => {
1157 self.st = Ground;
1158 VTAction::None
1159 }
1160 _ => VTAction::None,
1161 }
1162 }
1163
1164 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1166 use State::*;
1167 match b {
1168 CAN | SUB => {
1169 self.st = Ground;
1170 VTAction::None
1171 }
1172 DEL => VTAction::None,
1173 ESC => {
1174 self.st = Escape;
1175 VTAction::None
1176 }
1177 c if is_priv(c) => {
1178 self.priv_prefix = Some(c);
1179 self.st = DcsParam;
1180 VTAction::None
1181 }
1182 d if is_digit(d) => {
1183 self.cur_param.push(d);
1184 self.st = DcsParam;
1185 VTAction::None
1186 }
1187 b';' => {
1188 self.next_param();
1189 self.st = DcsParam;
1190 VTAction::None
1191 }
1192 b':' => {
1193 self.st = DcsIgnore;
1194 VTAction::None
1195 }
1196 c if is_intermediate(c) => {
1197 if self.ints.push(c) {
1198 self.st = DcsInt;
1199 } else {
1200 self.st = Ground;
1201 }
1202 VTAction::None
1203 }
1204 c if is_final(c) => {
1205 self.st = DcsPassthrough;
1206 self.dcs_start(c)
1207 }
1208 _ => {
1209 self.st = DcsIgnore;
1210 VTAction::None
1211 }
1212 }
1213 }
1214
1215 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1216 use State::*;
1217 match b {
1218 CAN | SUB => {
1219 self.st = Ground;
1220 VTAction::None
1221 }
1222 DEL => VTAction::None,
1223 ESC => {
1224 self.st = Escape;
1225 VTAction::None
1226 }
1227 d if is_digit(d) => {
1228 self.cur_param.push(d);
1229 VTAction::None
1230 }
1231 b';' => {
1232 self.next_param();
1233 VTAction::None
1234 }
1235 b':' => {
1236 self.st = DcsIgnore;
1237 VTAction::None
1238 }
1239 c if is_intermediate(c) => {
1240 if self.ints.push(c) {
1241 self.st = DcsInt;
1242 } else {
1243 self.st = Ground;
1244 }
1245 self.st = DcsInt;
1246 VTAction::None
1247 }
1248 c if is_final(c) => {
1249 self.st = DcsPassthrough;
1250 self.dcs_start(c)
1251 }
1252 _ => {
1253 self.st = DcsIgnore;
1254 VTAction::None
1255 }
1256 }
1257 }
1258
1259 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1260 use State::*;
1261 match b {
1262 CAN | SUB => {
1263 self.st = Ground;
1264 VTAction::None
1265 }
1266 DEL => VTAction::None,
1267 ESC => {
1268 self.st = Escape;
1269 VTAction::None
1270 }
1271 c if is_intermediate(c) => {
1272 if self.ints.push(c) {
1273 self.st = DcsInt;
1274 } else {
1275 self.st = Ground;
1276 }
1277 VTAction::None
1278 }
1279 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1280 self.st = DcsPassthrough;
1281 self.dcs_start(c)
1282 }
1283 _ => {
1284 self.st = DcsIgnore;
1285 VTAction::None
1286 }
1287 }
1288 }
1289
1290 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1291 use State::*;
1292 match b {
1293 CAN | SUB => {
1294 self.st = Ground;
1295 VTAction::None
1296 }
1297 DEL => VTAction::None,
1298 ESC => {
1299 self.st = DcsIgnoreEsc;
1300 VTAction::None
1301 }
1302 _ => VTAction::None,
1303 }
1304 }
1305
1306 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1307 use State::*;
1308 match b {
1309 CAN | SUB => {
1310 self.st = Ground;
1311 VTAction::None
1312 }
1313 ST_FINAL => {
1314 self.st = Ground;
1315 VTAction::None
1316 }
1317 DEL => VTAction::None,
1318 ESC => VTAction::None,
1319 _ => {
1320 self.st = DcsIgnore;
1321 VTAction::None
1322 }
1323 }
1324 }
1325
1326 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1327 use State::*;
1328 match b {
1329 CAN | SUB => {
1330 self.st = Ground;
1331 VTAction::Cancel(VTEmit::Dcs)
1332 }
1333 DEL => VTAction::None,
1334 ESC => {
1335 self.st = DcsEsc;
1336 VTAction::Hold(VTEmit::Dcs)
1337 }
1338 _ => VTAction::Buffer(VTEmit::Dcs),
1339 }
1340 }
1341
1342 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1343 use State::*;
1344 match b {
1345 ST_FINAL => {
1346 self.st = Ground;
1347 VTAction::End(VTEnd::Dcs)
1348 }
1349 DEL => VTAction::None,
1350 ESC => {
1351 VTAction::Hold(VTEmit::Dcs)
1353 }
1354 _ => {
1355 self.st = DcsPassthrough;
1357 VTAction::Buffer(VTEmit::Dcs)
1358 }
1359 }
1360 }
1361
1362 fn on_osc_string(&mut self, b: u8) -> VTAction {
1364 use State::*;
1365 match b {
1366 CAN | SUB => {
1367 self.st = Ground;
1368 VTAction::Cancel(VTEmit::Osc)
1369 }
1370 DEL => VTAction::None,
1371 BEL => {
1372 self.st = Ground;
1373 VTAction::End(VTEnd::Osc { used_bel: true })
1374 }
1375 ESC => {
1376 self.st = OscEsc;
1377 VTAction::Hold(VTEmit::Osc)
1378 }
1379 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1380 _ => VTAction::None, }
1382 }
1383
1384 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1385 use State::*;
1386 match b {
1387 ST_FINAL => {
1388 self.st = Ground;
1389 VTAction::End(VTEnd::Osc { used_bel: false })
1390 } ESC => VTAction::Hold(VTEmit::Osc),
1392 DEL => VTAction::None,
1393 _ => {
1394 self.st = OscString;
1395 VTAction::Buffer(VTEmit::Osc)
1396 }
1397 }
1398 }
1399
1400 fn on_spa_string(&mut self, b: u8) -> VTAction {
1402 use State::*;
1403 match b {
1404 CAN | SUB => {
1405 self.st = Ground;
1406 VTAction::None
1407 }
1408 DEL => VTAction::None,
1409 ESC => {
1410 self.st = SpaEsc;
1411 VTAction::None
1412 }
1413 _ => VTAction::None,
1414 }
1415 }
1416
1417 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1418 use State::*;
1419 match b {
1420 ST_FINAL => {
1421 self.st = Ground;
1422 VTAction::None
1423 }
1424 DEL => VTAction::None,
1425 ESC => {
1426 VTAction::None
1428 }
1429 _ => {
1430 self.st = State::SosPmApcString;
1431 VTAction::None
1432 }
1433 }
1434 }
1435}
1436
1437#[cfg(test)]
1438mod tests {
1439 use crate::event::VTOwnedEvent;
1440
1441 use super::*;
1442 use pretty_assertions::assert_eq;
1443
1444 #[test]
1445 fn test_edge_cases() {
1446 let mut result = String::new();
1448 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1449 assert_eq!(result.trim(), "");
1450
1451 let mut result = String::new();
1453 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1454 assert_eq!(result.trim(), "");
1455
1456 let mut result = String::new();
1458 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1459 assert_eq!(result.trim(), "");
1460
1461 let mut result = String::new();
1463 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1464 assert_eq!(result.trim(), "");
1465
1466 let mut result = String::new();
1468 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1469 assert_eq!(result.trim(), "OscStart");
1470 }
1471
1472 #[test]
1473 fn test_streaming_behavior() {
1474 let mut parser = VTPushParser::new(); let mut result = String::new();
1477 let mut callback = |vt_input: VTEvent<'_>| {
1478 result.push_str(&format!("{vt_input:?}\n"));
1479 };
1480
1481 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1483 parser.feed_with(b"data", &mut callback);
1484 parser.feed_with(b" more", &mut callback);
1485 parser.feed_with(b"\x1b\\", &mut callback);
1486
1487 assert_eq!(
1488 result.trim(),
1489 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1490 );
1491 }
1492
1493 #[test]
1494 fn test_dcs_payload_passthrough() {
1495 let dcs_cases: &[(&[u8], &str)] = &[
1503 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1505 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1507 (
1509 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1510 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1511 ),
1512 (
1514 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1515 "ABC<ESC><ESC>DEF<ESC>XG",
1516 ),
1517 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1519 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1521 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1523 (
1525 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1526 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1527 ),
1528 (
1530 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1531 "<ESC>[58:2::000:007:042m",
1532 ),
1533 ];
1534
1535 for (input, expected_body) in dcs_cases {
1536 let events = collect_owned_events(input);
1537
1538 let mut actual_body = Vec::new();
1540 for event in &events {
1541 match event {
1542 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1543 actual_body.extend(data);
1544 }
1545 _ => {}
1546 }
1547 }
1548
1549 let actual_body = String::from_utf8(actual_body).unwrap();
1550 let actual_body = actual_body
1551 .replace("\x1b", "<ESC>")
1552 .replace("\x07", "<BEL>");
1553
1554 assert_eq!(
1555 actual_body, *expected_body,
1556 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1557 input, events
1558 );
1559 }
1560 }
1561
1562 fn collect_events(input: &[u8]) -> Vec<String> {
1563 let mut out = Vec::new();
1564 let mut p = VTPushParser::new();
1565 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1566 out
1567 }
1568
1569 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1570 let mut out = Vec::new();
1571 let mut p = VTPushParser::new();
1572 p.feed_with(input, &mut |ev: VTEvent| out.push(ev.to_owned()));
1573 out
1574 }
1575
1576 #[test]
1577 fn dcs_esc_esc_del() {
1578 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1580 eprintln!("{ev:?}");
1582 }
1583
1584 #[test]
1585 fn dcs_header_with_colon_is_ignored_case1() {
1586 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1588 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1590 }
1591
1592 #[test]
1593 fn dcs_header_with_colon_is_ignored_case2() {
1594 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1596 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1597 }
1598
1599 #[test]
1600 fn dcs_header_with_colon_is_ignored_case3() {
1601 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1603 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1604 }
1605
1606 #[test]
1607 fn osc_aborted_by_can_mid_body() {
1608 let mut s = Vec::new();
1610 s.extend_from_slice(b"\x1b]0;Title");
1611 s.push(CAN);
1612 s.extend_from_slice(b"more\x07");
1613
1614 let ev = collect_debug(&s);
1615
1616 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1621 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1622 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1623 }
1624
1625 #[test]
1626 fn osc_aborted_by_sub_before_terminator() {
1627 let mut s = Vec::new();
1628 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1629 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1633 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1637 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1638 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1639 }
1640
1641 fn collect_debug(input: &[u8]) -> Vec<String> {
1643 let mut out = Vec::new();
1644 let mut p = VTPushParser::new();
1645 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1646 out
1647 }
1648
1649 #[test]
1650 fn dcs_aborted_by_can_before_body() {
1651 let mut s = Vec::new();
1653 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1655 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1658
1659 assert_eq!(ev.len(), 4, "{ev:#?}");
1660 assert_eq!(ev[0], "DcsStart('', q)");
1661 assert_eq!(ev[1], "DcsCancel");
1662 assert_eq!(ev[2], "Raw('IGNORED')");
1663 assert_eq!(ev[3], "Esc('', \\)");
1664 }
1665
1666 #[test]
1667 fn dcs_aborted_by_can_mid_body() {
1668 let mut s = Vec::new();
1670 s.extend_from_slice(b"\x1bPqABC");
1671 s.push(CAN);
1672 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1675
1676 assert_eq!(ev.len(), 4, "{ev:#?}");
1677 assert_eq!(ev[0], "DcsStart('', q)");
1678 assert_eq!(ev[1], "DcsCancel");
1679 assert_eq!(ev[2], "Raw('MORE')");
1680 assert_eq!(ev[3], "Esc('', \\)");
1681 }
1682
1683 #[test]
1686 fn spa_aborted_by_can_is_ignored() {
1687 let mut s = Vec::new();
1689 s.extend_from_slice(b"\x1b_hello");
1690 s.push(CAN);
1691 s.extend_from_slice(b"world\x1b\\");
1692
1693 let ev = collect_debug(&s);
1694 assert_eq!(ev.len(), 2, "{ev:#?}");
1695 assert_eq!(ev[0], "Raw('world')");
1696 assert_eq!(ev[1], "Esc('', \\)");
1697 }
1698
1699 #[test]
1700 fn spa_sub_aborts_too() {
1701 let mut s = Vec::new();
1702 s.extend_from_slice(b"\x1bXhello");
1703 s.push(SUB);
1704 s.extend_from_slice(b"world\x1b\\");
1705 let ev = collect_debug(&s);
1706 assert_eq!(ev.len(), 2, "{ev:#?}");
1707 assert_eq!(ev[0], "Raw('world')");
1708 assert_eq!(ev[1], "Esc('', \\)");
1709 }
1710
1711 #[test]
1714 fn can_in_ground_is_c0() {
1715 let mut s = Vec::new();
1716 s.extend_from_slice(b"abc");
1717 s.push(CAN);
1718 s.extend_from_slice(b"def");
1719 let ev = collect_debug(&s);
1720 assert_eq!(ev.len(), 3, "{ev:#?}");
1722 assert_eq!(ev[0], "Raw('abc')");
1723 assert_eq!(ev[1], "C0(18)");
1724 assert_eq!(ev[2], "Raw('def')");
1725 }
1726
1727 #[test]
1730 fn three_byte_sequences_capturable() {
1731 let mut bytes = vec![];
1732 for i in 0..=0xFFFFFF_u32 {
1733 bytes.clear();
1734 let test_bytes = i.to_le_bytes();
1735 let test_bytes = &test_bytes[..3];
1736 if test_bytes.iter().any(|b| b == &0) {
1737 continue;
1738 }
1739 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1740 continue;
1741 }
1742 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1743 continue;
1744 }
1745
1746 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1747 parser.feed_with(test_bytes, |event: VTEvent| {
1748 let mut chunk = [0_u8; 3];
1749 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1750 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1751 });
1752 bytes.extend_from_slice(&chunk[..b]);
1753 });
1754 if let Some(event) = parser.idle() {
1755 let mut chunk = [0_u8; 3];
1756 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1757 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1758 });
1759 bytes.extend_from_slice(&chunk[..b]);
1760 }
1761
1762 if bytes.len() != 3 || bytes != test_bytes {
1763 eprintln!("Failed to parse:");
1764 parser.feed_with(test_bytes, |event: VTEvent| {
1765 eprintln!("{event:?}");
1766 });
1767 if let Some(event) = parser.idle() {
1768 eprintln!("{event:?}");
1769 }
1770 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1771 }
1772 }
1773 }
1774}