diff options
Diffstat (limited to 'src/perform.rs')
-rw-r--r-- | src/perform.rs | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/perform.rs b/src/perform.rs new file mode 100644 index 0000000..1c172f1 --- /dev/null +++ b/src/perform.rs @@ -0,0 +1,222 @@ +pub struct WrappedScreen(pub crate::Screen); + +impl vte::Perform for WrappedScreen { + fn print(&mut self, c: char) { + if c == '\u{fffd}' || ('\u{80}'..'\u{a0}').contains(&c) { + log::debug!("unhandled text character: {c}"); + } + self.0.text(c); + } + + fn execute(&mut self, b: u8) { + match b { + 8 => self.0.bs(), + 9 => self.0.tab(), + 10 => self.0.lf(), + 11 => self.0.vt(), + 12 => self.0.ff(), + 13 => self.0.cr(), + // we don't implement shift in/out alternate character sets, but + // it shouldn't count as an "error" + 7 | 14 | 15 => {} + _ => { + log::debug!("unhandled control character: {b}"); + } + } + } + + fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, b: u8) { + intermediates.first().map_or_else( + || match b { + b'7' => self.0.decsc(), + b'8' => self.0.decrc(), + b'=' => self.0.deckpam(), + b'>' => self.0.deckpnm(), + b'M' => self.0.ri(), + b'c' => self.0.ris(), + b'g' => {} + _ => { + log::debug!("unhandled escape code: ESC {b}"); + } + }, + |i| { + log::debug!("unhandled escape code: ESC {i} {b}"); + }, + ); + } + + fn csi_dispatch( + &mut self, + params: &vte::Params, + intermediates: &[u8], + _ignore: bool, + c: char, + ) { + match intermediates.first() { + None => match c { + '@' => self.0.ich(canonicalize_params_1(params, 1)), + 'A' => self.0.cuu(canonicalize_params_1(params, 1)), + 'B' => self.0.cud(canonicalize_params_1(params, 1)), + 'C' => self.0.cuf(canonicalize_params_1(params, 1)), + 'D' => self.0.cub(canonicalize_params_1(params, 1)), + 'G' => self.0.cha(canonicalize_params_1(params, 1)), + 'H' => self.0.cup(canonicalize_params_2(params, 1, 1)), + 'J' => self.0.ed(canonicalize_params_1(params, 0)), + 'K' => self.0.el(canonicalize_params_1(params, 0)), + 'L' => self.0.il(canonicalize_params_1(params, 1)), + 'M' => self.0.dl(canonicalize_params_1(params, 1)), + 'P' => self.0.dch(canonicalize_params_1(params, 1)), + 'S' => self.0.su(canonicalize_params_1(params, 1)), + 'T' => self.0.sd(canonicalize_params_1(params, 1)), + 'X' => self.0.ech(canonicalize_params_1(params, 1)), + 'd' => self.0.vpa(canonicalize_params_1(params, 1)), + 'h' => self.0.sm(params), + 'l' => self.0.rm(params), + 'm' => self.0.sgr(params), + 'r' => self.0.decstbm(canonicalize_params_decstbm( + params, + self.0.grid().size(), + )), + 't' => self.0.xtwinops(params), + _ => { + if log::log_enabled!(log::Level::Debug) { + log::debug!( + "unhandled csi sequence: CSI {} {}", + param_str(params), + c + ); + } + } + }, + Some(b'?') => match c { + 'J' => self.0.decsed(canonicalize_params_1(params, 0)), + 'K' => self.0.decsel(canonicalize_params_1(params, 0)), + 'h' => self.0.decset(params), + 'l' => self.0.decrst(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]], _bel_terminated: bool) { + match (params.get(0), params.get(1)) { + (Some(&b"0"), Some(s)) => self.0.osc0(s), + (Some(&b"1"), Some(s)) => self.0.osc1(s), + (Some(&b"2"), Some(s)) => self.0.osc2(s), + _ => { + if log::log_enabled!(log::Level::Debug) { + log::debug!( + "unhandled osc sequence: OSC {}", + osc_param_str(params), + ); + } + } + } + } + + fn hook( + &mut self, + params: &vte::Params, + intermediates: &[u8], + _ignore: bool, + action: char, + ) { + if log::log_enabled!(log::Level::Debug) { + intermediates.first().map_or_else( + || { + log::debug!( + "unhandled dcs sequence: DCS {} {}", + param_str(params), + action, + ); + }, + |i| { + log::debug!( + "unhandled dcs sequence: DCS {} {} {}", + i, + param_str(params), + action, + ); + }, + ); + } + } +} + +fn canonicalize_params_1(params: &vte::Params, default: u16) -> u16 { + let first = params.iter().next().map_or(0, |x| *x.first().unwrap_or(&0)); + if first == 0 { + default + } else { + first + } +} + +fn canonicalize_params_2( + params: &vte::Params, + default1: u16, + default2: u16, +) -> (u16, u16) { + let mut iter = params.iter(); + let first = iter.next().map_or(0, |x| *x.first().unwrap_or(&0)); + let first = if first == 0 { default1 } else { first }; + + let second = iter.next().map_or(0, |x| *x.first().unwrap_or(&0)); + let second = if second == 0 { default2 } else { second }; + + (first, second) +} + +fn canonicalize_params_decstbm( + params: &vte::Params, + size: crate::grid::Size, +) -> (u16, u16) { + let mut iter = params.iter(); + let top = iter.next().map_or(0, |x| *x.first().unwrap_or(&0)); + let top = if top == 0 { 1 } else { top }; + + let bottom = iter.next().map_or(0, |x| *x.first().unwrap_or(&0)); + let bottom = if bottom == 0 { size.rows } else { bottom }; + + (top, bottom) +} + +pub fn param_str(params: &vte::Params) -> String { + let strs: Vec<_> = params + .iter() + .map(|subparams| { + let subparam_strs: Vec<_> = subparams + .iter() + .map(std::string::ToString::to_string) + .collect(); + subparam_strs.join(" : ") + }) + .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(" ; ") +} |