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'0'..=b'9').contains(&b)
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 VTPushParser {
235 pub const fn new() -> Self {
236 VTPushParser::new_with()
237 }
238
239 pub fn decode_buffer<'a>(input: &'a [u8], mut cb: impl for<'b> FnMut(VTEvent<'b>)) {
241 let mut parser = VTPushParser::new();
242 parser.feed_with(input, &mut cb);
243 parser.finish(&mut cb);
244 }
245
246 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
247 VTPushParser::new_with()
248 }
249}
250
251macro_rules! invalid {
253 ($self:ident .ints, $b:expr) => {
254 if $self.ints.len() == 1 {
255 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
256 } else {
257 VTEvent::EscInvalid(EscInvalid::Three(
258 $self.ints.data[0],
259 $self.ints.data[1],
260 $b,
261 ))
262 }
263 };
264 ($self:ident .ints) => {
265 if $self.ints.len() == 1 {
266 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
267 } else {
268 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
269 }
270 };
271 ($a:expr) => {
272 VTEvent::EscInvalid(EscInvalid::One($a))
273 };
274 ($a:expr, $b:expr) => {
275 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
276 };
277}
278
279impl<const INTEREST: u8> VTPushParser<INTEREST> {
280 const fn new_with() -> Self {
281 Self {
282 st: State::Ground,
283 ints: VTIntermediate::empty(),
284 params: SmallVec::new_const(),
285 cur_param: SmallVec::new_const(),
286 priv_prefix: None,
287 held_byte: None,
288 }
289 }
290
291 #[inline]
303 pub fn feed_with<'this, 'input, F: for<'any> FnMut(VTEvent<'any>)>(
304 &'this mut self,
305 input: &'input [u8],
306 cb: &mut F,
307 ) {
308 self.feed_with_internal(input, cb);
309 }
310
311 #[inline]
324 pub fn feed_with_abortable<'this, 'input, F: for<'any> FnMut(VTEvent<'any>) -> bool>(
325 &'this mut self,
326 input: &'input [u8],
327 cb: &mut F,
328 ) -> usize {
329 self.feed_with_internal(input, cb)
330 }
331
332 #[inline(always)]
333 fn feed_with_internal<
334 'this,
335 'input,
336 R: MaybeAbortable,
337 F: for<'any> FnMut(VTEvent<'any>) -> R,
338 >(
339 &'this mut self,
340 input: &'input [u8],
341 cb: &mut F,
342 ) -> usize {
343 if input.is_empty() {
344 return 0;
345 }
346
347 #[derive(Debug)]
348 struct FeedState {
349 buffer_idx: usize,
350 current_emit: Option<VTEmit>,
351 hold: bool,
352 }
353
354 let mut state = FeedState {
355 buffer_idx: 0,
356 current_emit: None,
357 hold: self.held_byte.is_some(),
358 };
359
360 macro_rules! emit {
361 ($state:ident, $i:expr, $cb:expr, $end:expr, $used_bel:expr) => {
362 let hold = std::mem::take(&mut $state.hold);
363 if let Some(emit) = $state.current_emit.take() {
364 let i = $i;
365 let range = $state.buffer_idx..(i - hold as usize);
366 if $end {
367 if match emit {
368 VTEmit::Ground => unreachable!(),
369 VTEmit::Dcs => $cb(VTEvent::DcsEnd(&input[range])),
370 VTEmit::Osc => $cb(VTEvent::OscEnd {
371 data: &input[range],
372 used_bel: $used_bel,
373 }),
374 }
375 .abort()
376 {
377 return i + 1;
378 }
379 } else if range.len() > 0 {
380 if match emit {
381 VTEmit::Ground => $cb(VTEvent::Raw(&input[range])),
382 VTEmit::Dcs => $cb(VTEvent::DcsData(&input[range])),
383 VTEmit::Osc => $cb(VTEvent::OscData(&input[range])),
384 }
385 .abort()
386 {
387 return i + 1;
388 }
389 }
390 }
391 };
392 }
393
394 let mut held_byte = self.held_byte.take();
395 let mut i = 0;
396
397 while i < input.len() {
398 if self.st == State::Ground {
400 let start = i;
401 loop {
402 if i >= input.len() {
403 cb(VTEvent::Raw(&input[start..]));
404 return input.len();
405 }
406 if ENDS_GROUND[input[i] as usize] {
407 break;
408 }
409 i += 1;
410 }
411
412 if start != i {
413 if cb(VTEvent::Raw(&input[start..i])).abort() {
414 return i;
415 }
416 }
417
418 if input[i] == ESC {
419 self.clear_hdr_collectors();
420 self.st = State::Escape;
421 i = i + 1;
422 continue;
423 }
424 }
425
426 if self.st == State::CsiIgnore {
428 loop {
429 if i >= input.len() {
430 return input.len();
431 }
432 if ENDS_CSI[input[i] as usize] {
433 break;
434 }
435 i += 1;
436 }
437
438 if input[i] == ESC {
439 self.st = State::Escape;
440 } else {
441 self.st = State::Ground;
442 }
443 i += 1;
444 continue;
445 }
446
447 let action = self.push_with(input[i]);
448
449 match action {
450 VTAction::None => {
451 if let Some(emit) = state.current_emit {
452 let range = state.buffer_idx..(i - state.hold as usize);
454 if !range.is_empty() {
455 if match emit {
456 VTEmit::Ground => cb(VTEvent::Raw(&input[range])),
457 VTEmit::Dcs => cb(VTEvent::DcsData(&input[range])),
458 VTEmit::Osc => cb(VTEvent::OscData(&input[range])),
459 }
460 .abort()
461 {
462 if state.hold {
463 self.held_byte = Some(0x1b);
464 }
465 return i + 1;
466 }
467 }
468 if state.hold {
469 held_byte = Some(0x1b);
470 }
471 state.current_emit = None;
472 }
473 }
474 VTAction::Event(e) => {
475 if cb(e).abort() {
476 return i + 1;
477 }
478 }
479 VTAction::End(VTEnd::Dcs) => {
480 held_byte = None;
481 emit!(state, i, cb, true, false);
482 }
483 VTAction::End(VTEnd::Osc { used_bel }) => {
484 held_byte = None;
485 emit!(state, i, cb, true, used_bel);
486 }
487 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
488 if state.current_emit.is_none() {
489 if let Some(h) = held_byte.take() {
490 if match emit {
491 VTEmit::Ground => cb(VTEvent::Raw(&[h])),
492 VTEmit::Dcs => cb(VTEvent::DcsData(&[h])),
493 VTEmit::Osc => cb(VTEvent::OscData(&[h])),
494 }
495 .abort()
496 {
497 if matches!(action, VTAction::Hold(_)) {
498 self.held_byte = Some(0x1b);
499 return 1;
500 }
501 return 0;
502 }
503 }
504 }
505
506 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
507
508 state.hold = matches!(action, VTAction::Hold(_));
509 if state.current_emit.is_none() {
510 state.buffer_idx = i;
511 state.current_emit = Some(emit);
512 }
513 }
514 VTAction::Cancel(emit) => {
515 state.current_emit = None;
516 state.hold = false;
517 if match emit {
518 VTEmit::Ground => unreachable!(),
519 VTEmit::Dcs => cb(VTEvent::DcsCancel),
520 VTEmit::Osc => cb(VTEvent::OscCancel),
521 }
522 .abort()
523 {
524 return i + 1;
525 }
526 }
527 };
528 i += 1;
529 }
530
531 if state.hold {
533 self.held_byte = Some(0x1b);
534 }
535
536 if let Some(emit) = state.current_emit.take() {
537 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
538 if !range.is_empty() {
539 match emit {
540 VTEmit::Ground => cb(VTEvent::Raw(range)),
541 VTEmit::Dcs => cb(VTEvent::DcsData(range)),
542 VTEmit::Osc => cb(VTEvent::OscData(range)),
543 };
544 }
545 };
546
547 input.len()
549 }
550
551 pub fn is_ground(&self) -> bool {
553 self.st == State::Ground
554 }
555
556 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
560 match self.st {
561 State::Escape => {
562 self.st = State::Ground;
563 Some(VTEvent::C0(ESC))
564 }
565 State::EscInt => {
566 self.st = State::Ground;
567 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
568 None
569 } else {
570 Some(invalid!(self.ints))
571 }
572 }
573 State::EscSs2 | State::EscSs3 => {
574 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
575 self.st = State::Ground;
576 None
577 } else {
578 let c = match self.st {
579 State::EscSs2 => SS2,
580 State::EscSs3 => SS3,
581 _ => unreachable!(),
582 };
583 self.st = State::Ground;
584 Some(invalid!(c))
585 }
586 }
587 _ => None,
588 }
589 }
590
591 fn push_with(&mut self, b: u8) -> VTAction {
592 use State::*;
593 match self.st {
594 Ground => self.on_ground(b),
595 Escape => self.on_escape(b),
596 EscInt => self.on_esc_int(b),
597 EscSs2 => self.on_esc_ss2(b),
598 EscSs3 => self.on_esc_ss3(b),
599
600 CsiEntry => self.on_csi_entry(b),
601 CsiParam => self.on_csi_param(b),
602 CsiInt => self.on_csi_int(b),
603 CsiIgnore => self.on_csi_ignore(b),
604
605 DcsEntry => self.on_dcs_entry(b),
606 DcsParam => self.on_dcs_param(b),
607 DcsInt => self.on_dcs_int(b),
608 DcsIgnore => self.on_dcs_ignore(b),
609 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
610 DcsPassthrough => self.on_dcs_pass(b),
611 DcsEsc => self.on_dcs_esc(b),
612
613 OscString => self.on_osc_string(b),
614 OscEsc => self.on_osc_esc(b),
615
616 SosPmApcString => self.on_spa_string(b),
617 SpaEsc => self.on_spa_esc(b),
618 }
619 }
620
621 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
622 self.reset_collectors();
623 self.st = State::Ground;
624
625 }
627
628 fn clear_hdr_collectors(&mut self) {
633 self.ints.clear();
634 self.params.clear();
635 self.cur_param.clear();
636 self.priv_prefix = None;
637 }
638
639 fn reset_collectors(&mut self) {
640 self.clear_hdr_collectors();
641 }
642
643 fn next_param(&mut self) {
644 self.params.push(std::mem::take(&mut self.cur_param));
645 }
646
647 fn finish_params_if_any(&mut self) {
648 if !self.cur_param.is_empty() || !self.params.is_empty() {
649 self.next_param();
650 }
651 }
652
653 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
654 self.finish_params_if_any();
655
656 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
658 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
659
660 let privp = self.priv_prefix.take();
661 VTAction::Event(VTEvent::Csi(CSI {
662 private: privp,
663 params: ParamBuf {
664 params: &self.params,
665 },
666 intermediates: self.ints,
667 final_byte,
668 }))
669 }
670
671 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
672 self.finish_params_if_any();
673
674 let privp = self.priv_prefix.take();
675 VTAction::Event(VTEvent::DcsStart(DCS {
676 private: privp,
677 params: ParamBuf {
678 params: &self.params,
679 },
680 intermediates: self.ints,
681 final_byte,
682 }))
683 }
684
685 fn on_ground(&mut self, b: u8) -> VTAction {
690 match b {
691 ESC => {
692 self.clear_hdr_collectors();
693 self.st = State::Escape;
694 VTAction::None
695 }
696 DEL => VTAction::Event(VTEvent::C0(DEL)),
697 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
698 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
699 _ => VTAction::Buffer(VTEmit::Ground), }
701 }
702
703 fn on_escape(&mut self, b: u8) -> VTAction {
704 use State::*;
705 match b {
706 CAN | SUB => {
707 self.st = Ground;
708 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
709 VTAction::None
710 } else {
711 VTAction::Event(invalid!(b))
712 }
713 }
714 DEL => {
717 self.st = Ground;
718 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
719 VTAction::None
720 } else {
721 VTAction::Event(invalid!(b))
722 }
723 }
724 c if is_intermediate(c) => {
725 if self.ints.push(c) {
726 self.st = EscInt;
727 } else {
728 self.st = Ground;
729 }
730 VTAction::None
731 }
732 CSI => {
733 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
734 self.st = CsiIgnore;
735 } else {
736 self.st = CsiEntry;
737 }
738 VTAction::None
739 }
740 DCS => {
741 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
742 self.st = DcsIgnore;
743 } else {
744 self.st = DcsEntry;
745 }
746 VTAction::None
747 }
748 OSC => {
749 self.st = OscString;
750 VTAction::Event(VTEvent::OscStart)
751 }
752 SS2 => {
753 self.st = EscSs2;
754 VTAction::None
755 }
756 SS3 => {
757 self.st = EscSs3;
758 VTAction::None
759 }
760 SOS | PM | APC => {
761 self.st = State::SosPmApcString;
762 VTAction::None
763 }
764 c if is_final(c) || is_digit(c) => {
765 self.st = Ground;
766 VTAction::Event(VTEvent::Esc(Esc {
767 intermediates: self.ints,
768 final_byte: c,
769 }))
770 }
771 ESC => {
772 VTAction::Event(VTEvent::C0(ESC))
774 }
775 _ => {
776 self.st = Ground;
777 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
778 VTAction::None
779 } else {
780 VTAction::Event(invalid!(b))
781 }
782 }
783 }
784 }
785
786 fn on_esc_int(&mut self, b: u8) -> VTAction {
787 use State::*;
788 match b {
789 CAN | SUB => {
790 self.st = Ground;
791 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
792 VTAction::None
793 } else {
794 VTAction::Event(invalid!(self.ints, b))
795 }
796 }
797 DEL => {
800 self.st = Ground;
801 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
802 VTAction::None
803 } else {
804 VTAction::Event(invalid!(self.ints, b))
805 }
806 }
807 c if is_intermediate(c) => {
808 if !self.ints.push(c) {
809 self.st = Ground;
810 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
811 VTAction::None
812 } else {
813 VTAction::Event(invalid!(self.ints, b))
814 }
815 } else {
816 VTAction::None
817 }
818 }
819 c if is_final(c) || is_digit(c) => {
820 self.st = Ground;
821 VTAction::Event(VTEvent::Esc(Esc {
822 intermediates: self.ints,
823 final_byte: c,
824 }))
825 }
826 ESC => {
829 self.st = Escape;
830 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
831 VTAction::None
832 } else {
833 VTAction::Event(invalid!(self.ints))
834 }
835 }
836 c => {
837 self.st = Ground;
838 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
839 VTAction::None
840 } else {
841 VTAction::Event(invalid!(self.ints, c))
842 }
843 }
844 }
845 }
846
847 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
848 use State::*;
849 self.st = Ground;
850 match b {
851 CAN | SUB => {
852 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
853 VTAction::None
854 } else {
855 VTAction::Event(invalid!(SS2, b))
856 }
857 }
858 ESC => {
861 self.st = Escape;
862 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
863 VTAction::None
864 } else {
865 VTAction::Event(invalid!(SS2))
866 }
867 }
868 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
869 }
870 }
871
872 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
873 use State::*;
874 self.st = Ground;
875 match b {
876 CAN | SUB => {
877 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
878 VTAction::None
879 } else {
880 VTAction::Event(invalid!(SS3, b))
881 }
882 }
883 ESC => {
886 self.st = Escape;
887 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
888 VTAction::None
889 } else {
890 VTAction::Event(invalid!(SS3))
891 }
892 }
893 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
894 }
895 }
896
897 fn on_csi_entry(&mut self, b: u8) -> VTAction {
899 use State::*;
900 match b {
901 CAN | SUB => {
902 self.st = Ground;
903 VTAction::None
904 }
905 DEL => VTAction::None,
906 ESC => {
907 self.st = Escape;
908 VTAction::None
909 }
910 c if is_priv(c) => {
911 self.priv_prefix = Some(c);
912 self.st = CsiParam;
913 VTAction::None
914 }
915 d if is_digit(d) => {
916 self.cur_param.push(d);
917 self.st = CsiParam;
918 VTAction::None
919 }
920 b';' => {
921 self.next_param();
922 self.st = CsiParam;
923 VTAction::None
924 }
925 b':' => {
926 self.cur_param.push(b':');
927 self.st = CsiParam;
928 VTAction::None
929 }
930 c if is_intermediate(c) => {
931 if self.ints.push(c) {
932 self.st = CsiInt;
933 } else {
934 self.st = Ground;
935 }
936 VTAction::None
937 }
938 c if is_final(c) => {
939 self.st = Ground;
940 self.emit_csi(c)
941 }
942 _ => {
943 self.st = CsiIgnore;
944 VTAction::None
945 }
946 }
947 }
948
949 fn on_csi_param(&mut self, b: u8) -> VTAction {
950 use State::*;
951 match b {
952 CAN | SUB => {
953 self.st = Ground;
954 VTAction::None
955 }
956 DEL => VTAction::None,
957 ESC => {
958 self.st = Escape;
959 VTAction::None
960 }
961 d if is_digit(d) => {
962 self.cur_param.push(d);
963 VTAction::None
964 }
965 b';' => {
966 self.next_param();
967 VTAction::None
968 }
969 b':' => {
970 self.cur_param.push(b':');
971 VTAction::None
972 }
973 c if is_intermediate(c) => {
974 if self.ints.push(c) {
975 self.st = CsiInt;
976 } else {
977 self.st = Ground;
978 }
979 VTAction::None
980 }
981 c if is_final(c) => {
982 self.st = Ground;
983 self.emit_csi(c)
984 }
985 _ => {
986 self.st = CsiIgnore;
987 VTAction::None
988 }
989 }
990 }
991
992 fn on_csi_int(&mut self, b: u8) -> VTAction {
993 use State::*;
994 match b {
995 CAN | SUB => {
996 self.st = Ground;
997 VTAction::None
998 }
999 DEL => VTAction::None,
1000 ESC => {
1001 self.st = Escape;
1002 VTAction::None
1003 }
1004 c if is_intermediate(c) => {
1005 if self.ints.push(c) {
1006 self.st = CsiInt;
1007 } else {
1008 self.st = Ground;
1009 }
1010 VTAction::None
1011 }
1012 c if is_final(c) => {
1013 self.st = Ground;
1014 self.emit_csi(c)
1015 }
1016 _ => {
1017 self.st = CsiIgnore;
1018 VTAction::None
1019 }
1020 }
1021 }
1022
1023 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1024 use State::*;
1025 match b {
1026 CAN | SUB => {
1027 self.st = Ground;
1028 VTAction::None
1029 }
1030 DEL => VTAction::None,
1031 ESC => {
1032 self.st = Escape;
1033 VTAction::None
1034 }
1035 c if is_final(c) => {
1036 self.st = Ground;
1037 VTAction::None
1038 }
1039 _ => VTAction::None,
1040 }
1041 }
1042
1043 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1045 use State::*;
1046 match b {
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_priv(c) => {
1057 self.priv_prefix = Some(c);
1058 self.st = DcsParam;
1059 VTAction::None
1060 }
1061 d if is_digit(d) => {
1062 self.cur_param.push(d);
1063 self.st = DcsParam;
1064 VTAction::None
1065 }
1066 b';' => {
1067 self.next_param();
1068 self.st = DcsParam;
1069 VTAction::None
1070 }
1071 b':' => {
1072 self.st = DcsIgnore;
1073 VTAction::None
1074 }
1075 c if is_intermediate(c) => {
1076 if self.ints.push(c) {
1077 self.st = DcsInt;
1078 } else {
1079 self.st = Ground;
1080 }
1081 VTAction::None
1082 }
1083 c if is_final(c) => {
1084 self.st = DcsPassthrough;
1085 self.dcs_start(c)
1086 }
1087 _ => {
1088 self.st = DcsIgnore;
1089 VTAction::None
1090 }
1091 }
1092 }
1093
1094 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1095 use State::*;
1096 match b {
1097 CAN | SUB => {
1098 self.st = Ground;
1099 VTAction::None
1100 }
1101 DEL => VTAction::None,
1102 ESC => {
1103 self.st = Escape;
1104 VTAction::None
1105 }
1106 d if is_digit(d) => {
1107 self.cur_param.push(d);
1108 VTAction::None
1109 }
1110 b';' => {
1111 self.next_param();
1112 VTAction::None
1113 }
1114 b':' => {
1115 self.st = DcsIgnore;
1116 VTAction::None
1117 }
1118 c if is_intermediate(c) => {
1119 if self.ints.push(c) {
1120 self.st = DcsInt;
1121 } else {
1122 self.st = Ground;
1123 }
1124 self.st = DcsInt;
1125 VTAction::None
1126 }
1127 c if is_final(c) => {
1128 self.st = DcsPassthrough;
1129 self.dcs_start(c)
1130 }
1131 _ => {
1132 self.st = DcsIgnore;
1133 VTAction::None
1134 }
1135 }
1136 }
1137
1138 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1139 use State::*;
1140 match b {
1141 CAN | SUB => {
1142 self.st = Ground;
1143 VTAction::None
1144 }
1145 DEL => VTAction::None,
1146 ESC => {
1147 self.st = Escape;
1148 VTAction::None
1149 }
1150 c if is_intermediate(c) => {
1151 if self.ints.push(c) {
1152 self.st = DcsInt;
1153 } else {
1154 self.st = Ground;
1155 }
1156 VTAction::None
1157 }
1158 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1159 self.st = DcsPassthrough;
1160 self.dcs_start(c)
1161 }
1162 _ => {
1163 self.st = DcsIgnore;
1164 VTAction::None
1165 }
1166 }
1167 }
1168
1169 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1170 use State::*;
1171 match b {
1172 CAN | SUB => {
1173 self.st = Ground;
1174 VTAction::None
1175 }
1176 DEL => VTAction::None,
1177 ESC => {
1178 self.st = DcsIgnoreEsc;
1179 VTAction::None
1180 }
1181 _ => VTAction::None,
1182 }
1183 }
1184
1185 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1186 use State::*;
1187 match b {
1188 CAN | SUB => {
1189 self.st = Ground;
1190 VTAction::None
1191 }
1192 ST_FINAL => {
1193 self.st = Ground;
1194 VTAction::None
1195 }
1196 DEL => VTAction::None,
1197 ESC => VTAction::None,
1198 _ => {
1199 self.st = DcsIgnore;
1200 VTAction::None
1201 }
1202 }
1203 }
1204
1205 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1206 use State::*;
1207 match b {
1208 CAN | SUB => {
1209 self.st = Ground;
1210 VTAction::Cancel(VTEmit::Dcs)
1211 }
1212 DEL => VTAction::None,
1213 ESC => {
1214 self.st = DcsEsc;
1215 VTAction::Hold(VTEmit::Dcs)
1216 }
1217 _ => VTAction::Buffer(VTEmit::Dcs),
1218 }
1219 }
1220
1221 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1222 use State::*;
1223 match b {
1224 ST_FINAL => {
1225 self.st = Ground;
1226 VTAction::End(VTEnd::Dcs)
1227 }
1228 DEL => VTAction::None,
1229 ESC => {
1230 VTAction::Hold(VTEmit::Dcs)
1232 }
1233 _ => {
1234 self.st = DcsPassthrough;
1236 VTAction::Buffer(VTEmit::Dcs)
1237 }
1238 }
1239 }
1240
1241 fn on_osc_string(&mut self, b: u8) -> VTAction {
1243 use State::*;
1244 match b {
1245 CAN | SUB => {
1246 self.st = Ground;
1247 VTAction::Cancel(VTEmit::Osc)
1248 }
1249 DEL => VTAction::None,
1250 BEL => {
1251 self.st = Ground;
1252 VTAction::End(VTEnd::Osc { used_bel: true })
1253 }
1254 ESC => {
1255 self.st = OscEsc;
1256 VTAction::Hold(VTEmit::Osc)
1257 }
1258 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1259 _ => VTAction::None, }
1261 }
1262
1263 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1264 use State::*;
1265 match b {
1266 ST_FINAL => {
1267 self.st = Ground;
1268 VTAction::End(VTEnd::Osc { used_bel: false })
1269 } ESC => VTAction::Hold(VTEmit::Osc),
1271 DEL => VTAction::None,
1272 _ => {
1273 self.st = OscString;
1274 VTAction::Buffer(VTEmit::Osc)
1275 }
1276 }
1277 }
1278
1279 fn on_spa_string(&mut self, b: u8) -> VTAction {
1281 use State::*;
1282 match b {
1283 CAN | SUB => {
1284 self.st = Ground;
1285 VTAction::None
1286 }
1287 DEL => VTAction::None,
1288 ESC => {
1289 self.st = SpaEsc;
1290 VTAction::None
1291 }
1292 _ => VTAction::None,
1293 }
1294 }
1295
1296 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1297 use State::*;
1298 match b {
1299 ST_FINAL => {
1300 self.st = Ground;
1301 VTAction::None
1302 }
1303 DEL => VTAction::None,
1304 ESC => {
1305 VTAction::None
1307 }
1308 _ => {
1309 self.st = State::SosPmApcString;
1310 VTAction::None
1311 }
1312 }
1313 }
1314}
1315
1316#[cfg(test)]
1317mod tests {
1318 use super::*;
1319 use pretty_assertions::assert_eq;
1320
1321 #[test]
1322 fn test_edge_cases() {
1323 let mut result = String::new();
1325 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{:?}\n", e)));
1326 assert_eq!(result.trim(), "");
1327
1328 let mut result = String::new();
1330 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{:?}\n", e)));
1331 assert_eq!(result.trim(), "");
1332
1333 let mut result = String::new();
1335 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{:?}\n", e)));
1336 assert_eq!(result.trim(), "");
1337
1338 let mut result = String::new();
1340 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{:?}\n", e)));
1341 assert_eq!(result.trim(), "");
1342
1343 let mut result = String::new();
1345 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{:?}\n", e)));
1346 assert_eq!(result.trim(), "OscStart");
1347 }
1348
1349 #[test]
1350 fn test_streaming_behavior() {
1351 let mut parser = VTPushParser::new(); let mut result = String::new();
1354 let mut callback = |vt_input: VTEvent<'_>| {
1355 result.push_str(&format!("{:?}\n", vt_input));
1356 };
1357
1358 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1360 parser.feed_with(b"data", &mut callback);
1361 parser.feed_with(b" more", &mut callback);
1362 parser.feed_with(b"\x1b\\", &mut callback);
1363
1364 assert_eq!(
1365 result.trim(),
1366 "DcsStart(, '1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1367 );
1368 }
1369
1370 #[test]
1371 fn test_finish_method() {
1372 let mut parser = VTPushParser::new();
1373 let mut result = String::new();
1374 let mut callback = |vt_input: VTEvent<'_>| {
1375 result.push_str(&format!("{:?}\n", vt_input));
1376 };
1377
1378 parser.feed_with(b"\x1b[1;2;3", &mut callback);
1380
1381 parser.finish(&mut callback);
1383
1384 assert_eq!(result.trim(), "");
1385 }
1386
1387 fn collect_events(input: &[u8]) -> Vec<String> {
1467 let mut out = Vec::new();
1468 let mut p = VTPushParser::new();
1469 p.feed_with(input, &mut |ev| out.push(format!("{:?}", ev)));
1470 out
1471 }
1472
1473 #[test]
1474 fn dcs_esc_esc_del() {
1475 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1477 eprintln!("{ev:?}");
1479 }
1480
1481 #[test]
1482 fn dcs_header_with_colon_is_ignored_case1() {
1483 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1485 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1487 }
1488
1489 #[test]
1490 fn dcs_header_with_colon_is_ignored_case2() {
1491 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1493 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1494 }
1495
1496 #[test]
1497 fn dcs_header_with_colon_is_ignored_case3() {
1498 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1500 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1501 }
1502
1503 #[test]
1504 fn osc_aborted_by_can_mid_body() {
1505 let mut s = Vec::new();
1507 s.extend_from_slice(b"\x1b]0;Title");
1508 s.push(CAN);
1509 s.extend_from_slice(b"more\x07");
1510
1511 let ev = collect_debug(&s);
1512
1513 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1518 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1519 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1520 }
1521
1522 #[test]
1523 fn osc_aborted_by_sub_before_terminator() {
1524 let mut s = Vec::new();
1525 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1526 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1530 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1534 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1535 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1536 }
1537
1538 fn collect_debug(input: &[u8]) -> Vec<String> {
1540 let mut out = Vec::new();
1541 let mut p = VTPushParser::new();
1542 p.feed_with(input, &mut |ev| out.push(format!("{:?}", ev)));
1543 out
1544 }
1545
1546 #[test]
1547 fn dcs_aborted_by_can_before_body() {
1548 let mut s = Vec::new();
1550 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1552 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1555
1556 assert_eq!(ev.len(), 4, "{ev:#?}");
1557 assert_eq!(ev[0], "DcsStart(, '', q)");
1558 assert_eq!(ev[1], "DcsCancel");
1559 assert_eq!(ev[2], "Raw('IGNORED')");
1560 assert_eq!(ev[3], "Esc('', \\)");
1561 }
1562
1563 #[test]
1564 fn dcs_aborted_by_can_mid_body() {
1565 let mut s = Vec::new();
1567 s.extend_from_slice(b"\x1bPqABC");
1568 s.push(CAN);
1569 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1572
1573 assert_eq!(ev.len(), 4, "{ev:#?}");
1574 assert_eq!(ev[0], "DcsStart(, '', q)");
1575 assert_eq!(ev[1], "DcsCancel");
1576 assert_eq!(ev[2], "Raw('MORE')");
1577 assert_eq!(ev[3], "Esc('', \\)");
1578 }
1579
1580 #[test]
1583 fn spa_aborted_by_can_is_ignored() {
1584 let mut s = Vec::new();
1586 s.extend_from_slice(b"\x1b_hello");
1587 s.push(CAN);
1588 s.extend_from_slice(b"world\x1b\\");
1589
1590 let ev = collect_debug(&s);
1591 assert_eq!(ev.len(), 2, "{ev:#?}");
1592 assert_eq!(ev[0], "Raw('world')");
1593 assert_eq!(ev[1], "Esc('', \\)");
1594 }
1595
1596 #[test]
1597 fn spa_sub_aborts_too() {
1598 let mut s = Vec::new();
1599 s.extend_from_slice(b"\x1bXhello");
1600 s.push(SUB);
1601 s.extend_from_slice(b"world\x1b\\");
1602 let ev = collect_debug(&s);
1603 assert_eq!(ev.len(), 2, "{ev:#?}");
1604 assert_eq!(ev[0], "Raw('world')");
1605 assert_eq!(ev[1], "Esc('', \\)");
1606 }
1607
1608 #[test]
1611 fn can_in_ground_is_c0() {
1612 let mut s = Vec::new();
1613 s.extend_from_slice(b"abc");
1614 s.push(CAN);
1615 s.extend_from_slice(b"def");
1616 let ev = collect_debug(&s);
1617 assert_eq!(ev.len(), 3, "{ev:#?}");
1619 assert_eq!(ev[0], "Raw('abc')");
1620 assert_eq!(ev[1], "C0(18)");
1621 assert_eq!(ev[2], "Raw('def')");
1622 }
1623
1624 #[test]
1627 fn three_byte_sequences_capturable() {
1628 let mut bytes = vec![];
1629 for i in 0..=0xFFFFFF_u32 {
1630 bytes.clear();
1631 let test_bytes = i.to_le_bytes();
1632 let test_bytes = &test_bytes[..3];
1633 if test_bytes.iter().any(|b| b == &0) {
1634 continue;
1635 }
1636 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1637 continue;
1638 }
1639 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1640 continue;
1641 }
1642
1643 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1644 parser.feed_with(test_bytes, &mut |event| {
1645 let mut chunk = [0_u8; 3];
1646 let b = event.encode(&mut chunk).unwrap();
1647 bytes.extend_from_slice(&chunk[..b]);
1648 });
1649 if let Some(event) = parser.idle() {
1650 let mut chunk = [0_u8; 3];
1651 let b = event.encode(&mut chunk).unwrap();
1652 bytes.extend_from_slice(&chunk[..b]);
1653 }
1654
1655 if bytes.len() != 3 || bytes != test_bytes {
1656 eprintln!("Failed to parse:");
1657 parser.feed_with(test_bytes, &mut |event| {
1658 eprintln!("{:?}", event);
1659 });
1660 if let Some(event) = parser.idle() {
1661 eprintln!("{:?}", event);
1662 }
1663 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1664 }
1665 }
1666 }
1667}