fix(compatibility): upgrade vte to support csi subparameters (#469)

* fix(compatibility): upgrade vte to support csi subparameters

* style(fmt): rustfmt and clippy
This commit is contained in:
Aram Drevekenin 2021-05-07 16:03:45 +02:00 committed by GitHub
parent 62991f138b
commit 632a7a3209
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 218 additions and 263 deletions

6
Cargo.lock generated
View File

@ -1871,9 +1871,9 @@ dependencies = [
[[package]]
name = "vte"
version = "0.8.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96cc8a191608603611e78c6ec11dafef37e3cca0775aeef1931824753e81711d"
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
dependencies = [
"arrayvec",
"utf8parse 0.2.0",
@ -2282,7 +2282,7 @@ dependencies = [
"termios",
"unicode-truncate",
"unicode-width",
"vte 0.8.0",
"vte 0.10.1",
"wasmer",
"wasmer-wasi",
"zellij-tile",

View File

@ -30,7 +30,7 @@ termion = "1.5.0"
termios = "0.3"
unicode-truncate = "0.2.0"
unicode-width = "0.1.8"
vte = "0.8.0"
vte = "0.10.1"
strum = "0.20.0"
lazy_static = "1.4.0"
wasmer = "1.0.0"

View File

@ -4,6 +4,8 @@ use std::{
fmt::{self, Debug, Formatter},
};
use vte::{Params, Perform};
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
const SCROLL_BACK: usize = 10_000;
@ -811,7 +813,8 @@ impl Grid {
pub fn show_cursor(&mut self) {
self.cursor.is_hidden = false;
}
pub fn set_scroll_region(&mut self, top_line_index: usize, bottom_line_index: usize) {
pub fn set_scroll_region(&mut self, top_line_index: usize, bottom_line_index: Option<usize>) {
let bottom_line_index = bottom_line_index.unwrap_or(self.height);
self.scroll_region = Some((top_line_index, bottom_line_index));
}
pub fn clear_scroll_region(&mut self) {
@ -925,7 +928,7 @@ impl Grid {
}
}
impl vte::Perform for Grid {
impl Perform for Grid {
fn print(&mut self, c: char) {
let c = self.cursor.charsets[self.active_charset].map(c);
// apparently, building TerminalCharacter like this without a "new" method
@ -966,7 +969,7 @@ impl vte::Perform for Grid {
}
}
fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {
fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {
// TBD
}
@ -982,80 +985,71 @@ impl vte::Perform for Grid {
// TBD
}
fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) {
fn csi_dispatch(&mut self, params: &Params, _intermediates: &[u8], _ignore: bool, c: char) {
let mut params_iter = params.iter();
let mut next_param_or = |default: u16| {
params_iter
.next()
.map(|param| param[0])
.filter(|&param| param != 0)
.unwrap_or(default) as usize
};
if c == 'm' {
self.cursor
.pending_styles
.add_style_from_ansi_params(params);
.add_style_from_ansi_params(&mut params_iter);
} else if c == 'C' {
// move cursor forward
let move_by = if params[0] == 0 {
1
} else {
params[0] as usize
};
let move_by = next_param_or(1);
self.move_cursor_forward_until_edge(move_by);
} else if c == 'K' {
// clear line (0 => right, 1 => left, 2 => all)
if params[0] == 0 {
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
char_to_replace.styles = self.cursor.pending_styles;
self.replace_characters_in_line_after_cursor(char_to_replace);
} else if params[0] == 1 {
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
char_to_replace.styles = self.cursor.pending_styles;
self.replace_characters_in_line_before_cursor(char_to_replace);
} else if params[0] == 2 {
self.clear_cursor_line();
}
if let Some(clear_type) = params_iter.next().map(|param| param[0]) {
if clear_type == 0 {
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
char_to_replace.styles = self.cursor.pending_styles;
self.replace_characters_in_line_after_cursor(char_to_replace);
} else if clear_type == 1 {
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
char_to_replace.styles = self.cursor.pending_styles;
self.replace_characters_in_line_before_cursor(char_to_replace);
} else if clear_type == 2 {
self.clear_cursor_line();
}
};
} else if c == 'J' {
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
char_to_replace.styles = self.cursor.pending_styles;
if params[0] == 0 {
self.clear_all_after_cursor(char_to_replace);
} else if params[0] == 1 {
self.clear_all_before_cursor(char_to_replace);
} else if params[0] == 2 {
self.clear_all(char_to_replace);
}
if let Some(clear_type) = params_iter.next().map(|param| param[0]) {
if clear_type == 0 {
self.clear_all_after_cursor(char_to_replace);
} else if clear_type == 1 {
self.clear_all_before_cursor(char_to_replace);
} else if clear_type == 2 {
self.clear_all(char_to_replace);
}
};
// TODO: implement 1
} else if c == 'H' || c == 'f' {
// goto row/col
// we subtract 1 from the row/column because these are 1 indexed
// (except when they are 0, in which case they should be 1
// don't look at me, I don't make the rules)
let (row, col) = if params.len() == 1 {
if params[0] == 0 {
(0, params[0] as usize)
} else {
((params[0] as usize).saturating_sub(1), params[0] as usize)
}
} else if params[0] == 0 {
(0, (params[1] as usize).saturating_sub(1))
} else {
(
(params[0] as usize).saturating_sub(1),
(params[1] as usize).saturating_sub(1),
)
};
let row = next_param_or(1).saturating_sub(1);
let col = next_param_or(1).saturating_sub(1);
let pad_character = EMPTY_TERMINAL_CHARACTER;
self.move_cursor_to(col, row, pad_character);
} else if c == 'A' {
// move cursor up until edge of screen
let move_up_count = if params[0] == 0 { 1 } else { params[0] };
let move_up_count = next_param_or(1);
self.move_cursor_up(move_up_count as usize);
} else if c == 'B' {
// move cursor down until edge of screen
let move_down_count = if params[0] == 0 { 1 } else { params[0] };
let move_down_count = next_param_or(1);
let pad_character = EMPTY_TERMINAL_CHARACTER;
self.move_cursor_down(move_down_count as usize, pad_character);
} else if c == 'D' {
let move_back_count = if params[0] == 0 {
1
} else {
params[0] as usize
};
let move_back_count = next_param_or(1);
self.move_cursor_back(move_back_count);
} else if c == 'l' {
let first_intermediate_is_questionmark = match _intermediates.get(0) {
@ -1064,8 +1058,8 @@ impl vte::Perform for Grid {
_ => false,
};
if first_intermediate_is_questionmark {
match params.get(0) {
Some(&1049) => {
match params_iter.next().map(|param| param[0]) {
Some(1049) => {
if let Some((
alternative_lines_above,
alternative_viewport,
@ -1081,29 +1075,29 @@ impl vte::Perform for Grid {
self.change_size(self.height, self.width); // the alternative_viewport might have been of a different size...
self.mark_for_rerender();
}
Some(&25) => {
Some(25) => {
self.hide_cursor();
self.mark_for_rerender();
}
Some(&1) => {
Some(1) => {
self.cursor_key_mode = false;
}
Some(&3) => {
Some(3) => {
// DECCOLM - only side effects
self.scroll_region = None;
self.clear_all(EMPTY_TERMINAL_CHARACTER);
self.cursor.x = 0;
self.cursor.y = 0;
}
Some(&6) => {
Some(6) => {
self.erasure_mode = false;
}
Some(&7) => {
Some(7) => {
self.disable_linewrap = true;
}
_ => {}
};
} else if let Some(&4) = params.get(0) {
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
self.insert_mode = false;
}
} else if c == 'h' {
@ -1113,12 +1107,12 @@ impl vte::Perform for Grid {
_ => false,
};
if first_intermediate_is_questionmark {
match params.get(0) {
Some(&25) => {
match params_iter.next().map(|param| param[0]) {
Some(25) => {
self.show_cursor();
self.mark_for_rerender();
}
Some(&1049) => {
Some(1049) => {
let current_lines_above = std::mem::replace(
&mut self.lines_above,
VecDeque::with_capacity(SCROLL_BACK),
@ -1130,99 +1124,75 @@ impl vte::Perform for Grid {
Some((current_lines_above, current_viewport, current_cursor));
self.clear_viewport_before_rendering = true;
}
Some(&1) => {
Some(1) => {
self.cursor_key_mode = true;
}
Some(&3) => {
Some(3) => {
// DECCOLM - only side effects
self.scroll_region = None;
self.clear_all(EMPTY_TERMINAL_CHARACTER);
self.cursor.x = 0;
self.cursor.y = 0;
}
Some(&6) => {
Some(6) => {
self.erasure_mode = true;
}
Some(&7) => {
Some(7) => {
self.disable_linewrap = false;
}
_ => {}
};
} else if let Some(&4) = params.get(0) {
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
self.insert_mode = true;
}
} else if c == 'r' {
if params.len() > 1 {
// minus 1 because these are 1 indexed
let top_line_index = (params[0] as usize).saturating_sub(1);
let bottom_line_index = (params[1] as usize).saturating_sub(1);
self.set_scroll_region(top_line_index, bottom_line_index);
let top = (next_param_or(1) as usize).saturating_sub(1);
let bottom = params_iter
.next()
.map(|param| param[0] as usize)
.filter(|&param| param != 0)
.map(|bottom| bottom.saturating_sub(1));
self.set_scroll_region(top, bottom);
if self.erasure_mode {
self.move_cursor_to_line(top_line_index, EMPTY_TERMINAL_CHARACTER);
self.move_cursor_to_line(top, EMPTY_TERMINAL_CHARACTER);
self.move_cursor_to_beginning_of_line();
}
self.show_cursor();
} else {
self.clear_scroll_region();
}
} else if c == 'M' {
// delete lines if currently inside scroll region
let line_count_to_delete = if params[0] == 0 {
1
} else {
params[0] as usize
};
let line_count_to_delete = next_param_or(1);
let pad_character = EMPTY_TERMINAL_CHARACTER;
self.delete_lines_in_scroll_region(line_count_to_delete, pad_character);
} else if c == 'L' {
// insert blank lines if inside scroll region
let line_count_to_add = if params[0] == 0 {
1
} else {
params[0] as usize
};
let line_count_to_add = next_param_or(1);
let pad_character = EMPTY_TERMINAL_CHARACTER;
self.add_empty_lines_in_scroll_region(line_count_to_add, pad_character);
} else if c == 'q' {
// ignore for now to run on mac
} else if c == 'G' {
let column = if params[0] == 0 {
0
} else {
params[0] as usize - 1
};
let column = next_param_or(1).saturating_sub(1);
self.move_cursor_to_column(column);
} else if c == 'g' {
if params[0] == 0 {
let clear_type = next_param_or(0);
if clear_type == 0 {
self.clear_tabstop(self.cursor.x);
} else if params[0] == 3 {
} else if clear_type == 3 {
self.clear_all_tabstops();
}
} else if c == 'd' {
// goto line
let line = if params[0] == 0 {
1
} else {
// minus 1 because this is 1 indexed
params[0] as usize - 1
};
let line = next_param_or(1).saturating_sub(1);
let pad_character = EMPTY_TERMINAL_CHARACTER;
self.move_cursor_to_line(line, pad_character);
} else if c == 'P' {
// erase characters
let count = if params[0] == 0 {
1
} else {
params[0] as usize
};
let count = next_param_or(1);
self.erase_characters(count, self.cursor.pending_styles);
} else if c == 'X' {
// erase characters and replace with empty characters of current style
let count = if params[0] == 0 {
1
} else {
params[0] as usize
};
let count = next_param_or(1);
self.replace_with_empty_chars(count, self.cursor.pending_styles);
} else if c == 'T' {
/*
@ -1230,32 +1200,18 @@ impl vte::Perform for Grid {
* Scroll down, new lines inserted at top of screen
* [4T = Scroll down 4, bring previous lines back into view
*/
let line_count: i64 = *params.get(0).expect("A number of lines was expected.");
if line_count >= 0 {
self.rotate_scroll_region_up(line_count as usize);
} else {
// TODO: can this actually happen?
self.rotate_scroll_region_down(line_count.abs() as usize);
}
let line_count = next_param_or(1);
self.rotate_scroll_region_up(line_count as usize);
} else if c == 'S' {
// move scroll up
let count = if params[0] == 0 {
1
} else {
params[0] as usize
};
let count = next_param_or(1);
self.rotate_scroll_region_down(count);
} else if c == 's' {
self.save_cursor_position();
} else if c == 'u' {
self.restore_cursor_position();
} else if c == '@' {
let count = if params[0] == 0 {
1
} else {
params[0] as usize
};
let count = next_param_or(1);
for _ in 0..count {
// TODO: should this be styled?
self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER);

View File

@ -1,8 +1,10 @@
use unicode_width::UnicodeWidthChar;
use crate::utils::logging::debug_log_to_file;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Index, IndexMut};
use vte::ParamsIter;
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
character: ' ',
@ -327,138 +329,123 @@ impl CharacterStyles {
self.hidden = Some(AnsiCode::Reset);
self.strike = Some(AnsiCode::Reset);
}
pub fn add_style_from_ansi_params(&mut self, ansi_params: &[i64]) {
let mut params_used = 1; // if there's a parameter, it is always used
match ansi_params {
[] | [0, ..] => self.reset_all(),
[1, ..] => *self = self.bold(Some(AnsiCode::On)),
[2, ..] => *self = self.dim(Some(AnsiCode::On)),
[3, ..] => *self = self.italic(Some(AnsiCode::On)),
[4, ..] => *self = self.underline(Some(AnsiCode::On)),
[5, ..] => *self = self.blink_slow(Some(AnsiCode::On)),
[6, ..] => *self = self.blink_fast(Some(AnsiCode::On)),
[7, ..] => *self = self.reverse(Some(AnsiCode::On)),
[8, ..] => *self = self.hidden(Some(AnsiCode::On)),
[9, ..] => *self = self.strike(Some(AnsiCode::On)),
[21, ..] => *self = self.bold(Some(AnsiCode::Reset)),
[22, ..] => {
*self = self.bold(Some(AnsiCode::Reset));
*self = self.dim(Some(AnsiCode::Reset));
}
[23, ..] => *self = self.italic(Some(AnsiCode::Reset)),
[24, ..] => *self = self.underline(Some(AnsiCode::Reset)),
[25, ..] => {
*self = self.blink_slow(Some(AnsiCode::Reset));
*self = self.blink_fast(Some(AnsiCode::Reset));
}
[27, ..] => *self = self.reverse(Some(AnsiCode::Reset)),
[28, ..] => *self = self.hidden(Some(AnsiCode::Reset)),
[29, ..] => *self = self.strike(Some(AnsiCode::Reset)),
[30, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))),
[31, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))),
[32, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))),
[33, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
[34, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))),
[35, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
[36, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
[37, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))),
[38, 2, ..] => {
let ansi_code = AnsiCode::RgbCode((
*ansi_params.get(2).unwrap() as u8,
*ansi_params.get(3).unwrap() as u8,
*ansi_params.get(4).unwrap() as u8,
));
*self = self.foreground(Some(ansi_code));
params_used += 4 // one for the indicator (2 in this case) and three for the rgb code
}
[38, 5, ..] => {
let ansi_code = AnsiCode::ColorIndex(*ansi_params.get(2).unwrap() as u8);
*self = self.foreground(Some(ansi_code));
params_used += 2 // one for the indicator (5 in this case) and one for the color index
}
[38, ..] => {
// this is a bug
// it means we got a color encoding we don't know how to handle (or is invalid)
params_used += 1; // even if it's a bug, let's not create an endless loop, eh?
}
[39, ..] => *self = self.foreground(Some(AnsiCode::Reset)),
[40, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))),
[41, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))),
[42, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))),
[43, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
[44, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))),
[45, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
[46, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
[47, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))),
[48, 2, ..] => {
let ansi_code = AnsiCode::RgbCode((
*ansi_params.get(2).unwrap() as u8,
*ansi_params.get(3).unwrap() as u8,
*ansi_params.get(4).unwrap() as u8,
));
*self = self.background(Some(ansi_code));
params_used += 4 // one for the indicator (2 in this case) and three for the rgb code
}
[48, 5, ..] => {
let ansi_code = AnsiCode::ColorIndex(*ansi_params.get(2).unwrap() as u8);
*self = self.background(Some(ansi_code));
params_used += 2 // one for the indicator (5 in this case) and one for the color index
}
[48, ..] => {
// this is a bug
// it means we got a color encoding we don't know how to handle (or is invalid)
params_used += 1; // even if it's a bug, let's not create an endless loop, eh?
}
[49, ..] => *self = self.background(Some(AnsiCode::Reset)),
[90, ..] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
}
[91, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
[92, ..] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
}
[93, ..] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
}
[94, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlue))),
[95, ..] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
}
[96, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightCyan))),
[97, ..] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
}
[100, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
}
[101, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
[102, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
}
[103, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
}
[104, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlue)))
}
[105, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
}
[106, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightCyan)))
}
[107, ..] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
}
_ => {
// if this happens, it's a bug
let _ = debug_log_to_file(format!("unhandled csi m code {:?}", ansi_params));
return;
}
}
if let Some(next_params) = ansi_params.get(params_used..) {
if !next_params.is_empty() {
self.add_style_from_ansi_params(next_params);
pub fn add_style_from_ansi_params(&mut self, params: &mut ParamsIter) {
while let Some(param) = params.next() {
match param {
[] | [0] => self.reset_all(),
[1] => *self = self.bold(Some(AnsiCode::On)),
[2] => *self = self.dim(Some(AnsiCode::On)),
[3] => *self = self.italic(Some(AnsiCode::On)),
[4] => *self = self.underline(Some(AnsiCode::On)),
[5] => *self = self.blink_slow(Some(AnsiCode::On)),
[6] => *self = self.blink_fast(Some(AnsiCode::On)),
[7] => *self = self.reverse(Some(AnsiCode::On)),
[8] => *self = self.hidden(Some(AnsiCode::On)),
[9] => *self = self.strike(Some(AnsiCode::On)),
[21] => *self = self.bold(Some(AnsiCode::Reset)),
[22] => {
*self = self.bold(Some(AnsiCode::Reset));
*self = self.dim(Some(AnsiCode::Reset));
}
[23] => *self = self.italic(Some(AnsiCode::Reset)),
[24] => *self = self.underline(Some(AnsiCode::Reset)),
[25] => {
*self = self.blink_slow(Some(AnsiCode::Reset));
*self = self.blink_fast(Some(AnsiCode::Reset));
}
[27] => *self = self.reverse(Some(AnsiCode::Reset)),
[28] => *self = self.hidden(Some(AnsiCode::Reset)),
[29] => *self = self.strike(Some(AnsiCode::Reset)),
[30] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))),
[31] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))),
[32] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))),
[33] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
[34] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))),
[35] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
[36] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
[37] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))),
[38] => {
let mut iter = params.map(|param| param[0]);
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
*self = self.foreground(Some(ansi_code));
}
}
[38, params @ ..] => {
let rgb_start = if params.len() > 4 { 2 } else { 1 };
let rgb_iter = params[rgb_start..].iter().copied();
let mut iter = std::iter::once(params[0]).chain(rgb_iter);
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
*self = self.foreground(Some(ansi_code));
}
}
[39] => *self = self.foreground(Some(AnsiCode::Reset)),
[40] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))),
[41] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))),
[42] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))),
[43] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
[44] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))),
[45] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
[46] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
[47] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))),
[48] => {
let mut iter = params.map(|param| param[0]);
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
*self = self.background(Some(ansi_code));
}
}
[48, params @ ..] => {
let rgb_start = if params.len() > 4 { 2 } else { 1 };
let rgb_iter = params[rgb_start..].iter().copied();
let mut iter = std::iter::once(params[0]).chain(rgb_iter);
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
*self = self.background(Some(ansi_code));
}
}
[49] => *self = self.background(Some(AnsiCode::Reset)),
[90] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
}
[91] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
[92] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
}
[93] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
}
[94] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlue))),
[95] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
}
[96] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightCyan))),
[97] => {
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
}
[100] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
}
[101] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
[102] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
}
[103] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
}
[104] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlue)))
}
[105] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
}
[106] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightCyan)))
}
[107] => {
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
}
_ => {
let _ = debug_log_to_file(format!("unhandled csi m code {:?}", param));
return;
}
}
}
}
@ -756,3 +743,15 @@ impl TerminalCharacter {
self.width() > 1
}
}
fn parse_sgr_color(params: &mut dyn Iterator<Item = u16>) -> Option<AnsiCode> {
match params.next() {
Some(2) => Some(AnsiCode::RgbCode((
u8::try_from(params.next()?).ok()?,
u8::try_from(params.next()?).ok()?,
u8::try_from(params.next()?).ok()?,
))),
Some(5) => Some(AnsiCode::ColorIndex(u8::try_from(params.next()?).ok()?)),
_ => None,
}
}

View File

@ -3,7 +3,7 @@ source: src/tests/integration/compatibility.rs
expression: snapshot_before_quit
---
1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
2 [ 0.0%] Load average: 1.40 1.43 1.38
3 [ 0.0%] Uptime: 2 days, 07:33:50