-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added APC support #110
Added APC support #110
Changes from 4 commits
1af8b6e
955d293
b6b8e50
946346a
e3efc4e
cc99a0f
e2c61e2
642e207
8e10a22
bb85177
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -48,7 +48,7 @@ mod table; | |||||||||
pub mod ansi; | ||||||||||
pub use params::{Params, ParamsIter}; | ||||||||||
|
||||||||||
use definitions::{unpack, Action, State}; | ||||||||||
use definitions::{Action, State}; | ||||||||||
|
||||||||||
const MAX_INTERMEDIATES: usize = 2; | ||||||||||
const MAX_OSC_PARAMS: usize = 16; | ||||||||||
|
@@ -73,7 +73,8 @@ impl<'a, P: Perform> utf8::Receiver for VtUtf8Receiver<'a, P> { | |||||||||
/// [`Perform`]: trait.Perform.html | ||||||||||
/// | ||||||||||
/// Generic over the value for the size of the raw Operating System Command | ||||||||||
/// buffer. Only used when the `no_std` feature is enabled. | ||||||||||
/// buffer. Only used when the `no_std` feature is enabled. This buffer is | ||||||||||
/// also used for APC (Application Program Commands.) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
#[derive(Default)] | ||||||||||
pub struct Parser<const OSC_RAW_BUF_SIZE: usize = MAX_OSC_RAW> { | ||||||||||
state: State, | ||||||||||
|
@@ -138,12 +139,12 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { | |||||||||
// for current state. | ||||||||||
let mut change = table::STATE_CHANGES[State::Anywhere as usize][byte as usize]; | ||||||||||
|
||||||||||
if change == 0 { | ||||||||||
if change == (State::Anywhere, Action::None) { | ||||||||||
change = table::STATE_CHANGES[self.state as usize][byte as usize]; | ||||||||||
} | ||||||||||
|
||||||||||
// Unpack into a state and action | ||||||||||
let (state, action) = unpack(change); | ||||||||||
let (state, action) = change; | ||||||||||
|
||||||||||
self.perform_state_change(performer, state, action, byte); | ||||||||||
} | ||||||||||
|
@@ -187,6 +188,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { | |||||||||
State::OscString => { | ||||||||||
self.perform_action(performer, Action::OscEnd, byte); | ||||||||||
}, | ||||||||||
State::ApcString => { | ||||||||||
self.perform_action(performer, Action::ApcEnd, byte); | ||||||||||
}, | ||||||||||
_ => (), | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -202,6 +206,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { | |||||||||
State::OscString => { | ||||||||||
self.perform_action(performer, Action::OscStart, byte); | ||||||||||
}, | ||||||||||
State::ApcString => { | ||||||||||
self.perform_action(performer, Action::ApcStart, byte); | ||||||||||
}, | ||||||||||
_ => (), | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -231,6 +238,10 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
fn apc_dispatch<P: Perform>(&self, performer: &mut P) { | ||||||||||
performer.apc_dispatch(&self.osc_raw); | ||||||||||
} | ||||||||||
|
||||||||||
#[inline] | ||||||||||
fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) { | ||||||||||
match action { | ||||||||||
|
@@ -364,6 +375,22 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { | |||||||||
Action::BeginUtf8 => self.process_utf8(performer, byte), | ||||||||||
Action::Ignore => (), | ||||||||||
Action::None => (), | ||||||||||
Action::ApcStart => { | ||||||||||
self.osc_raw.clear(); | ||||||||||
}, | ||||||||||
Action::ApcEnd => { | ||||||||||
self.apc_dispatch(performer); | ||||||||||
}, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Statements should be inlined. |
||||||||||
Action::ApcPut => { | ||||||||||
#[cfg(feature = "no_std")] | ||||||||||
{ | ||||||||||
if self.osc_raw.is_full() { | ||||||||||
return; | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
self.osc_raw.push(byte); | ||||||||||
}, | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -428,6 +455,10 @@ 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 | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
fn apc_dispatch(&mut self, _bytes: &[u8]) {} | ||||||||||
} | ||||||||||
|
||||||||||
#[cfg(all(test, feature = "no_std"))] | ||||||||||
|
@@ -459,6 +490,7 @@ mod tests { | |||||||||
Esc(Vec<u8>, bool, u8), | ||||||||||
DcsHook(Vec<Vec<u16>>, Vec<u8>, bool, char), | ||||||||||
DcsPut(u8), | ||||||||||
Apc(Vec<u8>), | ||||||||||
DcsUnhook, | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -492,6 +524,10 @@ 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())) | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
#[test] | ||||||||||
|
@@ -880,6 +916,35 @@ mod tests { | |||||||||
assert_eq!(dispatcher.dispatched[6], Sequence::DcsUnhook); | ||||||||||
} | ||||||||||
|
||||||||||
#[test] | ||||||||||
fn parse_apc() { | ||||||||||
const INPUT_1: &[u8] = b"\x1b_abc\x9c"; | ||||||||||
const INPUT_2: &[u8] = b"\x1b_abc\x1b\\"; | ||||||||||
|
||||||||||
// Test with ST terminator | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
let mut dispatcher = Dispatcher::default(); | ||||||||||
let mut parser = Parser::new(); | ||||||||||
|
||||||||||
for byte in INPUT_1 { | ||||||||||
parser.advance(&mut dispatcher, *byte); | ||||||||||
} | ||||||||||
assert_eq!(dispatcher.dispatched, vec![Sequence::Apc(b"abc".to_vec()),]); | ||||||||||
|
||||||||||
// Test with ESC \ terminator | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
let mut dispatcher = Dispatcher::default(); | ||||||||||
let mut parser = Parser::new(); | ||||||||||
|
||||||||||
for byte in INPUT_2 { | ||||||||||
parser.advance(&mut dispatcher, *byte); | ||||||||||
} | ||||||||||
assert_eq!(dispatcher.dispatched, vec![ | ||||||||||
Sequence::Apc(b"abc".to_vec()), | ||||||||||
Sequence::Esc(vec![], false, 92) | ||||||||||
]) | ||||||||||
} | ||||||||||
|
||||||||||
#[test] | ||||||||||
fn intermediate_reset_on_dcs_exit() { | ||||||||||
static INPUT: &[u8] = b"\x1bP=1sZZZ\x1b+\x5c"; | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
/// 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}; | ||
use crate::definitions::{Action, State}; | ||
|
||
use vte_generate_state_changes::generate_state_changes; | ||
|
||
// Generate state changes at compile-time | ||
pub static STATE_CHANGES: [[u8; 256]; 16] = state_changes(); | ||
pub static STATE_CHANGES: [[(State, Action); 256]; 17] = state_changes(); | ||
generate_state_changes!(state_changes, { | ||
Anywhere { | ||
0x18 => (Ground, Execute), | ||
|
@@ -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 => (SosPmString, None), | ||
0x5e => (SosPmString, None), | ||
0x5f => (ApcString, None), | ||
}, | ||
|
||
EscapeIntermediate { | ||
|
@@ -152,11 +152,11 @@ generate_state_changes!(state_changes, { | |
0x9c => (Ground, None), | ||
}, | ||
|
||
SosPmApcString { | ||
0x00..=0x17 => (Anywhere, Ignore), | ||
0x19 => (Anywhere, Ignore), | ||
0x1c..=0x1f => (Anywhere, Ignore), | ||
0x20..=0x7f => (Anywhere, Ignore), | ||
SosPmString { | ||
0x00..=0x17 => (SosPmString, Ignore), | ||
0x19 => (SosPmString, Ignore), | ||
0x1c..=0x1f => (SosPmString, Ignore), | ||
0x20..=0x7f => (SosPmString, Ignore), | ||
0x9c => (Ground, None), | ||
}, | ||
|
||
|
@@ -168,4 +168,13 @@ generate_state_changes!(state_changes, { | |
0x1c..=0x1f => (Anywhere, Ignore), | ||
0x20..=0xff => (Anywhere, OscPut), | ||
} | ||
|
||
ApcString { | ||
0x00..=0x06 => (Anywhere, Ignore), | ||
0x08..=0x17 => (Anywhere, Ignore), | ||
0x19 => (Anywhere, Ignore), | ||
0x1c..=0x1f => (Anywhere, Ignore), | ||
0x20..=0xff => (Anywhere, ApcPut), | ||
0x9c => (Ground, None), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haven't checked these yet, just for personal reference. |
||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be benchmarked. There is no way we'll merge a patch that reduces performance for a feature nobody should be using.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running some initial benchmarks I've got the following results from
cargo bench
:whilst the old code yields the following:
Which equates to roughly an 12% ~ 16% decrease in performance. I am using flamegraph now to investigate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also recommend testing with https://github.com/alacritty/vtebench. That's ultimately what decides which features get merged into Alacritty or not.