mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-23 08:57:14 +03:00
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:
parent
62991f138b
commit
632a7a3209
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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(|¶m| 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(|¶m| 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);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user