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
5 changed files with 218 additions and 263 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -1871,9 +1871,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vte"
|
name = "vte"
|
||||||
version = "0.8.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96cc8a191608603611e78c6ec11dafef37e3cca0775aeef1931824753e81711d"
|
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"utf8parse 0.2.0",
|
"utf8parse 0.2.0",
|
||||||
|
|
@ -2282,7 +2282,7 @@ dependencies = [
|
||||||
"termios",
|
"termios",
|
||||||
"unicode-truncate",
|
"unicode-truncate",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"vte 0.8.0",
|
"vte 0.10.1",
|
||||||
"wasmer",
|
"wasmer",
|
||||||
"wasmer-wasi",
|
"wasmer-wasi",
|
||||||
"zellij-tile",
|
"zellij-tile",
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ termion = "1.5.0"
|
||||||
termios = "0.3"
|
termios = "0.3"
|
||||||
unicode-truncate = "0.2.0"
|
unicode-truncate = "0.2.0"
|
||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
vte = "0.8.0"
|
vte = "0.10.1"
|
||||||
strum = "0.20.0"
|
strum = "0.20.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
wasmer = "1.0.0"
|
wasmer = "1.0.0"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ use std::{
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use vte::{Params, Perform};
|
||||||
|
|
||||||
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
|
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
|
||||||
const SCROLL_BACK: usize = 10_000;
|
const SCROLL_BACK: usize = 10_000;
|
||||||
|
|
||||||
|
|
@ -811,7 +813,8 @@ impl Grid {
|
||||||
pub fn show_cursor(&mut self) {
|
pub fn show_cursor(&mut self) {
|
||||||
self.cursor.is_hidden = false;
|
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));
|
self.scroll_region = Some((top_line_index, bottom_line_index));
|
||||||
}
|
}
|
||||||
pub fn clear_scroll_region(&mut self) {
|
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) {
|
fn print(&mut self, c: char) {
|
||||||
let c = self.cursor.charsets[self.active_charset].map(c);
|
let c = self.cursor.charsets[self.active_charset].map(c);
|
||||||
// apparently, building TerminalCharacter like this without a "new" method
|
// 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
|
// TBD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,80 +985,71 @@ impl vte::Perform for Grid {
|
||||||
// TBD
|
// 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' {
|
if c == 'm' {
|
||||||
self.cursor
|
self.cursor
|
||||||
.pending_styles
|
.pending_styles
|
||||||
.add_style_from_ansi_params(params);
|
.add_style_from_ansi_params(&mut params_iter);
|
||||||
} else if c == 'C' {
|
} else if c == 'C' {
|
||||||
// move cursor forward
|
// move cursor forward
|
||||||
let move_by = if params[0] == 0 {
|
let move_by = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
self.move_cursor_forward_until_edge(move_by);
|
self.move_cursor_forward_until_edge(move_by);
|
||||||
} else if c == 'K' {
|
} else if c == 'K' {
|
||||||
// clear line (0 => right, 1 => left, 2 => all)
|
// clear line (0 => right, 1 => left, 2 => all)
|
||||||
if params[0] == 0 {
|
if let Some(clear_type) = params_iter.next().map(|param| param[0]) {
|
||||||
|
if clear_type == 0 {
|
||||||
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
||||||
char_to_replace.styles = self.cursor.pending_styles;
|
char_to_replace.styles = self.cursor.pending_styles;
|
||||||
self.replace_characters_in_line_after_cursor(char_to_replace);
|
self.replace_characters_in_line_after_cursor(char_to_replace);
|
||||||
} else if params[0] == 1 {
|
} else if clear_type == 1 {
|
||||||
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
||||||
char_to_replace.styles = self.cursor.pending_styles;
|
char_to_replace.styles = self.cursor.pending_styles;
|
||||||
self.replace_characters_in_line_before_cursor(char_to_replace);
|
self.replace_characters_in_line_before_cursor(char_to_replace);
|
||||||
} else if params[0] == 2 {
|
} else if clear_type == 2 {
|
||||||
self.clear_cursor_line();
|
self.clear_cursor_line();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
} else if c == 'J' {
|
} else if c == 'J' {
|
||||||
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
|
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
|
||||||
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
||||||
char_to_replace.styles = self.cursor.pending_styles;
|
char_to_replace.styles = self.cursor.pending_styles;
|
||||||
if params[0] == 0 {
|
|
||||||
|
if let Some(clear_type) = params_iter.next().map(|param| param[0]) {
|
||||||
|
if clear_type == 0 {
|
||||||
self.clear_all_after_cursor(char_to_replace);
|
self.clear_all_after_cursor(char_to_replace);
|
||||||
} else if params[0] == 1 {
|
} else if clear_type == 1 {
|
||||||
self.clear_all_before_cursor(char_to_replace);
|
self.clear_all_before_cursor(char_to_replace);
|
||||||
} else if params[0] == 2 {
|
} else if clear_type == 2 {
|
||||||
self.clear_all(char_to_replace);
|
self.clear_all(char_to_replace);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// TODO: implement 1
|
// TODO: implement 1
|
||||||
} else if c == 'H' || c == 'f' {
|
} else if c == 'H' || c == 'f' {
|
||||||
// goto row/col
|
// goto row/col
|
||||||
// we subtract 1 from the row/column because these are 1 indexed
|
// we subtract 1 from the row/column because these are 1 indexed
|
||||||
// (except when they are 0, in which case they should be 1
|
let row = next_param_or(1).saturating_sub(1);
|
||||||
// don't look at me, I don't make the rules)
|
let col = next_param_or(1).saturating_sub(1);
|
||||||
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 pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.move_cursor_to(col, row, pad_character);
|
self.move_cursor_to(col, row, pad_character);
|
||||||
} else if c == 'A' {
|
} else if c == 'A' {
|
||||||
// move cursor up until edge of screen
|
// 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);
|
self.move_cursor_up(move_up_count as usize);
|
||||||
} else if c == 'B' {
|
} else if c == 'B' {
|
||||||
// move cursor down until edge of screen
|
// 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;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.move_cursor_down(move_down_count as usize, pad_character);
|
self.move_cursor_down(move_down_count as usize, pad_character);
|
||||||
} else if c == 'D' {
|
} else if c == 'D' {
|
||||||
let move_back_count = if params[0] == 0 {
|
let move_back_count = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
self.move_cursor_back(move_back_count);
|
self.move_cursor_back(move_back_count);
|
||||||
} else if c == 'l' {
|
} else if c == 'l' {
|
||||||
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
||||||
|
|
@ -1064,8 +1058,8 @@ impl vte::Perform for Grid {
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if first_intermediate_is_questionmark {
|
if first_intermediate_is_questionmark {
|
||||||
match params.get(0) {
|
match params_iter.next().map(|param| param[0]) {
|
||||||
Some(&1049) => {
|
Some(1049) => {
|
||||||
if let Some((
|
if let Some((
|
||||||
alternative_lines_above,
|
alternative_lines_above,
|
||||||
alternative_viewport,
|
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.change_size(self.height, self.width); // the alternative_viewport might have been of a different size...
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
Some(&25) => {
|
Some(25) => {
|
||||||
self.hide_cursor();
|
self.hide_cursor();
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
Some(&1) => {
|
Some(1) => {
|
||||||
self.cursor_key_mode = false;
|
self.cursor_key_mode = false;
|
||||||
}
|
}
|
||||||
Some(&3) => {
|
Some(3) => {
|
||||||
// DECCOLM - only side effects
|
// DECCOLM - only side effects
|
||||||
self.scroll_region = None;
|
self.scroll_region = None;
|
||||||
self.clear_all(EMPTY_TERMINAL_CHARACTER);
|
self.clear_all(EMPTY_TERMINAL_CHARACTER);
|
||||||
self.cursor.x = 0;
|
self.cursor.x = 0;
|
||||||
self.cursor.y = 0;
|
self.cursor.y = 0;
|
||||||
}
|
}
|
||||||
Some(&6) => {
|
Some(6) => {
|
||||||
self.erasure_mode = false;
|
self.erasure_mode = false;
|
||||||
}
|
}
|
||||||
Some(&7) => {
|
Some(7) => {
|
||||||
self.disable_linewrap = true;
|
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;
|
self.insert_mode = false;
|
||||||
}
|
}
|
||||||
} else if c == 'h' {
|
} else if c == 'h' {
|
||||||
|
|
@ -1113,12 +1107,12 @@ impl vte::Perform for Grid {
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if first_intermediate_is_questionmark {
|
if first_intermediate_is_questionmark {
|
||||||
match params.get(0) {
|
match params_iter.next().map(|param| param[0]) {
|
||||||
Some(&25) => {
|
Some(25) => {
|
||||||
self.show_cursor();
|
self.show_cursor();
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
Some(&1049) => {
|
Some(1049) => {
|
||||||
let current_lines_above = std::mem::replace(
|
let current_lines_above = std::mem::replace(
|
||||||
&mut self.lines_above,
|
&mut self.lines_above,
|
||||||
VecDeque::with_capacity(SCROLL_BACK),
|
VecDeque::with_capacity(SCROLL_BACK),
|
||||||
|
|
@ -1130,99 +1124,75 @@ impl vte::Perform for Grid {
|
||||||
Some((current_lines_above, current_viewport, current_cursor));
|
Some((current_lines_above, current_viewport, current_cursor));
|
||||||
self.clear_viewport_before_rendering = true;
|
self.clear_viewport_before_rendering = true;
|
||||||
}
|
}
|
||||||
Some(&1) => {
|
Some(1) => {
|
||||||
self.cursor_key_mode = true;
|
self.cursor_key_mode = true;
|
||||||
}
|
}
|
||||||
Some(&3) => {
|
Some(3) => {
|
||||||
// DECCOLM - only side effects
|
// DECCOLM - only side effects
|
||||||
self.scroll_region = None;
|
self.scroll_region = None;
|
||||||
self.clear_all(EMPTY_TERMINAL_CHARACTER);
|
self.clear_all(EMPTY_TERMINAL_CHARACTER);
|
||||||
self.cursor.x = 0;
|
self.cursor.x = 0;
|
||||||
self.cursor.y = 0;
|
self.cursor.y = 0;
|
||||||
}
|
}
|
||||||
Some(&6) => {
|
Some(6) => {
|
||||||
self.erasure_mode = true;
|
self.erasure_mode = true;
|
||||||
}
|
}
|
||||||
Some(&7) => {
|
Some(7) => {
|
||||||
self.disable_linewrap = false;
|
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;
|
self.insert_mode = true;
|
||||||
}
|
}
|
||||||
} else if c == 'r' {
|
} else if c == 'r' {
|
||||||
if params.len() > 1 {
|
if params.len() > 1 {
|
||||||
// minus 1 because these are 1 indexed
|
let top = (next_param_or(1) as usize).saturating_sub(1);
|
||||||
let top_line_index = (params[0] as usize).saturating_sub(1);
|
let bottom = params_iter
|
||||||
let bottom_line_index = (params[1] as usize).saturating_sub(1);
|
.next()
|
||||||
self.set_scroll_region(top_line_index, bottom_line_index);
|
.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 {
|
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.move_cursor_to_beginning_of_line();
|
||||||
}
|
}
|
||||||
self.show_cursor();
|
|
||||||
} else {
|
} else {
|
||||||
self.clear_scroll_region();
|
self.clear_scroll_region();
|
||||||
}
|
}
|
||||||
} else if c == 'M' {
|
} else if c == 'M' {
|
||||||
// delete lines if currently inside scroll region
|
// delete lines if currently inside scroll region
|
||||||
let line_count_to_delete = if params[0] == 0 {
|
let line_count_to_delete = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.delete_lines_in_scroll_region(line_count_to_delete, pad_character);
|
self.delete_lines_in_scroll_region(line_count_to_delete, pad_character);
|
||||||
} else if c == 'L' {
|
} else if c == 'L' {
|
||||||
// insert blank lines if inside scroll region
|
// insert blank lines if inside scroll region
|
||||||
let line_count_to_add = if params[0] == 0 {
|
let line_count_to_add = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.add_empty_lines_in_scroll_region(line_count_to_add, pad_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' {
|
} else if c == 'G' {
|
||||||
let column = if params[0] == 0 {
|
let column = next_param_or(1).saturating_sub(1);
|
||||||
0
|
|
||||||
} else {
|
|
||||||
params[0] as usize - 1
|
|
||||||
};
|
|
||||||
self.move_cursor_to_column(column);
|
self.move_cursor_to_column(column);
|
||||||
} else if c == 'g' {
|
} 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);
|
self.clear_tabstop(self.cursor.x);
|
||||||
} else if params[0] == 3 {
|
} else if clear_type == 3 {
|
||||||
self.clear_all_tabstops();
|
self.clear_all_tabstops();
|
||||||
}
|
}
|
||||||
} else if c == 'd' {
|
} else if c == 'd' {
|
||||||
// goto line
|
// goto line
|
||||||
let line = if params[0] == 0 {
|
let line = next_param_or(1).saturating_sub(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
// minus 1 because this is 1 indexed
|
|
||||||
params[0] as usize - 1
|
|
||||||
};
|
|
||||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.move_cursor_to_line(line, pad_character);
|
self.move_cursor_to_line(line, pad_character);
|
||||||
} else if c == 'P' {
|
} else if c == 'P' {
|
||||||
// erase characters
|
// erase characters
|
||||||
let count = if params[0] == 0 {
|
let count = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
self.erase_characters(count, self.cursor.pending_styles);
|
self.erase_characters(count, self.cursor.pending_styles);
|
||||||
} else if c == 'X' {
|
} else if c == 'X' {
|
||||||
// erase characters and replace with empty characters of current style
|
// erase characters and replace with empty characters of current style
|
||||||
let count = if params[0] == 0 {
|
let count = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
self.replace_with_empty_chars(count, self.cursor.pending_styles);
|
self.replace_with_empty_chars(count, self.cursor.pending_styles);
|
||||||
} else if c == 'T' {
|
} else if c == 'T' {
|
||||||
/*
|
/*
|
||||||
|
|
@ -1230,32 +1200,18 @@ impl vte::Perform for Grid {
|
||||||
* Scroll down, new lines inserted at top of screen
|
* Scroll down, new lines inserted at top of screen
|
||||||
* [4T = Scroll down 4, bring previous lines back into view
|
* [4T = Scroll down 4, bring previous lines back into view
|
||||||
*/
|
*/
|
||||||
let line_count: i64 = *params.get(0).expect("A number of lines was expected.");
|
let line_count = next_param_or(1);
|
||||||
|
|
||||||
if line_count >= 0 {
|
|
||||||
self.rotate_scroll_region_up(line_count as usize);
|
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);
|
|
||||||
}
|
|
||||||
} else if c == 'S' {
|
} else if c == 'S' {
|
||||||
// move scroll up
|
// move scroll up
|
||||||
let count = if params[0] == 0 {
|
let count = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
self.rotate_scroll_region_down(count);
|
self.rotate_scroll_region_down(count);
|
||||||
} else if c == 's' {
|
} else if c == 's' {
|
||||||
self.save_cursor_position();
|
self.save_cursor_position();
|
||||||
} else if c == 'u' {
|
} else if c == 'u' {
|
||||||
self.restore_cursor_position();
|
self.restore_cursor_position();
|
||||||
} else if c == '@' {
|
} else if c == '@' {
|
||||||
let count = if params[0] == 0 {
|
let count = next_param_or(1);
|
||||||
1
|
|
||||||
} else {
|
|
||||||
params[0] as usize
|
|
||||||
};
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
// TODO: should this be styled?
|
// TODO: should this be styled?
|
||||||
self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER);
|
self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use crate::utils::logging::debug_log_to_file;
|
use crate::utils::logging::debug_log_to_file;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
use vte::ParamsIter;
|
||||||
|
|
||||||
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
|
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
|
||||||
character: ' ',
|
character: ' ',
|
||||||
|
|
@ -327,139 +329,124 @@ impl CharacterStyles {
|
||||||
self.hidden = Some(AnsiCode::Reset);
|
self.hidden = Some(AnsiCode::Reset);
|
||||||
self.strike = Some(AnsiCode::Reset);
|
self.strike = Some(AnsiCode::Reset);
|
||||||
}
|
}
|
||||||
pub fn add_style_from_ansi_params(&mut self, ansi_params: &[i64]) {
|
pub fn add_style_from_ansi_params(&mut self, params: &mut ParamsIter) {
|
||||||
let mut params_used = 1; // if there's a parameter, it is always used
|
while let Some(param) = params.next() {
|
||||||
match ansi_params {
|
match param {
|
||||||
[] | [0, ..] => self.reset_all(),
|
[] | [0] => self.reset_all(),
|
||||||
[1, ..] => *self = self.bold(Some(AnsiCode::On)),
|
[1] => *self = self.bold(Some(AnsiCode::On)),
|
||||||
[2, ..] => *self = self.dim(Some(AnsiCode::On)),
|
[2] => *self = self.dim(Some(AnsiCode::On)),
|
||||||
[3, ..] => *self = self.italic(Some(AnsiCode::On)),
|
[3] => *self = self.italic(Some(AnsiCode::On)),
|
||||||
[4, ..] => *self = self.underline(Some(AnsiCode::On)),
|
[4] => *self = self.underline(Some(AnsiCode::On)),
|
||||||
[5, ..] => *self = self.blink_slow(Some(AnsiCode::On)),
|
[5] => *self = self.blink_slow(Some(AnsiCode::On)),
|
||||||
[6, ..] => *self = self.blink_fast(Some(AnsiCode::On)),
|
[6] => *self = self.blink_fast(Some(AnsiCode::On)),
|
||||||
[7, ..] => *self = self.reverse(Some(AnsiCode::On)),
|
[7] => *self = self.reverse(Some(AnsiCode::On)),
|
||||||
[8, ..] => *self = self.hidden(Some(AnsiCode::On)),
|
[8] => *self = self.hidden(Some(AnsiCode::On)),
|
||||||
[9, ..] => *self = self.strike(Some(AnsiCode::On)),
|
[9] => *self = self.strike(Some(AnsiCode::On)),
|
||||||
[21, ..] => *self = self.bold(Some(AnsiCode::Reset)),
|
[21] => *self = self.bold(Some(AnsiCode::Reset)),
|
||||||
[22, ..] => {
|
[22] => {
|
||||||
*self = self.bold(Some(AnsiCode::Reset));
|
*self = self.bold(Some(AnsiCode::Reset));
|
||||||
*self = self.dim(Some(AnsiCode::Reset));
|
*self = self.dim(Some(AnsiCode::Reset));
|
||||||
}
|
}
|
||||||
[23, ..] => *self = self.italic(Some(AnsiCode::Reset)),
|
[23] => *self = self.italic(Some(AnsiCode::Reset)),
|
||||||
[24, ..] => *self = self.underline(Some(AnsiCode::Reset)),
|
[24] => *self = self.underline(Some(AnsiCode::Reset)),
|
||||||
[25, ..] => {
|
[25] => {
|
||||||
*self = self.blink_slow(Some(AnsiCode::Reset));
|
*self = self.blink_slow(Some(AnsiCode::Reset));
|
||||||
*self = self.blink_fast(Some(AnsiCode::Reset));
|
*self = self.blink_fast(Some(AnsiCode::Reset));
|
||||||
}
|
}
|
||||||
[27, ..] => *self = self.reverse(Some(AnsiCode::Reset)),
|
[27] => *self = self.reverse(Some(AnsiCode::Reset)),
|
||||||
[28, ..] => *self = self.hidden(Some(AnsiCode::Reset)),
|
[28] => *self = self.hidden(Some(AnsiCode::Reset)),
|
||||||
[29, ..] => *self = self.strike(Some(AnsiCode::Reset)),
|
[29] => *self = self.strike(Some(AnsiCode::Reset)),
|
||||||
[30, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))),
|
[30] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))),
|
||||||
[31, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))),
|
[31] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))),
|
||||||
[32, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))),
|
[32] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))),
|
||||||
[33, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
|
[33] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
|
||||||
[34, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))),
|
[34] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))),
|
||||||
[35, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
|
[35] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
|
||||||
[36, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
[36] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
||||||
[37, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))),
|
[37] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))),
|
||||||
[38, 2, ..] => {
|
[38] => {
|
||||||
let ansi_code = AnsiCode::RgbCode((
|
let mut iter = params.map(|param| param[0]);
|
||||||
*ansi_params.get(2).unwrap() as u8,
|
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
|
||||||
*ansi_params.get(3).unwrap() as u8,
|
|
||||||
*ansi_params.get(4).unwrap() as u8,
|
|
||||||
));
|
|
||||||
*self = self.foreground(Some(ansi_code));
|
*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);
|
[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));
|
*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)),
|
[39] => *self = self.foreground(Some(AnsiCode::Reset)),
|
||||||
[40, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))),
|
[40] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))),
|
||||||
[41, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))),
|
[41] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))),
|
||||||
[42, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))),
|
[42] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))),
|
||||||
[43, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
|
[43] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))),
|
||||||
[44, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))),
|
[44] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))),
|
||||||
[45, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
|
[45] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))),
|
||||||
[46, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
[46] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
||||||
[47, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))),
|
[47] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))),
|
||||||
[48, 2, ..] => {
|
[48] => {
|
||||||
let ansi_code = AnsiCode::RgbCode((
|
let mut iter = params.map(|param| param[0]);
|
||||||
*ansi_params.get(2).unwrap() as u8,
|
if let Some(ansi_code) = parse_sgr_color(&mut iter) {
|
||||||
*ansi_params.get(3).unwrap() as u8,
|
|
||||||
*ansi_params.get(4).unwrap() as u8,
|
|
||||||
));
|
|
||||||
*self = self.background(Some(ansi_code));
|
*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);
|
[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));
|
*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)),
|
[49] => *self = self.background(Some(AnsiCode::Reset)),
|
||||||
[90, ..] => {
|
[90] => {
|
||||||
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
|
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
|
||||||
}
|
}
|
||||||
[91, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
|
[91] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
|
||||||
[92, ..] => {
|
[92] => {
|
||||||
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
|
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
|
||||||
}
|
}
|
||||||
[93, ..] => {
|
[93] => {
|
||||||
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
|
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
|
||||||
}
|
}
|
||||||
[94, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlue))),
|
[94] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightBlue))),
|
||||||
[95, ..] => {
|
[95] => {
|
||||||
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
|
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
|
||||||
}
|
}
|
||||||
[96, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightCyan))),
|
[96] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightCyan))),
|
||||||
[97, ..] => {
|
[97] => {
|
||||||
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
|
*self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
|
||||||
}
|
}
|
||||||
[100, ..] => {
|
[100] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlack)))
|
||||||
}
|
}
|
||||||
[101, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
|
[101] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightRed))),
|
||||||
[102, ..] => {
|
[102] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightGreen)))
|
||||||
}
|
}
|
||||||
[103, ..] => {
|
[103] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightYellow)))
|
||||||
}
|
}
|
||||||
[104, ..] => {
|
[104] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlue)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightBlue)))
|
||||||
}
|
}
|
||||||
[105, ..] => {
|
[105] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightMagenta)))
|
||||||
}
|
}
|
||||||
[106, ..] => {
|
[106] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightCyan)))
|
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightCyan)))
|
||||||
}
|
}
|
||||||
[107, ..] => {
|
[107] => {
|
||||||
*self = self.background(Some(AnsiCode::NamedColor(NamedColor::BrightWhite)))
|
*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 {:?}", param));
|
||||||
let _ = debug_log_to_file(format!("unhandled csi m code {:?}", ansi_params));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(next_params) = ansi_params.get(params_used..) {
|
|
||||||
if !next_params.is_empty() {
|
|
||||||
self.add_style_from_ansi_params(next_params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -756,3 +743,15 @@ impl TerminalCharacter {
|
||||||
self.width() > 1
|
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
|
expression: snapshot_before_quit
|
||||||
|
|
||||||
---
|
---
|
||||||
█
|
|
||||||
1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
|
1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
|
||||||
2 [ 0.0%] Load average: 1.40 1.43 1.38
|
2 [ 0.0%] Load average: 1.40 1.43 1.38
|
||||||
3 [ 0.0%] Uptime: 2 days, 07:33:50
|
3 [ 0.0%] Uptime: 2 days, 07:33:50
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue