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
152macro_rules! def_pattern {
153 ($name:ident => $pattern:pat) => {
154 #[inline]
155 #[allow(unused)]
156 const fn $name(b: u8) -> bool {
157 matches!(b, $pattern)
158 }
159
160 #[allow(unused)]
161 macro_rules! $name {
162 () => {
163 $pattern
164 };
165 }
166 };
167}
168
169def_pattern!(is_c0 => 0x00..=0x08 | 0x0b..=0x0c | 0x0e..=0x1f);
170def_pattern!(is_any_c0 => 0x00..=0x1f);
171def_pattern!(is_printable => b' '..=b'~');
172def_pattern!(is_intermediate => b' '..=b'/');
173def_pattern!(is_final => 0x40..=0x7e);
174def_pattern!(is_priv => b'<' | b'=' | b'>' | b'?');
175def_pattern!(is_priv_no_q => b'<' | b'=' | b'>');
176def_pattern!(is_digit => b'0'..=b'9');
177
178macro_rules! byte_predicate {
179 (|$p:ident| $body:block) => {{
180 let mut out: [bool; 256] = [false; 256];
181 let mut i = 0;
182 while i < 256 {
183 let $p: u8 = i as u8;
184 out[i] = $body;
185 i += 1;
186 }
187 out
188 }};
189}
190
191const ENDS_CSI: [bool; 256] =
192 byte_predicate!(|b| { is_final(b) || b == ESC || b == CAN || b == SUB });
193
194const ENDS_GROUND: [bool; 256] = byte_predicate!(|b| { is_c0(b) || b == DEL });
195
196#[derive(Debug, Copy, Clone, PartialEq, Eq)]
197enum State {
198 Ground,
199 Escape,
200 EscInt,
201 EscSs2,
202 EscSs3,
203 CsiEntry,
204 CsiParam,
205 CsiInt,
206 CsiIgnore,
207 DcsEntry,
208 DcsParam,
209 DcsInt,
210 DcsIgnore,
211 DcsIgnoreEsc,
212 DcsPassthrough,
213 DcsEsc,
214 OscString,
215 OscEsc,
216 SosPmApcString,
217 SpaEsc,
218}
219
220pub const VT_PARSER_INTEREST_NONE: u8 = 0;
222pub const VT_PARSER_INTEREST_CSI: u8 = 1 << 0;
224pub const VT_PARSER_INTEREST_DCS: u8 = 1 << 1;
226pub const VT_PARSER_INTEREST_OSC: u8 = 1 << 2;
228pub const VT_PARSER_INTEREST_ESCAPE_RECOVERY: u8 = 1 << 4;
230pub const VT_PARSER_INTEREST_OTHER: u8 = 1 << 5;
232
233pub const VT_PARSER_INTEREST_ALL: u8 = VT_PARSER_INTEREST_CSI
235 | VT_PARSER_INTEREST_DCS
236 | VT_PARSER_INTEREST_OSC
237 | VT_PARSER_INTEREST_ESCAPE_RECOVERY
238 | VT_PARSER_INTEREST_OTHER;
239
240pub const VT_PARSER_INTEREST_DEFAULT: u8 = VT_PARSER_INTEREST_CSI
242 | VT_PARSER_INTEREST_DCS
243 | VT_PARSER_INTEREST_OSC
244 | VT_PARSER_INTEREST_OTHER;
245
246#[must_use]
247trait MaybeAbortable {
248 fn abort(self) -> bool;
249}
250
251impl MaybeAbortable for bool {
252 #[inline(always)]
253 fn abort(self) -> bool {
254 !self
255 }
256}
257
258impl MaybeAbortable for () {
259 #[inline(always)]
260 fn abort(self) -> bool {
261 false
262 }
263}
264
265pub struct VTPushParser<const INTEREST: u8 = VT_PARSER_INTEREST_DEFAULT> {
270 st: State,
271
272 ints: VTIntermediate,
274 params: Params,
275 cur_param: Param,
276 priv_prefix: Option<u8>,
277 held_byte: Option<u8>,
278}
279
280impl Default for VTPushParser {
281 fn default() -> Self {
282 Self::new()
283 }
284}
285
286impl VTPushParser {
287 pub const fn new() -> Self {
288 VTPushParser::new_with()
289 }
290
291 pub fn decode_buffer<'a>(input: &'a [u8], mut cb: impl for<'b> FnMut(VTEvent<'b>)) {
293 let mut parser = VTPushParser::new();
294 parser.feed_with(input, &mut cb);
295 }
296
297 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
298 VTPushParser::new_with()
299 }
300}
301
302macro_rules! invalid {
304 ($self:ident .priv_prefix, $self_:ident .ints, $b:expr) => {
305 if let Some(p) = $self.priv_prefix {
306 if $self.ints.len() == 0 {
307 VTEvent::EscInvalid(EscInvalid::Two(p, $b))
308 } else if $self.ints.len() == 1 {
309 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $b))
310 } else {
311 VTEvent::EscInvalid(EscInvalid::Four(
312 p,
313 $self.ints.data[0],
314 $self.ints.data[1],
315 $b,
316 ))
317 }
318 } else {
319 if $self.ints.len() == 0 {
320 VTEvent::EscInvalid(EscInvalid::One($b))
321 } else if $self.ints.len() == 1 {
322 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
323 } else {
324 VTEvent::EscInvalid(EscInvalid::Three(
325 $self.ints.data[0],
326 $self.ints.data[1],
327 $b,
328 ))
329 }
330 }
331 };
332 ($self:ident .priv_prefix, $self_:ident .ints) => {
333 if let Some(p) = $self.priv_prefix {
334 if $self.ints.len() == 0 {
335 VTEvent::EscInvalid(EscInvalid::One(p))
336 } else if $self.ints.len() == 1 {
337 VTEvent::EscInvalid(EscInvalid::Two(p, $self.ints.data[0]))
338 } else {
339 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $self.ints.data[1]))
340 }
341 } else {
342 if $self.ints.len() == 0 {
343 VTEvent::C0(0x1b)
345 } else if $self.ints.len() == 1 {
346 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
347 } else {
348 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
349 }
350 }
351 };
352 ($a:expr) => {
353 VTEvent::EscInvalid(EscInvalid::One($a))
354 };
355 ($a:expr, $b:expr) => {
356 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
357 };
358}
359
360impl<const INTEREST: u8> VTPushParser<INTEREST> {
361 const fn new_with() -> Self {
362 Self {
363 st: State::Ground,
364 ints: VTIntermediate::empty(),
365 params: SmallVec::new_const(),
366 cur_param: SmallVec::new_const(),
367 priv_prefix: None,
368 held_byte: None,
369 }
370 }
371
372 #[inline]
416 pub fn feed_with<F: VTEventCallback>(&mut self, input: &[u8], mut cb: F) {
417 self.feed_with_internal(input, &mut cb);
418 }
419
420 #[inline]
433 pub fn feed_with_abortable<F: VTEventCallbackAbortable>(
434 &mut self,
435 input: &[u8],
436 mut cb: F,
437 ) -> usize {
438 self.feed_with_internal(input, &mut cb)
439 }
440
441 #[inline(always)]
442 fn feed_with_internal<R: MaybeAbortable, F: VTEventCallbackMaybeAbortable<R>>(
443 &mut self,
444 input: &[u8],
445 cb: &mut F,
446 ) -> usize {
447 if input.is_empty() {
448 return 0;
449 }
450
451 #[derive(Debug)]
452 struct FeedState {
453 buffer_idx: usize,
454 current_emit: Option<VTEmit>,
455 hold: bool,
456 }
457
458 let mut state = FeedState {
459 buffer_idx: 0,
460 current_emit: None,
461 hold: self.held_byte.is_some(),
462 };
463
464 let mut held_byte = self.held_byte.take();
465 let mut i = 0;
466
467 while i < input.len() {
468 if self.st == State::Ground {
470 let start = i;
471 loop {
472 if i >= input.len() {
473 cb.event(VTEvent::Raw(&input[start..]));
474 return input.len();
475 }
476 if ENDS_GROUND[input[i] as usize] {
477 break;
478 }
479 i += 1;
480 }
481
482 if start != i && cb.event(VTEvent::Raw(&input[start..i])).abort() {
483 return i;
484 }
485
486 if input[i] == ESC {
487 self.clear_hdr_collectors();
488 self.st = State::Escape;
489 i += 1;
490 continue;
491 }
492 }
493
494 if self.st == State::CsiIgnore {
496 loop {
497 if i >= input.len() {
498 return input.len();
499 }
500 if ENDS_CSI[input[i] as usize] {
501 break;
502 }
503 i += 1;
504 }
505
506 if input[i] == ESC {
507 self.st = State::Escape;
508 } else {
509 self.st = State::Ground;
510 }
511 i += 1;
512 continue;
513 }
514
515 let action = self.push_with(input[i]);
516
517 match action {
518 VTAction::None => {
519 if let Some(emit) = state.current_emit {
520 let range = state.buffer_idx..(i - state.hold as usize);
522 if !range.is_empty()
523 && match emit {
524 VTEmit::Ground => cb.event(VTEvent::Raw(&input[range])),
525 VTEmit::Dcs => cb.event(VTEvent::DcsData(&input[range])),
526 VTEmit::Osc => cb.event(VTEvent::OscData(&input[range])),
527 }
528 .abort()
529 {
530 if state.hold {
531 self.held_byte = Some(0x1b);
532 }
533 return i + 1;
534 }
535 if state.hold {
536 held_byte = Some(0x1b);
537 }
538 state.current_emit = None;
539 }
540 }
541 VTAction::Event(e) => {
542 if cb.event(e).abort() {
543 return i + 1;
544 }
545 }
546 VTAction::End(VTEnd::Dcs) => {
547 state.current_emit = None;
548 let hold = std::mem::take(&mut state.hold);
549 let range = state.buffer_idx..(i.saturating_sub(hold as usize));
550 if cb.event(VTEvent::DcsEnd(&input[range])).abort() {
551 return i + 1;
552 }
553 held_byte = None;
554 }
555 VTAction::End(VTEnd::Osc { used_bel }) => {
556 state.current_emit = None;
557 let hold = std::mem::take(&mut state.hold);
558 let range = state.buffer_idx..(i.saturating_sub(hold as usize));
559 if cb
560 .event(VTEvent::OscEnd {
561 data: &input[range],
562 used_bel,
563 })
564 .abort()
565 {
566 return i + 1;
567 }
568 held_byte = None;
569 }
570 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
571 if state.current_emit.is_none()
572 && let Some(h) = held_byte.take()
573 && match emit {
574 VTEmit::Ground => cb.event(VTEvent::Raw(&[h])),
575 VTEmit::Dcs => cb.event(VTEvent::DcsData(&[h])),
576 VTEmit::Osc => cb.event(VTEvent::OscData(&[h])),
577 }
578 .abort()
579 {
580 if matches!(action, VTAction::Hold(_)) {
581 self.held_byte = Some(0x1b);
582 return 1;
583 }
584 return 0;
585 }
586
587 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
588
589 state.hold = matches!(action, VTAction::Hold(_));
590 if state.current_emit.is_none() {
591 state.buffer_idx = i;
592 state.current_emit = Some(emit);
593 }
594 }
595 VTAction::Cancel(emit) => {
596 state.current_emit = None;
597 state.hold = false;
598 if match emit {
599 VTEmit::Ground => unreachable!(),
600 VTEmit::Dcs => cb.event(VTEvent::DcsCancel),
601 VTEmit::Osc => cb.event(VTEvent::OscCancel),
602 }
603 .abort()
604 {
605 return i + 1;
606 }
607 }
608 };
609 i += 1;
610 }
611
612 if state.hold {
614 self.held_byte = Some(0x1b);
615 }
616
617 if let Some(emit) = state.current_emit.take() {
618 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
619 if !range.is_empty() {
620 match emit {
621 VTEmit::Ground => cb.event(VTEvent::Raw(range)),
622 VTEmit::Dcs => cb.event(VTEvent::DcsData(range)),
623 VTEmit::Osc => cb.event(VTEvent::OscData(range)),
624 };
625 }
626 };
627
628 input.len()
630 }
631
632 pub fn is_ground(&self) -> bool {
634 self.st == State::Ground
635 }
636
637 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
641 match self.st {
642 State::Escape => {
643 self.st = State::Ground;
644 Some(VTEvent::C0(ESC))
645 }
646 State::EscInt => {
647 self.st = State::Ground;
648 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
649 None
650 } else {
651 Some(invalid!(self.priv_prefix, self.ints))
652 }
653 }
654 State::EscSs2 | State::EscSs3 => {
655 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
656 self.st = State::Ground;
657 None
658 } else {
659 let c = match self.st {
660 State::EscSs2 => SS2,
661 State::EscSs3 => SS3,
662 _ => unreachable!(),
663 };
664 self.st = State::Ground;
665 Some(invalid!(c))
666 }
667 }
668 _ => None,
669 }
670 }
671
672 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
673 self.reset_collectors();
674 self.st = State::Ground;
675
676 }
678
679 fn clear_hdr_collectors(&mut self) {
684 self.ints.clear();
685 self.params.clear();
686 self.cur_param.clear();
687 self.priv_prefix = None;
688 }
689
690 fn reset_collectors(&mut self) {
691 self.clear_hdr_collectors();
692 }
693
694 fn next_param(&mut self) {
695 self.params.push(std::mem::take(&mut self.cur_param));
696 }
697
698 fn finish_params_if_any(&mut self) {
699 if !self.cur_param.is_empty() || !self.params.is_empty() {
700 self.next_param();
701 }
702 }
703
704 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
705 self.finish_params_if_any();
706
707 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
709 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
710
711 let privp = self.priv_prefix.take();
712 VTAction::Event(VTEvent::Csi(CSI {
713 private: privp,
714 params: ParamBuf {
715 params: &self.params,
716 },
717 intermediates: self.ints,
718 final_byte,
719 }))
720 }
721
722 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
723 self.finish_params_if_any();
724
725 let privp = self.priv_prefix.take();
726 VTAction::Event(VTEvent::DcsStart(DCS {
727 private: privp,
728 params: ParamBuf {
729 params: &self.params,
730 },
731 intermediates: self.ints,
732 final_byte,
733 }))
734 }
735
736 fn push_with(&mut self, b: u8) -> VTAction {
741 use State::*;
742
743 macro_rules! state_machine {
744 (def $c:ident $(
745 $state:ident => { $( $p:pat
746 $(if $( $if_ident:ident $( ($call_ident:ident) )? $( == $literal:literal)? $(||)? )+)?
747 => $block:expr $(,)? )* }
748 )*) => {
749 #[allow(unused)]
750 match self.st {
751 $(
752 $state => {
753 match b {
754 $(
755 $c @ state_machine!(pattern $p $(if $( ($if_ident ($($call_ident)?) ($($literal)?)) )+ )?) => $block,
756 )*
757 }
758 }
759 )*
760 }
761 };
762 (pattern $pat:pat if $( ($if_ident:ident ($($call_ident:ident)?) ($($literal:literal)?)) )+ ) => {
763 $(
764 state_machine!(pattern_if ($if_ident) ($($call_ident)?) ($($literal)?) )
765 )|+
766 };
767 (pattern $pat:pat) => {
768 $pat
769 };
770 (pattern_if ($any:ident) ($call_ident:ident) ()) => {
771 $any!()
772 };
773 (pattern_if ($if_ident:ident) () ($literal:literal)) => {
774 $literal
775 };
776 }
777
778 state_machine! {
785 def c
786 Ground => {
787 ESC => {
788 self.clear_hdr_collectors();
789 self.st = State::Escape;
790 VTAction::None
791 }
792 DEL => VTAction::Event(VTEvent::C0(DEL)),
793 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
794 _ => VTAction::Buffer(VTEmit::Ground),
795 }
796 Escape => {
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_no_q(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 EscInt => {
892 CAN | SUB => {
893 self.st = Ground;
894 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
895 VTAction::None
896 } else {
897 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
898 }
899 }
900 DEL => {
903 self.st = Ground;
904 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
905 VTAction::None
906 } else {
907 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
908 }
909 }
910 c if is_intermediate(c) => {
911 if !self.ints.push(c) {
912 self.st = Ground;
913 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
914 VTAction::None
915 } else {
916 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
917 }
918 } else {
919 VTAction::None
920 }
921 }
922 c if is_final(c) || is_digit(c) => {
923 self.st = Ground;
924 VTAction::Event(VTEvent::Esc(Esc {
925 intermediates: self.ints,
926 private: self.priv_prefix.take(),
927 final_byte: c,
928 }))
929 }
930 ESC => {
933 self.st = Escape;
934 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
935 VTAction::None
936 } else {
937 VTAction::Event(invalid!(self.priv_prefix, self.ints))
938 }
939 }
940 _ => {
941 self.st = Ground;
942 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
943 VTAction::None
944 } else {
945 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
946 }
947 }
948 }
949 EscSs2 => {
950 CAN | SUB => {
951 self.st = Ground;
952 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
953 VTAction::None
954 } else {
955 VTAction::Event(invalid!(SS2, b))
956 }
957 }
958 ESC => {
961 self.st = Escape;
962 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
963 VTAction::None
964 } else {
965 VTAction::Event(invalid!(SS2))
966 }
967 }
968 _ => {
969 self.st = Ground;
970 VTAction::Event(VTEvent::Ss2(SS2 { char: c }))
971 }
972 }
973 EscSs3 => {
974 CAN | SUB => {
975 self.st = Ground;
976 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
977 VTAction::None
978 } else {
979 VTAction::Event(invalid!(SS3, b))
980 }
981 }
982 ESC => {
985 self.st = Escape;
986 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
987 VTAction::None
988 } else {
989 VTAction::Event(invalid!(SS3))
990 }
991 }
992 _ => {
993 self.st = Ground;
994 VTAction::Event(VTEvent::Ss3(SS3 { char: c }))
995 }
996 }
997 CsiEntry => {
998 CAN | SUB => {
999 self.st = Ground;
1000 VTAction::None
1001 }
1002 DEL => VTAction::None,
1003 ESC => {
1004 self.st = Escape;
1005 VTAction::None
1006 }
1007 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1009 c if is_priv(c) => {
1010 self.priv_prefix = Some(c);
1011 self.st = CsiParam;
1012 VTAction::None
1013 }
1014 c if is_digit(c) => {
1015 self.cur_param.push(c);
1016 self.st = CsiParam;
1017 VTAction::None
1018 }
1019 b';' => {
1020 self.next_param();
1021 self.st = CsiParam;
1022 VTAction::None
1023 }
1024 b':' => {
1025 self.cur_param.push(b':');
1026 self.st = CsiParam;
1027 VTAction::None
1028 }
1029 c if is_intermediate(c) => {
1030 if self.ints.push(c) {
1031 self.st = CsiInt;
1032 } else {
1033 self.st = Ground;
1034 }
1035 VTAction::None
1036 }
1037 c if is_final(c) => {
1038 self.st = Ground;
1039 self.emit_csi(c)
1040 }
1041 _ => {
1042 self.st = CsiIgnore;
1043 VTAction::None
1044 }
1045 }
1046 CsiParam => {
1047 CAN | SUB => {
1048 self.st = Ground;
1049 VTAction::None
1050 }
1051 DEL => VTAction::None,
1052 ESC => {
1053 self.st = Escape;
1054 VTAction::None
1055 }
1056 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1058 c if is_digit(c) => {
1059 self.cur_param.push(c);
1060 VTAction::None
1061 }
1062 b';' => {
1063 self.next_param();
1064 VTAction::None
1065 }
1066 b':' => {
1067 self.cur_param.push(b':');
1068 VTAction::None
1069 }
1070 c if is_intermediate(c) => {
1071 if self.ints.push(c) {
1072 self.st = CsiInt;
1073 } else {
1074 self.st = Ground;
1075 }
1076 VTAction::None
1077 }
1078 c if is_final(c) => {
1079 self.st = Ground;
1080 self.emit_csi(c)
1081 }
1082 _ => {
1083 self.st = CsiIgnore;
1084 VTAction::None
1085 }
1086 }
1087 CsiInt => {
1088 CAN | SUB => {
1089 self.st = Ground;
1090 VTAction::None
1091 }
1092 DEL => VTAction::None,
1093 ESC => {
1094 self.st = Escape;
1095 VTAction::None
1096 }
1097 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1099 c if is_intermediate(c) => {
1100 if self.ints.push(c) {
1101 self.st = CsiInt;
1102 } else {
1103 self.st = Ground;
1104 }
1105 VTAction::None
1106 }
1107 c if is_final(c) => {
1108 self.st = Ground;
1109 self.emit_csi(c)
1110 }
1111 _ => {
1112 self.st = CsiIgnore;
1113 VTAction::None
1114 }
1115 }
1116 CsiIgnore => {
1117 CAN | SUB => {
1118 self.st = Ground;
1119 VTAction::None
1120 }
1121 DEL => VTAction::None,
1122 ESC => {
1123 self.st = Escape;
1124 VTAction::None
1125 }
1126 c if is_final(c) => {
1127 self.st = Ground;
1128 VTAction::None
1129 }
1130 _ => VTAction::None,
1131 }
1132 DcsEntry => {
1133 CAN | SUB => {
1134 self.st = Ground;
1135 VTAction::None
1136 }
1137 DEL => VTAction::None,
1138 ESC => {
1139 self.st = Escape;
1140 VTAction::None
1141 }
1142 c if is_priv(c) => {
1143 self.priv_prefix = Some(c);
1144 self.st = DcsParam;
1145 VTAction::None
1146 }
1147 c if is_digit(c) => {
1148 self.cur_param.push(c);
1149 self.st = DcsParam;
1150 VTAction::None
1151 }
1152 b';' => {
1153 self.next_param();
1154 self.st = DcsParam;
1155 VTAction::None
1156 }
1157 b':' => {
1158 self.st = DcsIgnore;
1159 VTAction::None
1160 }
1161 c if is_intermediate(c) => {
1162 if self.ints.push(c) {
1163 self.st = DcsInt;
1164 } else {
1165 self.st = Ground;
1166 }
1167 VTAction::None
1168 }
1169 c if is_final(c) => {
1170 self.st = DcsPassthrough;
1171 self.dcs_start(c)
1172 }
1173 _ => {
1174 self.st = DcsIgnore;
1175 VTAction::None
1176 }
1177 }
1178 DcsParam => {
1179 CAN | SUB => {
1180 self.st = Ground;
1181 VTAction::None
1182 }
1183 DEL => VTAction::None,
1184 ESC => {
1185 self.st = Escape;
1186 VTAction::None
1187 }
1188 c if is_digit(c) => {
1189 self.cur_param.push(c);
1190 VTAction::None
1191 }
1192 b';' => {
1193 self.next_param();
1194 VTAction::None
1195 }
1196 b':' => {
1197 self.st = DcsIgnore;
1198 VTAction::None
1199 }
1200 c if is_intermediate(c) => {
1201 if self.ints.push(c) {
1202 self.st = DcsInt;
1203 } else {
1204 self.st = Ground;
1205 }
1206 self.st = DcsInt;
1207 VTAction::None
1208 }
1209 c if is_final(c) => {
1210 self.st = DcsPassthrough;
1211 self.dcs_start(c)
1212 }
1213 _ => {
1214 self.st = DcsIgnore;
1215 VTAction::None
1216 }
1217 }
1218 DcsInt => {
1219 CAN | SUB => {
1220 self.st = Ground;
1221 VTAction::None
1222 }
1223 DEL => VTAction::None,
1224 ESC => {
1225 self.st = Escape;
1226 VTAction::None
1227 }
1228 c if is_intermediate(c) => {
1229 if self.ints.push(c) {
1230 self.st = DcsInt;
1231 } else {
1232 self.st = Ground;
1233 }
1234 VTAction::None
1235 }
1236 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1237 self.st = DcsPassthrough;
1238 self.dcs_start(c)
1239 }
1240 _ => {
1241 self.st = DcsIgnore;
1242 VTAction::None
1243 }
1244 }
1245 DcsIgnore => {
1246 CAN | SUB => {
1247 self.st = Ground;
1248 VTAction::None
1249 }
1250 DEL => VTAction::None,
1251 ESC => {
1252 self.st = DcsIgnoreEsc;
1253 VTAction::None
1254 }
1255 _ => VTAction::None,
1256 }
1257 DcsIgnoreEsc => {
1258 CAN | SUB => {
1259 self.st = Ground;
1260 VTAction::None
1261 }
1262 ST_FINAL => {
1263 self.st = Ground;
1264 VTAction::None
1265 }
1266 DEL => VTAction::None,
1267 ESC => VTAction::None,
1268 _ => {
1269 self.st = DcsIgnore;
1270 VTAction::None
1271 }
1272 }
1273 DcsPassthrough => {
1274 CAN | SUB => {
1275 self.st = Ground;
1276 VTAction::Cancel(VTEmit::Dcs)
1277 }
1278 DEL => VTAction::None,
1279 ESC => {
1280 self.st = DcsEsc;
1281 VTAction::Hold(VTEmit::Dcs)
1282 }
1283 _ => VTAction::Buffer(VTEmit::Dcs),
1284 }
1285 DcsEsc => {
1286 ST_FINAL => {
1287 self.st = Ground;
1288 VTAction::End(VTEnd::Dcs)
1289 }
1290 DEL => VTAction::None,
1291 ESC => {
1292 VTAction::Hold(VTEmit::Dcs)
1294 }
1295 _ => {
1296 self.st = DcsPassthrough;
1298 VTAction::Buffer(VTEmit::Dcs)
1299 }
1300 }
1301 OscString => {
1302 CAN | SUB => {
1303 self.st = Ground;
1304 VTAction::Cancel(VTEmit::Osc)
1305 }
1306 DEL => VTAction::None,
1307 BEL => {
1308 self.st = Ground;
1309 VTAction::End(VTEnd::Osc { used_bel: true })
1310 }
1311 ESC => {
1312 self.st = OscEsc;
1313 VTAction::Hold(VTEmit::Osc)
1314 }
1315 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1316 _ => VTAction::None, }
1318 OscEsc => {
1319 ST_FINAL => {
1320 self.st = Ground;
1321 VTAction::End(VTEnd::Osc { used_bel: false })
1322 } ESC => VTAction::Hold(VTEmit::Osc),
1324 DEL => VTAction::None,
1325 _ => {
1326 self.st = OscString;
1327 VTAction::Buffer(VTEmit::Osc)
1328 }
1329 }
1330 SosPmApcString => {
1331 CAN | SUB => {
1332 self.st = Ground;
1333 VTAction::None
1334 }
1335 DEL => VTAction::None,
1336 ESC => {
1337 self.st = SpaEsc;
1338 VTAction::None
1339 }
1340 _ => VTAction::None,
1341 }
1342 SpaEsc => {
1343 ST_FINAL => {
1344 self.st = Ground;
1345 VTAction::None
1346 }
1347 DEL => VTAction::None,
1348 ESC => {
1349 VTAction::None
1351 }
1352 _ => {
1353 self.st = State::SosPmApcString;
1354 VTAction::None
1355 }
1356 }
1357 }
1358 }
1359}
1360
1361#[cfg(test)]
1362mod tests {
1363 use crate::event::VTOwnedEvent;
1364
1365 use super::*;
1366 use pretty_assertions::assert_eq;
1367
1368 #[test]
1369 fn test_edge_cases() {
1370 let mut result = String::new();
1372 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1373 assert_eq!(result.trim(), "");
1374
1375 let mut result = String::new();
1377 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1378 assert_eq!(result.trim(), "");
1379
1380 let mut result = String::new();
1382 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1383 assert_eq!(result.trim(), "");
1384
1385 let mut result = String::new();
1387 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1388 assert_eq!(result.trim(), "");
1389
1390 let mut result = String::new();
1392 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1393 assert_eq!(result.trim(), "OscStart");
1394 }
1395
1396 #[test]
1397 fn test_streaming_behavior() {
1398 let mut parser = VTPushParser::new(); let mut result = String::new();
1401 let mut callback = |vt_input: VTEvent<'_>| {
1402 result.push_str(&format!("{vt_input:?}\n"));
1403 };
1404
1405 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1407 parser.feed_with(b"data", &mut callback);
1408 parser.feed_with(b" more", &mut callback);
1409 parser.feed_with(b"\x1b\\", &mut callback);
1410
1411 assert_eq!(
1412 result.trim(),
1413 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1414 );
1415 }
1416
1417 #[test]
1418 fn test_dcs_payload_passthrough() {
1419 let dcs_cases: &[(&[u8], &str)] = &[
1427 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1429 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1431 (
1433 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1434 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1435 ),
1436 (
1438 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1439 "ABC<ESC><ESC>DEF<ESC>XG",
1440 ),
1441 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1443 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1445 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1447 (
1449 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1450 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1451 ),
1452 (
1454 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1455 "<ESC>[58:2::000:007:042m",
1456 ),
1457 ];
1458
1459 for (input, expected_body) in dcs_cases {
1460 let events = collect_owned_events(input);
1461
1462 let mut actual_body = Vec::new();
1464 for event in &events {
1465 match event {
1466 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1467 actual_body.extend(data);
1468 }
1469 _ => {}
1470 }
1471 }
1472
1473 let actual_body = String::from_utf8(actual_body).unwrap();
1474 let actual_body = actual_body
1475 .replace("\x1b", "<ESC>")
1476 .replace("\x07", "<BEL>");
1477
1478 assert_eq!(
1479 actual_body, *expected_body,
1480 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1481 input, events
1482 );
1483 }
1484 }
1485
1486 fn collect_events(input: &[u8]) -> Vec<String> {
1487 let mut out = Vec::new();
1488 let mut p = VTPushParser::new();
1489 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1490 out
1491 }
1492
1493 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1494 let mut out = Vec::new();
1495 let mut p = VTPushParser::new();
1496 p.feed_with(input, &mut |ev: VTEvent| out.push(ev.to_owned()));
1497 out
1498 }
1499
1500 #[test]
1501 fn dcs_esc_esc_del() {
1502 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1503 eprintln!("{ev:?}");
1504 }
1505
1506 #[test]
1507 fn osc_bel() {
1508 let mut parser = VTPushParser::new();
1509 let mut output = String::new();
1510 for b in b"\x1b]X\x07" {
1511 parser.feed_with(&[*b], &mut |ev: VTEvent| {
1512 output.push_str(&format!("{ev:?}\n"));
1513 });
1514 }
1515 assert_eq!(output.trim(), "OscStart\nOscData('X')\nOscEnd('')");
1516 }
1517
1518 #[test]
1519 fn dcs_header_with_colon_is_ignored_case1() {
1520 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1522 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1524 }
1525
1526 #[test]
1527 fn dcs_header_with_colon_is_ignored_case2() {
1528 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1530 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1531 }
1532
1533 #[test]
1534 fn dcs_header_with_colon_is_ignored_case3() {
1535 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1537 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1538 }
1539
1540 #[test]
1541 fn osc_aborted_by_can_mid_body() {
1542 let mut s = Vec::new();
1544 s.extend_from_slice(b"\x1b]0;Title");
1545 s.push(CAN);
1546 s.extend_from_slice(b"more\x07");
1547
1548 let ev = collect_debug(&s);
1549
1550 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1555 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1556 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1557 }
1558
1559 #[test]
1560 fn osc_aborted_by_sub_before_terminator() {
1561 let mut s = Vec::new();
1562 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1563 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1567 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1571 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1572 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1573 }
1574
1575 fn collect_debug(input: &[u8]) -> Vec<String> {
1577 let mut out = Vec::new();
1578 let mut p = VTPushParser::new();
1579 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1580 out
1581 }
1582
1583 #[test]
1584 fn dcs_aborted_by_can_before_body() {
1585 let mut s = Vec::new();
1587 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1589 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1592
1593 assert_eq!(ev.len(), 4, "{ev:#?}");
1594 assert_eq!(ev[0], "DcsStart('', q)");
1595 assert_eq!(ev[1], "DcsCancel");
1596 assert_eq!(ev[2], "Raw('IGNORED')");
1597 assert_eq!(ev[3], "Esc('', \\)");
1598 }
1599
1600 #[test]
1601 fn dcs_aborted_by_can_mid_body() {
1602 let mut s = Vec::new();
1604 s.extend_from_slice(b"\x1bPqABC");
1605 s.push(CAN);
1606 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1609
1610 assert_eq!(ev.len(), 4, "{ev:#?}");
1611 assert_eq!(ev[0], "DcsStart('', q)");
1612 assert_eq!(ev[1], "DcsCancel");
1613 assert_eq!(ev[2], "Raw('MORE')");
1614 assert_eq!(ev[3], "Esc('', \\)");
1615 }
1616
1617 #[test]
1620 fn spa_aborted_by_can_is_ignored() {
1621 let mut s = Vec::new();
1623 s.extend_from_slice(b"\x1b_hello");
1624 s.push(CAN);
1625 s.extend_from_slice(b"world\x1b\\");
1626
1627 let ev = collect_debug(&s);
1628 assert_eq!(ev.len(), 2, "{ev:#?}");
1629 assert_eq!(ev[0], "Raw('world')");
1630 assert_eq!(ev[1], "Esc('', \\)");
1631 }
1632
1633 #[test]
1634 fn spa_sub_aborts_too() {
1635 let mut s = Vec::new();
1636 s.extend_from_slice(b"\x1bXhello");
1637 s.push(SUB);
1638 s.extend_from_slice(b"world\x1b\\");
1639 let ev = collect_debug(&s);
1640 assert_eq!(ev.len(), 2, "{ev:#?}");
1641 assert_eq!(ev[0], "Raw('world')");
1642 assert_eq!(ev[1], "Esc('', \\)");
1643 }
1644
1645 #[test]
1648 fn can_in_ground_is_c0() {
1649 let mut s = Vec::new();
1650 s.extend_from_slice(b"abc");
1651 s.push(CAN);
1652 s.extend_from_slice(b"def");
1653 let ev = collect_debug(&s);
1654 assert_eq!(ev.len(), 3, "{ev:#?}");
1656 assert_eq!(ev[0], "Raw('abc')");
1657 assert_eq!(ev[1], "C0(18)");
1658 assert_eq!(ev[2], "Raw('def')");
1659 }
1660
1661 #[test]
1664 fn three_byte_sequences_capturable() {
1665 let mut bytes = vec![];
1666 for i in 0..=0xFFFFFF_u32 {
1667 bytes.clear();
1668 let test_bytes = i.to_le_bytes();
1669 let test_bytes = &test_bytes[..3];
1670 if test_bytes.iter().any(|b| b == &0) {
1671 continue;
1672 }
1673 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1674 continue;
1675 }
1676 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1677 continue;
1678 }
1679
1680 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1681 parser.feed_with(test_bytes, |event: VTEvent| {
1682 let mut chunk = [0_u8; 3];
1683 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1684 panic!("Failed to encode event {test_bytes:02X?} -> {event:?}")
1685 });
1686 bytes.extend_from_slice(&chunk[..b]);
1687 });
1688 if let Some(event) = parser.idle() {
1689 let mut chunk = [0_u8; 3];
1690 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1691 panic!("Failed to encode event {test_bytes:02X?} -> {event:?}")
1692 });
1693 bytes.extend_from_slice(&chunk[..b]);
1694 }
1695
1696 if bytes.len() != 3 || bytes != test_bytes {
1697 eprintln!("Failed to parse:");
1698 parser.feed_with(test_bytes, |event: VTEvent| {
1699 eprintln!("{event:?}");
1700 });
1701 if let Some(event) = parser.idle() {
1702 eprintln!("{event:?}");
1703 }
1704 assert_eq!(bytes, test_bytes, "{test_bytes:02X?} -> {bytes:02X?}");
1705 }
1706 }
1707 }
1708}