vt_push_parser/
event.rs

1use std::iter::Map;
2
3use crate::AsciiControl;
4
5#[derive(Default, Clone, Copy, PartialEq, Eq)]
6pub struct VTIntermediate {
7    data: [u8; 2],
8}
9
10impl VTIntermediate {
11    pub const fn empty() -> Self {
12        Self { data: [0, 0] }
13    }
14
15    pub const fn one(c: u8) -> Self {
16        assert!(c >= 0x20 && c <= 0x2F);
17        Self { data: [c, 0] }
18    }
19
20    pub const fn two(c1: u8, c2: u8) -> Self {
21        assert!(c1 >= 0x20 && c1 <= 0x2F);
22        assert!(c2 >= 0x20 && c2 <= 0x2F);
23        Self { data: [c1, c2] }
24    }
25
26    pub fn has(&self, c: u8) -> bool {
27        self.data[0] == c || self.data[1] == c
28    }
29
30    pub fn clear(&mut self) {
31        self.data[0] = 0;
32        self.data[1] = 0;
33    }
34
35    pub fn is_empty(&self) -> bool {
36        self.data[0] == 0 && self.data[1] == 0
37    }
38
39    pub fn len(&self) -> usize {
40        self.data.iter().filter(|&&c| c != 0).count()
41    }
42
43    #[must_use]
44    pub fn push(&mut self, c: u8) -> bool {
45        if c < 0x20 || c > 0x2F {
46            return false;
47        }
48
49        if self.data[0] == 0 {
50            self.data[0] = c;
51            true
52        } else if self.data[1] == 0 {
53            self.data[1] = c;
54            true
55        } else {
56            false
57        }
58    }
59
60    pub const fn const_eq(&self, other: &Self) -> bool {
61        self.data[0] == other.data[0] && self.data[1] == other.data[1]
62    }
63}
64
65impl std::fmt::Debug for VTIntermediate {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        // Inefficient
68        write!(f, "'")?;
69        for c in self.data.iter() {
70            if *c == 0 {
71                break;
72            }
73            write!(f, "{}", *c as char)?;
74        }
75        write!(f, "'")?;
76        Ok(())
77    }
78}
79
80#[derive(PartialEq, Eq)]
81#[repr(transparent)]
82pub struct ParamBuf<'a> {
83    pub(crate) params: &'a Vec<Vec<u8>>,
84}
85
86impl<'a> IntoIterator for ParamBuf<'a> {
87    type Item = &'a [u8];
88    type IntoIter = Map<std::slice::Iter<'a, Vec<u8>>, fn(&Vec<u8>) -> &[u8]>;
89    fn into_iter(self) -> Self::IntoIter {
90        self.params.iter().map(|p| p.as_slice())
91    }
92}
93
94impl<'b, 'a> IntoIterator for &'b ParamBuf<'a> {
95    type Item = &'a [u8];
96    type IntoIter = Map<std::slice::Iter<'a, Vec<u8>>, fn(&Vec<u8>) -> &[u8]>;
97    fn into_iter(self) -> Self::IntoIter {
98        self.params.iter().map(|p| p.as_slice())
99    }
100}
101
102impl<'a> ParamBuf<'a> {
103    pub fn len(&self) -> usize {
104        self.params.len()
105    }
106
107    pub fn is_empty(&self) -> bool {
108        self.params.is_empty()
109    }
110
111    pub fn to_owned(&self) -> ParamBufOwned {
112        ParamBufOwned {
113            params: self.params.iter().map(|p| p.to_vec()).collect(),
114        }
115    }
116}
117
118pub enum VTEvent<'a> {
119    // Plain printable text from GROUND (coalesced)
120    Raw(&'a [u8]),
121
122    // C0 control (EXECUTE)
123    C0(u8),
124
125    // ESC final (with intermediates)
126    Esc {
127        intermediates: VTIntermediate,
128        final_byte: u8,
129    },
130
131    // CSI short escape
132    Csi {
133        private: Option<u8>,
134        params: ParamBuf<'a>,
135        intermediates: VTIntermediate,
136        final_byte: u8,
137    },
138
139    // SS3 (ESC O …)
140    Ss3 {
141        intermediates: VTIntermediate,
142        final_byte: u8,
143    },
144
145    // DCS stream
146    DcsStart {
147        priv_prefix: Option<u8>,
148        params: ParamBuf<'a>,
149        intermediates: VTIntermediate,
150        final_byte: u8,
151    },
152    DcsData(&'a [u8]),
153    DcsEnd,
154    DcsCancel,
155
156    // OSC stream
157    OscStart,
158    OscData(&'a [u8]),
159    OscEnd {
160        used_bel: bool,
161    },
162    OscCancel,
163}
164
165impl<'a> std::fmt::Debug for VTEvent<'a> {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        use VTEvent::*;
168        match self {
169            Raw(s) => {
170                write!(f, "Raw('")?;
171                for chunk in s.utf8_chunks() {
172                    for c in chunk.valid().chars() {
173                        if let Ok(c) = AsciiControl::try_from(c) {
174                            write!(f, "{}", c)?;
175                        } else {
176                            write!(f, "{}", c)?;
177                        }
178                    }
179                    if !chunk.invalid().is_empty() {
180                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
181                    }
182                }
183                write!(f, "')")?;
184                Ok(())
185            }
186            C0(b) => write!(f, "C0({:02x})", b),
187            Esc {
188                intermediates,
189                final_byte,
190            } => {
191                write!(f, "Esc({:?}", intermediates)?;
192                write!(f, ", {})", *final_byte as char)?;
193                Ok(())
194            }
195            Csi {
196                private,
197                params,
198                intermediates,
199                final_byte,
200            } => {
201                write!(f, "Csi(")?;
202                if let Some(p) = private {
203                    write!(f, "{:?}", *p as char)?;
204                }
205                for param in params {
206                    write!(f, ", '")?;
207                    for chunk in param.utf8_chunks() {
208                        write!(f, "{}", chunk.valid())?;
209                        if !chunk.invalid().is_empty() {
210                            write!(f, "<{}>", hex::encode(chunk.invalid()))?;
211                        }
212                    }
213                    write!(f, "'")?;
214                }
215                write!(f, ", {:?}", intermediates)?;
216                write!(f, ", {:?})", *final_byte as char)?;
217                Ok(())
218            }
219            Ss3 {
220                intermediates,
221                final_byte,
222            } => {
223                write!(f, "Ss3(")?;
224                write!(f, "{:?}", intermediates)?;
225                write!(f, ", {})", *final_byte as char)?;
226                Ok(())
227            }
228            DcsStart {
229                priv_prefix,
230                params,
231                intermediates,
232                final_byte,
233            } => {
234                write!(f, "DcsStart(")?;
235                if let Some(p) = priv_prefix {
236                    write!(f, "{:?}", *p as char)?;
237                }
238                for param in params {
239                    write!(f, ", '")?;
240                    for chunk in param.utf8_chunks() {
241                        write!(f, "{}", chunk.valid())?;
242                        if !chunk.invalid().is_empty() {
243                            write!(f, "<{}>", hex::encode(chunk.invalid()))?;
244                        }
245                    }
246                    write!(f, "'")?;
247                }
248                write!(f, ", {:?}", intermediates)?;
249                write!(f, ", {})", *final_byte as char)?;
250                Ok(())
251            }
252            DcsData(s) => {
253                write!(f, "DcsData('")?;
254                for chunk in s.utf8_chunks() {
255                    for c in chunk.valid().chars() {
256                        if let Ok(c) = AsciiControl::try_from(c) {
257                            write!(f, "{}", c)?;
258                        } else {
259                            write!(f, "{}", c)?;
260                        }
261                    }
262                    if !chunk.invalid().is_empty() {
263                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
264                    }
265                }
266                write!(f, "')")?;
267                Ok(())
268            }
269            DcsEnd => write!(f, "DcsEnd"),
270            DcsCancel => write!(f, "DcsCancel"),
271            OscStart => write!(f, "OscStart"),
272            OscData(s) => {
273                write!(f, "OscData('")?;
274                for chunk in s.utf8_chunks() {
275                    for c in chunk.valid().chars() {
276                        if let Ok(c) = AsciiControl::try_from(c) {
277                            write!(f, "{}", c)?;
278                        } else {
279                            write!(f, "{}", c)?;
280                        }
281                    }
282                    if !chunk.invalid().is_empty() {
283                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
284                    }
285                }
286                write!(f, "')")?;
287                Ok(())
288            }
289            OscEnd { .. } => {
290                write!(f, "OscEnd")?;
291                Ok(())
292            }
293            OscCancel => write!(f, "OscCancel"),
294        }
295    }
296}
297
298impl<'a> VTEvent<'a> {
299    pub fn to_owned(&self) -> VTOwnedEvent {
300        use VTEvent::*;
301        match self {
302            Raw(s) => VTOwnedEvent::Raw(s.to_vec()),
303            C0(b) => VTOwnedEvent::C0(*b),
304            Esc {
305                intermediates,
306                final_byte,
307            } => VTOwnedEvent::Esc {
308                intermediates: intermediates.clone(),
309                final_byte: *final_byte,
310            },
311            Csi {
312                private,
313                params,
314                intermediates,
315                final_byte,
316            } => VTOwnedEvent::Csi {
317                private: private.clone(),
318                params: params.to_owned(),
319                intermediates: intermediates.clone(),
320                final_byte: *final_byte,
321            },
322            Ss3 {
323                intermediates,
324                final_byte,
325            } => VTOwnedEvent::Ss3 {
326                intermediates: intermediates.clone(),
327                final_byte: *final_byte,
328            },
329            DcsStart {
330                priv_prefix,
331                params,
332                intermediates,
333                final_byte,
334            } => VTOwnedEvent::DcsStart {
335                priv_prefix: priv_prefix.clone(),
336                params: params.to_owned(),
337                intermediates: intermediates.clone(),
338                final_byte: *final_byte,
339            },
340            DcsData(s) => VTOwnedEvent::DcsData(s.to_vec()),
341            DcsEnd => VTOwnedEvent::DcsEnd,
342            DcsCancel => VTOwnedEvent::DcsCancel,
343            OscStart => VTOwnedEvent::OscStart,
344            OscData(s) => VTOwnedEvent::OscData(s.to_vec()),
345            OscEnd { used_bel } => VTOwnedEvent::OscEnd {
346                used_bel: *used_bel,
347            },
348            OscCancel => VTOwnedEvent::OscCancel,
349        }
350    }
351}
352
353#[derive(Clone, PartialEq, Eq)]
354pub struct ParamBufOwned {
355    pub(crate) params: Vec<Vec<u8>>,
356}
357
358impl IntoIterator for ParamBufOwned {
359    type Item = Vec<u8>;
360    type IntoIter = std::vec::IntoIter<Vec<u8>>;
361    fn into_iter(self) -> Self::IntoIter {
362        self.params.into_iter()
363    }
364}
365
366impl<'b> IntoIterator for &'b ParamBufOwned {
367    type Item = &'b [u8];
368    type IntoIter = Map<std::slice::Iter<'b, Vec<u8>>, fn(&Vec<u8>) -> &[u8]>;
369    fn into_iter(self) -> Self::IntoIter {
370        self.params.iter().map(|p| p.as_slice())
371    }
372}
373
374impl ParamBufOwned {
375    pub fn len(&self) -> usize {
376        self.params.len()
377    }
378
379    pub fn is_empty(&self) -> bool {
380        self.params.is_empty()
381    }
382
383    pub fn borrow(&self) -> ParamBuf<'_> {
384        ParamBuf {
385            params: &self.params,
386        }
387    }
388}
389
390#[derive(Clone, PartialEq, Eq)]
391pub enum VTOwnedEvent {
392    Raw(Vec<u8>),
393    C0(u8),
394    Esc {
395        intermediates: VTIntermediate,
396        final_byte: u8,
397    },
398    Csi {
399        private: Option<u8>,
400        params: ParamBufOwned,
401        intermediates: VTIntermediate,
402        final_byte: u8,
403    },
404    Ss3 {
405        intermediates: VTIntermediate,
406        final_byte: u8,
407    },
408    DcsStart {
409        priv_prefix: Option<u8>,
410        params: ParamBufOwned,
411        intermediates: VTIntermediate,
412        final_byte: u8,
413    },
414    DcsData(Vec<u8>),
415    DcsEnd,
416    DcsCancel,
417    OscStart,
418    OscData(Vec<u8>),
419    OscEnd {
420        used_bel: bool,
421    },
422    OscCancel,
423}
424
425impl std::fmt::Debug for VTOwnedEvent {
426    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427        self.borrow().fmt(f)
428    }
429}
430
431impl VTOwnedEvent {
432    pub fn borrow(&self) -> VTEvent<'_> {
433        match self {
434            VTOwnedEvent::Raw(s) => VTEvent::Raw(s),
435            VTOwnedEvent::C0(b) => VTEvent::C0(*b),
436            VTOwnedEvent::Esc {
437                intermediates,
438                final_byte,
439            } => VTEvent::Esc {
440                intermediates: intermediates.clone(),
441                final_byte: *final_byte,
442            },
443            VTOwnedEvent::Csi {
444                private,
445                params,
446                intermediates,
447                final_byte,
448            } => VTEvent::Csi {
449                private: private.clone(),
450                params: params.borrow(),
451                intermediates: intermediates.clone(),
452                final_byte: *final_byte,
453            },
454            VTOwnedEvent::Ss3 {
455                intermediates,
456                final_byte,
457            } => VTEvent::Ss3 {
458                intermediates: intermediates.clone(),
459                final_byte: *final_byte,
460            },
461            VTOwnedEvent::DcsStart {
462                priv_prefix,
463                params,
464                intermediates,
465                final_byte,
466            } => VTEvent::DcsStart {
467                priv_prefix: priv_prefix.clone(),
468                params: params.borrow(),
469                intermediates: intermediates.clone(),
470                final_byte: *final_byte,
471            },
472            VTOwnedEvent::DcsData(s) => VTEvent::DcsData(s),
473            VTOwnedEvent::DcsEnd => VTEvent::DcsEnd,
474            VTOwnedEvent::DcsCancel => VTEvent::DcsCancel,
475            VTOwnedEvent::OscStart => VTEvent::OscStart,
476            VTOwnedEvent::OscData(s) => VTEvent::OscData(s),
477            VTOwnedEvent::OscEnd { used_bel } => VTEvent::OscEnd {
478                used_bel: *used_bel,
479            },
480            VTOwnedEvent::OscCancel => VTEvent::OscCancel,
481        }
482    }
483}