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 {
85 intermediates,
86 final_byte,
87 } => self.final_byte == *final_byte && self.intermediates.const_eq(intermediates),
88 VTEvent::Csi {
89 private,
90 params,
91 intermediates,
92 final_byte,
93 } => {
94 self.prefix == CSI
95 && self.final_byte == *final_byte
96 && self.intermediates.const_eq(intermediates)
97 && self.const_private_eq(private)
98 && self.const_contains(params.len())
99 }
100 VTEvent::DcsStart {
101 private,
102 params,
103 intermediates,
104 final_byte,
105 } => {
106 self.prefix == DCS
107 && self.final_byte == *final_byte
108 && self.intermediates.const_eq(intermediates)
109 && self.private == *private
110 && self.const_contains(params.len())
111 }
112 _ => false,
113 }
114 }
115
116 const fn const_private_eq(&self, other: &Option<u8>) -> bool {
117 match (self.private, other) {
118 (Some(a), Some(b)) => a == *b,
119 (None, None) => true,
120 _ => false,
121 }
122 }
123
124 fn const_contains(&self, len: usize) -> bool {
125 self.param_count.contains(&(len as u8))
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::VTPushParser;
134
135 const CURSOR_POSITION_REPORT: VTEscapeSignature =
136 VTEscapeSignature::csi(b'n').with_params_exact(2);
137
138 #[test]
139 fn test_matches() {
140 let input = b"\x1b[1;2n";
141 let mut found = false;
142 VTPushParser::decode_buffer(input, |event| {
143 assert!(!found);
144 found = true;
145 assert!(CURSOR_POSITION_REPORT.matches(&event));
146 });
147 assert!(found);
148 }
149}