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