| use crate::cell::Cell; |
|
|
| |
| #[derive(Clone, Debug, Default, PartialEq)] |
| pub struct Line { |
| pub cells: Vec<Cell>, |
| pub dirty: bool, |
| pub wrapped: bool, |
| } |
|
|
| impl Line { |
| pub fn new(cols: usize) -> Self { |
| Self { |
| cells: vec![Cell::default(); cols], |
| dirty: false, |
| wrapped: false, |
| } |
| } |
|
|
| pub fn clear(&mut self) { |
| for cell in &mut self.cells { |
| cell.reset(); |
| } |
| self.dirty = true; |
| self.wrapped = false; |
| } |
|
|
| pub fn resize(&mut self, cols: usize) { |
| if self.cells.len() < cols { |
| self.cells.resize(cols, Cell::default()); |
| } else if self.cells.len() > cols { |
| self.cells.truncate(cols); |
| } |
| } |
| } |
|
|
| |
| pub struct Grid { |
| pub lines: Vec<Line>, |
| pub scrollback: Vec<Line>, |
| pub cols: usize, |
| pub rows: usize, |
| pub scrollback_limit: usize, |
| pub cursor_row: usize, |
| pub cursor_col: usize, |
| pub saved_cursor_row: usize, |
| pub saved_cursor_col: usize, |
| pub top_margin: usize, |
| pub bottom_margin: usize, |
| } |
|
|
| impl Grid { |
| pub fn new(cols: usize, rows: usize, scrollback_limit: usize) -> Self { |
| Self { |
| lines: (0..rows).map(|_| Line::new(cols)).collect(), |
| scrollback: Vec::new(), |
| cols, |
| rows, |
| scrollback_limit, |
| cursor_row: 0, |
| cursor_col: 0, |
| saved_cursor_row: 0, |
| saved_cursor_col: 0, |
| top_margin: 0, |
| bottom_margin: rows.saturating_sub(1), |
| } |
| } |
|
|
| pub fn resize(&mut self, cols: usize, rows: usize) { |
| let old_rows = self.lines.len(); |
|
|
| for line in &mut self.lines { |
| line.resize(cols); |
| } |
|
|
| if rows > old_rows { |
| self.lines.reserve(rows - old_rows); |
| for _ in old_rows..rows { |
| self.lines.push(Line::new(cols)); |
| } |
| } else if rows < old_rows { |
| let excess = old_rows - rows; |
| let limit = self.scrollback_limit; |
| for line in self.lines.drain(0..excess) { |
| if self.scrollback.len() >= limit { |
| self.scrollback.remove(0); |
| } |
| self.scrollback.push(line); |
| } |
| } |
|
|
| self.cols = cols; |
| self.rows = rows; |
| self.cursor_row = self.cursor_row.min(rows.saturating_sub(1)); |
| self.cursor_col = self.cursor_col.min(cols.saturating_sub(1)); |
| self.top_margin = 0; |
| self.bottom_margin = rows.saturating_sub(1); |
| } |
|
|
| pub fn clear_screen(&mut self) { |
| for line in &mut self.lines { |
| line.clear(); |
| } |
| } |
|
|
| pub fn clear_line(&mut self, row: usize) { |
| if let Some(line) = self.lines.get_mut(row) { |
| line.clear(); |
| } |
| } |
|
|
| pub fn clear_line_right(&mut self, row: usize, col: usize) { |
| if let Some(line) = self.lines.get_mut(row) { |
| for cell in &mut line.cells[col..] { |
| cell.reset(); |
| } |
| line.dirty = true; |
| } |
| } |
|
|
| pub fn clear_line_left(&mut self, row: usize, col: usize) { |
| if let Some(line) = self.lines.get_mut(row) { |
| for cell in &mut line.cells[..=col] { |
| cell.reset(); |
| } |
| line.dirty = true; |
| } |
| } |
|
|
| pub fn scroll_up(&mut self, n: usize) { |
| let top = self.top_margin; |
| let bottom = self.bottom_margin; |
| let n = n.min(bottom.saturating_sub(top) + 1); |
|
|
| for _ in 0..n { |
| let removed = self.lines.remove(top); |
| if top == 0 && self.scrollback.len() < self.scrollback_limit { |
| self.scrollback.push(removed); |
| } |
| let mut new_line = Line::new(self.cols); |
| new_line.dirty = true; |
| self.lines.insert(bottom, new_line); |
| } |
|
|
| for i in top..=bottom { |
| if let Some(line) = self.lines.get_mut(i) { |
| line.dirty = true; |
| } |
| } |
| } |
|
|
| pub fn scroll_down(&mut self, n: usize) { |
| let top = self.top_margin; |
| let bottom = self.bottom_margin; |
| let n = n.min(bottom.saturating_sub(top) + 1); |
|
|
| for _ in 0..n { |
| self.lines.remove(bottom); |
| let mut new_line = Line::new(self.cols); |
| new_line.dirty = true; |
| self.lines.insert(top, new_line); |
| } |
|
|
| for i in top..=bottom { |
| if let Some(line) = self.lines.get_mut(i) { |
| line.dirty = true; |
| } |
| } |
| } |
|
|
| pub fn line(&self, row: usize) -> Option<&Line> { |
| self.lines.get(row) |
| } |
|
|
| pub fn line_mut(&mut self, row: usize) -> Option<&mut Line> { |
| self.lines.get_mut(row) |
| } |
|
|
| pub fn cell(&self, row: usize, col: usize) -> Option<&Cell> { |
| self.lines.get(row)?.cells.get(col) |
| } |
|
|
| pub fn cell_mut(&mut self, row: usize, col: usize) -> Option<&mut Cell> { |
| self.lines.get_mut(row)?.cells.get_mut(col) |
| } |
| } |
|
|