diff --git a/ui/src/terminal/cells.rs b/ui/src/terminal/cells.rs index 926cbd19..a1196982 100644 --- a/ui/src/terminal/cells.rs +++ b/ui/src/terminal/cells.rs @@ -33,67 +33,18 @@ use std::fmt; use std::ops::{Deref, DerefMut, Index, IndexMut}; use termion::color::{AnsiValue, Rgb as TermionRgb}; -/// Types and implementations taken from rustty for convenience. - -pub trait CellAccessor: HasSize { - fn cellvec(&self) -> &Vec; - fn cellvec_mut(&mut self) -> &mut Vec; - - /// Clears `self`, using the given `Cell` as a blank. - fn clear(&mut self, blank: Cell) { - for cell in self.cellvec_mut().iter_mut() { - *cell = blank; - } - } - - fn pos_to_index(&self, x: usize, y: usize) -> Option { - let (cols, rows) = self.size(); - if x < cols && y < rows { - Some((cols * y) + x) - } else { - None - } - } - - /// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of - /// bounds. - /// - /// # Examples - /// - /// ```norun - /// use rustty::{Terminal, CellAccessor}; - /// - /// let mut term = Terminal::new().unwrap(); - /// - /// let a_cell = term.get(5, 5); - /// ``` - fn get(&self, x: usize, y: usize) -> Option<&Cell> { - match self.pos_to_index(x, y) { - Some(i) => self.cellvec().get(i), - None => None, - } - } - - /// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index - /// is out of bounds. - /// - /// # Examples - /// - /// ```norun - /// use rustty::{Terminal, CellAccessor}; - /// - /// let mut term = Terminal::new().unwrap(); - /// - /// let a_mut_cell = term.get_mut(5, 5); - /// ``` - fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> { - match self.pos_to_index(x, y) { - Some(i) => self.cellvec_mut().get_mut(i), - None => None, - } - } +/// In a scroll region up and down cursor movements shift the region vertically. The new lines are +/// empty. +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct ScrollRegion { + pub top: usize, + pub bottom: usize, + pub left: usize, + pub right: usize, } +/// Types and implementations taken from rustty for convenience. + /// An array of `Cell`s that represents a terminal display. /// /// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices correspond to a @@ -216,22 +167,189 @@ impl CellBuffer { self.cols = 0; self.rows = 0; } -} -impl HasSize for CellBuffer { - fn size(&self) -> Size { + /// Clears `self`, using the given `Cell` as a blank. + pub fn clear(&mut self, blank: Cell) { + for cell in self.cellvec_mut().iter_mut() { + *cell = blank; + } + } + + pub fn pos_to_index(&self, x: usize, y: usize) -> Option { + let (cols, rows) = self.size(); + if x < cols && y < rows { + Some((cols * y) + x) + } else { + None + } + } + + /// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of + /// bounds. + /// + /// # Examples + /// + /// ```norun + /// use rustty::{Terminal, CellAccessor}; + /// + /// let mut term = Terminal::new().unwrap(); + /// + /// let a_cell = term.get(5, 5); + /// ``` + pub fn get(&self, x: usize, y: usize) -> Option<&Cell> { + match self.pos_to_index(x, y) { + Some(i) => self.cellvec().get(i), + None => None, + } + } + + /// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index + /// is out of bounds. + /// + /// # Examples + /// + /// ```norun + /// use rustty::{Terminal, CellAccessor}; + /// + /// let mut term = Terminal::new().unwrap(); + /// + /// let a_mut_cell = term.get_mut(5, 5); + /// ``` + pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> { + match self.pos_to_index(x, y) { + Some(i) => self.cellvec_mut().get_mut(i), + None => None, + } + } + + pub fn size(&self) -> (usize, usize) { (self.cols, self.rows) } -} -impl CellAccessor for CellBuffer { - fn cellvec(&self) -> &Vec { + pub fn cellvec(&self) -> &Vec { &self.buf } - fn cellvec_mut(&mut self) -> &mut Vec { + pub fn cellvec_mut(&mut self) -> &mut Vec { &mut self.buf } + + pub fn cols(&self) -> usize { + self.size().0 + } + + pub fn rows(&self) -> usize { + self.size().1 + } + + #[inline(always)] + /// Performs the normal scroll up motion: + /// + /// First clear offset number of lines: + /// + /// For offset = 1, top = 1: + /// + /// | 111111111111 | | | + /// | 222222222222 | | 222222222222 | + /// | 333333333333 | | 333333333333 | + /// | 444444444444 | --> | 444444444444 | + /// | 555555555555 | | 555555555555 | + /// | 666666666666 | | 666666666666 | + /// + /// In each step, swap the current line with the next by offset: + /// + /// | | | 222222222222 | + /// | 222222222222 | | | + /// | 333333333333 | | 333333333333 | + /// | 444444444444 | --> | 444444444444 | + /// | 555555555555 | | 555555555555 | + /// | 666666666666 | | 666666666666 | + /// + /// Result: + /// Before After + /// | 111111111111 | | 222222222222 | + /// | 222222222222 | | 333333333333 | + /// | 333333333333 | | 444444444444 | + /// | 444444444444 | | 555555555555 | + /// | 555555555555 | | 666666666666 | + /// | 666666666666 | | | + /// + pub fn scroll_up(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) { + //debug!( + // "scroll_up scroll_region {:?}, top: {} offset {}", + // scroll_region, top, offset + //); + let l = scroll_region.left; + let r = if scroll_region.right == 0 { + self.size().0 + } else { + scroll_region.right + }; + for y in top..=(top + offset - 1) { + for x in l..r { + self[(x, y)] = Cell::default(); + } + } + for y in top..=(scroll_region.bottom - offset) { + for x in l..r { + let temp = self[(x, y)]; + self[(x, y)] = self[(x, y + offset)]; + self[(x, y + offset)] = temp; + } + } + } + + #[inline(always)] + /// Performs the normal scroll down motion: + /// + /// First clear offset number of lines: + /// + /// For offset = 1, top = 1: + /// + /// | 111111111111 | | 111111111111 | + /// | 222222222222 | | 222222222222 | + /// | 333333333333 | | 333333333333 | + /// | 444444444444 | --> | 444444444444 | + /// | 555555555555 | | 555555555555 | + /// | 666666666666 | | | + /// + /// In each step, swap the current line with the prev by offset: + /// + /// | 111111111111 | | 111111111111 | + /// | 222222222222 | | 222222222222 | + /// | 333333333333 | | 333333333333 | + /// | 444444444444 | --> | 444444444444 | + /// | 555555555555 | | | + /// | | | 555555555555 | + /// + /// Result: + /// Before After + /// | 111111111111 | | | + /// | 222222222222 | | 111111111111 | + /// | 333333333333 | | 222222222222 | + /// | 444444444444 | | 333333333333 | + /// | 555555555555 | | 444444444444 | + /// | 666666666666 | | 555555555555 | + /// + pub fn scroll_down(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) { + //debug!( + // "scroll_down scroll_region {:?}, top: {} offset {}", + // scroll_region, top, offset + //); + for y in (scroll_region.bottom - offset + 1)..=scroll_region.bottom { + for x in 0..self.size().0 { + self[(x, y)] = Cell::default(); + } + } + + for y in ((top + offset)..=scroll_region.bottom).rev() { + for x in 0..self.size().0 { + let temp = self[(x, y)]; + self[(x, y)] = self[(x, y - offset)]; + self[(x, y - offset)] = temp; + } + } + } } impl Deref for CellBuffer { diff --git a/ui/src/terminal/embed/grid.rs b/ui/src/terminal/embed/grid.rs index 453e91ee..aa3d57e0 100644 --- a/ui/src/terminal/embed/grid.rs +++ b/ui/src/terminal/embed/grid.rs @@ -14,14 +14,6 @@ use text_processing::wcwidth; * The main process copies the grid whenever the actual terminal is redrawn. **/ -/// In a scroll region up and down cursor movements shift the region vertically. The new lines are -/// empty. -#[derive(Debug)] -struct ScrollRegion { - top: usize, - bottom: usize, -} - #[derive(Debug)] pub struct EmbedGrid { cursor: (usize, usize), @@ -63,7 +55,12 @@ impl EmbedGrid { pub fn new(stdin: std::fs::File, child_pid: nix::unistd::Pid) -> Self { EmbedGrid { cursor: (0, 0), - scroll_region: ScrollRegion { top: 0, bottom: 0 }, + scroll_region: ScrollRegion { + top: 0, + bottom: 0, + left: 0, + ..Default::default() + }, terminal_size: (0, 0), grid: CellBuffer::default(), state: State::Normal, @@ -191,7 +188,7 @@ impl EmbedGrid { // ESCD Linefeed debug!("{}", EscCode::from((&(*state), byte))); if cursor.1 == scroll_region.bottom { - scroll_up(grid, scroll_region, scroll_region.top, 1); + grid.scroll_up(scroll_region, scroll_region.top, 1); } else { cursor.1 += 1; } @@ -253,7 +250,7 @@ impl EmbedGrid { if cursor.1 + 1 < terminal_size.1 { if cursor.1 == scroll_region.bottom { - scroll_up(grid, scroll_region, cursor.1, 1); + grid.scroll_up(scroll_region, cursor.1, 1); } else { cursor.1 += 1; } @@ -335,7 +332,7 @@ impl EmbedGrid { if *auto_wrap_mode && *wrap_next { *wrap_next = false; if cursor.1 == scroll_region.bottom { - scroll_up(grid, scroll_region, scroll_region.top, 1); + grid.scroll_up(scroll_region, scroll_region.top, 1); } else { cursor.1 += 1; } @@ -488,7 +485,7 @@ impl EmbedGrid { 1 }; - scroll_down(grid, scroll_region, cursor.1, n); + grid.scroll_down(scroll_region, cursor.1, n); debug!("{}", EscCode::from((&(*state), byte))); *state = State::Normal; @@ -503,7 +500,7 @@ impl EmbedGrid { 1 }; - scroll_up(grid, scroll_region, cursor.1, n); + grid.scroll_up(scroll_region, cursor.1, n); debug!("{}", EscCode::from((&(*state), byte))); *state = State::Normal; @@ -1106,106 +1103,3 @@ impl EmbedGrid { } } } - -#[inline(always)] -/// Performs the normal scroll up motion: -/// -/// First clear offset number of lines: -/// -/// For offset = 1, top = 1: -/// -/// | 111111111111 | | | -/// | 222222222222 | | 222222222222 | -/// | 333333333333 | | 333333333333 | -/// | 444444444444 | --> | 444444444444 | -/// | 555555555555 | | 555555555555 | -/// | 666666666666 | | 666666666666 | -/// -/// In each step, swap the current line with the next by offset: -/// -/// | | | 222222222222 | -/// | 222222222222 | | | -/// | 333333333333 | | 333333333333 | -/// | 444444444444 | --> | 444444444444 | -/// | 555555555555 | | 555555555555 | -/// | 666666666666 | | 666666666666 | -/// -/// Result: -/// Before After -/// | 111111111111 | | 222222222222 | -/// | 222222222222 | | 333333333333 | -/// | 333333333333 | | 444444444444 | -/// | 444444444444 | | 555555555555 | -/// | 555555555555 | | 666666666666 | -/// | 666666666666 | | | -/// -fn scroll_up(grid: &mut CellBuffer, scroll_region: &ScrollRegion, top: usize, offset: usize) { - //debug!( - // "scroll_up scroll_region {:?}, top: {} offset {}", - // scroll_region, top, offset - //); - for y in top..=(top + offset - 1) { - for x in 0..grid.size().0 { - grid[(x, y)] = Cell::default(); - } - } - for y in top..=(scroll_region.bottom - offset) { - for x in 0..grid.size().0 { - let temp = grid[(x, y)]; - grid[(x, y)] = grid[(x, y + offset)]; - grid[(x, y + offset)] = temp; - } - } -} - -#[inline(always)] -/// Performs the normal scroll down motion: -/// -/// First clear offset number of lines: -/// -/// For offset = 1, top = 1: -/// -/// | 111111111111 | | 111111111111 | -/// | 222222222222 | | 222222222222 | -/// | 333333333333 | | 333333333333 | -/// | 444444444444 | --> | 444444444444 | -/// | 555555555555 | | 555555555555 | -/// | 666666666666 | | | -/// -/// In each step, swap the current line with the prev by offset: -/// -/// | 111111111111 | | 111111111111 | -/// | 222222222222 | | 222222222222 | -/// | 333333333333 | | 333333333333 | -/// | 444444444444 | --> | 444444444444 | -/// | 555555555555 | | | -/// | | | 555555555555 | -/// -/// Result: -/// Before After -/// | 111111111111 | | | -/// | 222222222222 | | 111111111111 | -/// | 333333333333 | | 222222222222 | -/// | 444444444444 | | 333333333333 | -/// | 555555555555 | | 444444444444 | -/// | 666666666666 | | 555555555555 | -/// -fn scroll_down(grid: &mut CellBuffer, scroll_region: &ScrollRegion, top: usize, offset: usize) { - //debug!( - // "scroll_down scroll_region {:?}, top: {} offset {}", - // scroll_region, top, offset - //); - for y in (scroll_region.bottom - offset + 1)..=scroll_region.bottom { - for x in 0..grid.size().0 { - grid[(x, y)] = Cell::default(); - } - } - - for y in ((top + offset)..=scroll_region.bottom).rev() { - for x in 0..grid.size().0 { - let temp = grid[(x, y)]; - grid[(x, y)] = grid[(x, y - offset)]; - grid[(x, y - offset)] = temp; - } - } -} diff --git a/ui/src/terminal/position.rs b/ui/src/terminal/position.rs index d592f7c9..702b7022 100644 --- a/ui/src/terminal/position.rs +++ b/ui/src/terminal/position.rs @@ -160,21 +160,3 @@ macro_rules! is_valid_area { !(get_y(upper_left) > get_y(bottom_right) || get_x(upper_left) > get_x(bottom_right)) }}; } - -/// A `(cols, rows)` size. -pub type Size = (usize, usize); - -pub trait HasSize { - fn size(&self) -> Size; - fn cols(&self) -> usize { - self.size().0 - } - fn rows(&self) -> usize { - self.size().1 - } -} - -pub trait HasPosition { - fn origin(&self) -> Pos; - fn set_origin(&mut self, new_origin: Pos); -}