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 && let Some(h) = held_byte.take()
522 && 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 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
537
538 state.hold = matches!(action, VTAction::Hold(_));
539 if state.current_emit.is_none() {
540 state.buffer_idx = i;
541 state.current_emit = Some(emit);
542 }
543 }
544 VTAction::Cancel(emit) => {
545 state.current_emit = None;
546 state.hold = false;
547 if match emit {
548 VTEmit::Ground => unreachable!(),
549 VTEmit::Dcs => cb(VTEvent::DcsCancel),
550 VTEmit::Osc => cb(VTEvent::OscCancel),
551 }
552 .abort()
553 {
554 return i + 1;
555 }
556 }
557 };
558 i += 1;
559 }
560
561 if state.hold {
563 self.held_byte = Some(0x1b);
564 }
565
566 if let Some(emit) = state.current_emit.take() {
567 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
568 if !range.is_empty() {
569 match emit {
570 VTEmit::Ground => cb(VTEvent::Raw(range)),
571 VTEmit::Dcs => cb(VTEvent::DcsData(range)),
572 VTEmit::Osc => cb(VTEvent::OscData(range)),
573 };
574 }
575 };
576
577 input.len()
579 }
580
581 pub fn is_ground(&self) -> bool {
583 self.st == State::Ground
584 }
585
586 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
590 match self.st {
591 State::Escape => {
592 self.st = State::Ground;
593 Some(VTEvent::C0(ESC))
594 }
595 State::EscInt => {
596 self.st = State::Ground;
597 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
598 None
599 } else {
600 Some(invalid!(self.priv_prefix, self.ints))
601 }
602 }
603 State::EscSs2 | State::EscSs3 => {
604 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
605 self.st = State::Ground;
606 None
607 } else {
608 let c = match self.st {
609 State::EscSs2 => SS2,
610 State::EscSs3 => SS3,
611 _ => unreachable!(),
612 };
613 self.st = State::Ground;
614 Some(invalid!(c))
615 }
616 }
617 _ => None,
618 }
619 }
620
621 fn push_with(&mut self, b: u8) -> VTAction {
622 use State::*;
623 match self.st {
624 Ground => self.on_ground(b),
625 Escape => self.on_escape(b),
626 EscInt => self.on_esc_int(b),
627 EscSs2 => self.on_esc_ss2(b),
628 EscSs3 => self.on_esc_ss3(b),
629
630 CsiEntry => self.on_csi_entry(b),
631 CsiParam => self.on_csi_param(b),
632 CsiInt => self.on_csi_int(b),
633 CsiIgnore => self.on_csi_ignore(b),
634
635 DcsEntry => self.on_dcs_entry(b),
636 DcsParam => self.on_dcs_param(b),
637 DcsInt => self.on_dcs_int(b),
638 DcsIgnore => self.on_dcs_ignore(b),
639 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
640 DcsPassthrough => self.on_dcs_pass(b),
641 DcsEsc => self.on_dcs_esc(b),
642
643 OscString => self.on_osc_string(b),
644 OscEsc => self.on_osc_esc(b),
645
646 SosPmApcString => self.on_spa_string(b),
647 SpaEsc => self.on_spa_esc(b),
648 }
649 }
650
651 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
652 self.reset_collectors();
653 self.st = State::Ground;
654
655 }
657
658 fn clear_hdr_collectors(&mut self) {
663 self.ints.clear();
664 self.params.clear();
665 self.cur_param.clear();
666 self.priv_prefix = None;
667 }
668
669 fn reset_collectors(&mut self) {
670 self.clear_hdr_collectors();
671 }
672
673 fn next_param(&mut self) {
674 self.params.push(std::mem::take(&mut self.cur_param));
675 }
676
677 fn finish_params_if_any(&mut self) {
678 if !self.cur_param.is_empty() || !self.params.is_empty() {
679 self.next_param();
680 }
681 }
682
683 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
684 self.finish_params_if_any();
685
686 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
688 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
689
690 let privp = self.priv_prefix.take();
691 VTAction::Event(VTEvent::Csi(CSI {
692 private: privp,
693 params: ParamBuf {
694 params: &self.params,
695 },
696 intermediates: self.ints,
697 final_byte,
698 }))
699 }
700
701 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
702 self.finish_params_if_any();
703
704 let privp = self.priv_prefix.take();
705 VTAction::Event(VTEvent::DcsStart(DCS {
706 private: privp,
707 params: ParamBuf {
708 params: &self.params,
709 },
710 intermediates: self.ints,
711 final_byte,
712 }))
713 }
714
715 fn on_ground(&mut self, b: u8) -> VTAction {
720 match b {
721 ESC => {
722 self.clear_hdr_collectors();
723 self.st = State::Escape;
724 VTAction::None
725 }
726 DEL => VTAction::Event(VTEvent::C0(DEL)),
727 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
728 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
729 _ => VTAction::Buffer(VTEmit::Ground), }
731 }
732
733 fn on_escape(&mut self, b: u8) -> VTAction {
734 use State::*;
735 match b {
736 CAN | SUB => {
737 self.st = Ground;
738 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
739 VTAction::None
740 } else {
741 VTAction::Event(invalid!(b))
742 }
743 }
744 DEL => {
747 self.st = Ground;
748 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
749 VTAction::None
750 } else {
751 VTAction::Event(invalid!(b))
752 }
753 }
754 c if is_intermediate(c) => {
755 if self.ints.push(c) {
756 self.st = EscInt;
757 } else {
758 self.st = Ground;
759 }
760 VTAction::None
761 }
762 c if is_priv(c) => {
763 self.priv_prefix = Some(c);
764 self.st = EscInt;
765 VTAction::None
766 }
767 CSI => {
768 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
769 self.st = CsiIgnore;
770 } else {
771 self.st = CsiEntry;
772 }
773 VTAction::None
774 }
775 DCS => {
776 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
777 self.st = DcsIgnore;
778 } else {
779 self.st = DcsEntry;
780 }
781 VTAction::None
782 }
783 OSC => {
784 self.st = OscString;
785 VTAction::Event(VTEvent::OscStart)
786 }
787 SS2 => {
788 self.st = EscSs2;
789 VTAction::None
790 }
791 SS3 => {
792 self.st = EscSs3;
793 VTAction::None
794 }
795 SOS | PM | APC => {
796 self.st = State::SosPmApcString;
797 VTAction::None
798 }
799 c if is_final(c) || is_digit(c) => {
800 self.st = Ground;
801 VTAction::Event(VTEvent::Esc(Esc {
802 intermediates: self.ints,
803 private: self.priv_prefix.take(),
804 final_byte: c,
805 }))
806 }
807 ESC => {
808 VTAction::Event(VTEvent::C0(ESC))
810 }
811 _ => {
812 self.st = Ground;
813 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
814 VTAction::None
815 } else {
816 VTAction::Event(invalid!(b))
817 }
818 }
819 }
820 }
821
822 fn on_esc_int(&mut self, b: u8) -> VTAction {
823 use State::*;
824 match b {
825 CAN | SUB => {
826 self.st = Ground;
827 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
828 VTAction::None
829 } else {
830 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
831 }
832 }
833 DEL => {
836 self.st = Ground;
837 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
838 VTAction::None
839 } else {
840 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
841 }
842 }
843 c if is_intermediate(c) => {
844 if !self.ints.push(c) {
845 self.st = Ground;
846 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
847 VTAction::None
848 } else {
849 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
850 }
851 } else {
852 VTAction::None
853 }
854 }
855 c if is_final(c) || is_digit(c) => {
856 self.st = Ground;
857 VTAction::Event(VTEvent::Esc(Esc {
858 intermediates: self.ints,
859 private: self.priv_prefix.take(),
860 final_byte: c,
861 }))
862 }
863 ESC => {
866 self.st = Escape;
867 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
868 VTAction::None
869 } else {
870 VTAction::Event(invalid!(self.priv_prefix, self.ints))
871 }
872 }
873 c => {
874 self.st = Ground;
875 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
876 VTAction::None
877 } else {
878 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
879 }
880 }
881 }
882 }
883
884 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
885 use State::*;
886 self.st = Ground;
887 match b {
888 CAN | SUB => {
889 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
890 VTAction::None
891 } else {
892 VTAction::Event(invalid!(SS2, b))
893 }
894 }
895 ESC => {
898 self.st = Escape;
899 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
900 VTAction::None
901 } else {
902 VTAction::Event(invalid!(SS2))
903 }
904 }
905 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
906 }
907 }
908
909 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
910 use State::*;
911 self.st = Ground;
912 match b {
913 CAN | SUB => {
914 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
915 VTAction::None
916 } else {
917 VTAction::Event(invalid!(SS3, b))
918 }
919 }
920 ESC => {
923 self.st = Escape;
924 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
925 VTAction::None
926 } else {
927 VTAction::Event(invalid!(SS3))
928 }
929 }
930 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
931 }
932 }
933
934 fn on_csi_entry(&mut self, b: u8) -> VTAction {
936 use State::*;
937 match b {
938 CAN | SUB => {
939 self.st = Ground;
940 VTAction::None
941 }
942 DEL => VTAction::None,
943 ESC => {
944 self.st = Escape;
945 VTAction::None
946 }
947 c if is_priv(c) => {
948 self.priv_prefix = Some(c);
949 self.st = CsiParam;
950 VTAction::None
951 }
952 d if is_digit(d) => {
953 self.cur_param.push(d);
954 self.st = CsiParam;
955 VTAction::None
956 }
957 b';' => {
958 self.next_param();
959 self.st = CsiParam;
960 VTAction::None
961 }
962 b':' => {
963 self.cur_param.push(b':');
964 self.st = CsiParam;
965 VTAction::None
966 }
967 c if is_intermediate(c) => {
968 if self.ints.push(c) {
969 self.st = CsiInt;
970 } else {
971 self.st = Ground;
972 }
973 VTAction::None
974 }
975 c if is_final(c) => {
976 self.st = Ground;
977 self.emit_csi(c)
978 }
979 _ => {
980 self.st = CsiIgnore;
981 VTAction::None
982 }
983 }
984 }
985
986 fn on_csi_param(&mut self, b: u8) -> VTAction {
987 use State::*;
988 match b {
989 CAN | SUB => {
990 self.st = Ground;
991 VTAction::None
992 }
993 DEL => VTAction::None,
994 ESC => {
995 self.st = Escape;
996 VTAction::None
997 }
998 d if is_digit(d) => {
999 self.cur_param.push(d);
1000 VTAction::None
1001 }
1002 b';' => {
1003 self.next_param();
1004 VTAction::None
1005 }
1006 b':' => {
1007 self.cur_param.push(b':');
1008 VTAction::None
1009 }
1010 c if is_intermediate(c) => {
1011 if self.ints.push(c) {
1012 self.st = CsiInt;
1013 } else {
1014 self.st = Ground;
1015 }
1016 VTAction::None
1017 }
1018 c if is_final(c) => {
1019 self.st = Ground;
1020 self.emit_csi(c)
1021 }
1022 _ => {
1023 self.st = CsiIgnore;
1024 VTAction::None
1025 }
1026 }
1027 }
1028
1029 fn on_csi_int(&mut self, b: u8) -> VTAction {
1030 use State::*;
1031 match b {
1032 CAN | SUB => {
1033 self.st = Ground;
1034 VTAction::None
1035 }
1036 DEL => VTAction::None,
1037 ESC => {
1038 self.st = Escape;
1039 VTAction::None
1040 }
1041 c if is_intermediate(c) => {
1042 if self.ints.push(c) {
1043 self.st = CsiInt;
1044 } else {
1045 self.st = Ground;
1046 }
1047 VTAction::None
1048 }
1049 c if is_final(c) => {
1050 self.st = Ground;
1051 self.emit_csi(c)
1052 }
1053 _ => {
1054 self.st = CsiIgnore;
1055 VTAction::None
1056 }
1057 }
1058 }
1059
1060 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1061 use State::*;
1062 match b {
1063 CAN | SUB => {
1064 self.st = Ground;
1065 VTAction::None
1066 }
1067 DEL => VTAction::None,
1068 ESC => {
1069 self.st = Escape;
1070 VTAction::None
1071 }
1072 c if is_final(c) => {
1073 self.st = Ground;
1074 VTAction::None
1075 }
1076 _ => VTAction::None,
1077 }
1078 }
1079
1080 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1082 use State::*;
1083 match b {
1084 CAN | SUB => {
1085 self.st = Ground;
1086 VTAction::None
1087 }
1088 DEL => VTAction::None,
1089 ESC => {
1090 self.st = Escape;
1091 VTAction::None
1092 }
1093 c if is_priv(c) => {
1094 self.priv_prefix = Some(c);
1095 self.st = DcsParam;
1096 VTAction::None
1097 }
1098 d if is_digit(d) => {
1099 self.cur_param.push(d);
1100 self.st = DcsParam;
1101 VTAction::None
1102 }
1103 b';' => {
1104 self.next_param();
1105 self.st = DcsParam;
1106 VTAction::None
1107 }
1108 b':' => {
1109 self.st = DcsIgnore;
1110 VTAction::None
1111 }
1112 c if is_intermediate(c) => {
1113 if self.ints.push(c) {
1114 self.st = DcsInt;
1115 } else {
1116 self.st = Ground;
1117 }
1118 VTAction::None
1119 }
1120 c if is_final(c) => {
1121 self.st = DcsPassthrough;
1122 self.dcs_start(c)
1123 }
1124 _ => {
1125 self.st = DcsIgnore;
1126 VTAction::None
1127 }
1128 }
1129 }
1130
1131 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1132 use State::*;
1133 match b {
1134 CAN | SUB => {
1135 self.st = Ground;
1136 VTAction::None
1137 }
1138 DEL => VTAction::None,
1139 ESC => {
1140 self.st = Escape;
1141 VTAction::None
1142 }
1143 d if is_digit(d) => {
1144 self.cur_param.push(d);
1145 VTAction::None
1146 }
1147 b';' => {
1148 self.next_param();
1149 VTAction::None
1150 }
1151 b':' => {
1152 self.st = DcsIgnore;
1153 VTAction::None
1154 }
1155 c if is_intermediate(c) => {
1156 if self.ints.push(c) {
1157 self.st = DcsInt;
1158 } else {
1159 self.st = Ground;
1160 }
1161 self.st = DcsInt;
1162 VTAction::None
1163 }
1164 c if is_final(c) => {
1165 self.st = DcsPassthrough;
1166 self.dcs_start(c)
1167 }
1168 _ => {
1169 self.st = DcsIgnore;
1170 VTAction::None
1171 }
1172 }
1173 }
1174
1175 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1176 use State::*;
1177 match b {
1178 CAN | SUB => {
1179 self.st = Ground;
1180 VTAction::None
1181 }
1182 DEL => VTAction::None,
1183 ESC => {
1184 self.st = Escape;
1185 VTAction::None
1186 }
1187 c if is_intermediate(c) => {
1188 if self.ints.push(c) {
1189 self.st = DcsInt;
1190 } else {
1191 self.st = Ground;
1192 }
1193 VTAction::None
1194 }
1195 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1196 self.st = DcsPassthrough;
1197 self.dcs_start(c)
1198 }
1199 _ => {
1200 self.st = DcsIgnore;
1201 VTAction::None
1202 }
1203 }
1204 }
1205
1206 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1207 use State::*;
1208 match b {
1209 CAN | SUB => {
1210 self.st = Ground;
1211 VTAction::None
1212 }
1213 DEL => VTAction::None,
1214 ESC => {
1215 self.st = DcsIgnoreEsc;
1216 VTAction::None
1217 }
1218 _ => VTAction::None,
1219 }
1220 }
1221
1222 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1223 use State::*;
1224 match b {
1225 CAN | SUB => {
1226 self.st = Ground;
1227 VTAction::None
1228 }
1229 ST_FINAL => {
1230 self.st = Ground;
1231 VTAction::None
1232 }
1233 DEL => VTAction::None,
1234 ESC => VTAction::None,
1235 _ => {
1236 self.st = DcsIgnore;
1237 VTAction::None
1238 }
1239 }
1240 }
1241
1242 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1243 use State::*;
1244 match b {
1245 CAN | SUB => {
1246 self.st = Ground;
1247 VTAction::Cancel(VTEmit::Dcs)
1248 }
1249 DEL => VTAction::None,
1250 ESC => {
1251 self.st = DcsEsc;
1252 VTAction::Hold(VTEmit::Dcs)
1253 }
1254 _ => VTAction::Buffer(VTEmit::Dcs),
1255 }
1256 }
1257
1258 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1259 use State::*;
1260 match b {
1261 ST_FINAL => {
1262 self.st = Ground;
1263 VTAction::End(VTEnd::Dcs)
1264 }
1265 DEL => VTAction::None,
1266 ESC => {
1267 VTAction::Hold(VTEmit::Dcs)
1269 }
1270 _ => {
1271 self.st = DcsPassthrough;
1273 VTAction::Buffer(VTEmit::Dcs)
1274 }
1275 }
1276 }
1277
1278 fn on_osc_string(&mut self, b: u8) -> VTAction {
1280 use State::*;
1281 match b {
1282 CAN | SUB => {
1283 self.st = Ground;
1284 VTAction::Cancel(VTEmit::Osc)
1285 }
1286 DEL => VTAction::None,
1287 BEL => {
1288 self.st = Ground;
1289 VTAction::End(VTEnd::Osc { used_bel: true })
1290 }
1291 ESC => {
1292 self.st = OscEsc;
1293 VTAction::Hold(VTEmit::Osc)
1294 }
1295 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1296 _ => VTAction::None, }
1298 }
1299
1300 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1301 use State::*;
1302 match b {
1303 ST_FINAL => {
1304 self.st = Ground;
1305 VTAction::End(VTEnd::Osc { used_bel: false })
1306 } ESC => VTAction::Hold(VTEmit::Osc),
1308 DEL => VTAction::None,
1309 _ => {
1310 self.st = OscString;
1311 VTAction::Buffer(VTEmit::Osc)
1312 }
1313 }
1314 }
1315
1316 fn on_spa_string(&mut self, b: u8) -> VTAction {
1318 use State::*;
1319 match b {
1320 CAN | SUB => {
1321 self.st = Ground;
1322 VTAction::None
1323 }
1324 DEL => VTAction::None,
1325 ESC => {
1326 self.st = SpaEsc;
1327 VTAction::None
1328 }
1329 _ => VTAction::None,
1330 }
1331 }
1332
1333 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1334 use State::*;
1335 match b {
1336 ST_FINAL => {
1337 self.st = Ground;
1338 VTAction::None
1339 }
1340 DEL => VTAction::None,
1341 ESC => {
1342 VTAction::None
1344 }
1345 _ => {
1346 self.st = State::SosPmApcString;
1347 VTAction::None
1348 }
1349 }
1350 }
1351}
1352
1353#[cfg(test)]
1354mod tests {
1355 use crate::event::VTOwnedEvent;
1356
1357 use super::*;
1358 use pretty_assertions::assert_eq;
1359
1360 #[test]
1361 fn test_edge_cases() {
1362 let mut result = String::new();
1364 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1365 assert_eq!(result.trim(), "");
1366
1367 let mut result = String::new();
1369 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1370 assert_eq!(result.trim(), "");
1371
1372 let mut result = String::new();
1374 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1375 assert_eq!(result.trim(), "");
1376
1377 let mut result = String::new();
1379 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1380 assert_eq!(result.trim(), "");
1381
1382 let mut result = String::new();
1384 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1385 assert_eq!(result.trim(), "OscStart");
1386 }
1387
1388 #[test]
1389 fn test_streaming_behavior() {
1390 let mut parser = VTPushParser::new(); let mut result = String::new();
1393 let mut callback = |vt_input: VTEvent<'_>| {
1394 result.push_str(&format!("{vt_input:?}\n"));
1395 };
1396
1397 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1399 parser.feed_with(b"data", &mut callback);
1400 parser.feed_with(b" more", &mut callback);
1401 parser.feed_with(b"\x1b\\", &mut callback);
1402
1403 assert_eq!(
1404 result.trim(),
1405 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1406 );
1407 }
1408
1409 #[test]
1410 fn test_dcs_payload_passthrough() {
1411 let dcs_cases: &[(&[u8], &str)] = &[
1419 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1421 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1423 (
1425 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1426 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1427 ),
1428 (
1430 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1431 "ABC<ESC><ESC>DEF<ESC>XG",
1432 ),
1433 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1435 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1437 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1439 (
1441 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1442 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1443 ),
1444 (
1446 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1447 "<ESC>[58:2::000:007:042m",
1448 ),
1449 ];
1450
1451 for (input, expected_body) in dcs_cases {
1452 let events = collect_owned_events(input);
1453
1454 let mut actual_body = Vec::new();
1456 for event in &events {
1457 match event {
1458 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1459 actual_body.extend(data);
1460 }
1461 _ => {}
1462 }
1463 }
1464
1465 let actual_body = String::from_utf8(actual_body).unwrap();
1466 let actual_body = actual_body
1467 .replace("\x1b", "<ESC>")
1468 .replace("\x07", "<BEL>");
1469
1470 assert_eq!(
1471 actual_body, *expected_body,
1472 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1473 input, events
1474 );
1475 }
1476 }
1477
1478 fn collect_events(input: &[u8]) -> Vec<String> {
1479 let mut out = Vec::new();
1480 let mut p = VTPushParser::new();
1481 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1482 out
1483 }
1484
1485 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1486 let mut out = Vec::new();
1487 let mut p = VTPushParser::new();
1488 p.feed_with(input, &mut |ev| out.push(ev.to_owned()));
1489 out
1490 }
1491
1492 #[test]
1493 fn dcs_esc_esc_del() {
1494 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1496 eprintln!("{ev:?}");
1498 }
1499
1500 #[test]
1501 fn dcs_header_with_colon_is_ignored_case1() {
1502 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1504 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1506 }
1507
1508 #[test]
1509 fn dcs_header_with_colon_is_ignored_case2() {
1510 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1512 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1513 }
1514
1515 #[test]
1516 fn dcs_header_with_colon_is_ignored_case3() {
1517 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1519 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1520 }
1521
1522 #[test]
1523 fn osc_aborted_by_can_mid_body() {
1524 let mut s = Vec::new();
1526 s.extend_from_slice(b"\x1b]0;Title");
1527 s.push(CAN);
1528 s.extend_from_slice(b"more\x07");
1529
1530 let ev = collect_debug(&s);
1531
1532 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 #[test]
1542 fn osc_aborted_by_sub_before_terminator() {
1543 let mut s = Vec::new();
1544 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1545 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1549 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1553 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1554 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1555 }
1556
1557 fn collect_debug(input: &[u8]) -> Vec<String> {
1559 let mut out = Vec::new();
1560 let mut p = VTPushParser::new();
1561 p.feed_with(input, &mut |ev| out.push(format!("{ev:?}")));
1562 out
1563 }
1564
1565 #[test]
1566 fn dcs_aborted_by_can_before_body() {
1567 let mut s = Vec::new();
1569 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1571 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1574
1575 assert_eq!(ev.len(), 4, "{ev:#?}");
1576 assert_eq!(ev[0], "DcsStart('', q)");
1577 assert_eq!(ev[1], "DcsCancel");
1578 assert_eq!(ev[2], "Raw('IGNORED')");
1579 assert_eq!(ev[3], "Esc('', \\)");
1580 }
1581
1582 #[test]
1583 fn dcs_aborted_by_can_mid_body() {
1584 let mut s = Vec::new();
1586 s.extend_from_slice(b"\x1bPqABC");
1587 s.push(CAN);
1588 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1591
1592 assert_eq!(ev.len(), 4, "{ev:#?}");
1593 assert_eq!(ev[0], "DcsStart('', q)");
1594 assert_eq!(ev[1], "DcsCancel");
1595 assert_eq!(ev[2], "Raw('MORE')");
1596 assert_eq!(ev[3], "Esc('', \\)");
1597 }
1598
1599 #[test]
1602 fn spa_aborted_by_can_is_ignored() {
1603 let mut s = Vec::new();
1605 s.extend_from_slice(b"\x1b_hello");
1606 s.push(CAN);
1607 s.extend_from_slice(b"world\x1b\\");
1608
1609 let ev = collect_debug(&s);
1610 assert_eq!(ev.len(), 2, "{ev:#?}");
1611 assert_eq!(ev[0], "Raw('world')");
1612 assert_eq!(ev[1], "Esc('', \\)");
1613 }
1614
1615 #[test]
1616 fn spa_sub_aborts_too() {
1617 let mut s = Vec::new();
1618 s.extend_from_slice(b"\x1bXhello");
1619 s.push(SUB);
1620 s.extend_from_slice(b"world\x1b\\");
1621 let ev = collect_debug(&s);
1622 assert_eq!(ev.len(), 2, "{ev:#?}");
1623 assert_eq!(ev[0], "Raw('world')");
1624 assert_eq!(ev[1], "Esc('', \\)");
1625 }
1626
1627 #[test]
1630 fn can_in_ground_is_c0() {
1631 let mut s = Vec::new();
1632 s.extend_from_slice(b"abc");
1633 s.push(CAN);
1634 s.extend_from_slice(b"def");
1635 let ev = collect_debug(&s);
1636 assert_eq!(ev.len(), 3, "{ev:#?}");
1638 assert_eq!(ev[0], "Raw('abc')");
1639 assert_eq!(ev[1], "C0(18)");
1640 assert_eq!(ev[2], "Raw('def')");
1641 }
1642
1643 #[test]
1646 fn three_byte_sequences_capturable() {
1647 let mut bytes = vec![];
1648 for i in 0..=0xFFFFFF_u32 {
1649 bytes.clear();
1650 let test_bytes = i.to_le_bytes();
1651 let test_bytes = &test_bytes[..3];
1652 if test_bytes.iter().any(|b| b == &0) {
1653 continue;
1654 }
1655 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1656 continue;
1657 }
1658 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1659 continue;
1660 }
1661
1662 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1663 parser.feed_with(test_bytes, &mut |event| {
1664 let mut chunk = [0_u8; 3];
1665 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1666 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1667 });
1668 bytes.extend_from_slice(&chunk[..b]);
1669 });
1670 if let Some(event) = parser.idle() {
1671 let mut chunk = [0_u8; 3];
1672 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1673 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1674 });
1675 bytes.extend_from_slice(&chunk[..b]);
1676 }
1677
1678 if bytes.len() != 3 || bytes != test_bytes {
1679 eprintln!("Failed to parse:");
1680 parser.feed_with(test_bytes, &mut |event| {
1681 eprintln!("{event:?}");
1682 });
1683 if let Some(event) = parser.idle() {
1684 eprintln!("{event:?}");
1685 }
1686 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1687 }
1688 }
1689 }
1690}