Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum State {
#[default]
Ground = 12,
OscString = 13,
SosPmApcString = 14,
Null = 14,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a bad name. A "null state" already exists, it's called Ground. Looking at State::Null alone would make it impossible to tell what that state is for.

Utf8 = 15,
}

Expand All @@ -35,9 +35,9 @@ pub enum Action {
Execute = 5,
Hook = 6,
Ignore = 7,
OscEnd = 8,
OscPut = 9,
OscStart = 10,
StringEnd = 8,
StringPut = 9,
StringStart = 10,
Param = 11,
Print = 12,
Put = 13,
Expand Down Expand Up @@ -76,7 +76,7 @@ mod tests {
#[test]
fn unpack_state_action() {
match unpack(0xee) {
(State::SosPmApcString, Action::Unhook) => (),
(State::Null, Action::Unhook) => (),
_ => panic!("unpack failed"),
}

Expand All @@ -94,7 +94,7 @@ mod tests {
#[test]
fn pack_state_action() {
match unpack(0xee) {
(State::SosPmApcString, Action::Unhook) => (),
(State::Null, Action::Unhook) => (),
_ => panic!("unpack failed"),
}

Expand Down
157 changes: 135 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ pub struct Parser<const OSC_RAW_BUF_SIZE: usize = MAX_OSC_RAW> {
osc_num_params: usize,
ignoring: bool,
utf8_parser: utf8::Parser,
str_start: u8,
}

impl Parser {
Expand Down Expand Up @@ -185,7 +186,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
self.perform_action(performer, Action::Unhook, byte);
},
State::OscString => {
self.perform_action(performer, Action::OscEnd, byte);
self.perform_action(performer, Action::StringEnd, byte);
},
_ => (),
}
Expand All @@ -200,7 +201,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
self.perform_action(performer, Action::Hook, byte);
},
State::OscString => {
self.perform_action(performer, Action::OscStart, byte);
self.perform_action(performer, Action::StringStart, byte);
},
_ => (),
}
Expand Down Expand Up @@ -231,6 +232,21 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
}
}

#[inline]
fn apc_dispatch<P: Perform>(&self, performer: &mut P) {
performer.apc_dispatch(&self.osc_raw);
}

#[inline]
fn pm_dispatch<P: Perform>(&self, performer: &mut P) {
performer.pm_dispatch(&self.osc_raw);
}

#[inline]
fn sos_dispatch<P: Perform>(&self, performer: &mut P) {
performer.sos_dispatch(&self.osc_raw);
}

#[inline]
fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) {
match action {
Expand All @@ -246,11 +262,12 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char);
},
Action::Put => performer.put(byte),
Action::OscStart => {
Action::StringStart => {
self.str_start = byte % 64;
self.osc_raw.clear();
self.osc_num_params = 0;
},
Action::OscPut => {
Action::StringPut => {
#[cfg(feature = "no_std")]
{
if self.osc_raw.is_full() {
Expand All @@ -261,7 +278,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
let idx = self.osc_raw.len();

// Param separator
if byte == b';' {
if self.str_start == 0x1d && byte == b';' {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra branch isn't going to be the end of the world, but I don't see how this isn't just going to be a net-negative for anyone who doesn't use APC escapes (which is basically everyone).

let param_idx = self.osc_num_params;
match param_idx {
// Only process up to MAX_OSC_PARAMS
Expand All @@ -285,29 +302,45 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
self.osc_raw.push(byte);
}
},
Action::OscEnd => {
Action::StringEnd => {
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;
match self.str_start {
0x1d => {
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;
},

// 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);
},

// 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;
0x18 => {
self.sos_dispatch(performer);
},
0x1e => {
self.pm_dispatch(performer);
},
0x1F => {
self.apc_dispatch(performer);
},
// This condition should never be hit under the
// current way in which the code is ran.
_ => unreachable!(),
Comment on lines +340 to +342
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is basically just a long way to say unreachable!(). It doesn't explain why it is unreachable it just states that it is, which unreachable!() does too. Should either add a useful comment or remove this.

}
Comment on lines +309 to 343
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically feels like an embedded parser. Most of our parser is structured in a way to stream through bytes and process them as they're coming in, however rather than creating state transitions you're storing a state transition to later then match on it instead. VTE is already too slow and I'm afraid this will just amplify that problem.

self.osc_dispatch(performer, byte);
},
Action::Unhook => performer.unhook(),
Action::CsiDispatch => {
Expand Down Expand Up @@ -428,6 +461,18 @@ pub trait Perform {
/// The `ignore` flag indicates that more than two intermediates arrived and
/// subsequent characters were ignored.
fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}

/// Called at the end of an APC (application program command), where
/// `bytes` is the content of the APC.
fn apc_dispatch(&mut self, _bytes: &[u8]) {}

/// Called at the end of an SOS (start of string), where
/// `bytes` is the content of the SOS.
fn sos_dispatch(&mut self, _bytes: &[u8]) {}

/// Called at the end of a PM (privacy message), where
/// `bytes` is the content of the PM.
fn pm_dispatch(&mut self, _bytes: &[u8]) {}
}

#[cfg(all(test, feature = "no_std"))]
Expand Down Expand Up @@ -460,6 +505,9 @@ mod tests {
DcsHook(Vec<Vec<u16>>, Vec<u8>, bool, char),
DcsPut(u8),
DcsUnhook,
Apc(Vec<u8>),
Pm(Vec<u8>),
Sos(Vec<u8>),
}

impl Perform for Dispatcher {
Expand Down Expand Up @@ -492,6 +540,18 @@ mod tests {
fn unhook(&mut self) {
self.dispatched.push(Sequence::DcsUnhook);
}

fn apc_dispatch(&mut self, bytes: &[u8]) {
self.dispatched.push(Sequence::Apc(bytes.to_vec()))
}

fn sos_dispatch(&mut self, bytes: &[u8]) {
self.dispatched.push(Sequence::Sos(bytes.to_vec()))
}

fn pm_dispatch(&mut self, bytes: &[u8]) {
self.dispatched.push(Sequence::Pm(bytes.to_vec()))
}
}

#[test]
Expand Down Expand Up @@ -880,6 +940,59 @@ mod tests {
assert_eq!(dispatcher.dispatched[6], Sequence::DcsUnhook);
}

#[test]
fn parse_apc() {
const INPUT: &[u8] = b"\x1b_abc\x1b\\";

// Test with ESC \ terminator.

let mut dispatcher = Dispatcher::default();
let mut parser = Parser::new();

for byte in INPUT {
parser.advance(&mut dispatcher, *byte);
}
assert_eq!(
dispatcher.dispatched,
vec![Sequence::Apc(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)]
)
}
#[test]
fn parse_pm() {
const INPUT: &[u8] = b"\x1b^abc\x1b\\";

// Test with ESC \ terminator.

let mut dispatcher = Dispatcher::default();
let mut parser = Parser::new();

for byte in INPUT {
parser.advance(&mut dispatcher, *byte);
}
assert_eq!(
dispatcher.dispatched,
vec![Sequence::Pm(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)]
)
}

#[test]
fn parse_sos() {
const INPUT: &[u8] = b"\x1bXabc\x1b\\";

// Test with ESC \ terminator.

let mut dispatcher = Dispatcher::default();
let mut parser = Parser::new();

for byte in INPUT {
parser.advance(&mut dispatcher, *byte);
}
assert_eq!(
dispatcher.dispatched,
vec![Sequence::Sos(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)]
)
}

#[test]
fn intermediate_reset_on_dcs_exit() {
static INPUT: &[u8] = b"\x1bP=1sZZZ\x1b+\x5c";
Expand Down
16 changes: 6 additions & 10 deletions src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ generate_state_changes!(state_changes, {
0x5b => (CsiEntry, None),
0x5d => (OscString, None),
0x50 => (DcsEntry, None),
0x58 => (SosPmApcString, None),
0x5e => (SosPmApcString, None),
0x5f => (SosPmApcString, None),
0x58 => (OscString, None),
0x5e => (OscString, None),
0x5f => (OscString, None),
},

EscapeIntermediate {
Expand Down Expand Up @@ -152,12 +152,8 @@ generate_state_changes!(state_changes, {
0x9c => (Ground, None),
},

SosPmApcString {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x20..=0x7f => (Anywhere, Ignore),
0x9c => (Ground, None),
Null {
0x00..=0xFF => (Anywhere, Ignore),
},

OscString {
Expand All @@ -166,6 +162,6 @@ generate_state_changes!(state_changes, {
0x08..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x20..=0xff => (Anywhere, OscPut),
0x20..=0xff => (Anywhere, StringPut),
}
});