aboutsummaryrefslogtreecommitdiffstats
path: root/src/perform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/perform.rs')
-rw-r--r--src/perform.rs222
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(" ; ")
+}