vt_push_parser/
event.rs

1use std::iter::Map;
2
3use smallvec::SmallVec;
4
5use crate::{AsciiControl, BEL, CAN, CSI, DCS, ESC, OSC, ST_FINAL};
6
7#[derive(Default, Clone, Copy, PartialEq, Eq)]
8pub struct VTIntermediate {
9    data: [u8; 2],
10}
11
12impl VTIntermediate {
13    pub const fn empty() -> Self {
14        Self { data: [0, 0] }
15    }
16
17    pub const fn one(c: u8) -> Self {
18        assert!(c >= 0x20 && c <= 0x2F);
19        Self { data: [c, 0] }
20    }
21
22    pub const fn two(c1: u8, c2: u8) -> Self {
23        assert!(c1 >= 0x20 && c1 <= 0x2F);
24        assert!(c2 >= 0x20 && c2 <= 0x2F);
25        Self { data: [c1, c2] }
26    }
27
28    pub fn has(&self, c: u8) -> bool {
29        self.data[0] == c || self.data[1] == c
30    }
31
32    pub fn clear(&mut self) {
33        self.data[0] = 0;
34        self.data[1] = 0;
35    }
36
37    pub fn is_empty(&self) -> bool {
38        self.data[0] == 0 && self.data[1] == 0
39    }
40
41    pub fn len(&self) -> usize {
42        self.data.iter().filter(|&&c| c != 0).count()
43    }
44
45    #[must_use]
46    pub fn push(&mut self, c: u8) -> bool {
47        if c < 0x20 || c > 0x2F {
48            return false;
49        }
50
51        // Invalid duplicate intermediate
52        if self.data[0] == c {
53            return false;
54        }
55
56        if self.data[0] == 0 {
57            self.data[0] = c;
58            true
59        } else if self.data[1] == 0 {
60            self.data[1] = c;
61            true
62        } else {
63            false
64        }
65    }
66
67    pub const fn const_eq(&self, other: &Self) -> bool {
68        self.data[0] == other.data[0] && self.data[1] == other.data[1]
69    }
70
71    pub fn byte_len(&self) -> usize {
72        self.data.iter().filter(|&&c| c != 0).count()
73    }
74}
75
76impl std::fmt::Debug for VTIntermediate {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        // Inefficient
79        write!(f, "'")?;
80        for c in self.data.iter() {
81            if *c == 0 {
82                break;
83            }
84            write!(f, "{}", *c as char)?;
85        }
86        write!(f, "'")?;
87        Ok(())
88    }
89}
90
91pub(crate) type Param = SmallVec<[u8; 32]>;
92pub(crate) type Params = SmallVec<[Param; 8]>;
93
94#[derive(PartialEq, Eq)]
95#[repr(transparent)]
96pub struct ParamBuf<'a> {
97    pub(crate) params: &'a Params,
98}
99
100impl<'a> IntoIterator for ParamBuf<'a> {
101    type Item = &'a [u8];
102    type IntoIter = Map<std::slice::Iter<'a, Param>, fn(&Param) -> &[u8]>;
103    fn into_iter(self) -> Self::IntoIter {
104        self.params.iter().map(|p| p.as_slice())
105    }
106}
107
108impl<'b, 'a> IntoIterator for &'b ParamBuf<'a> {
109    type Item = &'a [u8];
110    type IntoIter = Map<std::slice::Iter<'a, Param>, fn(&Param) -> &[u8]>;
111    fn into_iter(self) -> Self::IntoIter {
112        self.params.iter().map(|p| p.as_slice())
113    }
114}
115
116impl<'a> ParamBuf<'a> {
117    pub fn len(&self) -> usize {
118        self.params.len()
119    }
120
121    pub fn is_empty(&self) -> bool {
122        self.params.is_empty()
123    }
124
125    pub fn get(&self, index: usize) -> Option<&[u8]> {
126        self.params.get(index).map(|p| p.as_slice())
127    }
128
129    pub fn try_parse<T: std::str::FromStr>(&self, index: usize) -> Option<T> {
130        self.params.get(index).and_then(|p| {
131            std::str::from_utf8(p.as_slice())
132                .ok()
133                .and_then(|s| s.parse::<T>().ok())
134        })
135    }
136
137    pub fn to_owned(&self) -> ParamBufOwned {
138        ParamBufOwned {
139            params: self.params.iter().map(|p| p.clone()).collect(),
140        }
141    }
142
143    pub fn byte_len(&self) -> usize {
144        self.params.iter().map(|p| p.len()).sum::<usize>() + self.params.len().saturating_sub(1)
145    }
146}
147
148pub enum VTEvent<'a> {
149    // Plain printable text from GROUND (coalesced)
150    Raw(&'a [u8]),
151
152    // C0 control (EXECUTE)
153    C0(u8),
154
155    // ESC final (with intermediates)
156    Esc {
157        intermediates: VTIntermediate,
158        final_byte: u8,
159    },
160
161    // CSI short escape
162    Csi {
163        private: Option<u8>,
164        params: ParamBuf<'a>,
165        intermediates: VTIntermediate,
166        final_byte: u8,
167    },
168
169    // DCS stream
170    DcsStart {
171        private: Option<u8>,
172        params: ParamBuf<'a>,
173        intermediates: VTIntermediate,
174        final_byte: u8,
175    },
176    DcsData(&'a [u8]),
177    DcsEnd,
178    DcsCancel,
179
180    // OSC stream
181    OscStart,
182    OscData(&'a [u8]),
183    OscEnd {
184        /// Whether the BEL was used to end the OSC stream.
185        used_bel: bool,
186    },
187    OscCancel,
188}
189
190impl<'a> std::fmt::Debug for VTEvent<'a> {
191    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192        use VTEvent::*;
193        match self {
194            Raw(s) => {
195                write!(f, "Raw('")?;
196                for chunk in s.utf8_chunks() {
197                    for c in chunk.valid().chars() {
198                        if let Ok(c) = AsciiControl::try_from(c) {
199                            write!(f, "{}", c)?;
200                        } else {
201                            write!(f, "{}", c)?;
202                        }
203                    }
204                    if !chunk.invalid().is_empty() {
205                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
206                    }
207                }
208                write!(f, "')")?;
209                Ok(())
210            }
211            C0(b) => write!(f, "C0({:02x})", b),
212            Esc {
213                intermediates,
214                final_byte,
215            } => {
216                write!(f, "Esc({:?}", intermediates)?;
217                write!(f, ", {})", *final_byte as char)?;
218                Ok(())
219            }
220            Csi {
221                private,
222                params,
223                intermediates,
224                final_byte,
225            } => {
226                write!(f, "Csi(")?;
227                if let Some(p) = private {
228                    write!(f, "{:?}", *p as char)?;
229                }
230                for param in params {
231                    write!(f, ", '")?;
232                    for chunk in param.utf8_chunks() {
233                        write!(f, "{}", chunk.valid())?;
234                        if !chunk.invalid().is_empty() {
235                            write!(f, "<{}>", hex::encode(chunk.invalid()))?;
236                        }
237                    }
238                    write!(f, "'")?;
239                }
240                write!(f, ", {:?}", intermediates)?;
241                write!(f, ", {:?})", *final_byte as char)?;
242                Ok(())
243            }
244            DcsStart {
245                private,
246                params,
247                intermediates,
248                final_byte,
249            } => {
250                write!(f, "DcsStart(")?;
251                if let Some(p) = private {
252                    write!(f, "{:?}", *p as char)?;
253                }
254                for param in params {
255                    write!(f, ", '")?;
256                    for chunk in param.utf8_chunks() {
257                        write!(f, "{}", chunk.valid())?;
258                        if !chunk.invalid().is_empty() {
259                            write!(f, "<{}>", hex::encode(chunk.invalid()))?;
260                        }
261                    }
262                    write!(f, "'")?;
263                }
264                write!(f, ", {:?}", intermediates)?;
265                write!(f, ", {})", *final_byte as char)?;
266                Ok(())
267            }
268            DcsData(s) => {
269                write!(f, "DcsData('")?;
270                for chunk in s.utf8_chunks() {
271                    for c in chunk.valid().chars() {
272                        if let Ok(c) = AsciiControl::try_from(c) {
273                            write!(f, "{}", c)?;
274                        } else {
275                            write!(f, "{}", c)?;
276                        }
277                    }
278                    if !chunk.invalid().is_empty() {
279                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
280                    }
281                }
282                write!(f, "')")?;
283                Ok(())
284            }
285            DcsEnd => write!(f, "DcsEnd"),
286            DcsCancel => write!(f, "DcsCancel"),
287            OscStart => write!(f, "OscStart"),
288            OscData(s) => {
289                write!(f, "OscData('")?;
290                for chunk in s.utf8_chunks() {
291                    for c in chunk.valid().chars() {
292                        if let Ok(c) = AsciiControl::try_from(c) {
293                            write!(f, "{}", c)?;
294                        } else {
295                            write!(f, "{}", c)?;
296                        }
297                    }
298                    if !chunk.invalid().is_empty() {
299                        write!(f, "<{}>", hex::encode(chunk.invalid()))?;
300                    }
301                }
302                write!(f, "')")?;
303                Ok(())
304            }
305            OscEnd { .. } => {
306                write!(f, "OscEnd")?;
307                Ok(())
308            }
309            OscCancel => write!(f, "OscCancel"),
310        }
311    }
312}
313
314impl<'a> VTEvent<'a> {
315    pub fn byte_len(&self) -> usize {
316        use VTEvent::*;
317        let len = match self {
318            Raw(s) => s.len(),
319            C0(_) => 1,
320            Esc { intermediates, .. } => intermediates.len() + 2,
321            Csi {
322                private,
323                params,
324                intermediates,
325                ..
326            } => private.is_some() as usize + params.byte_len() + intermediates.byte_len() + 3,
327            DcsStart {
328                private,
329                params,
330                intermediates,
331                ..
332            } => private.is_some() as usize + params.byte_len() + intermediates.byte_len() + 3,
333            DcsData(s) => s.len(),
334            DcsEnd => 2,
335            DcsCancel => 1,
336            OscStart => 2,
337            OscData(s) => s.len(),
338            OscEnd { used_bel } => {
339                if *used_bel {
340                    1
341                } else {
342                    2
343                }
344            }
345            OscCancel => 1,
346        };
347        len
348    }
349
350    /// Encode the event into the provided buffer, returning the number of bytes
351    /// required for the escape sequence in either `Ok(n)` or `Err(n)`.
352    ///
353    /// Note that some events may have multiple possible encodings, so this method
354    /// may decide to choose whichever is more efficient.
355    pub fn encode(&self, mut buf: &mut [u8]) -> Result<usize, usize> {
356        use VTEvent::*;
357        let len = self.byte_len();
358
359        if len > buf.len() {
360            return Err(len);
361        }
362
363        match self {
364            Raw(s) | OscData(s) | DcsData(s) => {
365                buf[..s.len()].copy_from_slice(s);
366            }
367            OscCancel | DcsCancel => {
368                buf[0] = CAN;
369            }
370            C0(b) => {
371                buf[0] = *b;
372            }
373            Esc {
374                intermediates,
375                final_byte,
376            } => {
377                buf[0] = ESC;
378                buf[1..intermediates.len() + 1]
379                    .copy_from_slice(&intermediates.data[..intermediates.len()]);
380                buf[intermediates.len() + 1] = *final_byte;
381            }
382            Csi {
383                private,
384                params,
385                intermediates,
386                final_byte,
387            } => {
388                buf[0] = ESC;
389                buf[1] = CSI;
390                buf = &mut buf[2..];
391                if let Some(p) = private {
392                    buf[0] = *p;
393                    buf = &mut buf[1..];
394                }
395                let mut params = params.into_iter();
396                if let Some(param) = params.next() {
397                    buf[..param.len()].copy_from_slice(param);
398                    buf = &mut buf[param.len()..];
399                    for param in params {
400                        buf[0] = b';';
401                        buf = &mut buf[1..];
402                        buf[..param.len()].copy_from_slice(param);
403                        buf = &mut buf[param.len()..];
404                    }
405                }
406                buf[..intermediates.len()]
407                    .copy_from_slice(&intermediates.data[..intermediates.len()]);
408                buf[intermediates.len()] = *final_byte;
409            }
410            DcsStart {
411                private,
412                params,
413                intermediates,
414                final_byte,
415            } => {
416                buf[0] = ESC;
417                buf[1] = DCS;
418                buf = &mut buf[2..];
419                if let Some(p) = private {
420                    buf[0] = *p;
421                    buf = &mut buf[1..];
422                }
423                let mut params = params.into_iter();
424                if let Some(param) = params.next() {
425                    buf[..param.len()].copy_from_slice(param);
426                    buf = &mut buf[param.len()..];
427                    for param in params {
428                        buf[0] = b';';
429                        buf = &mut buf[1..];
430                        buf[..param.len()].copy_from_slice(param);
431                        buf = &mut buf[param.len()..];
432                    }
433                }
434                buf[..intermediates.len()]
435                    .copy_from_slice(&intermediates.data[..intermediates.len()]);
436                buf[intermediates.len()] = *final_byte;
437            }
438            DcsEnd => {
439                buf[0] = ESC;
440                buf[1] = ST_FINAL;
441            }
442            OscStart => {
443                buf[0] = ESC;
444                buf[1] = OSC;
445            }
446            OscEnd { used_bel } => {
447                if *used_bel {
448                    buf[0] = BEL;
449                } else {
450                    buf[0] = ESC;
451                    buf[1] = ST_FINAL
452                }
453            }
454        }
455
456        Ok(len)
457    }
458
459    pub fn to_owned(&self) -> VTOwnedEvent {
460        use VTEvent::*;
461        match self {
462            Raw(s) => VTOwnedEvent::Raw(s.to_vec()),
463            C0(b) => VTOwnedEvent::C0(*b),
464            Esc {
465                intermediates,
466                final_byte,
467            } => VTOwnedEvent::Esc {
468                intermediates: intermediates.clone(),
469                final_byte: *final_byte,
470            },
471            Csi {
472                private,
473                params,
474                intermediates,
475                final_byte,
476            } => VTOwnedEvent::Csi {
477                private: private.clone(),
478                params: params.to_owned(),
479                intermediates: intermediates.clone(),
480                final_byte: *final_byte,
481            },
482            DcsStart {
483                private,
484                params,
485                intermediates,
486                final_byte,
487            } => VTOwnedEvent::DcsStart {
488                private: private.clone(),
489                params: params.to_owned(),
490                intermediates: intermediates.clone(),
491                final_byte: *final_byte,
492            },
493            DcsData(s) => VTOwnedEvent::DcsData(s.to_vec()),
494            DcsEnd => VTOwnedEvent::DcsEnd,
495            DcsCancel => VTOwnedEvent::DcsCancel,
496            OscStart => VTOwnedEvent::OscStart,
497            OscData(s) => VTOwnedEvent::OscData(s.to_vec()),
498            OscEnd { used_bel } => VTOwnedEvent::OscEnd {
499                used_bel: *used_bel,
500            },
501            OscCancel => VTOwnedEvent::OscCancel,
502        }
503    }
504}
505
506#[derive(Clone, PartialEq, Eq)]
507pub struct ParamBufOwned {
508    pub(crate) params: Params,
509}
510
511impl IntoIterator for ParamBufOwned {
512    type Item = Param;
513    type IntoIter = <Params as IntoIterator>::IntoIter;
514    fn into_iter(self) -> Self::IntoIter {
515        self.params.into_iter()
516    }
517}
518
519impl<'b> IntoIterator for &'b ParamBufOwned {
520    type Item = &'b [u8];
521    type IntoIter = Map<std::slice::Iter<'b, Param>, fn(&Param) -> &[u8]>;
522    fn into_iter(self) -> Self::IntoIter {
523        self.params.iter().map(|p| p.as_slice())
524    }
525}
526
527impl ParamBufOwned {
528    pub fn len(&self) -> usize {
529        self.params.len()
530    }
531
532    pub fn is_empty(&self) -> bool {
533        self.params.is_empty()
534    }
535
536    pub fn get(&self, index: usize) -> Option<&[u8]> {
537        self.params.get(index).map(|p| p.as_slice())
538    }
539
540    pub fn try_parse<T: std::str::FromStr>(&self, index: usize) -> Option<T> {
541        self.params.get(index).and_then(|p| {
542            std::str::from_utf8(p.as_slice())
543                .ok()
544                .and_then(|s| s.parse::<T>().ok())
545        })
546    }
547
548    pub fn borrow(&self) -> ParamBuf<'_> {
549        ParamBuf {
550            params: &self.params,
551        }
552    }
553}
554
555#[derive(Clone, PartialEq, Eq)]
556pub enum VTOwnedEvent {
557    Raw(Vec<u8>),
558    C0(u8),
559    Esc {
560        intermediates: VTIntermediate,
561        final_byte: u8,
562    },
563    Csi {
564        private: Option<u8>,
565        params: ParamBufOwned,
566        intermediates: VTIntermediate,
567        final_byte: u8,
568    },
569    DcsStart {
570        private: Option<u8>,
571        params: ParamBufOwned,
572        intermediates: VTIntermediate,
573        final_byte: u8,
574    },
575    DcsData(Vec<u8>),
576    DcsEnd,
577    DcsCancel,
578    OscStart,
579    OscData(Vec<u8>),
580    OscEnd {
581        used_bel: bool,
582    },
583    OscCancel,
584}
585
586impl std::fmt::Debug for VTOwnedEvent {
587    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
588        self.borrow().fmt(f)
589    }
590}
591
592impl VTOwnedEvent {
593    pub fn borrow(&self) -> VTEvent<'_> {
594        match self {
595            VTOwnedEvent::Raw(s) => VTEvent::Raw(s),
596            VTOwnedEvent::C0(b) => VTEvent::C0(*b),
597            VTOwnedEvent::Esc {
598                intermediates,
599                final_byte,
600            } => VTEvent::Esc {
601                intermediates: intermediates.clone(),
602                final_byte: *final_byte,
603            },
604            VTOwnedEvent::Csi {
605                private,
606                params,
607                intermediates,
608                final_byte,
609            } => VTEvent::Csi {
610                private: private.clone(),
611                params: params.borrow(),
612                intermediates: intermediates.clone(),
613                final_byte: *final_byte,
614            },
615            VTOwnedEvent::DcsStart {
616                private,
617                params,
618                intermediates,
619                final_byte,
620            } => VTEvent::DcsStart {
621                private: private.clone(),
622                params: params.borrow(),
623                intermediates: intermediates.clone(),
624                final_byte: *final_byte,
625            },
626            VTOwnedEvent::DcsData(s) => VTEvent::DcsData(s),
627            VTOwnedEvent::DcsEnd => VTEvent::DcsEnd,
628            VTOwnedEvent::DcsCancel => VTEvent::DcsCancel,
629            VTOwnedEvent::OscStart => VTEvent::OscStart,
630            VTOwnedEvent::OscData(s) => VTEvent::OscData(s),
631            VTOwnedEvent::OscEnd { used_bel } => VTEvent::OscEnd {
632                used_bel: *used_bel,
633            },
634            VTOwnedEvent::OscCancel => VTEvent::OscCancel,
635        }
636    }
637}