From ef1a477d4ab0e511a85e5b162a27b0e3a27368b1 Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Thu, 18 Nov 2021 17:47:29 +0100 Subject: [PATCH] ansi parser: PtyView to display cursor & scrolling --- nested/src/terminal/ansi_parser.rs | 509 +++++++++++++++++++++-------- 1 file changed, 380 insertions(+), 129 deletions(-) diff --git a/nested/src/terminal/ansi_parser.rs b/nested/src/terminal/ansi_parser.rs index 60d1c48..da8854a 100644 --- a/nested/src/terminal/ansi_parser.rs +++ b/nested/src/terminal/ansi_parser.rs @@ -8,30 +8,45 @@ use { std::io::Read, //async_std::{io::{Read, ReadExt}}, crate::{ - core::{InnerViewPort, OuterViewPort}, + core::{View, InnerViewPort, OuterViewPort, ViewPort, Observer, ObserverBroadcast}, + projection::ProjectionHelper, terminal::{ TerminalAtom, TerminalStyle, TerminalView }, - index::buffer::IndexBuffer + singleton::{ + SingletonBuffer, + SingletonView + }, + index::{ + buffer::IndexBuffer, + IndexView, + IndexArea + } }, - cgmath::Point2, + cgmath::{Vector2, Point2}, vte::{Params, Parser, Perform} }; +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + pub fn read_ansi_from(ansi_reader: &mut R, port: InnerViewPort) { let mut statemachine = Parser::new(); + let buf_port = ViewPort::new(); + let size_port = ViewPort::>>::new(); + let cursor_port = ViewPort::>>::new(); + let offset_port = ViewPort::>>::new(); + let mut performer = PerfAtom { - cursor: Point2::new(0, 0), - style: TerminalStyle::default(), - invert: false, - term_width: 120, - - cursor_save: Point2::new(0, 0), - - buf: IndexBuffer::new(port), + buf: IndexBuffer::new(buf_port.inner()), + size: SingletonBuffer::new(Vector2::new(120, 40), size_port.inner()), + offset: SingletonBuffer::new(Vector2::new(0, 0), offset_port.inner()), + cursor: SingletonBuffer::new(Point2::new(0, 0), cursor_port.inner()), + cursty: TerminalStyle::default(), + curinv: false, + cursav: Point2::new(0, 0), colors: ColorPalett { black: (1, 1, 1), @@ -42,7 +57,16 @@ pub fn read_ansi_from(ansi_reader: &mut R, port: InnerViewPort< magenta: (118, 38, 113), cyan: (44, 181, 233), white: (204, 204, 204) - } + }, + + pty_proj: PtyView::new( + buf_port.outer(), + cursor_port.outer().map(|x| Some(x)), + offset_port.outer().map(|x| Some(x)), + size_port.outer().map(|x| Some(x)), + + port + ) }; let mut buf = [0; 2048]; @@ -63,6 +87,22 @@ pub fn read_ansi_from(ansi_reader: &mut R, port: InnerViewPort< } } +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +enum TTYColor { + Rgb(u8, u8, u8), + + // 3-Bit/4-Bit colors + Black, LightBlack, + Red, LightRed, + Green, LightGreen, + Yellow, LightYellow, + Blue, LightBlue, + Magenta,LightMagenta, + Cyan, LightCyan, + White, LightWhite, +} + struct ColorPalett { black: (u8, u8, u8), red: (u8, u8, u8), @@ -71,84 +111,279 @@ struct ColorPalett { blue: (u8, u8, u8), magenta: (u8, u8, u8), cyan: (u8, u8, u8), - white: (u8, u8, u8) + white: (u8, u8, u8), } +impl ColorPalett { + fn get_rgb(&self, col: &TTYColor) -> (u8, u8, u8) { + match col { + TTYColor::Rgb(r,g,b) => (*r,*g,*b), + TTYColor::Black | TTYColor::LightBlack => self.black, + TTYColor::Red | TTYColor::LightRed => self.red, + TTYColor::Green | TTYColor::LightGreen => self.green, + TTYColor::Yellow | TTYColor::LightYellow => self.yellow, + TTYColor::Blue | TTYColor::LightBlue => self.blue, + TTYColor::Magenta | TTYColor::LightMagenta => self.magenta, + TTYColor::Cyan | TTYColor::LightCyan => self.cyan, + TTYColor::White | TTYColor::LightWhite => self.white, + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +/// Display Cursor & scrolling +struct PtyView { + buf: Arc, Item = TerminalAtom>>, + curpos: Arc>>>, + offset: Arc>>>, + size: Arc>>>, + + old_offset: Vector2, + old_curpos: Point2, + old_size: Vector2, + + max_pt: Point2, + + cast: Arc>>, + proj_helper: ProjectionHelper +} + +impl View for PtyView { + type Msg = IndexArea>; +} + +impl IndexView> for PtyView { + type Item = TerminalAtom; + + fn get(&self, pt: &Point2) -> Option { + let atom = self.buf.get(&(pt + self.old_offset)); + if self.old_curpos == *pt { + if let Some(mut a) = atom { + let bg_col = a.style.fg_color.unwrap_or((255,255,255)); + let fg_col = a.style.bg_color.unwrap_or((0,0,0)); + a.style.fg_color = Some(fg_col); + a.style.bg_color = Some(bg_col); + Some(a) + } else { + Some(TerminalAtom::new(' ', TerminalStyle::bg_color((255, 255, 255)))) + } + } else { + atom + } + } + + fn area(&self) -> IndexArea> { + IndexArea::Range(Point2::new(0, 0) ..= Point2::new( + std::cmp::max(self.old_curpos.x, self.max_pt.x), + std::cmp::max(self.old_curpos.y, self.max_pt.y) + )) + } +} + +impl PtyView { + fn new( + buf_port: OuterViewPort, Item = TerminalAtom>>, + curpos_port: OuterViewPort>>>, + offset_port: OuterViewPort>>>, + size_port: OuterViewPort>>>, + + out_port: InnerViewPort + ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); + let proj = Arc::new(RwLock::new( + PtyView { + old_curpos: Point2::new(0, 0), + old_size: Vector2::new(0, 0), + old_offset: Vector2::new(0, 0), + max_pt: Point2::new(0, 0), + + curpos: proj_helper.new_singleton_arg( + 0, + curpos_port, + |s: &mut Self, _msg| { + s.cast.notify(&IndexArea::Set(vec![ s.old_curpos ])); + s.old_curpos = s.curpos.get().unwrap_or(Point2::new(0,0)); + s.cast.notify(&IndexArea::Set(vec![ s.old_curpos ])); + }), + + offset: proj_helper.new_singleton_arg( + 1, + offset_port, + |s: &mut Self, _msg| { + // todo + let new_offset = s.offset.get().unwrap_or(Vector2::new(0, 0)); + if s.old_offset != new_offset { + s.old_offset = new_offset; + s.cast.notify(&s.area()); + } + }), + + size: proj_helper.new_singleton_arg( + 2, + size_port, + |s: &mut Self, _msg| { + let new_size = s.size.get().unwrap_or(Vector2::new(0, 0)); + if s.old_size != new_size { + s.old_size = new_size; + s.cast.notify(&s.area()); + } + }), + + buf: proj_helper.new_index_arg( + 3, + buf_port, + |s: &mut Self, area| { + let size = s.old_size; + let area = area.map( + |pt| { + *pt - s.old_offset + } + ); + + if s.max_pt.x < size.x || s.max_pt.y < size.y { + match &area { + IndexArea::Empty => {} + IndexArea::Full => {} + IndexArea::Range(_) => {} + IndexArea::Set(v) => { + let mx = v.iter().map(|pt| pt.x).max().unwrap_or(0); + if mx > s.max_pt.x && mx < size.x { + s.max_pt.x = mx; + } + + let my = v.iter().map(|pt| pt.y).max().unwrap_or(0); + if my > s.max_pt.y && my < size.y { + s.max_pt.y = my; + } + } + } + } + + s.cast.notify(&area); + }), + + cast: out_port.get_broadcast(), + proj_helper + } + )); + + proj.write().unwrap().proj_helper.set_proj(&proj); + out_port.set_view(Some(proj.clone())); + + proj + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + struct PerfAtom { - colors: ColorPalett, - term_width: i16, - - cursor: Point2, - style: TerminalStyle, - invert: bool, - cursor_save: Point2, - buf: IndexBuffer, TerminalAtom>, + size: SingletonBuffer>, + offset: SingletonBuffer>, + cursor: SingletonBuffer>, + cursty: TerminalStyle, + curinv: bool, + cursav: Point2, + + colors: ColorPalett, + + pty_proj: Arc> } impl PerfAtom { fn write_atom(&mut self, pos: Point2, atom: Option) { if let Some(mut a) = atom { - self.buf.insert(pos, a); + self.buf.insert(pos + self.offset.get(), a); } else { self.buf.remove(pos); } } fn get_style(&self) -> TerminalStyle { - let mut style = self.style; - if self.invert { - style.fg_color = Some(self.style.bg_color.unwrap_or(self.colors.black)); - style.bg_color = Some(self.style.fg_color.unwrap_or(self.colors.white)); + let mut style = self.cursty; + if self.curinv { + style.fg_color = Some(self.cursty.bg_color.unwrap_or(self.colors.black)); + style.bg_color = Some(self.cursty.fg_color.unwrap_or(self.colors.white)); } style } + fn set_fg_color(&mut self, col: &TTYColor) { + self.cursty = self.cursty.add(TerminalStyle::fg_color(self.colors.get_rgb(col))); + } + + fn set_bg_color(&mut self, col: &TTYColor) { + self.cursty = self.cursty.add(TerminalStyle::bg_color(self.colors.get_rgb(col))); + } + fn linefeed(&mut self) { - self.cursor.x = 0; - self.cursor.y += 1; + let size = self.size.get(); + let mut c = self.cursor.get_mut(); + c.x = 0; + + if c.y+1 >= size.y { + self.scroll_up(1); + } else { + c.y += 1; + } } fn carriage_return(&mut self) { - self.cursor.x = 0; + let mut c = self.cursor.get_mut(); + c.x = 0; } fn horizontal_tab(&mut self) { - self.cursor.x += 8 - (self.cursor.x % 8); + let mut c = self.cursor.get_mut(); + c.x += 8 - (c.x % 8); } fn backspace(&mut self) { - self.write_atom(self.cursor, None); - self.cursor.x -= 1; - if self.cursor.x < 0 { - self.cursor.y -= 0; - self.cursor.x = self.term_width - 1; - } + //self.write_atom(self.cursor.get(), None); + let mut c = self.cursor.get_mut(); + c.x -= 1; + if c.x < 0 { + c.y -= 0; + c.x = self.size.get().x - 1; + } } fn cursor_up(&mut self, n: usize) { + self.cursor.get_mut().y -= n as i16; } - fn cursor_down(&mut self, n: usize) { + fn cursor_dn(&mut self, n: usize) { + self.cursor.get_mut().y += n as i16; + + // todo: scroll ? + } + + fn scroll_up(&mut self, n: usize) { + self.offset.get_mut().y += n as i16; + } + + fn scroll_dn(&mut self, n: usize) { + self.offset.get_mut().y -= n as i16; } fn save_cursor_position(&mut self) { - self.cursor_save = self.cursor; + self.cursav = self.cursor.get(); } fn restore_cursor_position(&mut self) { - self.cursor = self.cursor_save; + self.cursor.set(self.cursav); } } impl Perform for PerfAtom { - fn print(&mut self, c: char) { - self.write_atom(self.cursor, Some(TerminalAtom::new(c, self.get_style()))); + fn print(&mut self, ch: char) { + let mut c = self.cursor.get_mut(); + self.write_atom(*c, Some(TerminalAtom::new(ch, self.get_style()))); - self.cursor.x += 1; - if self.cursor.x >= self.term_width { - self.cursor.x = 0; - self.cursor.y += 1; + c.x += 1; + if c.x >= self.size.get().x { + self.linefeed(); } } @@ -192,44 +427,61 @@ impl Perform for PerfAtom { 'm' => while let Some(n) = piter.next() { match n[0] { 0 => { - self.style = TerminalStyle::default(); - self.invert = false; + self.cursty = TerminalStyle::default(); + self.curinv = false; } - 1 => self.style = self.style.add(TerminalStyle::bold(true)), - 3 => self.style = self.style.add(TerminalStyle::italic(true)), - 4 => self.style = self.style.add(TerminalStyle::underline(true)), - 7 => self.invert = true, - 27 => self.invert = false, + 1 => self.cursty = self.cursty.add(TerminalStyle::bold(true)), + 3 => self.cursty = self.cursty.add(TerminalStyle::italic(true)), + 4 => self.cursty = self.cursty.add(TerminalStyle::underline(true)), + 7 => self.curinv = true, + 27 => self.curinv = false, - 30 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.black)), - 40 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.black)), - 31 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.red)), - 41 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.red)), - 32 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.green)), - 42 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.green)), - 33 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.yellow)), - 43 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.yellow)), - 34 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.blue)), - 44 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.blue)), - 35 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.magenta)), - 45 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.magenta)), - 36 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.cyan)), - 46 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.cyan)), - 37 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.white)), - 47 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.white)), + 30 => self.set_fg_color(&TTYColor::Black), + 40 => self.set_bg_color(&TTYColor::Black), + 90 => self.set_fg_color(&TTYColor::LightBlack), + 100 => self.set_bg_color(&TTYColor::LightBlack), + 31 => self.set_fg_color(&TTYColor::Red), + 41 => self.set_bg_color(&TTYColor::Red), + 91 => self.set_fg_color(&TTYColor::LightRed), + 101 => self.set_bg_color(&TTYColor::LightRed), + 32 => self.set_fg_color(&TTYColor::Green), + 42 => self.set_bg_color(&TTYColor::Green), + 92 => self.set_fg_color(&TTYColor::LightGreen), + 102 => self.set_bg_color(&TTYColor::LightGreen), + 33 => self.set_fg_color(&TTYColor::Yellow), + 43 => self.set_bg_color(&TTYColor::Yellow), + 93 => self.set_fg_color(&TTYColor::LightYellow), + 103 => self.set_bg_color(&TTYColor::LightYellow), + 34 => self.set_fg_color(&TTYColor::Blue), + 44 => self.set_bg_color(&TTYColor::Blue), + 94 => self.set_fg_color(&TTYColor::LightBlue), + 104 => self.set_bg_color(&TTYColor::LightBlue), + 35 => self.set_fg_color(&TTYColor::Magenta), + 45 => self.set_bg_color(&TTYColor::Magenta), + 95 => self.set_fg_color(&TTYColor::LightMagenta), + 105 => self.set_bg_color(&TTYColor::LightMagenta), + 36 => self.set_fg_color(&TTYColor::Cyan), + 46 => self.set_bg_color(&TTYColor::Cyan), + 96 => self.set_fg_color(&TTYColor::LightCyan), + 106 => self.set_bg_color(&TTYColor::LightCyan), + 37 => self.set_fg_color(&TTYColor::White), + 47 => self.set_bg_color(&TTYColor::White), + 97 => self.set_fg_color(&TTYColor::LightWhite), + 107 => self.set_bg_color(&TTYColor::LightWhite), 38 => { let x = piter.next().unwrap(); match x[0] { 2 => { - let r = piter.next().unwrap(); - let g = piter.next().unwrap(); - let b = piter.next().unwrap(); - self.style = self.style.add(TerminalStyle::fg_color((r[0] as u8, g[0] as u8, b[0] as u8))) + let r = piter.next().unwrap()[0] as u8; + let g = piter.next().unwrap()[0] as u8; + let b = piter.next().unwrap()[0] as u8; + self.set_fg_color(&TTYColor::Rgb(r,g,b)); }, 5 => { let v = piter.next().unwrap(); - self.style = self.style.add(TerminalStyle::fg_color(ansi_colours::rgb_from_ansi256(v[0] as u8))) + let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8); + self.set_fg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2)); }, _ => {} } @@ -238,14 +490,15 @@ impl Perform for PerfAtom { let x = piter.next().unwrap(); match x[0] { 2 => { - let r = piter.next().unwrap(); - let g = piter.next().unwrap(); - let b = piter.next().unwrap(); - self.style = self.style.add(TerminalStyle::bg_color((r[0] as u8, g[0] as u8, b[0] as u8))) + let r = piter.next().unwrap()[0] as u8; + let g = piter.next().unwrap()[0] as u8; + let b = piter.next().unwrap()[0] as u8; + self.set_bg_color(&TTYColor::Rgb(r,g,b)); }, 5 => { let v = piter.next().unwrap(); - self.style = self.style.add(TerminalStyle::bg_color(ansi_colours::rgb_from_ansi256(v[0] as u8))) + let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8); + self.set_bg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2)); }, _ => {} } @@ -255,53 +508,52 @@ impl Perform for PerfAtom { } } '@' => { - for x in self.cursor.x .. self.term_width { - self.write_atom(Point2::new(x, self.cursor.y), Some(TerminalAtom::new(' ', self.style))); - } - } - 'A' => { - self.cursor.y -= piter.next().unwrap_or(&[1])[0] as i16; - } - 'B' => { - self.cursor.y += piter.next().unwrap_or(&[1])[0] as i16; - if self.cursor.x >= self.term_width { - self.cursor.x = 0; + let c = self.cursor.get(); + for x in c.x .. self.size.get().x { + self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.cursty))); } } + 'A' => { self.cursor_up(piter.next().unwrap_or(&[1])[0] as usize); } + 'B' => { self.cursor_dn(piter.next().unwrap_or(&[1])[0] as usize); } 'C' | 'a' => { - self.cursor.x += piter.next().unwrap_or(&[1])[0] as i16; - if self.cursor.x >= self.term_width { - self.cursor.y += self.cursor.x / self.term_width; - self.cursor.x %= self.term_width; + let mut c = self.cursor.get_mut(); + c.x += piter.next().unwrap_or(&[1])[0] as i16; + if c.x >= self.size.get().x { + c.y += c.x / self.size.get().x; + c.x %= self.size.get().x; } } 'D' => { - self.cursor.x -= piter.next().unwrap_or(&[1])[0] as i16; - if self.cursor.x < 0 { - self.cursor.x = self.term_width - 1; - self.cursor.y -= 1; + let mut c = self.cursor.get_mut(); + c.x -= piter.next().unwrap_or(&[1])[0] as i16; + if c.x < 0 { + c.x = self.size.get().x - 1; + c.y -= 1; } } 'd' => { - self.cursor.y = piter.next().unwrap_or(&[1])[0] as i16 - 1; + self.cursor.get_mut().y = piter.next().unwrap_or(&[1])[0] as i16 - 1; } 'E' => { - if self.cursor.x >= self.term_width { - self.cursor.y += 1; + let mut c = self.cursor.get_mut(); + if c.x >= self.size.get().x { + c.y += 1; } - self.cursor.x = 0; - self.cursor.y += piter.next().unwrap_or(&[1])[0] as i16; + c.x = 0; + c.y += piter.next().unwrap_or(&[1])[0] as i16; } 'F' => { - self.cursor.x = 0; - self.cursor.y -= piter.next().unwrap_or(&[1])[0] as i16; + let mut c = self.cursor.get_mut(); + c.x = 0; + c.y -= piter.next().unwrap_or(&[1])[0] as i16; } 'G' | '`' => { - self.cursor.x = piter.next().unwrap_or(&[1])[0] as i16 - 1; + self.cursor.get_mut().x = piter.next().unwrap_or(&[1])[0] as i16 - 1; } 'H' | 'f' => { - self.cursor.y = piter.next().unwrap_or(&[1])[0] as i16 - 1; - self.cursor.x = piter.next().unwrap_or(&[1])[0] as i16 - 1; + let mut c = self.cursor.get_mut(); + c.y = piter.next().unwrap_or(&[1])[0] as i16 - 1; + c.x = piter.next().unwrap_or(&[1])[0] as i16 - 1; } 'J' => { let x = piter.next().unwrap_or(&[0 as u16; 1]); @@ -309,13 +561,13 @@ impl Perform for PerfAtom { // clear from cursor until end of screen 0 => { - let mut pos = self.cursor; + let mut pos = self.cursor.get(); while pos.y < 100 { self.write_atom(pos, None); pos.x += 1; - if pos.x >= self.term_width { + if pos.x >= self.size.get().x { pos.x = 0; pos.y += 1; } @@ -324,13 +576,13 @@ impl Perform for PerfAtom { // clear from cursor to begin 1 => { - let mut pos = self.cursor; + let mut pos = self.cursor.get(); while pos.y >= 0 || pos.x >= 0 { self.write_atom(pos, None); pos.x -= 1; if pos.x < 0 { - pos.x = self.term_width; + pos.x = self.size.get().x; pos.y -= 1; } } @@ -341,12 +593,12 @@ impl Perform for PerfAtom { // erase entire screen 2 => { for y in 0 .. 100 { - for x in 0 .. self.term_width { + for x in 0 .. self.size.get().x { self.write_atom(Point2::new(x, y), None); } } - self.cursor = Point2::new(0, 0); + self.cursor.set(Point2::new(0, 0)); } // invalid @@ -359,22 +611,25 @@ impl Perform for PerfAtom { // clear from cursor until end of line 0 => { - for x in self.cursor.x .. self.term_width { - self.write_atom(Point2::new(x, self.cursor.y), Some(TerminalAtom::new(' ', self.get_style()))); + let c = self.cursor.get(); + for x in c.x .. self.size.get().x { + self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style()))); } }, // clear from start of line until cursor 1 => { - for x in 0 .. self.cursor.x { - self.write_atom(Point2::new(x, self.cursor.y), Some(TerminalAtom::new(' ', self.get_style()))); + let c = self.cursor.get(); + for x in 0 .. c.x { + self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style()))); } }, // clear entire line 2 => { - for x in 0 .. self.term_width { - self.write_atom(Point2::new(x, self.cursor.y), Some(TerminalAtom::new(' ', self.get_style()))); + let c = self.cursor.get(); + for x in 0 .. self.size.get().x { + self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style()))); } }, @@ -386,7 +641,7 @@ impl Perform for PerfAtom { 'M' => { let n = piter.next().unwrap_or(&[1])[0] as i16; for y in 0 .. n { - for x in 0 .. self.term_width { + for x in 0 .. self.size.get().x { self.write_atom(Point2::new(x, self.cursor.y+y), None); } } @@ -401,14 +656,11 @@ impl Perform for PerfAtom { self.write_atom(Point2::new(self.cursor.x + x as i16, self.cursor.y), None); } } -*/ - 's' => { - self.save_cursor_position(); - } - 'u' => { - self.restore_cursor_position(); - } - + */ + 'S' => { self.scroll_up(piter.next().unwrap_or(&[1])[0] as usize); } + 'T' => { self.scroll_dn(piter.next().unwrap_or(&[1])[0] as usize); } + 's' => { self.save_cursor_position(); } + 'u' => { self.restore_cursor_position(); } _ => { /* eprintln!( @@ -421,7 +673,6 @@ impl Perform for PerfAtom { } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { - match (byte, intermediates) { //(b'B', intermediates) => configure_charset!(StandardCharset::Ascii, intermediates), (b'D', []) => self.linefeed(),