diff options
-rw-r--r-- | examples/parselog.rs | 4 | ||||
-rw-r--r-- | src/definitions.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 121 | ||||
-rw-r--r-- | src/table.rs | 4 | ||||
-rw-r--r-- | utf8parse/src/lib.rs | 1 | ||||
-rw-r--r-- | utf8parse/src/types.rs | 2 | ||||
-rw-r--r-- | vte_generate_state_changes/src/lib.rs | 4 |
7 files changed, 83 insertions, 57 deletions
diff --git a/examples/parselog.rs b/examples/parselog.rs index 83ba2b5..331a003 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -30,8 +30,8 @@ impl vte::Perform for Log { println!("[unhook]"); } - fn osc_dispatch(&mut self, params: &[&[u8]]) { - println!("[osc_dispatch] params={:?}", params); + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + println!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { diff --git a/src/definitions.rs b/src/definitions.rs index 568eb41..5d01623 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -50,7 +50,7 @@ pub enum Action { impl State { #[inline] - pub fn entry_action(&self) -> Action { + pub fn entry_action(self) -> Action { match self { State::CsiEntry | State::DcsEntry | State::Escape => Action::Clear, State::DcsPassthrough => Action::Hook, @@ -60,7 +60,7 @@ impl State { } #[inline] - pub fn exit_action(&self) -> Action { + pub fn exit_action(self) -> Action { match self { State::DcsPassthrough => Action::Unhook, State::OscString => Action::OscEnd, @@ -30,6 +30,7 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "no_std", no_std)] @@ -179,7 +180,7 @@ impl Parser { /// /// The aliasing is needed here for multiple slices into self.osc_raw #[inline] - fn osc_dispatch<P: Perform>(&self, performer: &mut P) { + fn osc_dispatch<P: Perform>(&self, performer: &mut P, byte: u8) { let mut slices: [MaybeUninit<&[u8]>; MAX_PARAMS] = unsafe { MaybeUninit::uninit().assume_init() }; @@ -191,7 +192,7 @@ impl Parser { unsafe { let num_params = self.osc_num_params; let params = &slices[..num_params] as *const [MaybeUninit<&[u8]>] as *const [&[u8]]; - performer.osc_dispatch(&*params); + performer.osc_dispatch(&*params, byte == 0x07); } } @@ -268,7 +269,7 @@ impl Parser { self.osc_num_params += 1; }, } - self.osc_dispatch(performer); + self.osc_dispatch(performer, byte); }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { @@ -343,13 +344,13 @@ impl Parser { /// referenced if something isn't clear. If the site disappears at some point in /// the future, consider checking archive.org. pub trait Perform { - /// Draw a character to the screen and update states + /// Draw a character to the screen and update states. fn print(&mut self, _: char); - /// Execute a C0 or C1 control function + /// Execute a C0 or C1 control function. fn execute(&mut self, byte: u8); - /// Invoked when a final character arrives in first part of device control string + /// Invoked when a final character arrives in first part of device control string. /// /// The control function should be determined from the private marker, final character, and /// execute with a parameter list. A handler should be selected for remaining characters in the @@ -358,27 +359,27 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. fn put(&mut self, byte: u8); - /// Called when a device control string is terminated + /// Called when a device control string is terminated. /// /// The previously selected handler should be notified that the DCS has /// terminated. fn unhook(&mut self); - /// Dispatch an operating system command - fn osc_dispatch(&mut self, params: &[&[u8]]); + /// Dispatch an operating system command. + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool); /// A final character has arrived for a CSI sequence /// /// The `ignore` flag indicates that either more than two intermediates arrived /// or the number of parameters exceeded the maximum supported length, /// and subsequent characters were ignored. - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); /// The final character of an escape sequence has arrived. /// @@ -409,6 +410,7 @@ mod tests { #[derive(Default)] struct OscDispatcher { dispatched_osc: bool, + bell_terminated: bool, params: Vec<Vec<u8>>, } @@ -424,9 +426,10 @@ mod tests { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]]) { + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { // Set a flag so we know these assertions all run self.dispatched_osc = true; + self.bell_terminated = bell_terminated; self.params = params.iter().map(|p| p.to_vec()).collect(); } @@ -467,7 +470,7 @@ mod tests { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], ignore: bool, _c: char) { self.dispatched_csi = true; @@ -511,7 +514,7 @@ mod tests { self.dispatched_dcs = true; } - fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} fn csi_dispatch( &mut self, @@ -534,12 +537,9 @@ mod tests { #[test] fn parse_osc() { - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in OSC_BYTES { parser.advance(&mut dispatcher, *byte); } @@ -553,12 +553,9 @@ mod tests { #[test] fn parse_empty_osc() { - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in &[0x1b, 0x5d, 0x07] { parser.advance(&mut dispatcher, *byte); } @@ -570,13 +567,9 @@ mod tests { #[test] fn parse_osc_max_params() { static INPUT: &[u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; - - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -590,6 +583,48 @@ mod tests { } #[test] + fn osc_bell_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(dispatcher.bell_terminated); + } + + #[test] + fn osc_c1_st_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x9c"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(!dispatcher.bell_terminated); + } + + #[test] + fn osc_c0_st_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(!dispatcher.bell_terminated); + } + + #[test] fn parse_csi_max_params() { // This will build a list of repeating '1;'s // The length is MAX_PARAMS - 1 because the last semicolon is interpreted @@ -597,12 +632,9 @@ mod tests { let params = std::iter::repeat("1;").take(MAX_PARAMS - 1).collect::<String>(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - assert!(!dispatcher.dispatched_csi); - - // Run parser using INPUT let mut parser = Parser::new(); + for byte in input { parser.advance(&mut dispatcher, byte); } @@ -622,12 +654,9 @@ mod tests { let params = std::iter::repeat("1;").take(MAX_PARAMS).collect::<String>(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - assert!(!dispatcher.dispatched_csi); - - // Run parser using INPUT let mut parser = Parser::new(); + for byte in input { parser.advance(&mut dispatcher, byte); } @@ -656,9 +685,8 @@ mod tests { fn parse_semi_set_underline() { // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in b"\x1b[;4m" { parser.advance(&mut dispatcher, *byte); } @@ -671,10 +699,9 @@ mod tests { fn parse_long_csi_param() { // The important part is the parameter, which is (i64::MAX + 1) static INPUT: &[u8] = b"\x1b[9223372036854775808m"; - let mut dispatcher = CsiDispatcher::default(); - let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -689,12 +716,9 @@ mod tests { 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, ]; - - // Create dispatcher and check state - let mut dispatcher = OscDispatcher { params: vec![], dispatched_osc: false }; - - // Run parser using OSC_BYTES + let mut dispatcher = OscDispatcher::default(); let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -708,12 +732,9 @@ mod tests { fn parse_dcs() { static INPUT: &[u8] = &[0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c]; - - // Create dispatcher and check state let mut dispatcher = DcsDispatcher::default(); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -792,8 +813,8 @@ mod bench { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]]) { - black_box(params); + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + black_box((params, bell_terminated)); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { diff --git a/src/table.rs b/src/table.rs index c19e4ab..392cf05 100644 --- a/src/table.rs +++ b/src/table.rs @@ -170,6 +170,8 @@ generate_state_changes!(state_changes, { 0x08..=0x17 => (Anywhere, Ignore), 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), - 0x20..=0xff => (Anywhere, OscPut), + 0x20..=0x9b => (Anywhere, OscPut), + 0x9c => (Ground, None), + 0x9d..=0xff => (Anywhere, OscPut), } }); diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index c092647..6168e2e 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -3,6 +3,7 @@ //! This module implements a table-driven UTF-8 parser which should //! theoretically contain the minimal number of branches (1). The only branch is //! on the `Action` returned from unpacking a transition. +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![no_std] diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs index 5a70b3c..77a79cc 100644 --- a/utf8parse/src/types.rs +++ b/utf8parse/src/types.rs @@ -58,7 +58,7 @@ impl State { /// This takes the current state and input byte into consideration, to determine the next state /// and any action that should be taken. #[inline] - pub fn advance(&self, byte: u8) -> (State, Action) { + pub fn advance(self, byte: u8) -> (State, Action) { match self { State::Ground => match byte { 0x00..=0x7f => (State::Ground, Action::EmitByte), diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs index 5cfb3ac..cae8f65 100644 --- a/vte_generate_state_changes/src/lib.rs +++ b/vte_generate_state_changes/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] + extern crate proc_macro; use std::iter::Peekable; @@ -53,7 +55,7 @@ fn states_stream(iter: &mut impl Iterator<Item = TokenTree>) -> TokenStream { /// 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().into(); + let state = iter.next().unwrap(); // Token stream with all the byte->target mappings let mut changes_stream = next_group(iter).into_iter().peekable(); |