1pub mod ascii;
41pub mod capture;
42pub mod event;
43pub mod iter;
44pub mod signature;
45
46use smallvec::SmallVec;
47
48use ascii::AsciiControl;
49use event::{CSI, DCS, Esc, EscInvalid, SS2, SS3, VTEvent, VTIntermediate};
50
51const ESC: u8 = AsciiControl::Esc as _;
52const BEL: u8 = AsciiControl::Bel as _;
53const DEL: u8 = AsciiControl::Del as _;
54const CAN: u8 = AsciiControl::Can as _;
55const SUB: u8 = AsciiControl::Sub as _;
56const CSI: u8 = b'[';
57const OSC: u8 = b']';
58const SS2: u8 = b'N';
59const SS3: u8 = b'O';
60const DCS: u8 = b'P';
61const APC: u8 = b'_';
62const PM: u8 = b'^';
63const SOS: u8 = b'X';
64const ST_FINAL: u8 = b'\\';
65
66use crate::event::{Param, ParamBuf, Params};
67
68enum VTAction<'a> {
70 None,
73 Event(VTEvent<'a>),
76 End(VTEnd),
78 Buffer(VTEmit),
81 Hold(VTEmit),
84 Cancel(VTEmit),
86}
87
88#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89enum VTEmit {
90 Ground,
92 Dcs,
94 Osc,
96}
97
98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99enum VTEnd {
100 Dcs,
102 Osc { used_bel: bool },
104}
105
106#[inline]
107const fn is_c0(b: u8) -> bool {
108 b <= 0x1F && b != b'\r' && b != b'\n' && b != b'\t'
110}
111#[inline]
112fn is_printable(b: u8) -> bool {
113 (0x20..=0x7E).contains(&b)
114}
115#[inline]
116fn is_intermediate(b: u8) -> bool {
117 (0x20..=0x2F).contains(&b)
118}
119#[inline]
120const fn is_final(b: u8) -> bool {
121 b >= 0x40 && b <= 0x7E
122}
123#[inline]
124fn is_digit(b: u8) -> bool {
125 b.is_ascii_digit()
126}
127#[inline]
128fn is_priv(b: u8) -> bool {
129 matches!(b, b'<' | b'=' | b'>' | b'?')
130}
131
132macro_rules! byte_predicate {
133 (|$p:ident| $body:block) => {{
134 let mut out: [bool; 256] = [false; 256];
135 let mut i = 0;
136 while i < 256 {
137 let $p: u8 = i as u8;
138 out[i] = $body;
139 i += 1;
140 }
141 out
142 }};
143}
144
145const ENDS_CSI: [bool; 256] =
146 byte_predicate!(|b| { is_final(b) || b == ESC || b == CAN || b == SUB });
147
148const ENDS_GROUND: [bool; 256] = byte_predicate!(|b| { is_c0(b) || b == DEL });
149
150#[derive(Debug, Copy, Clone, PartialEq, Eq)]
151enum State {
152 Ground,
153 Escape,
154 EscInt,
155 EscSs2,
156 EscSs3,
157 CsiEntry,
158 CsiParam,
159 CsiInt,
160 CsiIgnore,
161 DcsEntry,
162 DcsParam,
163 DcsInt,
164 DcsIgnore,
165 DcsIgnoreEsc,
166 DcsPassthrough,
167 DcsEsc,
168 OscString,
169 OscEsc,
170 SosPmApcString,
171 SpaEsc,
172}
173
174pub const VT_PARSER_INTEREST_NONE: u8 = 0;
176pub const VT_PARSER_INTEREST_CSI: u8 = 1 << 0;
178pub const VT_PARSER_INTEREST_DCS: u8 = 1 << 1;
180pub const VT_PARSER_INTEREST_OSC: u8 = 1 << 2;
182pub const VT_PARSER_INTEREST_ESCAPE_RECOVERY: u8 = 1 << 4;
184pub const VT_PARSER_INTEREST_OTHER: u8 = 1 << 5;
186
187pub const VT_PARSER_INTEREST_ALL: u8 = VT_PARSER_INTEREST_CSI
189 | VT_PARSER_INTEREST_DCS
190 | VT_PARSER_INTEREST_OSC
191 | VT_PARSER_INTEREST_ESCAPE_RECOVERY
192 | VT_PARSER_INTEREST_OTHER;
193
194pub const VT_PARSER_INTEREST_DEFAULT: u8 = VT_PARSER_INTEREST_CSI
196 | VT_PARSER_INTEREST_DCS
197 | VT_PARSER_INTEREST_OSC
198 | VT_PARSER_INTEREST_OTHER;
199
200#[must_use]
201trait MaybeAbortable {
202 fn abort(self) -> bool;
203}
204
205impl MaybeAbortable for bool {
206 #[inline(always)]
207 fn abort(self) -> bool {
208 !self
209 }
210}
211
212impl MaybeAbortable for () {
213 #[inline(always)]
214 fn abort(self) -> bool {
215 false
216 }
217}
218
219pub struct VTPushParser<const INTEREST: u8 = VT_PARSER_INTEREST_DEFAULT> {
224 st: State,
225
226 ints: VTIntermediate,
228 params: Params,
229 cur_param: Param,
230 priv_prefix: Option<u8>,
231 held_byte: Option<u8>,
232}
233
234impl Default for VTPushParser {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl VTPushParser {
241 pub const fn new() -> Self {
242 VTPushParser::new_with()
243 }
244
245 pub fn decode_buffer<'a>(input: &'a [u8], mut cb: impl for<'b> FnMut(VTEvent<'b>)) {
247 let mut parser = VTPushParser::new();
248 parser.feed_with(input, &mut cb);
249 parser.finish(&mut cb);
250 }
251
252 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
253 VTPushParser::new_with()
254 }
255}
256
257macro_rules! invalid {
259 ($self:ident .ints, $b:expr) => {
260 if $self.ints.len() == 1 {
261 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
262 } else {
263 VTEvent::EscInvalid(EscInvalid::Three(
264 $self.ints.data[0],
265 $self.ints.data[1],
266 $b,
267 ))
268 }
269 };
270 ($self:ident .ints) => {
271 if $self.ints.len() == 1 {
272 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
273 } else {
274 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
275 }
276 };
277 ($a:expr) => {
278 VTEvent::EscInvalid(EscInvalid::One($a))
279 };
280 ($a:expr, $b:expr) => {
281 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
282 };
283}
284
285impl<const INTEREST: u8> VTPushParser<INTEREST> {
286 const fn new_with() -> Self {
287 Self {
288 st: State::Ground,
289 ints: VTIntermediate::empty(),
290 params: SmallVec::new_const(),
291 cur_param: SmallVec::new_const(),
292 priv_prefix: None,
293 held_byte: None,
294 }
295 }
296
297 #[inline]
309 pub fn feed_with<'this, 'input, F: for<'any> FnMut(VTEvent<'any>)>(
310 &'this mut self,
311 input: &'input [u8],
312 cb: &mut F,
313 ) {
314 self.feed_with_internal(input, cb);
315 }
316
317 #[inline]
330 pub fn feed_with_abortable<'this, 'input, F: for<'any> FnMut(VTEvent<'any>) -> bool>(
331 &'this mut self,
332 input: &'input [u8],
333 cb: &mut F,
334 ) -> usize {
335 self.feed_with_internal(input, cb)
336 }
337
338 #[inline(always)]
339 fn feed_with_internal<
340 'this,
341 'input,
342 R: MaybeAbortable,
343 F: for<'any> FnMut(VTEvent<'any>) -> R,
344 >(
345 &'this mut self,
346 input: &'input [u8],
347 cb: &mut F,
348 ) -> usize {
349 if input.is_empty() {
350 return 0;
351 }
352
353 #[derive(Debug)]
354 struct FeedState {
355 buffer_idx: usize,
356 current_emit: Option<VTEmit>,
357 hold: bool,
358 }
359
360 let mut state = FeedState {
361 buffer_idx: 0,
362 current_emit: None,
363 hold: self.held_byte.is_some(),
364 };
365
366 macro_rules! emit {
367 ($state:ident, $i:expr, $cb:expr, $end:expr, $used_bel:expr) => {
368 let hold = std::mem::take(&mut $state.hold);
369 if let Some(emit) = $state.current_emit.take() {
370 let i = $i;
371 let range = $state.buffer_idx..(i - hold as usize);
372 if $end {
373 if match emit {
374 VTEmit::Ground => unreachable!(),
375 VTEmit::Dcs => $cb(VTEvent::DcsEnd(&input[range])),
376 VTEmit::Osc => $cb(VTEvent::OscEnd {
377 data: &input[range],
378 used_bel: $used_bel,
379 }),
380 }
381 .abort()
382 {
383 return i + 1;
384 }
385 } else if range.len() > 0 {
386 if match emit {
387 VTEmit::Ground => $cb(VTEvent::Raw(&input[range])),
388 VTEmit::Dcs => $cb(VTEvent::DcsData(&input[range])),
389 VTEmit::Osc => $cb(VTEvent::OscData(&input[range])),
390 }
391 .abort()
392 {
393 return i + 1;
394 }
395 }
396 }
397 };
398 }
399
400 let mut held_byte = self.held_byte.take();
401 let mut i = 0;
402
403 while i < input.len() {
404 if self.st == State::Ground {
406 let start = i;
407 loop {
408 if i >= input.len() {
409 cb(VTEvent::Raw(&input[start..]));
410 return input.len();
411 }
412 if ENDS_GROUND[input[i] as usize] {
413 break;
414 }
415 i += 1;
416 }
417
418 if start != i && cb(VTEvent::Raw(&input[start..i])).abort() {
419 return i;
420 }
421
422 if input[i] == ESC {
423 self.clear_hdr_collectors();
424 self.st = State::Escape;
425 i += 1;
426 continue;
427 }
428 }
429
430 if self.st == State::CsiIgnore {
432 loop {
433 if i >= input.len() {
434 return input.len();
435 }
436 if ENDS_CSI[input[i] as usize] {
437 break;
438 }
439 i += 1;
440 }
441
442 if input[i] == ESC {
443 self.st = State::Escape;
444 } else {
445 self.st = State::Ground;
446 }
447 i += 1;
448 continue;
449 }
450
451 let action = self.push_with(input[i]);
452
453 match action {
454 VTAction::None => {
455 if let Some(emit) = state.current_emit {
456 let range = state.buffer_idx..(i - state.hold as usize);
458 if !range.is_empty()
459 && match emit {
460 VTEmit::Ground => cb(VTEvent::Raw(&input[range])),
461 VTEmit::Dcs => cb(VTEvent::DcsData(&input[range])),
462 VTEmit::Osc => cb(VTEvent::OscData(&input[range])),
463 }
464 .abort()
465 {
466 if state.hold {
467 self.held_byte = Some(0x1b);
468 }
469 return i + 1;
470 }
471 if state.hold {
472 held_byte = Some(0x1b);
473 }
474 state.current_emit = None;
475 }
476 }
477 VTAction::Event(e) => {
478 if cb(e).abort() {
479 return i + 1;
480 }
481 }
482 VTAction::End(VTEnd::Dcs) => {
483 held_byte = None;
484 emit!(state, i, cb, true, false);
485 }
486 VTAction::End(VTEnd::Osc { used_bel }) => {
487 held_byte = None;
488 emit!(state, i, cb, true, used_bel);
489 }
490 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
491 if state.current_emit.is_none() {
492 if let Some(h) = held_byte.take() {
493 if match emit {
494 VTEmit::Ground => cb(VTEvent::Raw(&[h])),
495 VTEmit::Dcs => cb(VTEvent::DcsData(&[h])),
496 VTEmit::Osc => cb(VTEvent::OscData(&[h])),
497 }
498 .abort()
499 {
500 if matches!(action, VTAction::Hold(_)) {
501 self.held_byte = Some(0x1b);
502 return 1;
503 }
504 return 0;
505 }
506 }
507 }
508
509 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
510
511 state.hold = matches!(action, VTAction::Hold(_));
512 if state.current_emit.is_none() {
513 state.buffer_idx = i;
514 state.current_emit = Some(emit);
515 }
516 }
517 VTAction::Cancel(emit) => {
518 state.current_emit = None;
519 state.hold = false;
520 if match emit {
521 VTEmit::Ground => unreachable!(),
522 VTEmit::Dcs => cb(VTEvent::DcsCancel),
523 VTEmit::Osc => cb(VTEvent::OscCancel),
524 }
525 .abort()
526 {
527 return i + 1;
528 }
529 }
530 };
531 i += 1;
532 }
533
534 if state.hold {
536 self.held_byte = Some(0x1b);
537 }
538
539 if let Some(emit) = state.current_emit.take() {
540 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
541 if !range.is_empty() {
542 match emit {
543 VTEmit::Ground => cb(VTEvent::Raw(range)),
544 VTEmit::Dcs => cb(VTEvent::DcsData(range)),
545 VTEmit::Osc => cb(VTEvent::OscData(range)),
546 };
547 }
548 };
549
550 input.len()
552 }
553
554 pub fn is_ground(&self) -> bool {
556 self.st == State::Ground
557 }
558
559 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
563 match self.st {
564 State::Escape => {
565 self.st = State::Ground;
566 Some(VTEvent::C0(ESC))
567 }
568 State::EscInt => {
569 self.st = State::Ground;
570 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
571 None
572 } else {
573 Some(invalid!(self.ints))
574 }
575 }
576 State::EscSs2 | State::EscSs3 => {
577 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
578 self.st = State::Ground;
579 None
580 } else {
581 let c = match self.st {
582 State::EscSs2 => SS2,
583 State::EscSs3 => SS3,
584 _ => unreachable!(),
585 };
586 self.st = State::Ground;
587 Some(invalid!(c))
588 }
589 }
590 _ => None,
591 }
592 }
593
594 fn push_with(&mut self, b: u8) -> VTAction {
595 use State::*;
596 match self.st {
597 Ground => self.on_ground(b),
598 Escape => self.on_escape(b),
599 EscInt => self.on_esc_int(b),
600 EscSs2 => self.on_esc_ss2(b),
601 EscSs3 => self.on_esc_ss3(b),
602
603 CsiEntry => self.on_csi_entry(b),
604 CsiParam => self.on_csi_param(b),
605 CsiInt => self.on_csi_int(b),
606 CsiIgnore => self.on_csi_ignore(b),
607
608 DcsEntry => self.on_dcs_entry(b),
609 DcsParam => self.on_dcs_param(b),
610 DcsInt => self.on_dcs_int(b),
611 DcsIgnore => self.on_dcs_ignore(b),
612 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
613 DcsPassthrough => self.on_dcs_pass(b),
614 DcsEsc => self.on_dcs_esc(b),
615
616 OscString => self.on_osc_string(b),
617 OscEsc => self.on_osc_esc(b),
618
619 SosPmApcString => self.on_spa_string(b),
620 SpaEsc => self.on_spa_esc(b),
621 }
622 }
623
624 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
625 self.reset_collectors();
626 self.st = State::Ground;
627
628 }
630
631 fn clear_hdr_collectors(&mut self) {
636 self.ints.clear();
637 self.params.clear();
638 self.cur_param.clear();
639 self.priv_prefix = None;
640 }
641
642 fn reset_collectors(&mut self) {
643 self.clear_hdr_collectors();
644 }
645
646 fn next_param(&mut self) {
647 self.params.push(std::mem::take(&mut self.cur_param));
648 }
649
650 fn finish_params_if_any(&mut self) {
651 if !self.cur_param.is_empty() || !self.params.is_empty() {
652 self.next_param();
653 }
654 }
655
656 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
657 self.finish_params_if_any();
658
659 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
661 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
662
663 let privp = self.priv_prefix.take();
664 VTAction::Event(VTEvent::Csi(CSI {
665 private: privp,
666 params: ParamBuf {
667 params: &self.params,
668 },
669 intermediates: self.ints,
670 final_byte,
671 }))
672 }
673
674 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
675 self.finish_params_if_any();
676
677 let privp = self.priv_prefix.take();
678 VTAction::Event(VTEvent::DcsStart(DCS {
679 private: privp,
680 params: ParamBuf {
681 params: &self.params,
682 },
683 intermediates: self.ints,
684 final_byte,
685 }))
686 }
687
688 fn on_ground(&mut self, b: u8) -> VTAction {
693 match b {
694 ESC => {
695 self.clear_hdr_collectors();
696 self.st = State::Escape;
697 VTAction::None
698 }
699 DEL => VTAction::Event(VTEvent::C0(DEL)),
700 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
701 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
702 _ => VTAction::Buffer(VTEmit::Ground), }
704 }
705
706 fn on_escape(&mut self, b: u8) -> VTAction {
707 use State::*;
708 match b {
709 CAN | SUB => {
710 self.st = Ground;
711 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
712 VTAction::None
713 } else {
714 VTAction::Event(invalid!(b))
715 }
716 }
717 DEL => {
720 self.st = Ground;
721 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
722 VTAction::None
723 } else {
724 VTAction::Event(invalid!(b))
725 }
726 }
727 c if is_intermediate(c) => {
728 if self.ints.push(c) {
729 self.st = EscInt;
730 } else {
731 self.st = Ground;
732 }
733 VTAction::None
734 }
735 CSI => {
736 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
737 self.st = CsiIgnore;
738 } else {
739 self.st = CsiEntry;
740 }
741 VTAction::None
742 }
743 DCS => {
744 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
745 self.st = DcsIgnore;
746 } else {
747 self.st = DcsEntry;
748 }
749 VTAction::None
750 }
751 OSC => {
752 self.st = OscString;
753 VTAction::Event(VTEvent::OscStart)
754 }
755 SS2 => {
756 self.st = EscSs2;
757 VTAction::None
758 }
759 SS3 => {
760 self.st = EscSs3;
761 VTAction::None
762 }
763 SOS | PM | APC => {
764 self.st = State::SosPmApcString;
765 VTAction::None
766 }
767 c if is_final(c) || is_digit(c) => {
768 self.st = Ground;
769 VTAction::Event(VTEvent::Esc(Esc {
770 intermediates: self.ints,
771 final_byte: c,
772 }))
773 }
774 ESC => {
775 VTAction::Event(VTEvent::C0(ESC))
777 }
778 _ => {
779 self.st = Ground;
780 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
781 VTAction::None
782 } else {
783 VTAction::Event(invalid!(b))
784 }
785 }
786 }
787 }
788
789 fn on_esc_int(&mut self, b: u8) -> VTAction {
790 use State::*;
791 match b {
792 CAN | SUB => {
793 self.st = Ground;
794 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
795 VTAction::None
796 } else {
797 VTAction::Event(invalid!(self.ints, b))
798 }
799 }
800 DEL => {
803 self.st = Ground;
804 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
805 VTAction::None
806 } else {
807 VTAction::Event(invalid!(self.ints, b))
808 }
809 }
810 c if is_intermediate(c) => {
811 if !self.ints.push(c) {
812 self.st = Ground;
813 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
814 VTAction::None
815 } else {
816 VTAction::Event(invalid!(self.ints, b))
817 }
818 } else {
819 VTAction::None
820 }
821 }
822 c if is_final(c) || is_digit(c) => {
823 self.st = Ground;
824 VTAction::Event(VTEvent::Esc(Esc {
825 intermediates: self.ints,
826 final_byte: c,
827 }))
828 }
829 ESC => {
832 self.st = Escape;
833 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
834 VTAction::None
835 } else {
836 VTAction::Event(invalid!(self.ints))
837 }
838 }
839 c => {
840 self.st = Ground;
841 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
842 VTAction::None
843 } else {
844 VTAction::Event(invalid!(self.ints, c))
845 }
846 }
847 }
848 }
849
850 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
851 use State::*;
852 self.st = Ground;
853 match b {
854 CAN | SUB => {
855 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
856 VTAction::None
857 } else {
858 VTAction::Event(invalid!(SS2, b))
859 }
860 }
861 ESC => {
864 self.st = Escape;
865 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
866 VTAction::None
867 } else {
868 VTAction::Event(invalid!(SS2))
869 }
870 }
871 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
872 }
873 }
874
875 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
876 use State::*;
877 self.st = Ground;
878 match b {
879 CAN | SUB => {
880 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
881 VTAction::None
882 } else {
883 VTAction::Event(invalid!(SS3, b))
884 }
885 }
886 ESC => {
889 self.st = Escape;
890 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
891 VTAction::None
892 } else {
893 VTAction::Event(invalid!(SS3))
894 }
895 }
896 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
897 }
898 }
899
900 fn on_csi_entry(&mut self, b: u8) -> VTAction {
902 use State::*;
903 match b {
904 CAN | SUB => {
905 self.st = Ground;
906 VTAction::None
907 }
908 DEL => VTAction::None,
909 ESC => {
910 self.st = Escape;
911 VTAction::None
912 }
913 c if is_priv(c) => {
914 self.priv_prefix = Some(c);
915 self.st = CsiParam;
916 VTAction::None
917 }
918 d if is_digit(d) => {
919 self.cur_param.push(d);
920 self.st = CsiParam;
921 VTAction::None
922 }
923 b';' => {
924 self.next_param();
925 self.st = CsiParam;
926 VTAction::None
927 }
928 b':' => {
929 self.cur_param.push(b':');
930 self.st = CsiParam;
931 VTAction::None
932 }
933 c if is_intermediate(c) => {
934 if self.ints.push(c) {
935 self.st = CsiInt;
936 } else {
937 self.st = Ground;
938 }
939 VTAction::None
940 }
941 c if is_final(c) => {
942 self.st = Ground;
943 self.emit_csi(c)
944 }
945 _ => {
946 self.st = CsiIgnore;
947 VTAction::None
948 }
949 }
950 }
951
952 fn on_csi_param(&mut self, b: u8) -> VTAction {
953 use State::*;
954 match b {
955 CAN | SUB => {
956 self.st = Ground;
957 VTAction::None
958 }
959 DEL => VTAction::None,
960 ESC => {
961 self.st = Escape;
962 VTAction::None
963 }
964 d if is_digit(d) => {
965 self.cur_param.push(d);
966 VTAction::None
967 }
968 b';' => {
969 self.next_param();
970 VTAction::None
971 }
972 b':' => {
973 self.cur_param.push(b':');
974 VTAction::None
975 }
976 c if is_intermediate(c) => {
977 if self.ints.push(c) {
978 self.st = CsiInt;
979 } else {
980 self.st = Ground;
981 }
982 VTAction::None
983 }
984 c if is_final(c) => {
985 self.st = Ground;
986 self.emit_csi(c)
987 }
988 _ => {
989 self.st = CsiIgnore;
990 VTAction::None
991 }
992 }
993 }
994
995 fn on_csi_int(&mut self, b: u8) -> VTAction {
996 use State::*;
997 match b {
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_intermediate(c) => {
1008 if self.ints.push(c) {
1009 self.st = CsiInt;
1010 } else {
1011 self.st = Ground;
1012 }
1013 VTAction::None
1014 }
1015 c if is_final(c) => {
1016 self.st = Ground;
1017 self.emit_csi(c)
1018 }
1019 _ => {
1020 self.st = CsiIgnore;
1021 VTAction::None
1022 }
1023 }
1024 }
1025
1026 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1027 use State::*;
1028 match b {
1029 CAN | SUB => {
1030 self.st = Ground;
1031 VTAction::None
1032 }
1033 DEL => VTAction::None,
1034 ESC => {
1035 self.st = Escape;
1036 VTAction::None
1037 }
1038 c if is_final(c) => {
1039 self.st = Ground;
1040 VTAction::None
1041 }
1042 _ => VTAction::None,
1043 }
1044 }
1045
1046 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1048 use State::*;
1049 match b {
1050 CAN | SUB => {
1051 self.st = Ground;
1052 VTAction::None
1053 }
1054 DEL => VTAction::None,
1055 ESC => {
1056 self.st = Escape;
1057 VTAction::None
1058 }
1059 c if is_priv(c) => {
1060 self.priv_prefix = Some(c);
1061 self.st = DcsParam;
1062 VTAction::None
1063 }
1064 d if is_digit(d) => {
1065 self.cur_param.push(d);
1066 self.st = DcsParam;
1067 VTAction::None
1068 }
1069 b';' => {
1070 self.next_param();
1071 self.st = DcsParam;
1072 VTAction::None
1073 }
1074 b':' => {
1075 self.st = DcsIgnore;
1076 VTAction::None
1077 }
1078 c if is_intermediate(c) => {
1079 if self.ints.push(c) {
1080 self.st = DcsInt;
1081 } else {
1082 self.st = Ground;
1083 }
1084 VTAction::None
1085 }
1086 c if is_final(c) => {
1087 self.st = DcsPassthrough;
1088 self.dcs_start(c)
1089 }
1090 _ => {
1091 self.st = DcsIgnore;
1092 VTAction::None
1093 }
1094 }
1095 }
1096
1097 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1098 use State::*;
1099 match b {
1100 CAN | SUB => {
1101 self.st = Ground;
1102 VTAction::None
1103 }
1104 DEL => VTAction::None,
1105 ESC => {
1106 self.st = Escape;
1107 VTAction::None
1108 }
1109 d if is_digit(d) => {
1110 self.cur_param.push(d);
1111 VTAction::None
1112 }
1113 b';' => {
1114 self.next_param();
1115 VTAction::None
1116 }
1117 b':' => {
1118 self.st = DcsIgnore;
1119 VTAction::None
1120 }
1121 c if is_intermediate(c) => {
1122 if self.ints.push(c) {
1123 self.st = DcsInt;
1124 } else {
1125 self.st = Ground;
1126 }
1127 self.st = DcsInt;
1128 VTAction::None
1129 }
1130 c if is_final(c) => {
1131 self.st = DcsPassthrough;
1132 self.dcs_start(c)
1133 }
1134 _ => {
1135 self.st = DcsIgnore;
1136 VTAction::None
1137 }
1138 }
1139 }
1140
1141 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1142 use State::*;
1143 match b {
1144 CAN | SUB => {
1145 self.st = Ground;
1146 VTAction::None
1147 }
1148 DEL => VTAction::None,
1149 ESC => {
1150 self.st = Escape;
1151 VTAction::None
1152 }
1153 c if is_intermediate(c) => {
1154 if self.ints.push(c) {
1155 self.st = DcsInt;
1156 } else {
1157 self.st = Ground;
1158 }
1159 VTAction::None
1160 }
1161 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1162 self.st = DcsPassthrough;
1163 self.dcs_start(c)
1164 }
1165 _ => {
1166 self.st = DcsIgnore;
1167 VTAction::None
1168 }
1169 }
1170 }
1171
1172 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1173 use State::*;
1174 match b {
1175 CAN | SUB => {
1176 self.st = Ground;
1177 VTAction::None
1178 }
1179 DEL => VTAction::None,
1180 ESC => {
1181 self.st = DcsIgnoreEsc;
1182 VTAction::None
1183 }
1184 _ => VTAction::None,
1185 }
1186 }
1187
1188 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1189 use State::*;
1190 match b {
1191 CAN | SUB => {
1192 self.st = Ground;
1193 VTAction::None
1194 }
1195 ST_FINAL => {
1196 self.st = Ground;
1197 VTAction::None
1198 }
1199 DEL => VTAction::None,
1200 ESC => VTAction::None,
1201 _ => {
1202 self.st = DcsIgnore;
1203 VTAction::None
1204 }
1205 }
1206 }
1207
1208 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1209 use State::*;
1210 match b {
1211 CAN | SUB => {
1212 self.st = Ground;
1213 VTAction::Cancel(VTEmit::Dcs)
1214 }
1215 DEL => VTAction::None,
1216 ESC => {
1217 self.st = DcsEsc;
1218 VTAction::Hold(VTEmit::Dcs)
1219 }
1220 _ => VTAction::Buffer(VTEmit::Dcs),
1221 }
1222 }
1223
1224 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1225 use State::*;
1226 match b {
1227 ST_FINAL => {
1228 self.st = Ground;
1229 VTAction::End(VTEnd::Dcs)
1230 }
1231 DEL => VTAction::None,
1232 ESC => {
1233 VTAction::Hold(VTEmit::Dcs)
1235 }
1236 _ => {
1237 self.st = DcsPassthrough;
1239 VTAction::Buffer(VTEmit::Dcs)
1240 }
1241 }
1242 }
1243
1244 fn on_osc_string(&mut self, b: u8) -> VTAction {
1246 use State::*;
1247 match b {
1248 CAN | SUB => {
1249 self.st = Ground;
1250 VTAction::Cancel(VTEmit::Osc)
1251 }
1252 DEL => VTAction::None,
1253 BEL => {
1254 self.st = Ground;
1255 VTAction::End(VTEnd::Osc { used_bel: true })
1256 }
1257 ESC => {
1258 self.st = OscEsc;
1259 VTAction::Hold(VTEmit::Osc)
1260 }
1261 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1262 _ => VTAction::None, }
1264 }
1265
1266 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1267 use State::*;
1268 match b {
1269 ST_FINAL => {
1270 self.st = Ground;
1271 VTAction::End(VTEnd::Osc { used_bel: false })
1272 } ESC => VTAction::Hold(VTEmit::Osc),
1274 DEL => VTAction::None,
1275 _ => {
1276 self.st = OscString;
1277 VTAction::Buffer(VTEmit::Osc)
1278 }
1279 }
1280 }
1281
1282 fn on_spa_string(&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 = SpaEsc;
1293 VTAction::None
1294 }
1295 _ => VTAction::None,
1296 }
1297 }
1298
1299 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1300 use State::*;
1301 match b {
1302 ST_FINAL => {
1303 self.st = Ground;
1304 VTAction::None
1305 }
1306 DEL => VTAction::None,
1307 ESC => {
1308 VTAction::None
1310 }
1311 _ => {
1312 self.st = State::SosPmApcString;
1313 VTAction::None
1314 }
1315 }
1316 }
1317}
1318
1319#[cfg(test)]
1320mod tests {
1321 use super::*;
1322 use pretty_assertions::assert_eq;
1323
1324 #[test]
1325 fn test_edge_cases() {
1326 let mut result = String::new();
1328 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1329 assert_eq!(result.trim(), "");
1330
1331 let mut result = String::new();
1333 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1334 assert_eq!(result.trim(), "");
1335
1336 let mut result = String::new();
1338 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1339 assert_eq!(result.trim(), "");
1340
1341 let mut result = String::new();
1343 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1344 assert_eq!(result.trim(), "");
1345
1346 let mut result = String::new();
1348 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1349 assert_eq!(result.trim(), "OscStart");
1350 }
1351
1352 #[test]
1353 fn test_streaming_behavior() {
1354 let mut parser = VTPushParser::new(); let mut result = String::new();
1357 let mut callback = |vt_input: VTEvent<'_>| {
1358 result.push_str(&format!("{vt_input:?}\n"));
1359 };
1360
1361 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1363 parser.feed_with(b"data", &mut callback);
1364 parser.feed_with(b" more", &mut callback);
1365 parser.feed_with(b"\x1b\\", &mut callback);
1366
1367 assert_eq!(
1368 result.trim(),
1369 "DcsStart(, '1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1370 );
1371 }
1372
1373 #[test]
1374 fn test_finish_method() {
1375 let mut parser = VTPushParser::new();
1376 let mut result = String::new();
1377 let mut callback = |vt_input: VTEvent<'_>| {
1378 result.push_str(&format!("{vt_input:?}\n"));
1379 };
1380
1381 parser.feed_with(b"\x1b[1;2;3", &mut callback);
1383
1384 parser.finish(&mut callback);
1386
1387 assert_eq!(result.trim(), "");
1388 }
1389
1390 fn collect_events(input: &[u8]) -> Vec<String> {
1470 let mut out = Vec::new();
1471 let mut p = VTPushParser::new();
1472 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1473 out
1474 }
1475
1476 #[test]
1477 fn dcs_esc_esc_del() {
1478 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1480 eprintln!("{ev:?}");
1482 }
1483
1484 #[test]
1485 fn dcs_header_with_colon_is_ignored_case1() {
1486 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1488 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1490 }
1491
1492 #[test]
1493 fn dcs_header_with_colon_is_ignored_case2() {
1494 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1496 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1497 }
1498
1499 #[test]
1500 fn dcs_header_with_colon_is_ignored_case3() {
1501 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1503 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1504 }
1505
1506 #[test]
1507 fn osc_aborted_by_can_mid_body() {
1508 let mut s = Vec::new();
1510 s.extend_from_slice(b"\x1b]0;Title");
1511 s.push(CAN);
1512 s.extend_from_slice(b"more\x07");
1513
1514 let ev = collect_debug(&s);
1515
1516 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1521 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1522 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1523 }
1524
1525 #[test]
1526 fn osc_aborted_by_sub_before_terminator() {
1527 let mut s = Vec::new();
1528 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1529 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1533 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1537 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1538 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1539 }
1540
1541 fn collect_debug(input: &[u8]) -> Vec<String> {
1543 let mut out = Vec::new();
1544 let mut p = VTPushParser::new();
1545 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1546 out
1547 }
1548
1549 #[test]
1550 fn dcs_aborted_by_can_before_body() {
1551 let mut s = Vec::new();
1553 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1555 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1558
1559 assert_eq!(ev.len(), 4, "{ev:#?}");
1560 assert_eq!(ev[0], "DcsStart(, '', q)");
1561 assert_eq!(ev[1], "DcsCancel");
1562 assert_eq!(ev[2], "Raw('IGNORED')");
1563 assert_eq!(ev[3], "Esc('', \\)");
1564 }
1565
1566 #[test]
1567 fn dcs_aborted_by_can_mid_body() {
1568 let mut s = Vec::new();
1570 s.extend_from_slice(b"\x1bPqABC");
1571 s.push(CAN);
1572 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1575
1576 assert_eq!(ev.len(), 4, "{ev:#?}");
1577 assert_eq!(ev[0], "DcsStart(, '', q)");
1578 assert_eq!(ev[1], "DcsCancel");
1579 assert_eq!(ev[2], "Raw('MORE')");
1580 assert_eq!(ev[3], "Esc('', \\)");
1581 }
1582
1583 #[test]
1586 fn spa_aborted_by_can_is_ignored() {
1587 let mut s = Vec::new();
1589 s.extend_from_slice(b"\x1b_hello");
1590 s.push(CAN);
1591 s.extend_from_slice(b"world\x1b\\");
1592
1593 let ev = collect_debug(&s);
1594 assert_eq!(ev.len(), 2, "{ev:#?}");
1595 assert_eq!(ev[0], "Raw('world')");
1596 assert_eq!(ev[1], "Esc('', \\)");
1597 }
1598
1599 #[test]
1600 fn spa_sub_aborts_too() {
1601 let mut s = Vec::new();
1602 s.extend_from_slice(b"\x1bXhello");
1603 s.push(SUB);
1604 s.extend_from_slice(b"world\x1b\\");
1605 let ev = collect_debug(&s);
1606 assert_eq!(ev.len(), 2, "{ev:#?}");
1607 assert_eq!(ev[0], "Raw('world')");
1608 assert_eq!(ev[1], "Esc('', \\)");
1609 }
1610
1611 #[test]
1614 fn can_in_ground_is_c0() {
1615 let mut s = Vec::new();
1616 s.extend_from_slice(b"abc");
1617 s.push(CAN);
1618 s.extend_from_slice(b"def");
1619 let ev = collect_debug(&s);
1620 assert_eq!(ev.len(), 3, "{ev:#?}");
1622 assert_eq!(ev[0], "Raw('abc')");
1623 assert_eq!(ev[1], "C0(18)");
1624 assert_eq!(ev[2], "Raw('def')");
1625 }
1626
1627 #[test]
1630 fn three_byte_sequences_capturable() {
1631 let mut bytes = vec![];
1632 for i in 0..=0xFFFFFF_u32 {
1633 bytes.clear();
1634 let test_bytes = i.to_le_bytes();
1635 let test_bytes = &test_bytes[..3];
1636 if test_bytes.iter().any(|b| b == &0) {
1637 continue;
1638 }
1639 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1640 continue;
1641 }
1642 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1643 continue;
1644 }
1645
1646 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1647 parser.feed_with(test_bytes, &mut |event| {
1648 let mut chunk = [0_u8; 3];
1649 let b = event.encode(&mut chunk).unwrap();
1650 bytes.extend_from_slice(&chunk[..b]);
1651 });
1652 if let Some(event) = parser.idle() {
1653 let mut chunk = [0_u8; 3];
1654 let b = event.encode(&mut chunk).unwrap();
1655 bytes.extend_from_slice(&chunk[..b]);
1656 }
1657
1658 if bytes.len() != 3 || bytes != test_bytes {
1659 eprintln!("Failed to parse:");
1660 parser.feed_with(test_bytes, &mut |event| {
1661 eprintln!("{event:?}");
1662 });
1663 if let Some(event) = parser.idle() {
1664 eprintln!("{event:?}");
1665 }
1666 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1667 }
1668 }
1669 }
1670}