diff options
| author | Kirill Chibisov <contact@kchibisov.com> | 2025-01-12 22:54:18 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-12 22:54:18 +0300 |
| commit | b3fba5651a264d164d840bfd4f8f0a30fa0b555b (patch) | |
| tree | 7063e6cd422f4f23b41a98a1e9ec29a4f5d10016 /src | |
| parent | c18ef2206af630f729835da237381628650005aa (diff) | |
| download | r-alacritty-vte-b3fba5651a264d164d840bfd4f8f0a30fa0b555b.tar.gz r-alacritty-vte-b3fba5651a264d164d840bfd4f8f0a30fa0b555b.tar.bz2 r-alacritty-vte-b3fba5651a264d164d840bfd4f8f0a30fa0b555b.zip | |
Rewrite table based state change to `match` based
The table based state change was too complex to make guesses why it's
getting slow and too fragile, as in modifying the amount of
states/actions were slowing down, even though, they were not used.
Rewrite the state + action change exactly how it's in [1] with respect
to our modifications/C1, etc. The new implementation is generally faster
than the previous one and is easier for compiler to reason about and
generate more efficient structures.
Also, the structure got way simpler to follow, since it matches the
spec pretty much exactly.
[1] - https://vt100.net/emu/dec_ansi_parser
Diffstat (limited to 'src')
| -rw-r--r-- | src/definitions.rs | 99 | ||||
| -rw-r--r-- | src/lib.rs | 540 | ||||
| -rw-r--r-- | src/table.rs | 188 |
3 files changed, 392 insertions, 435 deletions
diff --git a/src/definitions.rs b/src/definitions.rs deleted file mode 100644 index 694c783..0000000 --- a/src/definitions.rs +++ /dev/null @@ -1,99 +0,0 @@ -use core::mem; - -#[allow(dead_code)] -#[repr(u8)] -#[derive(PartialEq, Eq, Debug, Default, Copy, Clone)] -pub enum State { - CsiEntry, - CsiIgnore, - CsiIntermediate, - CsiParam, - DcsEntry, - DcsIgnore, - DcsIntermediate, - DcsParam, - DcsPassthrough, - Escape, - EscapeIntermediate, - OscString, - SosPmApcString, - Anywhere, - #[default] - Ground, -} - -// NOTE: Removing the unused actions prefixed with `_` will reduce performance. -#[allow(dead_code)] -#[repr(u8)] -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum Action { - None, - _Clear, - Collect, - CsiDispatch, - EscDispatch, - Execute, - _Hook, - _Ignore, - _OscEnd, - OscPut, - _OscStart, - Param, - _Print, - Put, - _Unhook, -} - -/// Unpack a u8 into a State and Action -/// -/// The implementation of this assumes that there are *precisely* 16 variants -/// for both Action and State. Furthermore, it assumes that the enums are -/// tag-only; that is, there is no data in any variant. -/// -/// Bad things will happen if those invariants are violated. -#[inline(always)] -pub fn unpack(delta: u8) -> (State, Action) { - unsafe { - ( - // State is stored in bottom 4 bits - mem::transmute::<u8, State>(delta & 0x0F), - // Action is stored in top 4 bits - mem::transmute::<u8, Action>(delta >> 4), - ) - } -} - -#[inline(always)] -pub const fn pack(state: State, action: Action) -> u8 { - (action as u8) << 4 | state as u8 -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn unpack_state_action() { - match unpack(0xEE) { - (State::Ground, Action::_Unhook) => (), - _ => panic!("unpack failed"), - } - - match unpack(0x0E) { - (State::Ground, Action::None) => (), - _ => panic!("unpack failed"), - } - - match unpack(0xE0) { - (State::CsiEntry, Action::_Unhook) => (), - _ => panic!("unpack failed"), - } - } - - #[test] - fn pack_state_action() { - assert_eq!(pack(State::Ground, Action::_Unhook), 0xEE); - assert_eq!(pack(State::Ground, Action::None), 0x0E); - assert_eq!(pack(State::CsiEntry, Action::_Unhook), 0xE0); - } -} @@ -35,13 +35,10 @@ use core::str; #[cfg(feature = "no_std")] use arrayvec::ArrayVec; -mod definitions; mod params; -mod table; #[cfg(feature = "ansi")] pub mod ansi; -use definitions::{unpack, Action, State}; pub use params::{Params, ParamsIter}; const MAX_INTERMEDIATES: usize = 2; @@ -113,7 +110,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { let mut i = 0; // Handle partial codepoints from previous calls to `advance`. - if self.partial_utf8_len > 0 { + if self.partial_utf8_len != 0 { i += self.advance_partial_utf8(performer, bytes); } @@ -121,12 +118,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { match self.state { State::Ground => i += self.advance_ground(performer, &bytes[i..]), _ => { + // Inlining it results in worse codegen. let byte = bytes[i]; - let change = table::STATE_CHANGES[self.state as usize][byte as usize]; - let (state, action) = unpack(change); - - self.perform_state_change(performer, state, action, byte); - + self.change_state(performer, byte); i += 1; }, } @@ -159,12 +153,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { match self.state { State::Ground => i += self.advance_ground(performer, &bytes[i..]), _ => { + // Inlining it results in worse codegen. let byte = bytes[i]; - let change = table::STATE_CHANGES[self.state as usize][byte as usize]; - let (state, action) = unpack(change); - - self.perform_state_change(performer, state, action, byte); - + self.change_state(performer, byte); i += 1; }, } @@ -173,164 +164,398 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { i } - #[inline] - fn perform_state_change<P>(&mut self, performer: &mut P, state: State, action: Action, byte: u8) - where - P: Perform, - { - if state == State::Anywhere { - self.perform_action(performer, action, byte); - return; + #[inline(always)] + fn change_state<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match self.state { + State::CsiEntry => self.advance_csi_entry(performer, byte), + State::CsiIgnore => self.advance_csi_ignore(performer, byte), + State::CsiIntermediate => self.advance_csi_intermediate(performer, byte), + State::CsiParam => self.advance_csi_param(performer, byte), + State::DcsEntry => self.advance_dcs_entry(performer, byte), + State::DcsIgnore => self.anywhere(performer, byte), + State::DcsIntermediate => self.advance_dcs_intermediate(performer, byte), + State::DcsParam => self.advance_dcs_param(performer, byte), + State::DcsPassthrough => self.advance_dcs_passthrough(performer, byte), + State::Escape => self.advance_esc(performer, byte), + State::EscapeIntermediate => self.advance_esc_intermediate(performer, byte), + State::OscString => self.advance_osc_string(performer, byte), + State::SosPmApcString => self.anywhere(performer, byte), + State::Ground => unreachable!(), } + } - match self.state { - State::DcsPassthrough => performer.unhook(), - State::OscString => { - let param_idx = self.osc_num_params; - let idx = self.osc_raw.len(); - - match param_idx { - // Finish last parameter if not already maxed - MAX_OSC_PARAMS => (), - - // First param is special - 0 to current byte index - 0 => { - self.osc_params[param_idx] = (0, idx); - self.osc_num_params += 1; - }, + #[inline(always)] + fn advance_csi_entry<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::CsiIntermediate + }, + 0x30..=0x39 => { + self.action_paramnext(byte); + self.state = State::CsiParam + }, + 0x3A => { + self.action_subparam(); + self.state = State::CsiParam + }, + 0x3B => { + self.action_param(); + self.state = State::CsiParam + }, + 0x3C..=0x3F => { + self.action_collect(byte); + self.state = State::CsiParam + }, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + _ => self.anywhere(performer, byte), + } + } - // All other params depend on previous indexing - _ => { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); - self.osc_num_params += 1; - }, - } - self.osc_dispatch(performer, byte); + #[inline(always)] + fn advance_csi_ignore<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x3F => (), + 0x40..=0x7E => self.state = State::Ground, + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_csi_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x3F => self.state = State::CsiIgnore, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_csi_param<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::CsiIntermediate }, - _ => (), + 0x30..=0x39 => self.action_paramnext(byte), + 0x3A => self.action_subparam(), + 0x3B => self.action_param(), + 0x3C..=0x3F => self.state = State::CsiIgnore, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), } + } - if action == Action::None { - match state { - State::CsiEntry | State::DcsEntry | State::Escape => self.reset_params(), - State::DcsPassthrough => { - if self.params.is_full() { - self.ignoring = true; - } else { - self.params.push(self.param); - } + #[inline(always)] + fn advance_dcs_entry<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::DcsIntermediate + }, + 0x30..=0x39 => { + self.action_paramnext(byte); + self.state = State::DcsParam + }, + 0x3A => { + self.action_subparam(); + self.state = State::DcsParam + }, + 0x3B => { + self.action_param(); + self.state = State::DcsParam + }, + 0x3C..=0x3F => { + self.action_collect(byte); + self.state = State::DcsParam + }, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } - performer.hook( - self.params(), - self.intermediates(), - self.ignoring, - byte as char, - ); - }, - State::OscString => { - self.osc_raw.clear(); - self.osc_num_params = 0; - }, - _ => (), - } - } else { - self.perform_action(performer, action, byte); + #[inline(always)] + fn advance_dcs_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x3F => self.state = State::DcsIgnore, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), } + } - self.state = state; + #[inline(always)] + fn advance_dcs_param<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::DcsIntermediate + }, + 0x30..=0x39 => self.action_paramnext(byte), + 0x3A => self.action_subparam(), + 0x3B => self.action_param(), + 0x3C..=0x3F => self.state = State::DcsIgnore, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), + } } - #[inline] - fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) { - match action { - Action::Execute => performer.execute(byte), - Action::Put => performer.put(byte), - Action::OscPut => { + #[inline(always)] + fn advance_dcs_passthrough<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x7E => performer.put(byte), + 0x18 | 0x1A => { + performer.unhook(); + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => { + performer.unhook(); + self.reset_params(); + self.state = State::Escape + }, + 0x7F => (), + 0x9C => { + performer.unhook(); + self.state = State::Ground + }, + _ => (), + } + } + + #[inline(always)] + fn advance_esc<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::EscapeIntermediate + }, + 0x30..=0x4F => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x50 => { + self.reset_params(); + self.state = State::DcsEntry + }, + 0x51..=0x57 => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x58 => self.state = State::SosPmApcString, + 0x59..=0x5A => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x5B => { + self.reset_params(); + self.state = State::CsiEntry + }, + 0x5C => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x5D => { + self.osc_raw.clear(); + self.osc_num_params = 0; + self.state = State::OscString + }, + 0x5E..=0x5F => self.state = State::SosPmApcString, + 0x60..=0x7E => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + // Anywhere. + 0x18 | 0x1A => { + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => (), + _ => (), + } + } + + #[inline(always)] + fn advance_esc_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x7E => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_osc_string<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x06 | 0x08..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x07 => { + self.osc_end(performer, byte); + self.state = State::Ground + }, + 0x18 | 0x1A => { + self.osc_end(performer, byte); + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => { + self.osc_end(performer, byte); + self.reset_params(); + self.state = State::Escape + }, + 0x3B => { #[cfg(feature = "no_std")] { if self.osc_raw.is_full() { return; } } - - let idx = self.osc_raw.len(); - - // Param separator - if byte == b';' { - let param_idx = self.osc_num_params; - match param_idx { - // Only process up to MAX_OSC_PARAMS - MAX_OSC_PARAMS => return, - - // First param is special - 0 to current byte index - 0 => { - self.osc_params[param_idx] = (0, idx); - }, - - // All other params depend on previous indexing - _ => { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); - }, - } - - self.osc_num_params += 1; - } else { - self.osc_raw.push(byte); - } + self.action_osc_put_param() }, - Action::CsiDispatch => { - if self.params.is_full() { - self.ignoring = true; - } else { - self.params.push(self.param); - } + _ => self.action_osc_put(byte), + } + } - performer.csi_dispatch( - self.params(), - self.intermediates(), - self.ignoring, - byte as char, - ); - }, - Action::EscDispatch => { - performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + #[inline(always)] + fn anywhere<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x18 | 0x1A => { + performer.execute(byte); + self.state = State::Ground }, - Action::Collect => { - if self.intermediate_idx == MAX_INTERMEDIATES { - self.ignoring = true; - } else { - self.intermediates[self.intermediate_idx] = byte; - self.intermediate_idx += 1; - } + 0x1B => { + self.reset_params(); + self.state = State::Escape }, - Action::Param => { - if self.params.is_full() { - self.ignoring = true; - return; - } + _ => (), + } + } - match byte { - b';' => { - self.params.push(self.param); - self.param = 0; - }, - b':' => { - self.params.extend(self.param); - self.param = 0; - }, - _ => { - // Continue collecting bytes into param - self.param = self.param.saturating_mul(10); - self.param = self.param.saturating_add((byte - b'0') as u16); - }, - } + #[inline] + fn action_csi_dispatch<P: Perform>(&mut self, performer: &mut P, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + performer.csi_dispatch(self.params(), self.intermediates(), self.ignoring, byte as char); + + self.state = State::Ground + } + + #[inline] + fn action_hook<P: Perform>(&mut self, performer: &mut P, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); + self.state = State::DcsPassthrough; + } + + #[inline] + fn action_collect(&mut self, byte: u8) { + if self.intermediate_idx == MAX_INTERMEDIATES { + self.ignoring = true; + } else { + self.intermediates[self.intermediate_idx] = byte; + self.intermediate_idx += 1; + } + } + + /// Advance to the next subparameter. + #[inline] + fn action_subparam(&mut self) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.extend(self.param); + self.param = 0; + } + } + + /// Advance to the next parameter. + #[inline] + fn action_param(&mut self) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + self.param = 0; + } + } + + /// Advance inside the parameter without terminating it. + #[inline] + fn action_paramnext(&mut self, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + // Continue collecting bytes into param. + self.param = self.param.saturating_mul(10); + self.param = self.param.saturating_add((byte - b'0') as u16); + } + } + + /// Add OSC param separator. + #[inline] + fn action_osc_put_param(&mut self) { + let idx = self.osc_raw.len(); + + let param_idx = self.osc_num_params; + match param_idx { + // First param is special - 0 to current byte index. + 0 => self.osc_params[param_idx] = (0, idx), + + // Only process up to MAX_OSC_PARAMS. + MAX_OSC_PARAMS => return, + + // All other params depend on previous indexing. + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); }, - _ => (), } + + self.osc_num_params += 1; + } + + #[inline(always)] + fn action_osc_put(&mut self, byte: u8) { + #[cfg(feature = "no_std")] + { + if self.osc_raw.is_full() { + return; + } + } + self.osc_raw.push(byte); + } + + fn osc_end<P: Perform>(&mut self, performer: &mut P, byte: u8) { + self.action_osc_put_param(); + self.osc_dispatch(performer, byte); + self.osc_raw.clear(); + self.osc_num_params = 0; } /// Reset escape sequence parameters and intermediates. @@ -504,6 +729,25 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { } } +#[derive(PartialEq, Eq, Debug, Default, Copy, Clone)] +enum State { + CsiEntry, + CsiIgnore, + CsiIntermediate, + CsiParam, + DcsEntry, + DcsIgnore, + DcsIntermediate, + DcsParam, + DcsPassthrough, + Escape, + EscapeIntermediate, + OscString, + SosPmApcString, + #[default] + Ground, +} + /// Performs actions requested by the Parser /// /// Actions in this case mean, for example, handling a CSI escape sequence diff --git a/src/table.rs b/src/table.rs deleted file mode 100644 index ac288e7..0000000 --- a/src/table.rs +++ /dev/null @@ -1,188 +0,0 @@ -use vte_generate_state_changes::generate_state_changes; - -/// This is the state change table. It's indexed first by current state and then -/// by the next character in the pty stream. -use crate::definitions::{pack, Action, State}; - -// Generate state changes at compile-time -pub const STATE_CHANGES: [[u8; 256]; 13] = state_changes(); -generate_state_changes!(state_changes, { - Escape { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x7f => (Anywhere, None), - 0x20..=0x2f => (EscapeIntermediate, Collect), - 0x30..=0x4f => (Ground, EscDispatch), - 0x51..=0x57 => (Ground, EscDispatch), - 0x59 => (Ground, EscDispatch), - 0x5a => (Ground, EscDispatch), - 0x5c => (Ground, EscDispatch), - 0x60..=0x7e => (Ground, EscDispatch), - 0x5b => (CsiEntry, None), - 0x5d => (OscString, None), - 0x50 => (DcsEntry, None), - 0x58 => (SosPmApcString, None), - 0x5e => (SosPmApcString, None), - 0x5f => (SosPmApcString, None), - }, - - EscapeIntermediate { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x20..=0x2f => (Anywhere, Collect), - 0x7f => (Anywhere, None), - 0x30..=0x7e => (Ground, EscDispatch), - }, - - CsiEntry { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x7f => (Anywhere, None), - 0x20..=0x2f => (CsiIntermediate, Collect), - 0x30..=0x39 => (CsiParam, Param), - 0x3a..=0x3b => (CsiParam, Param), - 0x3c..=0x3f => (CsiParam, Collect), - 0x40..=0x7e => (Ground, CsiDispatch), - }, - - CsiIgnore { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x20..=0x3f => (Anywhere, None), - 0x7f => (Anywhere, None), - 0x40..=0x7e => (Ground, None), - }, - - CsiParam { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x30..=0x39 => (Anywhere, Param), - 0x3a..=0x3b => (Anywhere, Param), - 0x7f => (Anywhere, None), - 0x3c..=0x3f => (CsiIgnore, None), - 0x20..=0x2f => (CsiIntermediate, Collect), - 0x40..=0x7e => (Ground, CsiDispatch), - }, - - CsiIntermediate { - 0x00..=0x17 => (Anywhere, Execute), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Execute), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Execute), - 0x20..=0x2f => (Anywhere, Collect), - 0x7f => (Anywhere, None), - 0x30..=0x3f => (CsiIgnore, None), - 0x40..=0x7e => (Ground, CsiDispatch), - }, - - DcsEntry { - 0x00..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x7f => (Anywhere, None), - 0x20..=0x2f => (DcsIntermediate, Collect), - 0x30..=0x39 => (DcsParam, Param), - 0x3a..=0x3b => (DcsParam, Param), - 0x3c..=0x3f => (DcsParam, Collect), - 0x40..=0x7e => (DcsPassthrough, None), - }, - - DcsIntermediate { - 0x00..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x20..=0x2f => (Anywhere, Collect), - 0x7f => (Anywhere, None), - 0x30..=0x3f => (DcsIgnore, None), - 0x40..=0x7e => (DcsPassthrough, None), - }, - - DcsIgnore { - 0x00..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x20..=0x7f => (Anywhere, None), - 0x9c => (Ground, None), - }, - - DcsParam { - 0x00..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x30..=0x39 => (Anywhere, Param), - 0x3a..=0x3b => (Anywhere, Param), - 0x7f => (Anywhere, None), - 0x3c..=0x3f => (DcsIgnore, None), - 0x20..=0x2f => (DcsIntermediate, Collect), - 0x40..=0x7e => (DcsPassthrough, None), - }, - - DcsPassthrough { - 0x00..=0x17 => (Anywhere, Put), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, Put), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, Put), - 0x20..=0x7e => (Anywhere, Put), - 0x7f => (Anywhere, None), - 0x9c => (Ground, None), - }, - - SosPmApcString { - 0x00..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x20..=0x7f => (Anywhere, None), - 0x9c => (Ground, None), - }, - - OscString { - 0x00..=0x06 => (Anywhere, None), - 0x07 => (Ground, None), - 0x08..=0x17 => (Anywhere, None), - 0x18 => (Ground, Execute), - 0x19 => (Anywhere, None), - 0x1a => (Ground, Execute), - 0x1b => (Escape, None), - 0x1c..=0x1f => (Anywhere, None), - 0x20..=0xff => (Anywhere, OscPut), - } -}); |