summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2021-05-07 16:03:45 +0200
committerGitHub <noreply@github.com>2021-05-07 16:03:45 +0200
commit632a7a3209f16da1ff7330f8465106959e996d75 (patch)
tree9e7780cf0f2b66d97f1d968a56f4ef530f3b30ca
parent62991f138bfa35b739234fd89e252b16c9c1cc97 (diff)
fix(compatibility): upgrade vte to support csi subparameters (#469)
* fix(compatibility): upgrade vte to support csi subparameters * style(fmt): rustfmt and clippy
-rw-r--r--Cargo.lock6
-rw-r--r--Cargo.toml2
-rw-r--r--src/client/panes/grid.rs208
-rw-r--r--src/client/panes/terminal_character.rs263
-rw-r--r--src/tests/integration/snapshots/zellij__tests__integration__compatibility__htop_scrolling.snap2
5 files changed, 218 insertions, 263 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f499d1b8b..4f7255dfa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index df9b199d4..0e9136c81 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/src/client/panes/grid.rs b/src/client/panes/grid.rs
index 9d9242209..824c83844 100644
--- a/src/client/panes/grid.rs
+++ b/src/client/panes/grid.rs
@@ -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);
diff --git a/src/client/panes/terminal_character.rs b/src/client/panes/terminal_character.rs
index 31e017b11..c7c616c17 100644
--- a/src/client/panes/terminal_character.rs
+++ b/src/client/panes/terminal_character.rs
@@ -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]);