mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
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.
This commit is contained in:
parent
b20d285782
commit
33cfc52909
7 changed files with 167 additions and 138 deletions
|
@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- On Linux, respect fontconfig's `embeddedbitmap` configuration option
|
||||
- Selecting trailing tab with semantic expansion
|
||||
- URL parser incorrectly handling Markdown URLs and angled brackets
|
||||
- Intermediate bytes of CSI sequences not checked
|
||||
|
||||
## 0.3.3
|
||||
|
||||
|
|
|
@ -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(¶meters[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(¶meters[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 {
|
||||
|
|
|
@ -53,6 +53,7 @@ ref_tests! {
|
|||
grid_reset
|
||||
row_reset
|
||||
zerowidth
|
||||
selective_erasure
|
||||
}
|
||||
|
||||
fn read_u8<P>(path: P) -> Vec<u8>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[HA[1"qB[2"qC[?2J
|
||||
A[1"qB[2"qC[?2K
|
|
@ -0,0 +1 @@
|
|||
{"history_size":0}
|
1
alacritty_terminal/tests/ref/selective_erasure/grid.json
Normal file
1
alacritty_terminal/tests/ref/selective_erasure/grid.json
Normal file
|
@ -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}
|
1
alacritty_terminal/tests/ref/selective_erasure/size.json
Normal file
1
alacritty_terminal/tests/ref/selective_erasure/size.json
Normal file
|
@ -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}
|
Loading…
Reference in a new issue