vt_push_parser/
signature.rs1use std::ops::Range;
2
3use crate::event::{VTEvent, VTIntermediate};
4
5const CSI: u8 = b'[';
6const SS3: u8 = b'O';
7const DCS: u8 = b'P';
8const OSC: u8 = b']';
9
10pub struct VTEscapeSignature {
12 pub prefix: u8,
13 pub private: Option<u8>,
14 pub intermediates: VTIntermediate,
15 pub final_byte: u8,
16 pub param_count: Range<u8>,
17}
18
19impl VTEscapeSignature {
20 pub const fn with_private(self, private: u8) -> Self {
21 Self {
22 private: Some(private),
23 ..self
24 }
25 }
26
27 pub const fn with_intermediate(self, intermediate: u8) -> Self {
28 Self {
29 intermediates: VTIntermediate::one(intermediate),
30 ..self
31 }
32 }
33
34 pub const fn with_params_exact(self, param_count: u8) -> Self {
35 Self {
36 param_count: param_count..param_count + 1,
37 ..self
38 }
39 }
40
41 pub const fn csi(final_byte: u8) -> Self {
42 Self {
43 prefix: CSI,
44 final_byte,
45 param_count: 0..1,
46 intermediates: VTIntermediate::empty(),
47 private: None,
48 }
49 }
50
51 pub const fn ss3(final_byte: u8) -> Self {
52 Self {
53 prefix: SS3,
54 private: None,
55 intermediates: VTIntermediate::empty(),
56 final_byte,
57 param_count: 0..1,
58 }
59 }
60
61 pub const fn dcs(final_byte: u8) -> Self {
62 Self {
63 prefix: DCS,
64 private: None,
65 intermediates: VTIntermediate::empty(),
66 final_byte,
67 param_count: 0..1,
68 }
69 }
70
71 pub const fn osc(final_byte: u8) -> Self {
72 Self {
73 prefix: OSC,
74 private: None,
75 intermediates: VTIntermediate::empty(),
76 final_byte,
77 param_count: 0..1,
78 }
79 }
80
81 pub fn matches(&self, entry: &VTEvent) -> bool {
82 match entry {
84 VTEvent::Esc(esc) => {
85 self.final_byte == esc.final_byte && self.intermediates.const_eq(&esc.intermediates)
86 }
87 VTEvent::Csi(csi) => {
88 self.prefix == CSI
89 && self.final_byte == csi.final_byte
90 && self.intermediates.const_eq(&csi.intermediates)
91 && self.const_private_eq(&csi.private)
92 && self.const_contains(csi.params.len())
93 }
94 VTEvent::DcsStart(dcs_start) => {
95 self.prefix == DCS
96 && self.final_byte == dcs_start.final_byte
97 && self.intermediates.const_eq(&dcs_start.intermediates)
98 && self.private == dcs_start.private
99 && self.const_contains(dcs_start.params.len())
100 }
101 _ => false,
102 }
103 }
104
105 const fn const_private_eq(&self, other: &Option<u8>) -> bool {
106 match (self.private, other) {
107 (Some(a), Some(b)) => a == *b,
108 (None, None) => true,
109 _ => false,
110 }
111 }
112
113 fn const_contains(&self, len: usize) -> bool {
114 self.param_count.contains(&(len as u8))
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::VTPushParser;
123
124 const CURSOR_POSITION_REPORT: VTEscapeSignature =
125 VTEscapeSignature::csi(b'n').with_params_exact(2);
126
127 #[test]
128 fn test_matches() {
129 let input = b"\x1b[1;2n";
130 let mut found = false;
131 VTPushParser::decode_buffer(input, |event| {
132 assert!(!found);
133 found = true;
134 assert!(CURSOR_POSITION_REPORT.matches(&event));
135 });
136 assert!(found);
137 }
138}