summaryrefslogtreecommitdiffstats
path: root/alacritty_terminal
diff options
context:
space:
mode:
authorKoichi Murase <myoga.murase@gmail.com>2019-08-07 07:59:16 +0900
committerChristian Duerr <contact@christianduerr.com>2019-08-06 22:59:16 +0000
commit33cfc52909bda1e2d5ceeae5397f254509d00539 (patch)
tree5c216e26de4c095058844cfab1ad18e7140157bd /alacritty_terminal
parentb20d28578229a570b72f420fa50a64040bd2105b (diff)
Ignore unsupported CSI sequences
Instead of ignoring unexpected intermediates in CSI escape sequences, the intermediates are now explicitly checked and the escape sequence is rejected when an unexpected intermediate is found. Fixes #2171.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/src/ansi.rs298
-rw-r--r--alacritty_terminal/tests/ref.rs1
-rw-r--r--alacritty_terminal/tests/ref/selective_erasure/alacritty.recording2
-rw-r--r--alacritty_terminal/tests/ref/selective_erasure/config.json1
-rw-r--r--alacritty_terminal/tests/ref/selective_erasure/grid.json1
-rw-r--r--alacritty_terminal/tests/ref/selective_erasure/size.json1
6 files changed, 166 insertions, 138 deletions
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
index b4cf4476..1914e952 100644
--- a/alacritty_terminal/src/ansi.rs
+++ b/alacritty_terminal/src/ansi.rs
@@ -890,11 +890,7 @@ where
}
#[inline]
- fn csi_dispatch(&mut self, args: &[i64], intermediates: &[u8], _ignore: bool, action: char) {
- let private = intermediates.get(0).map(|b| *b == b'?').unwrap_or(false);
- let handler = &mut self.handler;
- let writer = &mut self.writer;
-
+ fn csi_dispatch(&mut self, args: &[i64], intermediates: &[u8], has_ignored_intermediates: bool, action: char) {
macro_rules! unhandled {
() => {{
debug!(
@@ -913,12 +909,19 @@ where
};
}
- match action {
- '@' => handler.insert_blank(Column(arg_or_default!(idx: 0, default: 1) as usize)),
- 'A' => {
+ if has_ignored_intermediates || intermediates.len() > 1 {
+ unhandled!();
+ }
+
+ let handler = &mut self.handler;
+ let writer = &mut self.writer;
+
+ match (action, intermediates.get(0)) {
+ ('@', None) => handler.insert_blank(Column(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('A', None) => {
handler.move_up(Line(arg_or_default!(idx: 0, default: 1) as usize));
},
- 'b' => {
+ ('b', None) => {
if let Some(c) = self._state.preceding_char {
for _ in 0..arg_or_default!(idx: 0, default: 1) {
handler.input(c);
@@ -927,13 +930,13 @@ where
debug!("tried to repeat with no preceding char");
}
},
- 'B' | 'e' => handler.move_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'c' => handler.identify_terminal(writer),
- 'C' | 'a' => handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
- 'D' => handler.move_backward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
- 'E' => handler.move_down_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'F' => handler.move_up_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'g' => {
+ ('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) | ('a', None) => handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('D', None) => handler.move_backward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('E', None) => handler.move_down_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('F', None) => handler.move_up_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('g', None) => {
let mode = match arg_or_default!(idx: 0, default: 0) {
0 => TabulationClearMode::Current,
3 => TabulationClearMode::All,
@@ -942,14 +945,14 @@ where
handler.clear_tabs(mode);
},
- 'G' | '`' => handler.goto_col(Column(arg_or_default!(idx: 0, default: 1) as usize - 1)),
- 'H' | 'f' => {
+ ('G', None) | ('`', None) => handler.goto_col(Column(arg_or_default!(idx: 0, default: 1) as usize - 1)),
+ ('H', None) | ('f', None) => {
let y = arg_or_default!(idx: 0, default: 1) as usize;
let x = arg_or_default!(idx: 1, default: 1) as usize;
handler.goto(Line(y - 1), Column(x - 1));
},
- 'I' => handler.move_forward_tabs(arg_or_default!(idx: 0, default: 1)),
- 'J' => {
+ ('I', None) => handler.move_forward_tabs(arg_or_default!(idx: 0, default: 1)),
+ ('J', None) => {
let mode = match arg_or_default!(idx: 0, default: 0) {
0 => ClearMode::Below,
1 => ClearMode::Above,
@@ -960,7 +963,7 @@ where
handler.clear_screen(mode);
},
- 'K' => {
+ ('K', None) => {
let mode = match arg_or_default!(idx: 0, default: 0) {
0 => LineClearMode::Right,
1 => LineClearMode::Left,
@@ -970,129 +973,68 @@ where
handler.clear_line(mode);
},
- 'S' => handler.scroll_up(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'T' => handler.scroll_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'L' => handler.insert_blank_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'l' => {
+ ('S', None) => handler.scroll_up(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('T', None) => handler.scroll_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('L', None) => handler.insert_blank_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('l', intermediate) => {
+ let is_private_mode = match intermediate {
+ Some(b'?') => true,
+ None => false,
+ _ => unhandled!(),
+ };
for arg in args {
- let mode = Mode::from_primitive(private, *arg);
+ let mode = Mode::from_primitive(is_private_mode, *arg);
match mode {
Some(mode) => handler.unset_mode(mode),
None => unhandled!(),
}
}
},
- 'M' => handler.delete_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
- 'X' => handler.erase_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
- 'P' => handler.delete_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
- 'Z' => handler.move_backward_tabs(arg_or_default!(idx: 0, default: 1)),
- 'd' => handler.goto_line(Line(arg_or_default!(idx: 0, default: 1) as usize - 1)),
- 'h' => {
+ ('M', None) => handler.delete_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('X', None) => handler.erase_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('P', None) => handler.delete_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
+ ('Z', None) => handler.move_backward_tabs(arg_or_default!(idx: 0, default: 1)),
+ ('d', None) => handler.goto_line(Line(arg_or_default!(idx: 0, default: 1) as usize - 1)),
+ ('h', intermediate) => {
+ let is_private_mode = match intermediate {
+ Some(b'?') => true,
+ None => false,
+ _ => unhandled!(),
+ };
for arg in args {
- let mode = Mode::from_primitive(private, *arg);
+ let mode = Mode::from_primitive(is_private_mode, *arg);
match mode {
Some(mode) => handler.set_mode(mode),
None => unhandled!(),
}
}
},
- 'm' => {
- // Sometimes a C-style for loop is just what you need
- let mut i = 0; // C-for initializer
+ ('m', None) => {
if args.is_empty() {
handler.terminal_attribute(Attr::Reset);
- return;
- }
- loop {
- if i >= args.len() {
- // C-for condition
- break;
+ } else {
+ for attr in attrs_from_sgr_parameters(args) {
+ match attr {
+ Some(attr) => handler.terminal_attribute(attr),
+ None => unhandled!(),
+ }
}
-
- let attr = match args[i] {
- 0 => Attr::Reset,
- 1 => Attr::Bold,
- 2 => Attr::Dim,
- 3 => Attr::Italic,
- 4 => Attr::Underscore,
- 5 => Attr::BlinkSlow,
- 6 => Attr::BlinkFast,
- 7 => Attr::Reverse,
- 8 => Attr::Hidden,
- 9 => Attr::Strike,
- 21 => Attr::CancelBold,
- 22 => Attr::CancelBoldDim,
- 23 => Attr::CancelItalic,
- 24 => Attr::CancelUnderline,
- 25 => Attr::CancelBlink,
- 27 => Attr::CancelReverse,
- 28 => Attr::CancelHidden,
- 29 => Attr::CancelStrike,
- 30 => Attr::Foreground(Color::Named(NamedColor::Black)),
- 31 => Attr::Foreground(Color::Named(NamedColor::Red)),
- 32 => Attr::Foreground(Color::Named(NamedColor::Green)),
- 33 => Attr::Foreground(Color::Named(NamedColor::Yellow)),
- 34 => Attr::Foreground(Color::Named(NamedColor::Blue)),
- 35 => Attr::Foreground(Color::Named(NamedColor::Magenta)),
- 36 => Attr::Foreground(Color::Named(NamedColor::Cyan)),
- 37 => Attr::Foreground(Color::Named(NamedColor::White)),
- 38 => {
- let mut start = 0;
- if let Some(color) = parse_color(&args[i..], &mut start) {
- i += start;
- Attr::Foreground(color)
- } else {
- break;
- }
- },
- 39 => Attr::Foreground(Color::Named(NamedColor::Foreground)),
- 40 => Attr::Background(Color::Named(NamedColor::Black)),
- 41 => Attr::Background(Color::Named(NamedColor::Red)),
- 42 => Attr::Background(Color::Named(NamedColor::Green)),
- 43 => Attr::Background(Color::Named(NamedColor::Yellow)),
- 44 => Attr::Background(Color::Named(NamedColor::Blue)),
- 45 => Attr::Background(Color::Named(NamedColor::Magenta)),
- 46 => Attr::Background(Color::Named(NamedColor::Cyan)),
- 47 => Attr::Background(Color::Named(NamedColor::White)),
- 48 => {
- let mut start = 0;
- if let Some(color) = parse_color(&args[i..], &mut start) {
- i += start;
- Attr::Background(color)
- } else {
- break;
- }
- },
- 49 => Attr::Background(Color::Named(NamedColor::Background)),
- 90 => Attr::Foreground(Color::Named(NamedColor::BrightBlack)),
- 91 => Attr::Foreground(Color::Named(NamedColor::BrightRed)),
- 92 => Attr::Foreground(Color::Named(NamedColor::BrightGreen)),
- 93 => Attr::Foreground(Color::Named(NamedColor::BrightYellow)),
- 94 => Attr::Foreground(Color::Named(NamedColor::BrightBlue)),
- 95 => Attr::Foreground(Color::Named(NamedColor::BrightMagenta)),
- 96 => Attr::Foreground(Color::Named(NamedColor::BrightCyan)),
- 97 => Attr::Foreground(Color::Named(NamedColor::BrightWhite)),
- 100 => Attr::Background(Color::Named(NamedColor::BrightBlack)),
- 101 => Attr::Background(Color::Named(NamedColor::BrightRed)),
- 102 => Attr::Background(Color::Named(NamedColor::BrightGreen)),
- 103 => Attr::Background(Color::Named(NamedColor::BrightYellow)),
- 104 => Attr::Background(Color::Named(NamedColor::BrightBlue)),
- 105 => Attr::Background(Color::Named(NamedColor::BrightMagenta)),
- 106 => Attr::Background(Color::Named(NamedColor::BrightCyan)),
- 107 => Attr::Background(Color::Named(NamedColor::BrightWhite)),
- _ => unhandled!(),
- };
-
- handler.terminal_attribute(attr);
-
- i += 1; // C-for expr
}
},
- 'n' => handler.device_status(writer, arg_or_default!(idx: 0, default: 0) as usize),
- 'r' => {
- if private {
- unhandled!();
- }
+ ('n', None) => handler.device_status(writer, arg_or_default!(idx: 0, default: 0) as usize),
+ ('q', Some(b' ')) => {
+ // DECSCUSR (CSI Ps SP q) -- Set Cursor Style
+ let style = match arg_or_default!(idx: 0, default: 0) {
+ 0 => None,
+ 1 | 2 => Some(CursorStyle::Block),
+ 3 | 4 => Some(CursorStyle::Underline),
+ 5 | 6 => Some(CursorStyle::Beam),
+ _ => unhandled!(),
+ };
+
+ handler.set_cursor_style(style);
+ },
+ ('r', None) => {
let arg0 = arg_or_default!(idx: 0, default: 1) as usize;
let top = Line(arg0 - 1);
// Bottom should be included in the range, but range end is not
@@ -1104,19 +1046,8 @@ where
handler.set_scrolling_region(top..bottom);
},
- 's' => handler.save_cursor_position(),
- 'u' => handler.restore_cursor_position(),
- 'q' => {
- let style = match arg_or_default!(idx: 0, default: 0) {
- 0 => None,
- 1 | 2 => Some(CursorStyle::Block),
- 3 | 4 => Some(CursorStyle::Underline),
- 5 | 6 => Some(CursorStyle::Beam),
- _ => unhandled!(),
- };
-
- handler.set_cursor_style(style);
- },
+ ('s', None) => handler.save_cursor_position(),
+ ('u', None) => handler.restore_cursor_position(),
_ => unhandled!(),
}
}
@@ -1174,6 +1105,97 @@ where
}
}
+fn attrs_from_sgr_parameters(parameters: &[i64]) -> Vec<Option<Attr>> {
+ // Sometimes a C-style for loop is just what you need
+ let mut i = 0; // C-for initializer
+ let mut attrs = Vec::with_capacity(parameters.len());
+ loop {
+ if i >= parameters.len() {
+ // C-for condition
+ break;
+ }
+
+ let attr = match parameters[i] {
+ 0 => Some(Attr::Reset),
+ 1 => Some(Attr::Bold),
+ 2 => Some(Attr::Dim),
+ 3 => Some(Attr::Italic),
+ 4 => Some(Attr::Underscore),
+ 5 => Some(Attr::BlinkSlow),
+ 6 => Some(Attr::BlinkFast),
+ 7 => Some(Attr::Reverse),
+ 8 => Some(Attr::Hidden),
+ 9 => Some(Attr::Strike),
+ 21 => Some(Attr::CancelBold),
+ 22 => Some(Attr::CancelBoldDim),
+ 23 => Some(Attr::CancelItalic),
+ 24 => Some(Attr::CancelUnderline),
+ 25 => Some(Attr::CancelBlink),
+ 27 => Some(Attr::CancelReverse),
+ 28 => Some(Attr::CancelHidden),
+ 29 => Some(Attr::CancelStrike),
+ 30 => Some(Attr::Foreground(Color::Named(NamedColor::Black))),
+ 31 => Some(Attr::Foreground(Color::Named(NamedColor::Red))),
+ 32 => Some(Attr::Foreground(Color::Named(NamedColor::Green))),
+ 33 => Some(Attr::Foreground(Color::Named(NamedColor::Yellow))),
+ 34 => Some(Attr::Foreground(Color::Named(NamedColor::Blue))),
+ 35 => Some(Attr::Foreground(Color::Named(NamedColor::Magenta))),
+ 36 => Some(Attr::Foreground(Color::Named(NamedColor::Cyan))),
+ 37 => Some(Attr::Foreground(Color::Named(NamedColor::White))),
+ 38 => {
+ let mut start = 0;
+ if let Some(color) = parse_color(&parameters[i..], &mut start) {
+ i += start;
+ Some(Attr::Foreground(color))
+ } else {
+ None
+ }
+ },
+ 39 => Some(Attr::Foreground(Color::Named(NamedColor::Foreground))),
+ 40 => Some(Attr::Background(Color::Named(NamedColor::Black))),
+ 41 => Some(Attr::Background(Color::Named(NamedColor::Red))),
+ 42 => Some(Attr::Background(Color::Named(NamedColor::Green))),
+ 43 => Some(Attr::Background(Color::Named(NamedColor::Yellow))),
+ 44 => Some(Attr::Background(Color::Named(NamedColor::Blue))),
+ 45 => Some(Attr::Background(Color::Named(NamedColor::Magenta))),
+ 46 => Some(Attr::Background(Color::Named(NamedColor::Cyan))),
+ 47 => Some(Attr::Background(Color::Named(NamedColor::White))),
+ 48 => {
+ let mut start = 0;
+ if let Some(color) = parse_color(&parameters[i..], &mut start) {
+ i += start;
+ Some(Attr::Background(color))
+ } else {
+ None
+ }
+ },
+ 49 => Some(Attr::Background(Color::Named(NamedColor::Background))),
+ 90 => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlack))),
+ 91 => Some(Attr::Foreground(Color::Named(NamedColor::BrightRed))),
+ 92 => Some(Attr::Foreground(Color::Named(NamedColor::BrightGreen))),
+ 93 => Some(Attr::Foreground(Color::Named(NamedColor::BrightYellow))),
+ 94 => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlue))),
+ 95 => Some(Attr::Foreground(Color::Named(NamedColor::BrightMagenta))),
+ 96 => Some(Attr::Foreground(Color::Named(NamedColor::BrightCyan))),
+ 97 => Some(Attr::Foreground(Color::Named(NamedColor::BrightWhite))),
+ 100 => Some(Attr::Background(Color::Named(NamedColor::BrightBlack))),
+ 101 => Some(Attr::Background(Color::Named(NamedColor::BrightRed))),
+ 102 => Some(Attr::Background(Color::Named(NamedColor::BrightGreen))),
+ 103 => Some(Attr::Background(Color::Named(NamedColor::BrightYellow))),
+ 104 => Some(Attr::Background(Color::Named(NamedColor::BrightBlue))),
+ 105 => Some(Attr::Background(Color::Named(NamedColor::BrightMagenta))),
+ 106 => Some(Attr::Background(Color::Named(NamedColor::BrightCyan))),
+ 107 => Some(Attr::Background(Color::Named(NamedColor::BrightWhite))),
+ _ => None,
+ };
+
+ attrs.push(attr);
+
+ i += 1; // C-for expr
+ }
+ attrs
+}
+
/// Parse a color specifier from list of attributes
fn parse_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
if attrs.len() < 2 {
diff --git a/alacritty_terminal/tests/ref.rs b/alacritty_terminal/tests/ref.rs
index fb87adb1..b6efb6a8 100644
--- a/alacritty_terminal/tests/ref.rs
+++ b/alacritty_terminal/tests/ref.rs
@@ -53,6 +53,7 @@ ref_tests! {
grid_reset
row_reset
zerowidth
+ selective_erasure
}
fn read_u8<P>(path: P) -> Vec<u8>
diff --git a/alacritty_terminal/tests/ref/selective_erasure/alacritty.recording b/alacritty_terminal/tests/ref/selective_erasure/alacritty.recording
new file mode 100644
index 00000000..aae1560f
--- /dev/null
+++ b/alacritty_terminal/tests/ref/selective_erasure/alacritty.recording
@@ -0,0 +1,2 @@
+A[1"qB[2"qC[?2J
+A[1"qB[2"qC[?2K
diff --git a/alacritty_terminal/tests/ref/selective_erasure/config.json b/alacritty_terminal/tests/ref/selective_erasure/config.json
new file mode 100644
index 00000000..6fc49fd7
--- /dev/null
+++ b/alacritty_terminal/tests/ref/selective_erasure/config.json
@@ -0,0 +1 @@
+{"history_size":0} \ No newline at end of file
diff --git a/alacritty_terminal/tests/ref/selective_erasure/grid.json b/alacritty_terminal/tests/ref/selective_erasure/grid.json
new file mode 100644
index 00000000..08632f7d
--- /dev/null
+++ b/alacritty_terminal/tests/ref/selective_erasure/grid.json
@@ -0,0 +1 @@
+{"raw":{"inner":[{"inner":[{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":0},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3}],"zero":0,"visible_lines":2,"len":3},"cols":10,"lines":3,"display_offset":0,"scroll_limit":0,"max_scroll_limit":0,"url_highlight":null} \ No newline at end of file
diff --git a/alacritty_terminal/tests/ref/selective_erasure/size.json b/alacritty_terminal/tests/ref/selective_erasure/size.json
new file mode 100644
index 00000000..58891d8a
--- /dev/null
+++ b/alacritty_terminal/tests/ref/selective_erasure/size.json
@@ -0,0 +1 @@
+{"width":70.0,"height":63.0,"cell_width":7.0,"cell_height":21.0,"padding_x":0.0,"padding_y":0.0,"dpr":1.0} \ No newline at end of file