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 privp = self.priv_prefix.take();
708 VTAction::Event(VTEvent::Csi(CSI {
709 private: privp,
710 params: ParamBuf {
711 params: &self.params,
712 },
713 intermediates: self.ints,
714 final_byte,
715 }))
716 }
717
718 fn dcs_start(&mut self, final_byte: u8) -> VTAction<'_> {
719 self.finish_params_if_any();
720
721 let privp = self.priv_prefix.take();
722 VTAction::Event(VTEvent::DcsStart(DCS {
723 private: privp,
724 params: ParamBuf {
725 params: &self.params,
726 },
727 intermediates: self.ints,
728 final_byte,
729 }))
730 }
731
732 fn push_with(&mut self, b: u8) -> VTAction<'_> {
737 use State::*;
738
739 macro_rules! state_machine {
740 (def $c:ident $(
741 $state:ident => { $( $p:pat
742 $(if $( $if_ident:ident $( ($call_ident:ident) )? $( == $literal:literal)? $(||)? )+)?
743 => $block:expr $(,)? )* }
744 )*) => {
745 #[allow(unused, clippy::redundant_pattern)]
746 match self.st {
747 $(
748 $state => {
749 match b {
750 $(
751 $c @ state_machine!(pattern $p $(if $( ($if_ident ($($call_ident)?) ($($literal)?)) )+ )?) => $block,
752 )*
753 }
754 }
755 )*
756 }
757 };
758 (pattern $pat:pat if $( ($if_ident:ident ($($call_ident:ident)?) ($($literal:literal)?)) )+ ) => {
759 $(
760 state_machine!(pattern_if ($if_ident) ($($call_ident)?) ($($literal)?) )
761 )|+
762 };
763 (pattern $pat:pat) => {
764 $pat
765 };
766 (pattern_if ($any:ident) ($call_ident:ident) ()) => {
767 $any!()
768 };
769 (pattern_if ($if_ident:ident) () ($literal:literal)) => {
770 $literal
771 };
772 }
773
774 state_machine! {
781 def c
782 Ground => {
783 ESC => {
784 self.clear_hdr_collectors();
785 self.st = State::Escape;
786 VTAction::None
787 }
788 DEL => VTAction::Event(VTEvent::C0(DEL)),
789 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
790 _ => VTAction::Buffer(VTEmit::Ground),
791 }
792 Escape => {
793 CAN | SUB => {
794 self.st = Ground;
795 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
796 VTAction::None
797 } else {
798 VTAction::Event(invalid!(b))
799 }
800 }
801 DEL => {
804 self.st = Ground;
805 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
806 VTAction::None
807 } else {
808 VTAction::Event(invalid!(b))
809 }
810 }
811 c if is_intermediate(c) => {
812 if self.ints.push(c) {
813 self.st = EscInt;
814 } else {
815 self.st = Ground;
816 }
817 VTAction::None
818 }
819 b'?' => {
821 self.priv_prefix = Some(b);
822 self.st = EscInt;
823 VTAction::None
824 }
825 c if is_priv_no_q(c) => {
827 self.st = Ground;
828 VTAction::Event(VTEvent::Esc(Esc {
829 intermediates: VTIntermediate::empty(),
830 private: None,
831 final_byte: b,
832 }))
833 }
834 CSI => {
835 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
836 self.st = CsiIgnore;
837 } else {
838 self.st = CsiEntry;
839 }
840 VTAction::None
841 }
842 DCS => {
843 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
844 self.st = DcsIgnore;
845 } else {
846 self.st = DcsEntry;
847 }
848 VTAction::None
849 }
850 OSC => {
851 self.st = OscString;
852 VTAction::Event(VTEvent::OscStart)
853 }
854 SS2 => {
855 self.st = EscSs2;
856 VTAction::None
857 }
858 SS3 => {
859 self.st = EscSs3;
860 VTAction::None
861 }
862 SOS | PM | APC => {
863 self.st = State::SosPmApcString;
864 VTAction::None
865 }
866 c if is_final(c) || is_digit(c) => {
867 self.st = Ground;
868 VTAction::Event(VTEvent::Esc(Esc {
869 intermediates: self.ints,
870 private: self.priv_prefix.take(),
871 final_byte: c,
872 }))
873 }
874 ESC => {
875 VTAction::Event(VTEvent::C0(ESC))
877 }
878 _ => {
879 self.st = Ground;
880 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
881 VTAction::None
882 } else {
883 VTAction::Event(invalid!(b))
884 }
885 }
886 }
887 EscInt => {
888 CAN | SUB => {
889 self.st = Ground;
890 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
891 VTAction::None
892 } else {
893 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
894 }
895 }
896 DEL => {
899 self.st = Ground;
900 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
901 VTAction::None
902 } else {
903 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
904 }
905 }
906 c if is_intermediate(c) => {
907 if !self.ints.push(c) {
908 self.st = Ground;
909 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
910 VTAction::None
911 } else {
912 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
913 }
914 } else {
915 VTAction::None
916 }
917 }
918 c if is_final(c) || is_digit(c) => {
919 self.st = Ground;
920 VTAction::Event(VTEvent::Esc(Esc {
921 intermediates: self.ints,
922 private: self.priv_prefix.take(),
923 final_byte: c,
924 }))
925 }
926 ESC => {
929 self.st = Escape;
930 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
931 VTAction::None
932 } else {
933 VTAction::Event(invalid!(self.priv_prefix, self.ints))
934 }
935 }
936 _ => {
937 self.st = Ground;
938 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
939 VTAction::None
940 } else {
941 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
942 }
943 }
944 }
945 EscSs2 => {
946 CAN | SUB => {
947 self.st = Ground;
948 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
949 VTAction::None
950 } else {
951 VTAction::Event(invalid!(SS2, b))
952 }
953 }
954 ESC => {
957 self.st = Escape;
958 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
959 VTAction::None
960 } else {
961 VTAction::Event(invalid!(SS2))
962 }
963 }
964 _ => {
965 self.st = Ground;
966 VTAction::Event(VTEvent::Ss2(SS2 { char: c }))
967 }
968 }
969 EscSs3 => {
970 CAN | SUB => {
971 self.st = Ground;
972 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
973 VTAction::None
974 } else {
975 VTAction::Event(invalid!(SS3, b))
976 }
977 }
978 ESC => {
981 self.st = Escape;
982 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
983 VTAction::None
984 } else {
985 VTAction::Event(invalid!(SS3))
986 }
987 }
988 _ => {
989 self.st = Ground;
990 VTAction::Event(VTEvent::Ss3(SS3 { char: c }))
991 }
992 }
993 CsiEntry => {
994 CAN | SUB => {
995 self.st = Ground;
996 VTAction::None
997 }
998 DEL => VTAction::None,
999 ESC => {
1000 self.st = Escape;
1001 VTAction::None
1002 }
1003 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1005 c if is_priv(c) => {
1006 self.priv_prefix = Some(c);
1007 self.st = CsiParam;
1008 VTAction::None
1009 }
1010 c if is_digit(c) => {
1011 self.cur_param.push(c);
1012 self.st = CsiParam;
1013 VTAction::None
1014 }
1015 b';' => {
1016 self.next_param();
1017 self.st = CsiParam;
1018 VTAction::None
1019 }
1020 b':' => {
1021 self.cur_param.push(b':');
1022 self.st = CsiParam;
1023 VTAction::None
1024 }
1025 c if is_intermediate(c) => {
1026 if self.ints.push(c) {
1027 self.st = CsiInt;
1028 } else {
1029 self.st = Ground;
1030 }
1031 VTAction::None
1032 }
1033 c if is_final(c) => {
1034 self.st = Ground;
1035 self.emit_csi(c)
1036 }
1037 _ => {
1038 self.st = CsiIgnore;
1039 VTAction::None
1040 }
1041 }
1042 CsiParam => {
1043 CAN | SUB => {
1044 self.st = Ground;
1045 VTAction::None
1046 }
1047 DEL => VTAction::None,
1048 ESC => {
1049 self.st = Escape;
1050 VTAction::None
1051 }
1052 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1054 c if is_digit(c) => {
1055 self.cur_param.push(c);
1056 VTAction::None
1057 }
1058 b';' => {
1059 self.next_param();
1060 VTAction::None
1061 }
1062 b':' => {
1063 self.cur_param.push(b':');
1064 VTAction::None
1065 }
1066 c if is_intermediate(c) => {
1067 if self.ints.push(c) {
1068 self.st = CsiInt;
1069 } else {
1070 self.st = Ground;
1071 }
1072 VTAction::None
1073 }
1074 c if is_final(c) => {
1075 self.st = Ground;
1076 self.emit_csi(c)
1077 }
1078 _ => {
1079 self.st = CsiIgnore;
1080 VTAction::None
1081 }
1082 }
1083 CsiInt => {
1084 CAN | SUB => {
1085 self.st = Ground;
1086 VTAction::None
1087 }
1088 DEL => VTAction::None,
1089 ESC => {
1090 self.st = Escape;
1091 VTAction::None
1092 }
1093 c if is_any_c0(c) => VTAction::Event(VTEvent::C0(c)),
1095 c if is_intermediate(c) => {
1096 if self.ints.push(c) {
1097 self.st = CsiInt;
1098 } else {
1099 self.st = Ground;
1100 }
1101 VTAction::None
1102 }
1103 c if is_final(c) => {
1104 self.st = Ground;
1105 self.emit_csi(c)
1106 }
1107 _ => {
1108 self.st = CsiIgnore;
1109 VTAction::None
1110 }
1111 }
1112 CsiIgnore => {
1113 CAN | SUB => {
1114 self.st = Ground;
1115 VTAction::None
1116 }
1117 DEL => VTAction::None,
1118 ESC => {
1119 self.st = Escape;
1120 VTAction::None
1121 }
1122 c if is_final(c) => {
1123 self.st = Ground;
1124 VTAction::None
1125 }
1126 _ => VTAction::None,
1127 }
1128 DcsEntry => {
1129 CAN | SUB => {
1130 self.st = Ground;
1131 VTAction::None
1132 }
1133 DEL => VTAction::None,
1134 ESC => {
1135 self.st = Escape;
1136 VTAction::None
1137 }
1138 c if is_priv(c) => {
1139 self.priv_prefix = Some(c);
1140 self.st = DcsParam;
1141 VTAction::None
1142 }
1143 c if is_digit(c) => {
1144 self.cur_param.push(c);
1145 self.st = DcsParam;
1146 VTAction::None
1147 }
1148 b';' => {
1149 self.next_param();
1150 self.st = DcsParam;
1151 VTAction::None
1152 }
1153 b':' => {
1154 self.st = DcsIgnore;
1155 VTAction::None
1156 }
1157 c if is_intermediate(c) => {
1158 if self.ints.push(c) {
1159 self.st = DcsInt;
1160 } else {
1161 self.st = Ground;
1162 }
1163 VTAction::None
1164 }
1165 c if is_final(c) => {
1166 self.st = DcsPassthrough;
1167 self.dcs_start(c)
1168 }
1169 _ => {
1170 self.st = DcsIgnore;
1171 VTAction::None
1172 }
1173 }
1174 DcsParam => {
1175 CAN | SUB => {
1176 self.st = Ground;
1177 VTAction::None
1178 }
1179 DEL => VTAction::None,
1180 ESC => {
1181 self.st = Escape;
1182 VTAction::None
1183 }
1184 c if is_digit(c) => {
1185 self.cur_param.push(c);
1186 VTAction::None
1187 }
1188 b';' => {
1189 self.next_param();
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 self.st = DcsInt;
1203 VTAction::None
1204 }
1205 c if is_final(c) => {
1206 self.st = DcsPassthrough;
1207 self.dcs_start(c)
1208 }
1209 _ => {
1210 self.st = DcsIgnore;
1211 VTAction::None
1212 }
1213 }
1214 DcsInt => {
1215 CAN | SUB => {
1216 self.st = Ground;
1217 VTAction::None
1218 }
1219 DEL => VTAction::None,
1220 ESC => {
1221 self.st = Escape;
1222 VTAction::None
1223 }
1224 c if is_intermediate(c) => {
1225 if self.ints.push(c) {
1226 self.st = DcsInt;
1227 } else {
1228 self.st = Ground;
1229 }
1230 VTAction::None
1231 }
1232 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1233 self.st = DcsPassthrough;
1234 self.dcs_start(c)
1235 }
1236 _ => {
1237 self.st = DcsIgnore;
1238 VTAction::None
1239 }
1240 }
1241 DcsIgnore => {
1242 CAN | SUB => {
1243 self.st = Ground;
1244 VTAction::None
1245 }
1246 DEL => VTAction::None,
1247 ESC => {
1248 self.st = DcsIgnoreEsc;
1249 VTAction::None
1250 }
1251 _ => VTAction::None,
1252 }
1253 DcsIgnoreEsc => {
1254 CAN | SUB => {
1255 self.st = Ground;
1256 VTAction::None
1257 }
1258 ST_FINAL => {
1259 self.st = Ground;
1260 VTAction::None
1261 }
1262 DEL => VTAction::None,
1263 ESC => VTAction::None,
1264 _ => {
1265 self.st = DcsIgnore;
1266 VTAction::None
1267 }
1268 }
1269 DcsPassthrough => {
1270 CAN | SUB => {
1271 self.st = Ground;
1272 VTAction::Cancel(VTEmit::Dcs)
1273 }
1274 DEL => VTAction::None,
1275 ESC => {
1276 self.st = DcsEsc;
1277 VTAction::Hold(VTEmit::Dcs)
1278 }
1279 _ => VTAction::Buffer(VTEmit::Dcs),
1280 }
1281 DcsEsc => {
1282 ST_FINAL => {
1283 self.st = Ground;
1284 VTAction::End(VTEnd::Dcs)
1285 }
1286 DEL => VTAction::None,
1287 ESC => {
1288 VTAction::Hold(VTEmit::Dcs)
1290 }
1291 _ => {
1292 self.st = DcsPassthrough;
1294 VTAction::Buffer(VTEmit::Dcs)
1295 }
1296 }
1297 OscString => {
1298 CAN | SUB => {
1299 self.st = Ground;
1300 VTAction::Cancel(VTEmit::Osc)
1301 }
1302 DEL => VTAction::None,
1303 BEL => {
1304 self.st = Ground;
1305 VTAction::End(VTEnd::Osc { used_bel: true })
1306 }
1307 ESC => {
1308 self.st = OscEsc;
1309 VTAction::Hold(VTEmit::Osc)
1310 }
1311 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1312 _ => VTAction::None, }
1314 OscEsc => {
1315 ST_FINAL => {
1316 self.st = Ground;
1317 VTAction::End(VTEnd::Osc { used_bel: false })
1318 } ESC => VTAction::Hold(VTEmit::Osc),
1320 DEL => VTAction::None,
1321 _ => {
1322 self.st = OscString;
1323 VTAction::Buffer(VTEmit::Osc)
1324 }
1325 }
1326 SosPmApcString => {
1327 CAN | SUB => {
1328 self.st = Ground;
1329 VTAction::None
1330 }
1331 DEL => VTAction::None,
1332 ESC => {
1333 self.st = SpaEsc;
1334 VTAction::None
1335 }
1336 _ => VTAction::None,
1337 }
1338 SpaEsc => {
1339 ST_FINAL => {
1340 self.st = Ground;
1341 VTAction::None
1342 }
1343 DEL => VTAction::None,
1344 ESC => {
1345 VTAction::None
1347 }
1348 _ => {
1349 self.st = State::SosPmApcString;
1350 VTAction::None
1351 }
1352 }
1353 }
1354 }
1355}
1356
1357#[cfg(test)]
1358mod tests {
1359 use crate::event::VTOwnedEvent;
1360
1361 use super::*;
1362 use pretty_assertions::assert_eq;
1363
1364 #[test]
1365 fn test_edge_cases() {
1366 let mut result = String::new();
1368 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1369 assert_eq!(result.trim(), "");
1370
1371 let mut result = String::new();
1373 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1374 assert_eq!(result.trim(), "");
1375
1376 let mut result = String::new();
1378 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1379 assert_eq!(result.trim(), "");
1380
1381 let mut result = String::new();
1383 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1384 assert_eq!(result.trim(), "");
1385
1386 let mut result = String::new();
1388 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1389 assert_eq!(result.trim(), "OscStart");
1390 }
1391
1392 #[test]
1393 fn test_streaming_behavior() {
1394 let mut parser = VTPushParser::new(); let mut result = String::new();
1397 let mut callback = |vt_input: VTEvent<'_>| {
1398 result.push_str(&format!("{vt_input:?}\n"));
1399 };
1400
1401 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1403 parser.feed_with(b"data", &mut callback);
1404 parser.feed_with(b" more", &mut callback);
1405 parser.feed_with(b"\x1b\\", &mut callback);
1406
1407 assert_eq!(
1408 result.trim(),
1409 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1410 );
1411 }
1412
1413 #[test]
1414 fn test_dcs_payload_passthrough() {
1415 let dcs_cases: &[(&[u8], &str)] = &[
1423 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1425 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1427 (
1429 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1430 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1431 ),
1432 (
1434 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1435 "ABC<ESC><ESC>DEF<ESC>XG",
1436 ),
1437 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1439 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1441 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1443 (
1445 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1446 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1447 ),
1448 (
1450 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1451 "<ESC>[58:2::000:007:042m",
1452 ),
1453 ];
1454
1455 for (input, expected_body) in dcs_cases {
1456 let events = collect_owned_events(input);
1457
1458 let mut actual_body = Vec::new();
1460 for event in &events {
1461 match event {
1462 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1463 actual_body.extend(data);
1464 }
1465 _ => {}
1466 }
1467 }
1468
1469 let actual_body = String::from_utf8(actual_body).unwrap();
1470 let actual_body = actual_body
1471 .replace("\x1b", "<ESC>")
1472 .replace("\x07", "<BEL>");
1473
1474 assert_eq!(
1475 actual_body, *expected_body,
1476 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1477 input, events
1478 );
1479 }
1480 }
1481
1482 fn collect_events(input: &[u8]) -> Vec<String> {
1483 let mut out = Vec::new();
1484 let mut p = VTPushParser::new();
1485 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1486 out
1487 }
1488
1489 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1490 let mut out = Vec::new();
1491 let mut p = VTPushParser::new();
1492 p.feed_with(input, &mut |ev: VTEvent| out.push(ev.to_owned()));
1493 out
1494 }
1495
1496 #[test]
1497 fn dcs_esc_esc_del() {
1498 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1499 eprintln!("{ev:?}");
1500 }
1501
1502 #[test]
1503 fn osc_bel() {
1504 let mut parser = VTPushParser::new();
1505 let mut output = String::new();
1506 for b in b"\x1b]X\x07" {
1507 parser.feed_with(&[*b], &mut |ev: VTEvent| {
1508 output.push_str(&format!("{ev:?}\n"));
1509 });
1510 }
1511 assert_eq!(output.trim(), "OscStart\nOscData('X')\nOscEnd('')");
1512 }
1513
1514 #[test]
1515 fn dcs_header_with_colon_is_ignored_case1() {
1516 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1518 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1520 }
1521
1522 #[test]
1523 fn dcs_header_with_colon_is_ignored_case2() {
1524 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1526 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1527 }
1528
1529 #[test]
1530 fn dcs_header_with_colon_is_ignored_case3() {
1531 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1533 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1534 }
1535
1536 #[test]
1537 fn osc_aborted_by_can_mid_body() {
1538 let mut s = Vec::new();
1540 s.extend_from_slice(b"\x1b]0;Title");
1541 s.push(CAN);
1542 s.extend_from_slice(b"more\x07");
1543
1544 let ev = collect_debug(&s);
1545
1546 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1551 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1552 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1553 }
1554
1555 #[test]
1556 fn osc_aborted_by_sub_before_terminator() {
1557 let mut s = Vec::new();
1558 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1559 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1563 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1567 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1568 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1569 }
1570
1571 fn collect_debug(input: &[u8]) -> Vec<String> {
1573 let mut out = Vec::new();
1574 let mut p = VTPushParser::new();
1575 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1576 out
1577 }
1578
1579 #[test]
1580 fn dcs_aborted_by_can_before_body() {
1581 let mut s = Vec::new();
1583 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1585 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1588
1589 assert_eq!(ev.len(), 4, "{ev:#?}");
1590 assert_eq!(ev[0], "DcsStart('', q)");
1591 assert_eq!(ev[1], "DcsCancel");
1592 assert_eq!(ev[2], "Raw('IGNORED')");
1593 assert_eq!(ev[3], "Esc('', \\)");
1594 }
1595
1596 #[test]
1597 fn dcs_aborted_by_can_mid_body() {
1598 let mut s = Vec::new();
1600 s.extend_from_slice(b"\x1bPqABC");
1601 s.push(CAN);
1602 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1605
1606 assert_eq!(ev.len(), 4, "{ev:#?}");
1607 assert_eq!(ev[0], "DcsStart('', q)");
1608 assert_eq!(ev[1], "DcsCancel");
1609 assert_eq!(ev[2], "Raw('MORE')");
1610 assert_eq!(ev[3], "Esc('', \\)");
1611 }
1612
1613 #[test]
1616 fn spa_aborted_by_can_is_ignored() {
1617 let mut s = Vec::new();
1619 s.extend_from_slice(b"\x1b_hello");
1620 s.push(CAN);
1621 s.extend_from_slice(b"world\x1b\\");
1622
1623 let ev = collect_debug(&s);
1624 assert_eq!(ev.len(), 2, "{ev:#?}");
1625 assert_eq!(ev[0], "Raw('world')");
1626 assert_eq!(ev[1], "Esc('', \\)");
1627 }
1628
1629 #[test]
1630 fn spa_sub_aborts_too() {
1631 let mut s = Vec::new();
1632 s.extend_from_slice(b"\x1bXhello");
1633 s.push(SUB);
1634 s.extend_from_slice(b"world\x1b\\");
1635 let ev = collect_debug(&s);
1636 assert_eq!(ev.len(), 2, "{ev:#?}");
1637 assert_eq!(ev[0], "Raw('world')");
1638 assert_eq!(ev[1], "Esc('', \\)");
1639 }
1640
1641 #[test]
1644 fn can_in_ground_is_c0() {
1645 let mut s = Vec::new();
1646 s.extend_from_slice(b"abc");
1647 s.push(CAN);
1648 s.extend_from_slice(b"def");
1649 let ev = collect_debug(&s);
1650 assert_eq!(ev.len(), 3, "{ev:#?}");
1652 assert_eq!(ev[0], "Raw('abc')");
1653 assert_eq!(ev[1], "C0(18)");
1654 assert_eq!(ev[2], "Raw('def')");
1655 }
1656
1657 #[test]
1660 fn three_byte_sequences_capturable() {
1661 let mut bytes = vec![];
1662 for i in 0..=0xFFFFFF_u32 {
1663 bytes.clear();
1664 let test_bytes = i.to_le_bytes();
1665 let test_bytes = &test_bytes[..3];
1666 if test_bytes.iter().any(|b| b == &0) {
1667 continue;
1668 }
1669 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1670 continue;
1671 }
1672 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1673 continue;
1674 }
1675
1676 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1677 parser.feed_with(test_bytes, |event: VTEvent| {
1678 let mut chunk = [0_u8; 3];
1679 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1680 panic!("Failed to encode event {test_bytes:02X?} -> {event:?}")
1681 });
1682 bytes.extend_from_slice(&chunk[..b]);
1683 });
1684 if let Some(event) = parser.idle() {
1685 let mut chunk = [0_u8; 3];
1686 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1687 panic!("Failed to encode event {test_bytes:02X?} -> {event:?}")
1688 });
1689 bytes.extend_from_slice(&chunk[..b]);
1690 }
1691
1692 if bytes.len() != 3 || bytes != test_bytes {
1693 eprintln!("Failed to parse:");
1694 parser.feed_with(test_bytes, |event: VTEvent| {
1695 eprintln!("{event:?}");
1696 });
1697 if let Some(event) = parser.idle() {
1698 eprintln!("{event:?}");
1699 }
1700 assert_eq!(bytes, test_bytes, "{test_bytes:02X?} -> {bytes:02X?}");
1701 }
1702 }
1703 }
1704}