aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml4
-rw-r--r--src/definitions.rs99
-rw-r--r--src/lib.rs540
-rw-r--r--src/table.rs188
-rw-r--r--vte_generate_state_changes/Cargo.toml15
l---------vte_generate_state_changes/LICENSE-APACHE1
l---------vte_generate_state_changes/LICENSE-MIT1
-rw-r--r--vte_generate_state_changes/src/lib.rs176
8 files changed, 392 insertions, 632 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 629057d..bdaa8c6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,9 +13,6 @@ name = "vte"
edition = "2021"
rust-version = "1.62.1"
-[workspace]
-members = ["vte_generate_state_changes"]
-
[features]
ansi = ["log", "cursor-icon", "bitflags"]
default = ["no_std"]
@@ -29,4 +26,3 @@ cursor-icon = { version = "1.0.0", default-features = false, optional = true }
log = { version = "0.4.17", optional = true }
memchr = "2.7.4"
serde = { version = "1.0.160", features = ["derive"], optional = true }
-vte_generate_state_changes = { version = "0.2.0", path = "vte_generate_state_changes" }
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);
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
index 1f229a3..55fa676 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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),
- }
-});
diff --git a/vte_generate_state_changes/Cargo.toml b/vte_generate_state_changes/Cargo.toml
deleted file mode 100644
index dd0e714..0000000
--- a/vte_generate_state_changes/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-authors = ["Christian Duerr <contact@christianduerr.com>"]
-description = "Proc macro for generating VTE state changes"
-repository = "https://github.com/alacritty/vte"
-name = "vte_generate_state_changes"
-license = "Apache-2.0 OR MIT"
-version = "0.2.0"
-edition = "2018"
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = "1.0.6"
-quote = "1.0.2"
diff --git a/vte_generate_state_changes/LICENSE-APACHE b/vte_generate_state_changes/LICENSE-APACHE
deleted file mode 120000
index 965b606..0000000
--- a/vte_generate_state_changes/LICENSE-APACHE
+++ /dev/null
@@ -1 +0,0 @@
-../LICENSE-APACHE \ No newline at end of file
diff --git a/vte_generate_state_changes/LICENSE-MIT b/vte_generate_state_changes/LICENSE-MIT
deleted file mode 120000
index 76219eb..0000000
--- a/vte_generate_state_changes/LICENSE-MIT
+++ /dev/null
@@ -1 +0,0 @@
-../LICENSE-MIT \ No newline at end of file
diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs
deleted file mode 100644
index ff8ea49..0000000
--- a/vte_generate_state_changes/src/lib.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]
-
-extern crate proc_macro;
-
-use std::iter::Peekable;
-
-use proc_macro2::TokenTree::{Group, Literal, Punct};
-use proc_macro2::{token_stream, TokenStream, TokenTree};
-use quote::quote;
-
-/// Create a `const fn` which will return an array with all state changes.
-#[proc_macro]
-pub fn generate_state_changes(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
- // Convert from proc_macro -> proc_macro2
- let item: TokenStream = item.into();
- let mut iter = item.into_iter().peekable();
-
- // Determine output function name
- let fn_name = iter.next().unwrap();
-
- // Separator between name and body with state changes
- expect_punct(&mut iter, ',');
-
- // Create token stream to assign each state change to the array
- let assignments_stream = states_stream(&mut iter);
-
- quote!(
- const fn #fn_name() -> [[u8; 256]; 13] {
- let mut state_changes = [[0; 256]; 13];
-
- #assignments_stream
-
- state_changes
- }
- )
- .into()
-}
-
-/// Generate the array assignment statements for all origin states.
-fn states_stream(iter: &mut impl Iterator<Item = TokenTree>) -> TokenStream {
- let mut states_stream = next_group(iter).into_iter().peekable();
-
- // Loop over all origin state entries
- let mut tokens = quote!();
- while states_stream.peek().is_some() {
- // Add all mappings for this state
- tokens.extend(state_entry_stream(&mut states_stream));
-
- // Allow trailing comma
- optional_punct(&mut states_stream, ',');
- }
- tokens
-}
-
-/// Generate the array assignment statements for one origin state.
-fn state_entry_stream(iter: &mut Peekable<token_stream::IntoIter>) -> TokenStream {
- // Origin state name
- let state = iter.next().unwrap();
-
- // Token stream with all the byte->target mappings
- let mut changes_stream = next_group(iter).into_iter().peekable();
-
- let mut tokens = quote!();
- while changes_stream.peek().is_some() {
- // Add next mapping for this state
- tokens.extend(change_stream(&mut changes_stream, &state));
-
- // Allow trailing comma
- optional_punct(&mut changes_stream, ',');
- }
- tokens
-}
-
-/// Generate the array assignment statement for a single byte->target mapping
-/// for one state.
-fn change_stream(iter: &mut Peekable<token_stream::IntoIter>, state: &TokenTree) -> TokenStream {
- // Start of input byte range
- let start = next_usize(iter);
-
- // End of input byte range
- let end = if optional_punct(iter, '.') {
- // Read inclusive end of range
- expect_punct(iter, '.');
- expect_punct(iter, '=');
- next_usize(iter)
- } else {
- // Without range, end is equal to start
- start
- };
-
- // Separator between byte input range and output state
- expect_punct(iter, '=');
- expect_punct(iter, '>');
-
- // Token stream with target state and action
- let mut target_change_stream = next_group(iter).into_iter().peekable();
-
- let mut tokens = quote!();
- while target_change_stream.peek().is_some() {
- // Target state/action for all bytes in the range
- let (target_state, target_action) = target_change(&mut target_change_stream);
-
- // Create a new entry for every byte in the range
- for byte in start..=end {
- tokens.extend(quote!(
- state_changes[State::#state as usize][#byte] =
- pack(State::#target_state, Action::#target_action);
- ));
- }
- }
- tokens
-}
-
-/// Get next target state and action.
-fn target_change(iter: &mut Peekable<token_stream::IntoIter>) -> (TokenTree, TokenTree) {
- let target_state = iter.next().unwrap();
-
- // Separator between state and action
- expect_punct(iter, ',');
-
- let target_action = iter.next().unwrap();
-
- (target_state, target_action)
-}
-
-/// Check if next token matches specific punctuation.
-fn optional_punct(iter: &mut Peekable<token_stream::IntoIter>, c: char) -> bool {
- match iter.peek() {
- Some(Punct(punct)) if punct.as_char() == c => iter.next().is_some(),
- _ => false,
- }
-}
-
-/// Ensure next token matches specific punctuation.
-///
-/// # Panics
-///
-/// Panics if the punctuation does not match.
-fn expect_punct(iter: &mut impl Iterator<Item = TokenTree>, c: char) {
- match iter.next() {
- Some(Punct(ref punct)) if punct.as_char() == c => (),
- token => panic!("Expected punctuation '{}', but got {:?}", c, token),
- }
-}
-
-/// Get next token as [`usize`].
-///
-/// # Panics
-///
-/// Panics if the next token is not a [`usize`] in hex or decimal literal
-/// format.
-fn next_usize(iter: &mut impl Iterator<Item = TokenTree>) -> usize {
- match iter.next() {
- Some(Literal(literal)) => {
- let literal = literal.to_string();
- if let Some(prefix) = literal.strip_prefix("0x") {
- usize::from_str_radix(prefix, 16).unwrap()
- } else {
- literal.parse::<usize>().unwrap()
- }
- },
- token => panic!("Expected literal, but got {:?}", token),
- }
-}
-
-/// Get next token as [`Group`].
-///
-/// # Panics
-///
-/// Panics if the next token is not a [`Group`].
-fn next_group(iter: &mut impl Iterator<Item = TokenTree>) -> TokenStream {
- match iter.next() {
- Some(Group(group)) => group.stream(),
- token => panic!("Expected group, but got {:?}", token),
- }
-}