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 }
250
251 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
252 VTPushParser::new_with()
253 }
254}
255
256macro_rules! invalid {
258 ($self:ident .priv_prefix, $self_:ident .ints, $b:expr) => {
259 if let Some(p) = $self.priv_prefix {
260 if $self.ints.len() == 0 {
261 VTEvent::EscInvalid(EscInvalid::Two(p, $b))
262 } else if $self.ints.len() == 1 {
263 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $b))
264 } else {
265 VTEvent::EscInvalid(EscInvalid::Four(
266 p,
267 $self.ints.data[0],
268 $self.ints.data[1],
269 $b,
270 ))
271 }
272 } else {
273 if $self.ints.len() == 0 {
274 VTEvent::EscInvalid(EscInvalid::One($b))
275 } else if $self.ints.len() == 1 {
276 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
277 } else {
278 VTEvent::EscInvalid(EscInvalid::Three(
279 $self.ints.data[0],
280 $self.ints.data[1],
281 $b,
282 ))
283 }
284 }
285 };
286 ($self:ident .priv_prefix, $self_:ident .ints) => {
287 if let Some(p) = $self.priv_prefix {
288 if $self.ints.len() == 0 {
289 VTEvent::EscInvalid(EscInvalid::One(p))
290 } else if $self.ints.len() == 1 {
291 VTEvent::EscInvalid(EscInvalid::Two(p, $self.ints.data[0]))
292 } else {
293 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $self.ints.data[1]))
294 }
295 } else {
296 if $self.ints.len() == 0 {
297 VTEvent::C0(0x1b)
299 } else if $self.ints.len() == 1 {
300 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
301 } else {
302 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
303 }
304 }
305 };
306 ($a:expr) => {
307 VTEvent::EscInvalid(EscInvalid::One($a))
308 };
309 ($a:expr, $b:expr) => {
310 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
311 };
312}
313
314impl<const INTEREST: u8> VTPushParser<INTEREST> {
315 const fn new_with() -> Self {
316 Self {
317 st: State::Ground,
318 ints: VTIntermediate::empty(),
319 params: SmallVec::new_const(),
320 cur_param: SmallVec::new_const(),
321 priv_prefix: None,
322 held_byte: None,
323 }
324 }
325
326 #[inline]
338 pub fn feed_with<'this, 'input, F: for<'any> FnMut(VTEvent<'any>)>(
339 &'this mut self,
340 input: &'input [u8],
341 cb: &mut F,
342 ) {
343 self.feed_with_internal(input, cb);
344 }
345
346 #[inline]
359 pub fn feed_with_abortable<'this, 'input, F: for<'any> FnMut(VTEvent<'any>) -> bool>(
360 &'this mut self,
361 input: &'input [u8],
362 cb: &mut F,
363 ) -> usize {
364 self.feed_with_internal(input, cb)
365 }
366
367 #[inline(always)]
368 fn feed_with_internal<
369 'this,
370 'input,
371 R: MaybeAbortable,
372 F: for<'any> FnMut(VTEvent<'any>) -> R,
373 >(
374 &'this mut self,
375 input: &'input [u8],
376 cb: &mut F,
377 ) -> usize {
378 if input.is_empty() {
379 return 0;
380 }
381
382 #[derive(Debug)]
383 struct FeedState {
384 buffer_idx: usize,
385 current_emit: Option<VTEmit>,
386 hold: bool,
387 }
388
389 let mut state = FeedState {
390 buffer_idx: 0,
391 current_emit: None,
392 hold: self.held_byte.is_some(),
393 };
394
395 macro_rules! emit {
396 ($state:ident, $i:expr, $cb:expr, $end:expr, $used_bel:expr) => {
397 let hold = std::mem::take(&mut $state.hold);
398 if let Some(emit) = $state.current_emit.take() {
399 let i = $i;
400 let range = $state.buffer_idx..(i - hold as usize);
401 if $end {
402 if match emit {
403 VTEmit::Ground => unreachable!(),
404 VTEmit::Dcs => $cb(VTEvent::DcsEnd(&input[range])),
405 VTEmit::Osc => $cb(VTEvent::OscEnd {
406 data: &input[range],
407 used_bel: $used_bel,
408 }),
409 }
410 .abort()
411 {
412 return i + 1;
413 }
414 } else if range.len() > 0 {
415 if match emit {
416 VTEmit::Ground => $cb(VTEvent::Raw(&input[range])),
417 VTEmit::Dcs => $cb(VTEvent::DcsData(&input[range])),
418 VTEmit::Osc => $cb(VTEvent::OscData(&input[range])),
419 }
420 .abort()
421 {
422 return i + 1;
423 }
424 }
425 }
426 };
427 }
428
429 let mut held_byte = self.held_byte.take();
430 let mut i = 0;
431
432 while i < input.len() {
433 if self.st == State::Ground {
435 let start = i;
436 loop {
437 if i >= input.len() {
438 cb(VTEvent::Raw(&input[start..]));
439 return input.len();
440 }
441 if ENDS_GROUND[input[i] as usize] {
442 break;
443 }
444 i += 1;
445 }
446
447 if start != i && cb(VTEvent::Raw(&input[start..i])).abort() {
448 return i;
449 }
450
451 if input[i] == ESC {
452 self.clear_hdr_collectors();
453 self.st = State::Escape;
454 i += 1;
455 continue;
456 }
457 }
458
459 if self.st == State::CsiIgnore {
461 loop {
462 if i >= input.len() {
463 return input.len();
464 }
465 if ENDS_CSI[input[i] as usize] {
466 break;
467 }
468 i += 1;
469 }
470
471 if input[i] == ESC {
472 self.st = State::Escape;
473 } else {
474 self.st = State::Ground;
475 }
476 i += 1;
477 continue;
478 }
479
480 let action = self.push_with(input[i]);
481
482 match action {
483 VTAction::None => {
484 if let Some(emit) = state.current_emit {
485 let range = state.buffer_idx..(i - state.hold as usize);
487 if !range.is_empty()
488 && match emit {
489 VTEmit::Ground => cb(VTEvent::Raw(&input[range])),
490 VTEmit::Dcs => cb(VTEvent::DcsData(&input[range])),
491 VTEmit::Osc => cb(VTEvent::OscData(&input[range])),
492 }
493 .abort()
494 {
495 if state.hold {
496 self.held_byte = Some(0x1b);
497 }
498 return i + 1;
499 }
500 if state.hold {
501 held_byte = Some(0x1b);
502 }
503 state.current_emit = None;
504 }
505 }
506 VTAction::Event(e) => {
507 if cb(e).abort() {
508 return i + 1;
509 }
510 }
511 VTAction::End(VTEnd::Dcs) => {
512 held_byte = None;
513 emit!(state, i, cb, true, false);
514 }
515 VTAction::End(VTEnd::Osc { used_bel }) => {
516 held_byte = None;
517 emit!(state, i, cb, true, used_bel);
518 }
519 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
520 if state.current_emit.is_none() {
521 if let Some(h) = held_byte.take() {
522 if match emit {
523 VTEmit::Ground => cb(VTEvent::Raw(&[h])),
524 VTEmit::Dcs => cb(VTEvent::DcsData(&[h])),
525 VTEmit::Osc => cb(VTEvent::OscData(&[h])),
526 }
527 .abort()
528 {
529 if matches!(action, VTAction::Hold(_)) {
530 self.held_byte = Some(0x1b);
531 return 1;
532 }
533 return 0;
534 }
535 }
536 }
537
538 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
539
540 state.hold = matches!(action, VTAction::Hold(_));
541 if state.current_emit.is_none() {
542 state.buffer_idx = i;
543 state.current_emit = Some(emit);
544 }
545 }
546 VTAction::Cancel(emit) => {
547 state.current_emit = None;
548 state.hold = false;
549 if match emit {
550 VTEmit::Ground => unreachable!(),
551 VTEmit::Dcs => cb(VTEvent::DcsCancel),
552 VTEmit::Osc => cb(VTEvent::OscCancel),
553 }
554 .abort()
555 {
556 return i + 1;
557 }
558 }
559 };
560 i += 1;
561 }
562
563 if state.hold {
565 self.held_byte = Some(0x1b);
566 }
567
568 if let Some(emit) = state.current_emit.take() {
569 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
570 if !range.is_empty() {
571 match emit {
572 VTEmit::Ground => cb(VTEvent::Raw(range)),
573 VTEmit::Dcs => cb(VTEvent::DcsData(range)),
574 VTEmit::Osc => cb(VTEvent::OscData(range)),
575 };
576 }
577 };
578
579 input.len()
581 }
582
583 pub fn is_ground(&self) -> bool {
585 self.st == State::Ground
586 }
587
588 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
592 match self.st {
593 State::Escape => {
594 self.st = State::Ground;
595 Some(VTEvent::C0(ESC))
596 }
597 State::EscInt => {
598 self.st = State::Ground;
599 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
600 None
601 } else {
602 Some(invalid!(self.priv_prefix, self.ints))
603 }
604 }
605 State::EscSs2 | State::EscSs3 => {
606 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
607 self.st = State::Ground;
608 None
609 } else {
610 let c = match self.st {
611 State::EscSs2 => SS2,
612 State::EscSs3 => SS3,
613 _ => unreachable!(),
614 };
615 self.st = State::Ground;
616 Some(invalid!(c))
617 }
618 }
619 _ => None,
620 }
621 }
622
623 fn push_with(&mut self, b: u8) -> VTAction {
624 use State::*;
625 match self.st {
626 Ground => self.on_ground(b),
627 Escape => self.on_escape(b),
628 EscInt => self.on_esc_int(b),
629 EscSs2 => self.on_esc_ss2(b),
630 EscSs3 => self.on_esc_ss3(b),
631
632 CsiEntry => self.on_csi_entry(b),
633 CsiParam => self.on_csi_param(b),
634 CsiInt => self.on_csi_int(b),
635 CsiIgnore => self.on_csi_ignore(b),
636
637 DcsEntry => self.on_dcs_entry(b),
638 DcsParam => self.on_dcs_param(b),
639 DcsInt => self.on_dcs_int(b),
640 DcsIgnore => self.on_dcs_ignore(b),
641 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
642 DcsPassthrough => self.on_dcs_pass(b),
643 DcsEsc => self.on_dcs_esc(b),
644
645 OscString => self.on_osc_string(b),
646 OscEsc => self.on_osc_esc(b),
647
648 SosPmApcString => self.on_spa_string(b),
649 SpaEsc => self.on_spa_esc(b),
650 }
651 }
652
653 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
654 self.reset_collectors();
655 self.st = State::Ground;
656
657 }
659
660 fn clear_hdr_collectors(&mut self) {
665 self.ints.clear();
666 self.params.clear();
667 self.cur_param.clear();
668 self.priv_prefix = None;
669 }
670
671 fn reset_collectors(&mut self) {
672 self.clear_hdr_collectors();
673 }
674
675 fn next_param(&mut self) {
676 self.params.push(std::mem::take(&mut self.cur_param));
677 }
678
679 fn finish_params_if_any(&mut self) {
680 if !self.cur_param.is_empty() || !self.params.is_empty() {
681 self.next_param();
682 }
683 }
684
685 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
686 self.finish_params_if_any();
687
688 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
690 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
691
692 let privp = self.priv_prefix.take();
693 VTAction::Event(VTEvent::Csi(CSI {
694 private: privp,
695 params: ParamBuf {
696 params: &self.params,
697 },
698 intermediates: self.ints,
699 final_byte,
700 }))
701 }
702
703 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
704 self.finish_params_if_any();
705
706 let privp = self.priv_prefix.take();
707 VTAction::Event(VTEvent::DcsStart(DCS {
708 private: privp,
709 params: ParamBuf {
710 params: &self.params,
711 },
712 intermediates: self.ints,
713 final_byte,
714 }))
715 }
716
717 fn on_ground(&mut self, b: u8) -> VTAction {
722 match b {
723 ESC => {
724 self.clear_hdr_collectors();
725 self.st = State::Escape;
726 VTAction::None
727 }
728 DEL => VTAction::Event(VTEvent::C0(DEL)),
729 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
730 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
731 _ => VTAction::Buffer(VTEmit::Ground), }
733 }
734
735 fn on_escape(&mut self, b: u8) -> VTAction {
736 use State::*;
737 match b {
738 CAN | SUB => {
739 self.st = Ground;
740 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
741 VTAction::None
742 } else {
743 VTAction::Event(invalid!(b))
744 }
745 }
746 DEL => {
749 self.st = Ground;
750 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
751 VTAction::None
752 } else {
753 VTAction::Event(invalid!(b))
754 }
755 }
756 c if is_intermediate(c) => {
757 if self.ints.push(c) {
758 self.st = EscInt;
759 } else {
760 self.st = Ground;
761 }
762 VTAction::None
763 }
764 c if is_priv(c) => {
765 self.priv_prefix = Some(c);
766 self.st = EscInt;
767 VTAction::None
768 }
769 CSI => {
770 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
771 self.st = CsiIgnore;
772 } else {
773 self.st = CsiEntry;
774 }
775 VTAction::None
776 }
777 DCS => {
778 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
779 self.st = DcsIgnore;
780 } else {
781 self.st = DcsEntry;
782 }
783 VTAction::None
784 }
785 OSC => {
786 self.st = OscString;
787 VTAction::Event(VTEvent::OscStart)
788 }
789 SS2 => {
790 self.st = EscSs2;
791 VTAction::None
792 }
793 SS3 => {
794 self.st = EscSs3;
795 VTAction::None
796 }
797 SOS | PM | APC => {
798 self.st = State::SosPmApcString;
799 VTAction::None
800 }
801 c if is_final(c) || is_digit(c) => {
802 self.st = Ground;
803 VTAction::Event(VTEvent::Esc(Esc {
804 intermediates: self.ints,
805 private: self.priv_prefix.take(),
806 final_byte: c,
807 }))
808 }
809 ESC => {
810 VTAction::Event(VTEvent::C0(ESC))
812 }
813 _ => {
814 self.st = Ground;
815 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
816 VTAction::None
817 } else {
818 VTAction::Event(invalid!(b))
819 }
820 }
821 }
822 }
823
824 fn on_esc_int(&mut self, b: u8) -> VTAction {
825 use State::*;
826 match b {
827 CAN | SUB => {
828 self.st = Ground;
829 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
830 VTAction::None
831 } else {
832 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
833 }
834 }
835 DEL => {
838 self.st = Ground;
839 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
840 VTAction::None
841 } else {
842 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
843 }
844 }
845 c if is_intermediate(c) => {
846 if !self.ints.push(c) {
847 self.st = Ground;
848 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
849 VTAction::None
850 } else {
851 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
852 }
853 } else {
854 VTAction::None
855 }
856 }
857 c if is_final(c) || is_digit(c) => {
858 self.st = Ground;
859 VTAction::Event(VTEvent::Esc(Esc {
860 intermediates: self.ints,
861 private: self.priv_prefix.take(),
862 final_byte: c,
863 }))
864 }
865 ESC => {
868 self.st = Escape;
869 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
870 VTAction::None
871 } else {
872 VTAction::Event(invalid!(self.priv_prefix, self.ints))
873 }
874 }
875 c => {
876 self.st = Ground;
877 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
878 VTAction::None
879 } else {
880 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
881 }
882 }
883 }
884 }
885
886 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
887 use State::*;
888 self.st = Ground;
889 match b {
890 CAN | SUB => {
891 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
892 VTAction::None
893 } else {
894 VTAction::Event(invalid!(SS2, b))
895 }
896 }
897 ESC => {
900 self.st = Escape;
901 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
902 VTAction::None
903 } else {
904 VTAction::Event(invalid!(SS2))
905 }
906 }
907 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
908 }
909 }
910
911 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
912 use State::*;
913 self.st = Ground;
914 match b {
915 CAN | SUB => {
916 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
917 VTAction::None
918 } else {
919 VTAction::Event(invalid!(SS3, b))
920 }
921 }
922 ESC => {
925 self.st = Escape;
926 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
927 VTAction::None
928 } else {
929 VTAction::Event(invalid!(SS3))
930 }
931 }
932 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
933 }
934 }
935
936 fn on_csi_entry(&mut self, b: u8) -> VTAction {
938 use State::*;
939 match b {
940 CAN | SUB => {
941 self.st = Ground;
942 VTAction::None
943 }
944 DEL => VTAction::None,
945 ESC => {
946 self.st = Escape;
947 VTAction::None
948 }
949 c if is_priv(c) => {
950 self.priv_prefix = Some(c);
951 self.st = CsiParam;
952 VTAction::None
953 }
954 d if is_digit(d) => {
955 self.cur_param.push(d);
956 self.st = CsiParam;
957 VTAction::None
958 }
959 b';' => {
960 self.next_param();
961 self.st = CsiParam;
962 VTAction::None
963 }
964 b':' => {
965 self.cur_param.push(b':');
966 self.st = CsiParam;
967 VTAction::None
968 }
969 c if is_intermediate(c) => {
970 if self.ints.push(c) {
971 self.st = CsiInt;
972 } else {
973 self.st = Ground;
974 }
975 VTAction::None
976 }
977 c if is_final(c) => {
978 self.st = Ground;
979 self.emit_csi(c)
980 }
981 _ => {
982 self.st = CsiIgnore;
983 VTAction::None
984 }
985 }
986 }
987
988 fn on_csi_param(&mut self, b: u8) -> VTAction {
989 use State::*;
990 match b {
991 CAN | SUB => {
992 self.st = Ground;
993 VTAction::None
994 }
995 DEL => VTAction::None,
996 ESC => {
997 self.st = Escape;
998 VTAction::None
999 }
1000 d if is_digit(d) => {
1001 self.cur_param.push(d);
1002 VTAction::None
1003 }
1004 b';' => {
1005 self.next_param();
1006 VTAction::None
1007 }
1008 b':' => {
1009 self.cur_param.push(b':');
1010 VTAction::None
1011 }
1012 c if is_intermediate(c) => {
1013 if self.ints.push(c) {
1014 self.st = CsiInt;
1015 } else {
1016 self.st = Ground;
1017 }
1018 VTAction::None
1019 }
1020 c if is_final(c) => {
1021 self.st = Ground;
1022 self.emit_csi(c)
1023 }
1024 _ => {
1025 self.st = CsiIgnore;
1026 VTAction::None
1027 }
1028 }
1029 }
1030
1031 fn on_csi_int(&mut self, b: u8) -> VTAction {
1032 use State::*;
1033 match b {
1034 CAN | SUB => {
1035 self.st = Ground;
1036 VTAction::None
1037 }
1038 DEL => VTAction::None,
1039 ESC => {
1040 self.st = Escape;
1041 VTAction::None
1042 }
1043 c if is_intermediate(c) => {
1044 if self.ints.push(c) {
1045 self.st = CsiInt;
1046 } else {
1047 self.st = Ground;
1048 }
1049 VTAction::None
1050 }
1051 c if is_final(c) => {
1052 self.st = Ground;
1053 self.emit_csi(c)
1054 }
1055 _ => {
1056 self.st = CsiIgnore;
1057 VTAction::None
1058 }
1059 }
1060 }
1061
1062 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1063 use State::*;
1064 match b {
1065 CAN | SUB => {
1066 self.st = Ground;
1067 VTAction::None
1068 }
1069 DEL => VTAction::None,
1070 ESC => {
1071 self.st = Escape;
1072 VTAction::None
1073 }
1074 c if is_final(c) => {
1075 self.st = Ground;
1076 VTAction::None
1077 }
1078 _ => VTAction::None,
1079 }
1080 }
1081
1082 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1084 use State::*;
1085 match b {
1086 CAN | SUB => {
1087 self.st = Ground;
1088 VTAction::None
1089 }
1090 DEL => VTAction::None,
1091 ESC => {
1092 self.st = Escape;
1093 VTAction::None
1094 }
1095 c if is_priv(c) => {
1096 self.priv_prefix = Some(c);
1097 self.st = DcsParam;
1098 VTAction::None
1099 }
1100 d if is_digit(d) => {
1101 self.cur_param.push(d);
1102 self.st = DcsParam;
1103 VTAction::None
1104 }
1105 b';' => {
1106 self.next_param();
1107 self.st = DcsParam;
1108 VTAction::None
1109 }
1110 b':' => {
1111 self.st = DcsIgnore;
1112 VTAction::None
1113 }
1114 c if is_intermediate(c) => {
1115 if self.ints.push(c) {
1116 self.st = DcsInt;
1117 } else {
1118 self.st = Ground;
1119 }
1120 VTAction::None
1121 }
1122 c if is_final(c) => {
1123 self.st = DcsPassthrough;
1124 self.dcs_start(c)
1125 }
1126 _ => {
1127 self.st = DcsIgnore;
1128 VTAction::None
1129 }
1130 }
1131 }
1132
1133 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1134 use State::*;
1135 match b {
1136 CAN | SUB => {
1137 self.st = Ground;
1138 VTAction::None
1139 }
1140 DEL => VTAction::None,
1141 ESC => {
1142 self.st = Escape;
1143 VTAction::None
1144 }
1145 d if is_digit(d) => {
1146 self.cur_param.push(d);
1147 VTAction::None
1148 }
1149 b';' => {
1150 self.next_param();
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 self.st = DcsInt;
1164 VTAction::None
1165 }
1166 c if is_final(c) => {
1167 self.st = DcsPassthrough;
1168 self.dcs_start(c)
1169 }
1170 _ => {
1171 self.st = DcsIgnore;
1172 VTAction::None
1173 }
1174 }
1175 }
1176
1177 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1178 use State::*;
1179 match b {
1180 CAN | SUB => {
1181 self.st = Ground;
1182 VTAction::None
1183 }
1184 DEL => VTAction::None,
1185 ESC => {
1186 self.st = Escape;
1187 VTAction::None
1188 }
1189 c if is_intermediate(c) => {
1190 if self.ints.push(c) {
1191 self.st = DcsInt;
1192 } else {
1193 self.st = Ground;
1194 }
1195 VTAction::None
1196 }
1197 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1198 self.st = DcsPassthrough;
1199 self.dcs_start(c)
1200 }
1201 _ => {
1202 self.st = DcsIgnore;
1203 VTAction::None
1204 }
1205 }
1206 }
1207
1208 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1209 use State::*;
1210 match b {
1211 CAN | SUB => {
1212 self.st = Ground;
1213 VTAction::None
1214 }
1215 DEL => VTAction::None,
1216 ESC => {
1217 self.st = DcsIgnoreEsc;
1218 VTAction::None
1219 }
1220 _ => VTAction::None,
1221 }
1222 }
1223
1224 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1225 use State::*;
1226 match b {
1227 CAN | SUB => {
1228 self.st = Ground;
1229 VTAction::None
1230 }
1231 ST_FINAL => {
1232 self.st = Ground;
1233 VTAction::None
1234 }
1235 DEL => VTAction::None,
1236 ESC => VTAction::None,
1237 _ => {
1238 self.st = DcsIgnore;
1239 VTAction::None
1240 }
1241 }
1242 }
1243
1244 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1245 use State::*;
1246 match b {
1247 CAN | SUB => {
1248 self.st = Ground;
1249 VTAction::Cancel(VTEmit::Dcs)
1250 }
1251 DEL => VTAction::None,
1252 ESC => {
1253 self.st = DcsEsc;
1254 VTAction::Hold(VTEmit::Dcs)
1255 }
1256 _ => VTAction::Buffer(VTEmit::Dcs),
1257 }
1258 }
1259
1260 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1261 use State::*;
1262 match b {
1263 ST_FINAL => {
1264 self.st = Ground;
1265 VTAction::End(VTEnd::Dcs)
1266 }
1267 DEL => VTAction::None,
1268 ESC => {
1269 VTAction::Hold(VTEmit::Dcs)
1271 }
1272 _ => {
1273 self.st = DcsPassthrough;
1275 VTAction::Buffer(VTEmit::Dcs)
1276 }
1277 }
1278 }
1279
1280 fn on_osc_string(&mut self, b: u8) -> VTAction {
1282 use State::*;
1283 match b {
1284 CAN | SUB => {
1285 self.st = Ground;
1286 VTAction::Cancel(VTEmit::Osc)
1287 }
1288 DEL => VTAction::None,
1289 BEL => {
1290 self.st = Ground;
1291 VTAction::End(VTEnd::Osc { used_bel: true })
1292 }
1293 ESC => {
1294 self.st = OscEsc;
1295 VTAction::Hold(VTEmit::Osc)
1296 }
1297 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1298 _ => VTAction::None, }
1300 }
1301
1302 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1303 use State::*;
1304 match b {
1305 ST_FINAL => {
1306 self.st = Ground;
1307 VTAction::End(VTEnd::Osc { used_bel: false })
1308 } ESC => VTAction::Hold(VTEmit::Osc),
1310 DEL => VTAction::None,
1311 _ => {
1312 self.st = OscString;
1313 VTAction::Buffer(VTEmit::Osc)
1314 }
1315 }
1316 }
1317
1318 fn on_spa_string(&mut self, b: u8) -> VTAction {
1320 use State::*;
1321 match b {
1322 CAN | SUB => {
1323 self.st = Ground;
1324 VTAction::None
1325 }
1326 DEL => VTAction::None,
1327 ESC => {
1328 self.st = SpaEsc;
1329 VTAction::None
1330 }
1331 _ => VTAction::None,
1332 }
1333 }
1334
1335 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1336 use State::*;
1337 match b {
1338 ST_FINAL => {
1339 self.st = Ground;
1340 VTAction::None
1341 }
1342 DEL => VTAction::None,
1343 ESC => {
1344 VTAction::None
1346 }
1347 _ => {
1348 self.st = State::SosPmApcString;
1349 VTAction::None
1350 }
1351 }
1352 }
1353}
1354
1355#[cfg(test)]
1356mod tests {
1357 use crate::event::VTOwnedEvent;
1358
1359 use super::*;
1360 use pretty_assertions::assert_eq;
1361
1362 #[test]
1363 fn test_edge_cases() {
1364 let mut result = String::new();
1366 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1367 assert_eq!(result.trim(), "");
1368
1369 let mut result = String::new();
1371 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1372 assert_eq!(result.trim(), "");
1373
1374 let mut result = String::new();
1376 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1377 assert_eq!(result.trim(), "");
1378
1379 let mut result = String::new();
1381 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1382 assert_eq!(result.trim(), "");
1383
1384 let mut result = String::new();
1386 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1387 assert_eq!(result.trim(), "OscStart");
1388 }
1389
1390 #[test]
1391 fn test_streaming_behavior() {
1392 let mut parser = VTPushParser::new(); let mut result = String::new();
1395 let mut callback = |vt_input: VTEvent<'_>| {
1396 result.push_str(&format!("{vt_input:?}\n"));
1397 };
1398
1399 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1401 parser.feed_with(b"data", &mut callback);
1402 parser.feed_with(b" more", &mut callback);
1403 parser.feed_with(b"\x1b\\", &mut callback);
1404
1405 assert_eq!(
1406 result.trim(),
1407 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1408 );
1409 }
1410
1411 #[test]
1412 fn test_dcs_payload_passthrough() {
1413 let dcs_cases: &[(&[u8], &str)] = &[
1421 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1423 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1425 (
1427 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1428 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1429 ),
1430 (
1432 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1433 "ABC<ESC><ESC>DEF<ESC>XG",
1434 ),
1435 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1437 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1439 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1441 (
1443 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1444 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1445 ),
1446 (
1448 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1449 "<ESC>[58:2::000:007:042m",
1450 ),
1451 ];
1452
1453 for (input, expected_body) in dcs_cases {
1454 let events = collect_owned_events(input);
1455
1456 let mut actual_body = Vec::new();
1458 for event in &events {
1459 match event {
1460 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1461 actual_body.extend(data);
1462 }
1463 _ => {}
1464 }
1465 }
1466
1467 let actual_body = String::from_utf8(actual_body).unwrap();
1468 let actual_body = actual_body
1469 .replace("\x1b", "<ESC>")
1470 .replace("\x07", "<BEL>");
1471
1472 assert_eq!(
1473 actual_body, *expected_body,
1474 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1475 input, events
1476 );
1477 }
1478 }
1479
1480 fn collect_events(input: &[u8]) -> Vec<String> {
1481 let mut out = Vec::new();
1482 let mut p = VTPushParser::new();
1483 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1484 out
1485 }
1486
1487 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1488 let mut out = Vec::new();
1489 let mut p = VTPushParser::new();
1490 p.feed_with(input, &mut |ev| out.push(ev.to_owned()));
1491 out
1492 }
1493
1494 #[test]
1495 fn dcs_esc_esc_del() {
1496 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1498 eprintln!("{ev:?}");
1500 }
1501
1502 #[test]
1503 fn dcs_header_with_colon_is_ignored_case1() {
1504 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1506 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1508 }
1509
1510 #[test]
1511 fn dcs_header_with_colon_is_ignored_case2() {
1512 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1514 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1515 }
1516
1517 #[test]
1518 fn dcs_header_with_colon_is_ignored_case3() {
1519 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1521 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1522 }
1523
1524 #[test]
1525 fn osc_aborted_by_can_mid_body() {
1526 let mut s = Vec::new();
1528 s.extend_from_slice(b"\x1b]0;Title");
1529 s.push(CAN);
1530 s.extend_from_slice(b"more\x07");
1531
1532 let ev = collect_debug(&s);
1533
1534 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1539 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1540 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1541 }
1542
1543 #[test]
1544 fn osc_aborted_by_sub_before_terminator() {
1545 let mut s = Vec::new();
1546 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1547 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1551 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1555 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1556 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1557 }
1558
1559 fn collect_debug(input: &[u8]) -> Vec<String> {
1561 let mut out = Vec::new();
1562 let mut p = VTPushParser::new();
1563 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1564 out
1565 }
1566
1567 #[test]
1568 fn dcs_aborted_by_can_before_body() {
1569 let mut s = Vec::new();
1571 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1573 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1576
1577 assert_eq!(ev.len(), 4, "{ev:#?}");
1578 assert_eq!(ev[0], "DcsStart('', q)");
1579 assert_eq!(ev[1], "DcsCancel");
1580 assert_eq!(ev[2], "Raw('IGNORED')");
1581 assert_eq!(ev[3], "Esc('', \\)");
1582 }
1583
1584 #[test]
1585 fn dcs_aborted_by_can_mid_body() {
1586 let mut s = Vec::new();
1588 s.extend_from_slice(b"\x1bPqABC");
1589 s.push(CAN);
1590 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1593
1594 assert_eq!(ev.len(), 4, "{ev:#?}");
1595 assert_eq!(ev[0], "DcsStart('', q)");
1596 assert_eq!(ev[1], "DcsCancel");
1597 assert_eq!(ev[2], "Raw('MORE')");
1598 assert_eq!(ev[3], "Esc('', \\)");
1599 }
1600
1601 #[test]
1604 fn spa_aborted_by_can_is_ignored() {
1605 let mut s = Vec::new();
1607 s.extend_from_slice(b"\x1b_hello");
1608 s.push(CAN);
1609 s.extend_from_slice(b"world\x1b\\");
1610
1611 let ev = collect_debug(&s);
1612 assert_eq!(ev.len(), 2, "{ev:#?}");
1613 assert_eq!(ev[0], "Raw('world')");
1614 assert_eq!(ev[1], "Esc('', \\)");
1615 }
1616
1617 #[test]
1618 fn spa_sub_aborts_too() {
1619 let mut s = Vec::new();
1620 s.extend_from_slice(b"\x1bXhello");
1621 s.push(SUB);
1622 s.extend_from_slice(b"world\x1b\\");
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]
1632 fn can_in_ground_is_c0() {
1633 let mut s = Vec::new();
1634 s.extend_from_slice(b"abc");
1635 s.push(CAN);
1636 s.extend_from_slice(b"def");
1637 let ev = collect_debug(&s);
1638 assert_eq!(ev.len(), 3, "{ev:#?}");
1640 assert_eq!(ev[0], "Raw('abc')");
1641 assert_eq!(ev[1], "C0(18)");
1642 assert_eq!(ev[2], "Raw('def')");
1643 }
1644
1645 #[test]
1648 fn three_byte_sequences_capturable() {
1649 let mut bytes = vec![];
1650 for i in 0..=0xFFFFFF_u32 {
1651 bytes.clear();
1652 let test_bytes = i.to_le_bytes();
1653 let test_bytes = &test_bytes[..3];
1654 if test_bytes.iter().any(|b| b == &0) {
1655 continue;
1656 }
1657 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1658 continue;
1659 }
1660 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1661 continue;
1662 }
1663
1664 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1665 parser.feed_with(test_bytes, &mut |event| {
1666 let mut chunk = [0_u8; 3];
1667 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1668 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1669 });
1670 bytes.extend_from_slice(&chunk[..b]);
1671 });
1672 if let Some(event) = parser.idle() {
1673 let mut chunk = [0_u8; 3];
1674 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1675 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1676 });
1677 bytes.extend_from_slice(&chunk[..b]);
1678 }
1679
1680 if bytes.len() != 3 || bytes != test_bytes {
1681 eprintln!("Failed to parse:");
1682 parser.feed_with(test_bytes, &mut |event| {
1683 eprintln!("{event:?}");
1684 });
1685 if let Some(event) = parser.idle() {
1686 eprintln!("{event:?}");
1687 }
1688 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1689 }
1690 }
1691 }
1692}