use crate::term::BufWrite as _;
use std::convert::TryInto as _;
use unicode_width::UnicodeWidthChar as _;
const DEFAULT_MULTI_PARAMS: &[i64] = &[0];
#[derive(enumset::EnumSetType, Debug)]
enum Mode {
ApplicationKeypad,
ApplicationCursor,
HideCursor,
AlternateScreen,
BracketedPaste,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MouseProtocolMode {
None,
Press,
PressRelease,
ButtonMotion,
AnyMotion,
}
impl Default for MouseProtocolMode {
fn default() -> Self {
Self::None
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MouseProtocolEncoding {
Default,
Utf8,
Sgr,
}
impl Default for MouseProtocolEncoding {
fn default() -> Self {
Self::Default
}
}
#[derive(Clone, Debug)]
pub struct Screen {
grid: crate::grid::Grid,
alternate_grid: crate::grid::Grid,
attrs: crate::attrs::Attrs,
saved_attrs: crate::attrs::Attrs,
title: String,
icon_name: String,
modes: enumset::EnumSet<Mode>,
mouse_protocol_mode: MouseProtocolMode,
mouse_protocol_encoding: MouseProtocolEncoding,
audible_bell_count: usize,
visual_bell_count: usize,
}
impl Screen {
pub(crate) fn new(
size: crate::grid::Size,
scrollback_len: usize,
) -> Self {
Self {
grid: crate::grid::Grid::new(size, scrollback_len),
alternate_grid: crate::grid::Grid::new(size, 0),
attrs: crate::attrs::Attrs::default(),
saved_attrs: crate::attrs::Attrs::default(),
title: String::default(),
icon_name: String::default(),
modes: enumset::EnumSet::default(),
mouse_protocol_mode: MouseProtocolMode::default(),
mouse_protocol_encoding: MouseProtocolEncoding::default(),
audible_bell_count: 0,
visual_bell_count: 0,
}
}
pub(crate) fn set_size(&mut self, rows: u16, cols: u16) {
self.grid.set_size(crate::grid::Size { rows, cols });
self.alternate_grid
.set_size(crate::grid::Size { rows, cols });
}
pub fn size(&self) -> (u16, u16) {
let size = self.grid().size();
(size.rows, size.cols)
}
pub fn scrollback(&self) -> usize {
self.grid().scrollback()
}
pub(crate) fn set_scrollback(&mut self, rows: usize) {
self.grid_mut().set_scrollback(rows);
}
pub fn contents(&self) -> String {
let mut contents = String::new();
self.write_contents(&mut contents);
contents
}
fn write_contents(&self, contents: &mut String) {
self.grid().write_contents(contents);
}
pub fn rows(
&self,
start: u16,
width: u16,
) -> impl Iterator<Item = String> + '_ {
self.grid().visible_rows().map(move |row| {
let mut contents = String::new();
row.write_contents(&mut contents, start, width, false);
contents
})
}
pub fn contents_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
self.write_contents_formatted(&mut contents);
contents
}
fn write_contents_formatted(&self, contents: &mut Vec<u8>) {
crate::term::HideCursor::new(self.hide_cursor()).write_buf(contents);
let prev_attrs = self.grid().write_contents_formatted(contents);
self.attrs.write_escape_code_diff(contents, &prev_attrs);
}
pub fn rows_formatted(
&self,
start: u16,
width: u16,
) -> impl Iterator<Item = Vec<u8>> + '_ {
self.grid().visible_rows().enumerate().map(move |(i, row)| {
let i = i.try_into().unwrap();
let mut contents = vec![];
row.write_contents_formatted(
&mut contents,
start,
width,
i,
false,
crate::grid::Pos { row: i, col: start },
crate::attrs::Attrs::default(),
);
contents
})
}
pub fn contents_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
self.write_contents_diff(&mut contents, prev);
contents
}
fn write_contents_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
if self.hide_cursor() != prev.hide_cursor() {
crate::term::HideCursor::new(self.hide_cursor())
.write_buf(contents);
}
let prev_attrs = self.grid().write_contents_diff(
contents,
prev.grid(),
prev.attrs,
);
self.attrs.write_escape_code_diff(contents, &prev_attrs);
}
pub fn rows_diff<'a>(
&'a self,
prev: &'a Self,
start: u16,
width: u16,
) -> impl Iterator<Item = Vec<u8>> + 'a {
self.grid()
.visible_rows()
.zip(prev.grid().visible_rows())
.enumerate()
.map(move |(i, (row, prev_row))| {
let i = i.try_into().unwrap();
let mut contents = vec![];
row.write_contents_diff(
&mut contents,
prev_row,
start,
width,
i,
false,
crate::grid::Pos { row: i, col: start },
crate::attrs::Attrs::default(),
);
contents
})
}
pub fn input_mode_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
self.write_input_mode_formatted(&mut contents);
contents
}
fn write_input_mode_formatted(&self, contents: &mut Vec<u8>) {
crate::term::ApplicationKeypad::new(
self.mode(Mode::ApplicationKeypad),
)
.write_buf(contents);
crate::term::ApplicationCursor::new(
self.mode(Mode::ApplicationCursor),
)
.write_buf(contents);
crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste))
.write_buf(contents);
crate::term::MouseProtocolMode::new(
self.mouse_protocol_mode,
MouseProtocolMode::None,
)
.write_buf(contents);
crate::term::MouseProtocolEncoding::new(
self.mouse_protocol_encoding,
MouseProtocolEncoding::Default,
)
.write_buf(contents);
}
pub fn input_mode_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
self.write_input_mode_diff(&mut contents, prev);
contents
}
fn write_input_mode_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
if self.mode(Mode::ApplicationKeypad)
!= prev.mode(Mode::ApplicationKeypad)
{
crate::term::ApplicationKeypad::new(
self.mode(Mode::ApplicationKeypad),
)
.write_buf(contents);
}
if self.mode(Mode::ApplicationCursor)
!= prev.mode(Mode::ApplicationCursor)
{
crate::term::ApplicationCursor::new(
self.mode(Mode::ApplicationCursor),
)
.write_buf(contents);
}
if self.mode(Mode::BracketedPaste) != prev.mode(Mode::BracketedPaste)
{
crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste))
.write_buf(contents);
}
crate::term::MouseProtocolMode::new(
self.mouse_protocol_mode,
prev.mouse_protocol_mode,
)
.write_buf(contents);
crate::term::MouseProtocolEncoding::new(
self.mouse_protocol_encoding,
prev.mouse_protocol_encoding,
)
.write_buf(contents);
}
pub fn title_formatted(&self) -> Vec<u8> {
let mut contents = vec![];
self.write_title_formatted(&mut contents);
contents
}
fn write_title_formatted(&self, contents: &mut Vec<u8>) {
crate::term::ChangeTitle::new(&self.icon_name, &self.title, "", "")
.write_buf(contents);
}
pub fn title_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
self.write_title_diff(&mut contents, prev);
contents
}
fn write_title_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
crate::term::ChangeTitle::new(
&self.icon_name,
&self.title,
&prev.icon_name,
&prev.title,
)
.write_buf(contents);
}
pub fn bells_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
self.write_bells_diff(&mut contents, prev);
contents
}
fn write_bells_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
if self.audible_bell_count != prev.audible_bell_count {
crate::term::AudibleBell::default().write_buf(contents);
}
if self.visual_bell_count != prev.visual_bell_count {
crate::term::VisualBell::default().write_buf(contents);
}
}
pub fn cell(&self, row: u16, col: u16) -> Option<&crate::cell::Cell> {
self.grid().visible_cell(crate::grid::Pos { row, col })
}
pub fn cursor_position(&self) -> (u16, u16) {
let pos = self.grid().pos();
(pos.row, pos.col)
}
pub fn title(&self) -> &str {
&self.title
}
pub fn icon_name(&self) -> &str {
&self.icon_name
}
pub fn audible_bell_count(&self) -> usize {
self.audible_bell_count
}
pub fn visual_bell_count(&self) -> usize {
self.visual_bell_count
}
pub fn application_keypad(&self) -> bool {
self.mode(Mode::ApplicationKeypad)
}
pub fn application_cursor(&self) -> bool {
self.mode(Mode::ApplicationCursor)
}
pub fn hide_cursor(&self) -> bool {
self.mode(Mode::HideCursor)
}
pub fn bracketed_paste(&self) -> bool {
self.mode(Mode::BracketedPaste)
}
pub fn mouse_protocol_mode(&self) -> MouseProtocolMode {
self.mouse_protocol_mode
}
pub fn mouse_protocol_encoding(&self) -> MouseProtocolEncoding {
self.mouse_protocol_encoding
}
fn grid(&self) -> &crate::grid::Grid {
if self.mode(Mode::AlternateScreen) {
&self.alternate_grid
} else {
&self.grid
}
}
fn grid_mut(&mut self) -> &mut crate::grid::Grid {
if self.mode(Mode::AlternateScreen) {
&mut self.alternate_grid
} else {
&mut self.grid
}
}
fn drawing_row(&self, pos: crate::grid::Pos) -> Option<&crate::row::Row> {
self.grid().drawing_row(pos)
}
fn drawing_cell(
&self,
pos: crate::grid::Pos,
) -> Option<&crate::cell::Cell> {
self.grid().drawing_cell(pos)
}
fn drawing_cell_mut(
&mut self,
pos: crate::grid::Pos,
) -> Option<&mut crate::cell::Cell> {
self.grid_mut().drawing_cell_mut(pos)
}
fn current_cell(&self) -> &crate::cell::Cell {
self.grid().current_cell()
}
fn current_cell_mut(&mut self) -> &mut crate::cell::Cell {
self.grid_mut().current_cell_mut()
}
fn enter_alternate_grid(&mut self) {
self.grid_mut().set_scrollback(0);
self.set_mode(Mode::AlternateScreen);
}
fn exit_alternate_grid(&mut self) {
self.clear_mode(Mode::AlternateScreen);
}
fn save_cursor(&mut self) {
self.grid_mut().save_cursor();
self.saved_attrs = self.attrs;
}
fn restore_cursor(&mut self) {
self.grid_mut().restore_cursor();
self.attrs = self.saved_attrs;
}
fn set_mode(&mut self, mode: Mode) {
self.modes.insert(mode);
}
fn clear_mode(&mut self, mode: Mode) {
self.modes.remove(mode);
}
fn mode(&self, mode: Mode) -> bool {
self.modes.contains(mode)
}
fn set_mouse_mode(&mut self, mode: MouseProtocolMode) {
self.mouse_protocol_mode = mode;
}
fn clear_mouse_mode(&mut self, mode: MouseProtocolMode) {
if self.mouse_protocol_mode == mode {
self.mouse_protocol_mode = MouseProtocolMode::default();
}
}
fn set_mouse_encoding(&mut self, encoding: MouseProtocolEncoding) {
self.mouse_protocol_encoding = encoding;
}
fn clear_mouse_encoding(&mut self, encoding: MouseProtocolEncoding) {
if self.mouse_protocol_encoding == encoding {
self.mouse_protocol_encoding = MouseProtocolEncoding::default();
}
}
}
impl Screen {
#[allow(clippy::too_many_lines)]
fn text(&mut self, c: char) {
let pos = self.grid().pos();
let size = self.grid().size();
let attrs = self.attrs;
let width = c.width().unwrap_or(0).try_into().unwrap();
let wrap_width = if width == 0 { 1 } else { width };
let mut wrap = false;
if pos.col > size.cols - wrap_width {
let last_cell = self
.drawing_cell(crate::grid::Pos {
row: pos.row,
col: size.cols - 1,
})
.unwrap();
if last_cell.has_contents() || last_cell.is_wide_continuation() {
wrap = true;
}
}
self.grid_mut().col_wrap(wrap_width, wrap);
let pos = self.grid().pos();
if width == 0 {
if pos.col > 0 {
let mut prev_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: pos.row,
col: pos.col - 1,
})
.unwrap();
if prev_cell.is_wide_continuation() {
prev_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: pos.row,
col: pos.col - 2,
})
.unwrap();
}
prev_cell.append(c);
} else if pos.row > 0 {
let prev_row = self
.drawing_row(crate::grid::Pos {
row: pos.row - 1,
col: 0,
})
.unwrap();
if prev_row.wrapped() {
let mut prev_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: pos.row - 1,
col: size.cols - 1,
})
.unwrap();
if prev_cell.is_wide_continuation() {
prev_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: pos.row - 1,
col: size.cols - 2,
})
.unwrap();
}
prev_cell.append(c);
}
}
} else {
let drawing_pos = if pos.col < size.cols {
pos
} else {
crate::grid::Pos {
row: pos.row + 1,
col: 0,
}
};
if self
.drawing_cell(drawing_pos)
.unwrap()
.is_wide_continuation()
{
let prev_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: drawing_pos.row,
col: drawing_pos.col - 1,
})
.unwrap();
prev_cell.clear(attrs);
}
if self.drawing_cell(drawing_pos).unwrap().is_wide() {
let next_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: drawing_pos.row,
col: drawing_pos.col + 1,
})
.unwrap();
next_cell.clear(attrs);
}
let cell = self.current_cell_mut();
cell.set(c, attrs);
self.grid_mut().col_inc(1);
if width > 1 {
let pos = self.grid().pos();
if self.current_cell().is_wide() {
let next_next_cell = self
.drawing_cell_mut(crate::grid::Pos {
row: pos.row,
col: pos.col + 1,
})
.unwrap();
next_next_cell.clear(attrs);
}
let next_cell = self.current_cell_mut();
next_cell.clear(attrs);
next_cell.set_wide_continuation(true);
self.grid_mut().col_inc(1);
}
}
}
fn bel(&mut self) {
self.audible_bell_count += 1;
}
fn bs(&mut self) {
self.grid_mut().col_dec(1);
}
fn tab(&mut self) {
self.grid_mut().col_tab();
}
fn lf(&mut self) {
self.grid_mut().row_inc_scroll(1);
}
fn vt(&mut self) {
self.lf();
}
fn ff(&mut self) {
self.lf();
}
fn cr(&mut self) {
self.grid_mut().col_set(0);
}
fn decsc(&mut self) {
self.save_cursor();
}
fn decrc(&mut self) {
self.restore_cursor();
}
fn deckpam(&mut self) {
self.set_mode(Mode::ApplicationKeypad);
}
fn deckpnm(&mut self) {
self.clear_mode(Mode::ApplicationKeypad);
}
fn ri(&mut self) {
self.grid_mut().row_dec_scroll(1);
}
fn ris(&mut self) {
let title = self.title.clone();
let icon_name = self.icon_name.clone();
let audible_bell_count = self.audible_bell_count;
let visual_bell_count = self.visual_bell_count;
*self = Self::new(self.grid.size(), self.grid.scrollback_len());
self.title = title;
self.icon_name = icon_name;
self.audible_bell_count = audible_bell_count;
self.visual_bell_count = visual_bell_count;
}
fn vb(&mut self) {
self.visual_bell_count += 1;
}
fn ich(&mut self, count: u16) {
self.grid_mut().insert_cells(count);
}
fn cuu(&mut self, offset: u16) {
self.grid_mut().row_dec_clamp(offset);
}
fn cud(&mut self, offset: u16) {
self.grid_mut().row_inc_clamp(offset);
}
fn cuf(&mut self, offset: u16) {
self.grid_mut().col_inc_clamp(offset);
}
fn cub(&mut self, offset: u16) {
self.grid_mut().col_dec(offset);
}
fn cha(&mut self, col: u16) {
self.grid_mut().col_set(col - 1);
}
fn cup(&mut self, (row, col): (u16, u16)) {
self.grid_mut().set_pos(crate::grid::Pos {
row: row - 1,
col: col - 1,
});
}
fn ed(&mut self, mode: u16) {
let attrs = self.attrs;
match mode {
0 => self.grid_mut().erase_all_forward(attrs),
1 => self.grid_mut().erase_all_backward(attrs),
2 => self.grid_mut().erase_all(attrs),
n => {
log::debug!("unhandled ED mode: {}", n);
}
}
}
fn decsed(&mut self, mode: u16) {
self.ed(mode);
}
fn el(&mut self, mode: u16) {
let attrs = self.attrs;
match mode {
0 => self.grid_mut().erase_row_forward(attrs),
1 => self.grid_mut().erase_row_backward(attrs),
2 => self.grid_mut().erase_row(attrs),
n => {
log::debug!("unhandled EL mode: {}", n);
}
}
}
fn decsel(&mut self, mode: u16) {
self.el(mode);
}
fn il(&mut self, count: u16) {
self.grid_mut().insert_lines(count);
}
fn dl(&mut self, count: u16) {
self.grid_mut().delete_lines(count);
}
fn dch(&mut self, count: u16) {
self.grid_mut().delete_cells(count);
}
fn su(&mut self, count: u16) {
self.grid_mut().scroll_up(count);
}
fn sd(&mut self, count: u16) {
self.grid_mut().scroll_down(count);
}
fn ech(&mut self, count: u16) {
let attrs = self.attrs;
self.grid_mut().erase_cells(count, attrs);
}
fn vpa(&mut self, row: u16) {
self.grid_mut().row_set(row - 1);
}
fn sm(&mut self, params: &[i64]) {
if log::log_enabled!(log::Level::Debug) {
log::debug!("unhandled SM mode: {}", param_str(params))
}
}
fn decset(&mut self, params: &[i64]) {
for param in params {
match param {
1 => self.set_mode(Mode::ApplicationCursor),
6 => self.grid_mut().set_origin_mode(true),
9 => self.set_mouse_mode(MouseProtocolMode::Press),
25 => self.clear_mode(Mode::HideCursor),
47 => self.enter_alternate_grid(),
1000 => self.set_mouse_mode(MouseProtocolMode::PressRelease),
1002 => self.set_mouse_mode(MouseProtocolMode::ButtonMotion),
1003 => self.set_mouse_mode(MouseProtocolMode::AnyMotion),
1005 => self.set_mouse_encoding(MouseProtocolEncoding::Utf8),
1006 => self.set_mouse_encoding(MouseProtocolEncoding::Sgr),
1049 => {
self.decsc();
self.alternate_grid.clear();
self.enter_alternate_grid();
}
2004 => self.set_mode(Mode::BracketedPaste),
n => {
log::debug!("unhandled DECSET mode: {}", n);
}
}
}
}
fn rm(&mut self, params: &[i64]) {
if log::log_enabled!(log::Level::Debug) {
log::debug!("unhandled RM mode: {}", param_str(params))
}
}
fn decrst(&mut self, params: &[i64]) {
for param in params {
match param {
1 => self.clear_mode(Mode::ApplicationCursor),
6 => self.grid_mut().set_origin_mode(false),
9 => self.clear_mouse_mode(MouseProtocolMode::Press),
25 => self.set_mode(Mode::HideCursor),
47 => {
self.exit_alternate_grid();
}
1000 => {
self.clear_mouse_mode(MouseProtocolMode::PressRelease)
}
1002 => {
self.clear_mouse_mode(MouseProtocolMode::ButtonMotion)
}
1003 => self.clear_mouse_mode(MouseProtocolMode::AnyMotion),
1005 => {
self.clear_mouse_encoding(MouseProtocolEncoding::Utf8)
}
1006 => self.clear_mouse_encoding(MouseProtocolEncoding::Sgr),
1049 => {
self.exit_alternate_grid();
self.decrc();
}
2004 => self.clear_mode(Mode::BracketedPaste),
n => {
log::debug!("unhandled DECRST mode: {}", n);
}
}
}
}
fn sgr(&mut self, params: &[i64]) {
let mut i = 0;
macro_rules! next_param {
() => {
if i >= params.len() {
return;
} else if let Some(n) = i64_to_u8(params[i]) {
i += 1;
n
} else {
return;
}
};
}
loop {
match next_param!() {
0 => self.attrs = crate::attrs::Attrs::default(),
1 => self.attrs.set_bold(true),
3 => self.attrs.set_italic(true),
4 => self.attrs.set_underline(true),
7 => self.attrs.set_inverse(true),
22 => self.attrs.set_bold(false),
23 => self.attrs.set_italic(false),
24 => self.attrs.set_underline(false),
27 => self.attrs.set_inverse(false),
n if n >= 30 && n <= 37 => {
self.attrs.fgcolor = crate::attrs::Color::Idx(n - 30);
}
38 => match next_param!() {
2 => {
let r = next_param!();
let g = next_param!();
let b = next_param!();
self.attrs.fgcolor =
crate::attrs::Color::Rgb(r, g, b);
}
5 => {
self.attrs.fgcolor =
crate::attrs::Color::Idx(next_param!());
}
n => {
log::debug!("unhandled SGR mode: 38 {}", n);
return;
}
},
39 => {
self.attrs.fgcolor = crate::attrs::Color::Default;
}
n if n >= 40 && n <= 47 => {
self.attrs.bgcolor = crate::attrs::Color::Idx(n - 40);
}
48 => match next_param!() {
2 => {
let r = next_param!();
let g = next_param!();
let b = next_param!();
self.attrs.bgcolor =
crate::attrs::Color::Rgb(r, g, b);
}
5 => {
self.attrs.bgcolor =
crate::attrs::Color::Idx(next_param!());
}
n => {
log::debug!("unhandled SGR mode: 48 {}", n);
return;
}
},
49 => {
self.attrs.bgcolor = crate::attrs::Color::Default;
}
n if n >= 90 && n <= 97 => {
self.attrs.fgcolor = crate::attrs::Color::Idx(n - 82);
}
n if n >= 100 && n <= 107 => {
self.attrs.bgcolor = crate::attrs::Color::Idx(n - 92);
}
n => {
log::debug!("unhandled SGR mode: {}", n);
}
}
}
}
fn decstbm(&mut self, (top, bottom): (u16, u16)) {
self.grid_mut().set_scroll_region(top - 1, bottom - 1);
}
fn osc0(&mut self, s: &[u8]) {
self.osc1(s);
self.osc2(s);
}
fn osc1(&mut self, s: &[u8]) {
if let Ok(s) = std::str::from_utf8(s) {
self.icon_name = s.to_string();
}
}
fn osc2(&mut self, s: &[u8]) {
if let Ok(s) = std::str::from_utf8(s) {
self.title = s.to_string();
}
}
}
impl vte::Perform for Screen {
fn print(&mut self, c: char) {
self.text(c)
}
fn execute(&mut self, b: u8) {
match b {
7 => self.bel(),
8 => self.bs(),
9 => self.tab(),
10 => self.lf(),
11 => self.vt(),
12 => self.ff(),
13 => self.cr(),
_ => {
log::debug!("unhandled control character: {}", b);
}
}
}
fn esc_dispatch(
&mut self,
_params: &[i64],
intermediates: &[u8],
_ignore: bool,
b: u8,
) {
match intermediates.get(0) {
None => match b {
b'7' => self.decsc(),
b'8' => self.decrc(),
b'=' => self.deckpam(),
b'>' => self.deckpnm(),
b'M' => self.ri(),
b'c' => self.ris(),
b'g' => self.vb(),
_ => {
log::debug!("unhandled escape code: ESC {}", b);
}
},
Some(i) => {
log::debug!("unhandled escape code: ESC {} {}", i, b);
}
}
}
fn csi_dispatch(
&mut self,
params: &[i64],
intermediates: &[u8],
_ignore: bool,
c: char,
) {
match intermediates.get(0) {
None => match c {
'@' => self.ich(canonicalize_params_1(params, 1)),
'A' => self.cuu(canonicalize_params_1(params, 1)),
'B' => self.cud(canonicalize_params_1(params, 1)),
'C' => self.cuf(canonicalize_params_1(params, 1)),
'D' => self.cub(canonicalize_params_1(params, 1)),
'G' => self.cha(canonicalize_params_1(params, 1)),
'H' => self.cup(canonicalize_params_2(params, 1, 1)),
'J' => self.ed(canonicalize_params_1(params, 0)),
'K' => self.el(canonicalize_params_1(params, 0)),
'L' => self.il(canonicalize_params_1(params, 1)),
'M' => self.dl(canonicalize_params_1(params, 1)),
'P' => self.dch(canonicalize_params_1(params, 1)),
'S' => self.su(canonicalize_params_1(params, 1)),
'T' => self.sd(canonicalize_params_1(params, 1)),
'X' => self.ech(canonicalize_params_1(params, 1)),
'd' => self.vpa(canonicalize_params_1(params, 1)),
'h' => self.sm(canonicalize_params_multi(params)),
'l' => self.rm(canonicalize_params_multi(params)),
'm' => self.sgr(canonicalize_params_multi(params)),
'r' => self.decstbm(canonicalize_params_decstbm(
params,
self.grid().size(),
)),
_ => {
if log::log_enabled!(log::Level::Debug) {
log::debug!(
"unhandled csi sequence: CSI {} {}",
param_str(params),
c
)
}
}
},
Some(b'?') => match c {
'J' => self.decsed(canonicalize_params_1(params, 0)),
'K' => self.decsel(canonicalize_params_1(params, 0)),
'h' => self.decset(canonicalize_params_multi(params)),
'l' => self.decrst(canonicalize_params_multi(params)),
_ => {
if log::log_enabled!(log::Level::Debug) {
log::debug!(
"unhandled csi sequence: CSI ? {} {}",
param_str(params),
c
)
}
}
},
Some(i) => {
if log::log_enabled!(log::Level::Debug) {
log::debug!(
"unhandled csi sequence: CSI {} {} {}",
i,
param_str(params),
c
)
}
}
}
}
fn osc_dispatch(&mut self, params: &[&[u8]]) {
match (params.get(0), params.get(1)) {
(Some(&b"0"), Some(s)) => self.osc0(s),
(Some(&b"1"), Some(s)) => self.osc1(s),
(Some(&b"2"), Some(s)) => self.osc2(s),
_ => {
if log::log_enabled!(log::Level::Debug) {
log::debug!(
"unhandled osc sequence: OSC {}",
osc_param_str(params),
)
}
}
}
}
fn hook(&mut self, params: &[i64], intermediates: &[u8], _ignore: bool) {
if log::log_enabled!(log::Level::Debug) {
match intermediates.get(0) {
None => log::debug!(
"unhandled dcs sequence: DCS {}",
param_str(params),
),
Some(i) => log::debug!(
"unhandled dcs sequence: DCS {} {}",
i,
param_str(params),
),
}
}
}
fn put(&mut self, _: u8) {}
fn unhook(&mut self) {}
}
fn canonicalize_params_1(params: &[i64], default: u16) -> u16 {
let first = params.get(0).copied().unwrap_or(0);
if first == 0 {
default
} else {
i64_to_u16(first)
}
}
fn canonicalize_params_2(
params: &[i64],
default1: u16,
default2: u16,
) -> (u16, u16) {
let first = params.get(0).copied().unwrap_or(0);
let first = if first == 0 {
default1
} else {
i64_to_u16(first)
};
let second = params.get(1).copied().unwrap_or(0);
let second = if second == 0 {
default2
} else {
i64_to_u16(second)
};
(first, second)
}
fn canonicalize_params_multi(params: &[i64]) -> &[i64] {
if params.is_empty() {
DEFAULT_MULTI_PARAMS
} else {
params
}
}
fn canonicalize_params_decstbm(
params: &[i64],
size: crate::grid::Size,
) -> (u16, u16) {
let top = params.get(0).copied().unwrap_or(0);
let top = if top == 0 { 1 } else { i64_to_u16(top) };
let bottom = params.get(1).copied().unwrap_or(0);
let bottom = if bottom == 0 {
size.rows
} else {
i64_to_u16(bottom)
};
(top, bottom)
}
fn i64_to_u16(i: i64) -> u16 {
if i < 0 {
0
} else if i > i64::from(u16::max_value()) {
u16::max_value()
} else {
i.try_into().unwrap()
}
}
fn i64_to_u8(i: i64) -> Option<u8> {
if i < 0 || i > i64::from(u8::max_value()) {
None
} else {
Some(i.try_into().unwrap())
}
}
fn param_str(params: &[i64]) -> String {
let strs: Vec<_> = params
.iter()
.map(std::string::ToString::to_string)
.collect();
strs.join(" ; ")
}
fn osc_param_str(params: &[&[u8]]) -> String {
let strs: Vec<_> = params
.iter()
.map(|b| format!("\"{}\"", std::string::String::from_utf8_lossy(*b)))
.collect();
strs.join(" ; ")
}