aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal
diff options
context:
space:
mode:
authorKirill Chibisov <wchibisovkirill@gmail.com>2019-11-17 05:10:11 +0300
committerChristian Duerr <contact@christianduerr.com>2019-11-17 03:10:11 +0100
commitbcdc605436ebe137173c531844a739eda6ee41ae (patch)
tree70b9a2655571a6df15bff7fa08b94425e4e6bfa3 /alacritty_terminal
parent495a6f3526f5127c342d67980d0335f1ed4e235b (diff)
downloadalacritty-bcdc605436ebe137173c531844a739eda6ee41ae.tar.gz
alacritty-bcdc605436ebe137173c531844a739eda6ee41ae.zip
Fix ESC escapes not ignoring invalid intermediates
Previously, `ESC` escapes would ignore invalid intermediates and still execute the specified actions, leading to false positives. If there's an unexpected, intermediate specified now, the escape will be dropped. This also fixes an issue with `CSI Ps c` not dropping the escape with invalid intermediates.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/src/ansi.rs246
-rw-r--r--alacritty_terminal/src/term/mod.rs1
2 files changed, 146 insertions, 101 deletions
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
index a889862f..c2388540 100644
--- a/alacritty_terminal/src/ansi.rs
+++ b/alacritty_terminal/src/ansi.rs
@@ -943,7 +943,9 @@ where
('B', None) | ('e', None) => {
handler.move_down(Line(arg_or_default!(idx: 0, default: 1) as usize))
},
- ('c', None) => handler.identify_terminal(writer),
+ ('c', None) if arg_or_default!(idx: 0, default: 0) == 0 => {
+ handler.identify_terminal(writer)
+ },
('C', None) | ('a', None) => {
handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize))
},
@@ -1104,8 +1106,8 @@ where
}
macro_rules! configure_charset {
- ($charset:path) => {{
- let index: CharsetIndex = match intermediates.first().cloned() {
+ ($charset:path, $intermediate:expr) => {{
+ let index: CharsetIndex = match $intermediate {
Some(b'(') => CharsetIndex::G0,
Some(b')') => CharsetIndex::G1,
Some(b'*') => CharsetIndex::G2,
@@ -1119,29 +1121,27 @@ where
}};
}
- match byte {
- b'B' => configure_charset!(StandardCharset::Ascii),
- b'D' => self.handler.linefeed(),
- b'E' => {
+ match (byte, intermediates.get(0)) {
+ (b'B', intermediate) => configure_charset!(StandardCharset::Ascii, intermediate),
+ (b'D', None) => self.handler.linefeed(),
+ (b'E', None) => {
self.handler.linefeed();
self.handler.carriage_return();
},
- b'H' => self.handler.set_horizontal_tabstop(),
- b'M' => self.handler.reverse_index(),
- b'Z' => self.handler.identify_terminal(self.writer),
- b'c' => self.handler.reset_state(),
- b'0' => configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing),
- b'7' => self.handler.save_cursor_position(),
- b'8' => {
- if !intermediates.is_empty() && intermediates[0] == b'#' {
- self.handler.decaln();
- } else {
- self.handler.restore_cursor_position();
- }
+ (b'H', None) => self.handler.set_horizontal_tabstop(),
+ (b'M', None) => self.handler.reverse_index(),
+ (b'Z', None) => self.handler.identify_terminal(self.writer),
+ (b'c', None) => self.handler.reset_state(),
+ (b'0', intermediate) => {
+ configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing, intermediate)
},
- b'=' => self.handler.set_keypad_application_mode(),
- b'>' => self.handler.unset_keypad_application_mode(),
- b'\\' => (), // String terminator, do nothing (parser handles as string terminator)
+ (b'7', None) => self.handler.save_cursor_position(),
+ (b'8', Some(b'#')) => self.handler.decaln(),
+ (b'8', None) => self.handler.restore_cursor_position(),
+ (b'=', None) => self.handler.set_keypad_application_mode(),
+ (b'>', None) => self.handler.unset_keypad_application_mode(),
+ // String terminator, do nothing (parser handles as string terminator)
+ (b'\\', None) => (),
_ => unhandled!(),
}
}
@@ -1446,129 +1446,173 @@ mod tests {
use crate::term::color::Rgb;
use std::io;
- /// The /dev/null of `io::Write`
- struct Void;
+ struct MockHandler {
+ index: CharsetIndex,
+ charset: StandardCharset,
+ attr: Option<Attr>,
+ identity_reported: bool,
+ }
- impl io::Write for Void {
- fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
- Ok(bytes.len())
+ impl Handler for MockHandler {
+ fn terminal_attribute(&mut self, attr: Attr) {
+ self.attr = Some(attr);
}
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
+ fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
+ self.index = index;
+ self.charset = charset;
}
- }
- #[derive(Default)]
- struct AttrHandler {
- attr: Option<Attr>,
- }
+ fn set_active_charset(&mut self, index: CharsetIndex) {
+ self.index = index;
+ }
- impl Handler for AttrHandler {
- fn terminal_attribute(&mut self, attr: Attr) {
- self.attr = Some(attr);
+ fn identify_terminal<W: io::Write>(&mut self, _: &mut W) {
+ self.identity_reported = true;
+ }
+
+ fn reset_state(&mut self) {
+ *self = Self::default();
}
}
- impl TermInfo for AttrHandler {
+ impl TermInfo for MockHandler {
fn lines(&self) -> Line {
- Line(24)
+ Line(200)
}
fn cols(&self) -> Column {
- Column(80)
+ Column(90)
+ }
+ }
+
+ impl Default for MockHandler {
+ fn default() -> MockHandler {
+ MockHandler {
+ index: CharsetIndex::G0,
+ charset: StandardCharset::Ascii,
+ attr: None,
+ identity_reported: false,
+ }
}
}
#[test]
fn parse_control_attribute() {
- static BYTES: &[u8] = &[0x1b, 0x5b, 0x31, 0x6d];
+ static BYTES: &[u8] = &[0x1b, b'[', b'1', b'm'];
let mut parser = Processor::new();
- let mut handler = AttrHandler::default();
+ let mut handler = MockHandler::default();
for byte in &BYTES[..] {
- parser.advance(&mut handler, *byte, &mut Void);
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
assert_eq!(handler.attr, Some(Attr::Bold));
}
#[test]
- fn parse_truecolor_attr() {
- static BYTES: &[u8] = &[
- 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x32, 0x3b, 0x31, 0x32, 0x38, 0x3b, 0x36, 0x36, 0x3b,
- 0x32, 0x35, 0x35, 0x6d,
- ];
+ fn parse_terminal_identity_csi() {
+ let bytes: &[u8] = &[0x1b, b'[', b'1', b'c'];
let mut parser = Processor::new();
- let mut handler = AttrHandler::default();
+ let mut handler = MockHandler::default();
- for byte in &BYTES[..] {
- parser.advance(&mut handler, *byte, &mut Void);
+ for byte in &bytes[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
- let spec = Rgb { r: 128, g: 66, b: 255 };
+ assert!(!handler.identity_reported);
+ handler.reset_state();
- assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
+ let bytes: &[u8] = &[0x1b, b'[', b'c'];
+
+ for byte in &bytes[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
+ }
+
+ assert!(handler.identity_reported);
+ handler.reset_state();
+
+ let bytes: &[u8] = &[0x1b, b'[', b'0', b'c'];
+
+ for byte in &bytes[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
+ }
+
+ assert!(handler.identity_reported);
}
- /// No exactly a test; useful for debugging
#[test]
- fn parse_zsh_startup() {
- static BYTES: &[u8] = &[
- 0x1b, 0x5b, 0x31, 0x6d, 0x1b, 0x5b, 0x37, 0x6d, 0x25, 0x1b, 0x5b, 0x32, 0x37, 0x6d,
- 0x1b, 0x5b, 0x31, 0x6d, 0x1b, 0x5b, 0x30, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x0d, 0x20, 0x0d, 0x0d, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x32,
- 0x37, 0x6d, 0x1b, 0x5b, 0x32, 0x34, 0x6d, 0x1b, 0x5b, 0x4a, 0x6a, 0x77, 0x69, 0x6c,
- 0x6d, 0x40, 0x6a, 0x77, 0x69, 0x6c, 0x6d, 0x2d, 0x64, 0x65, 0x73, 0x6b, 0x20, 0x1b,
- 0x5b, 0x30, 0x31, 0x3b, 0x33, 0x32, 0x6d, 0xe2, 0x9e, 0x9c, 0x20, 0x1b, 0x5b, 0x30,
- 0x31, 0x3b, 0x33, 0x32, 0x6d, 0x20, 0x1b, 0x5b, 0x33, 0x36, 0x6d, 0x7e, 0x2f, 0x63,
- 0x6f, 0x64, 0x65,
- ];
+ fn parse_terminal_identity_esc() {
+ let bytes: &[u8] = &[0x1b, b'Z'];
- let mut handler = AttrHandler::default();
let mut parser = Processor::new();
+ let mut handler = MockHandler::default();
- for byte in &BYTES[..] {
- parser.advance(&mut handler, *byte, &mut Void);
+ for byte in &bytes[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
- }
- struct CharsetHandler {
- index: CharsetIndex,
- charset: StandardCharset,
- }
+ assert!(handler.identity_reported);
+ handler.reset_state();
+
+ let bytes: &[u8] = &[0x1b, b'#', b'Z'];
+
+ let mut parser = Processor::new();
+ let mut handler = MockHandler::default();
- impl Default for CharsetHandler {
- fn default() -> CharsetHandler {
- CharsetHandler { index: CharsetIndex::G0, charset: StandardCharset::Ascii }
+ for byte in &bytes[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
+
+ assert!(!handler.identity_reported);
+ handler.reset_state();
}
- impl Handler for CharsetHandler {
- fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
- self.index = index;
- self.charset = charset;
- }
+ #[test]
+ fn parse_truecolor_attr() {
+ static BYTES: &[u8] = &[
+ 0x1b, b'[', b'3', b'8', b';', b'2', b';', b'1', b'2', b'8', b';', b'6', b'6', b';',
+ b'2', b'5', b'5', b'm',
+ ];
- fn set_active_charset(&mut self, index: CharsetIndex) {
- self.index = index;
+ let mut parser = Processor::new();
+ let mut handler = MockHandler::default();
+
+ for byte in &BYTES[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
+
+ let spec = Rgb { r: 128, g: 66, b: 255 };
+
+ assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
}
- impl TermInfo for CharsetHandler {
- fn lines(&self) -> Line {
- Line(200)
- }
+ /// No exactly a test; useful for debugging
+ #[test]
+ fn parse_zsh_startup() {
+ static BYTES: &[u8] = &[
+ 0x1b, b'[', b'1', b'm', 0x1b, b'[', b'7', b'm', b'%', 0x1b, b'[', b'2', b'7', b'm',
+ 0x1b, b'[', b'1', b'm', 0x1b, b'[', b'0', b'm', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
+ b' ', b' ', b' ', b'\r', b' ', b'\r', b'\r', 0x1b, b'[', b'0', b'm', 0x1b, b'[', b'2',
+ b'7', b'm', 0x1b, b'[', b'2', b'4', b'm', 0x1b, b'[', b'J', b'j', b'w', b'i', b'l',
+ b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', b'e', b's', b'k', b' ', 0x1b,
+ b'[', b'0', b'1', b';', b'3', b'2', b'm', 0xe2, 0x9e, 0x9c, b' ', 0x1b, b'[', b'0',
+ b'1', b';', b'3', b'2', b'm', b' ', 0x1b, b'[', b'3', b'6', b'm', b'~', b'/', b'c',
+ b'o', b'd', b'e',
+ ];
- fn cols(&self) -> Column {
- Column(90)
+ let mut handler = MockHandler::default();
+ let mut parser = Processor::new();
+
+ for byte in &BYTES[..] {
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
}
@@ -1576,10 +1620,10 @@ mod tests {
fn parse_designate_g0_as_line_drawing() {
static BYTES: &[u8] = &[0x1b, b'(', b'0'];
let mut parser = Processor::new();
- let mut handler = CharsetHandler::default();
+ let mut handler = MockHandler::default();
for byte in &BYTES[..] {
- parser.advance(&mut handler, *byte, &mut Void);
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
assert_eq!(handler.index, CharsetIndex::G0);
@@ -1588,19 +1632,19 @@ mod tests {
#[test]
fn parse_designate_g1_as_line_drawing_and_invoke() {
- static BYTES: &[u8] = &[0x1b, 0x29, 0x30, 0x0e];
+ static BYTES: &[u8] = &[0x1b, b')', b'0', 0x0e];
let mut parser = Processor::new();
- let mut handler = CharsetHandler::default();
+ let mut handler = MockHandler::default();
for byte in &BYTES[..3] {
- parser.advance(&mut handler, *byte, &mut Void);
+ parser.advance(&mut handler, *byte, &mut io::sink());
}
assert_eq!(handler.index, CharsetIndex::G1);
assert_eq!(handler.charset, StandardCharset::SpecialCharacterAndLineDrawing);
- let mut handler = CharsetHandler::default();
- parser.advance(&mut handler, BYTES[3], &mut Void);
+ let mut handler = MockHandler::default();
+ parser.advance(&mut handler, BYTES[3], &mut io::sink());
assert_eq!(handler.index, CharsetIndex::G1);
}
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index ce63c407..8d69fb3b 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -1397,6 +1397,7 @@ impl<T: EventListener> ansi::Handler for Term<T> {
#[inline]
fn identify_terminal<W: io::Write>(&mut self, writer: &mut W) {
+ trace!("Reporting terminal identity");
let _ = writer.write_all(b"\x1b[?6c");
}