diff options
author | Christian Duerr <contact@christianduerr.com> | 2021-01-24 21:45:36 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-24 21:45:36 +0000 |
commit | 530de00049c2afcc562d36ccdb3e6afa2fe396a5 (patch) | |
tree | 3dabbcef3fc4a2041f9027d82243aa0d70928153 /alacritty_terminal/src/grid | |
parent | 7291702f6b4fff10f2470f084abe0785b95659a0 (diff) | |
download | alacritty-530de00049c2afcc562d36ccdb3e6afa2fe396a5.tar.gz alacritty-530de00049c2afcc562d36ccdb3e6afa2fe396a5.zip |
Move renderable cell transformation to alacritty
This refactors a large chunk of the alacritty_terminal API to expose all
data necessary for rendering uniformly through the `renderable_content`
call. This also no longer transforms the cells for rendering by a GUI
but instead just reports the content from a terminal emulation
perspective. The transformation into renderable cells is now done inside
the alacritty crate.
Since the terminal itself only ever needs to know about modified color
RGB values, the configuration for colors was moved to the alacritty UI
code.
Diffstat (limited to 'alacritty_terminal/src/grid')
-rw-r--r-- | alacritty_terminal/src/grid/mod.rs | 506 | ||||
-rw-r--r-- | alacritty_terminal/src/grid/resize.rs | 26 | ||||
-rw-r--r-- | alacritty_terminal/src/grid/tests.rs | 28 |
3 files changed, 204 insertions, 356 deletions
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs index 4b3c86dc..7949489a 100644 --- a/alacritty_terminal/src/grid/mod.rs +++ b/alacritty_terminal/src/grid/mod.rs @@ -1,7 +1,8 @@ //! A specialized 2D grid implementation optimized for use in a terminal. use std::cmp::{max, min}; -use std::ops::{Deref, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; +use std::iter::{Map, TakeWhile}; +use std::ops::{Bound, Deref, Index, IndexMut, Range, RangeBounds, RangeInclusive}; use serde::{Deserialize, Serialize}; @@ -18,37 +19,6 @@ mod tests; pub use self::row::Row; use self::storage::Storage; -/// Bidirectional iterator. -pub trait BidirectionalIterator: Iterator { - fn prev(&mut self) -> Option<Self::Item>; -} - -/// An item in the grid along with its Line and Column. -pub struct Indexed<T> { - pub inner: T, - pub line: Line, - pub column: Column, -} - -impl<T> Deref for Indexed<T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.inner - } -} - -impl<T: PartialEq> ::std::cmp::PartialEq for Grid<T> { - fn eq(&self, other: &Self) -> bool { - // Compare struct fields and check result of grid comparison. - self.raw.eq(&other.raw) - && self.cols.eq(&other.cols) - && self.lines.eq(&other.lines) - && self.display_offset.eq(&other.display_offset) - } -} - pub trait GridCell: Sized { /// Check if the cell contains any content. fn is_empty(&self) -> bool; @@ -99,6 +69,15 @@ impl IndexMut<CharsetIndex> for Charsets { } } +#[derive(Debug, Copy, Clone)] +pub enum Scroll { + Delta(isize), + PageUp, + PageDown, + Top, + Bottom, +} + /// Grid based terminal content storage. /// /// ```notrust @@ -157,15 +136,6 @@ pub struct Grid<T> { max_scroll_limit: usize, } -#[derive(Debug, Copy, Clone)] -pub enum Scroll { - Delta(isize), - PageUp, - PageDown, - Top, - Bottom, -} - impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { pub fn new(lines: Line, cols: Column, max_scroll_limit: usize) -> Grid<T> { Grid { @@ -341,15 +311,15 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { D: PartialEq, { // Determine how many lines to scroll up by. - let end = Point { line: 0, col: self.cols() }; + let end = Point { line: 0, column: self.cols() }; let mut iter = self.iter_from(end); while let Some(cell) = iter.prev() { - if !cell.is_empty() || iter.cur.line >= *self.lines { + if !cell.is_empty() || cell.point.line >= *self.lines { break; } } - debug_assert!(iter.cur.line <= *self.lines); - let positions = self.lines - iter.cur.line; + debug_assert!(iter.point.line <= *self.lines); + let positions = self.lines - iter.point.line; let region = Line(0)..self.screen_lines(); // Reset display offset. @@ -383,8 +353,33 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { } } -#[allow(clippy::len_without_is_empty)] impl<T> Grid<T> { + /// Reset a visible region within the grid. + pub fn reset_region<D, R: RangeBounds<Line>>(&mut self, bounds: R) + where + T: ResetDiscriminant<D> + GridCell + Clone + Default, + D: PartialEq, + { + let start = match bounds.start_bound() { + Bound::Included(line) => *line, + Bound::Excluded(line) => *line + 1, + Bound::Unbounded => Line(0), + }; + + let end = match bounds.end_bound() { + Bound::Included(line) => *line + 1, + Bound::Excluded(line) => *line, + Bound::Unbounded => self.screen_lines(), + }; + + debug_assert!(start < self.screen_lines()); + debug_assert!(end <= self.screen_lines()); + + for row in start.0..end.0 { + self.raw[Line(row)].reset(&self.cursor.template); + } + } + /// Clamp a buffer point to the visible region. pub fn clamp_buffer_to_visible(&self, point: Point<usize>) -> Point { if point.line < self.display_offset { @@ -424,12 +419,7 @@ impl<T> Grid<T> { /// Convert viewport relative point to global buffer indexing. #[inline] pub fn visible_to_buffer(&self, point: Point) -> Point<usize> { - Point { line: self.lines.0 + self.display_offset - point.line.0 - 1, col: point.col } - } - - #[inline] - pub fn display_iter(&self) -> DisplayIter<'_, T> { - DisplayIter::new(self) + Point { line: self.lines.0 + self.display_offset - point.line.0 - 1, column: point.column } } #[inline] @@ -459,126 +449,51 @@ impl<T> Grid<T> { #[inline] pub fn iter_from(&self, point: Point<usize>) -> GridIterator<'_, T> { - GridIterator { grid: self, cur: point } - } - - #[inline] - pub fn display_offset(&self) -> usize { - self.display_offset + GridIterator { grid: self, point } } + /// Iterator over all visible cells. #[inline] - pub fn cursor_cell(&mut self) -> &mut T { - let point = self.cursor.point; - &mut self[&point] - } -} - -/// Grid dimensions. -pub trait Dimensions { - /// Total number of lines in the buffer, this includes scrollback and visible lines. - fn total_lines(&self) -> usize; + pub fn display_iter(&self) -> DisplayIter<'_, T> { + let start = Point::new(self.display_offset + self.lines.0, self.cols() - 1); + let end = Point::new(self.display_offset, self.cols()); - /// Height of the viewport in lines. - fn screen_lines(&self) -> Line; + let iter = GridIterator { grid: self, point: start }; - /// Width of the terminal in columns. - fn cols(&self) -> Column; + let display_offset = self.display_offset; + let lines = self.lines.0; - /// Number of invisible lines part of the scrollback history. - #[inline] - fn history_size(&self) -> usize { - self.total_lines() - self.screen_lines().0 - } -} - -impl<G> Dimensions for Grid<G> { - #[inline] - fn total_lines(&self) -> usize { - self.raw.len() + let take_while: DisplayIterTakeFun<'_, T> = + Box::new(move |indexed: &Indexed<&T>| indexed.point <= end); + let map: DisplayIterMapFun<'_, T> = Box::new(move |indexed: Indexed<&T>| { + let line = Line(lines + display_offset - indexed.point.line - 1); + Indexed { point: Point::new(line, indexed.point.column), cell: indexed.cell } + }); + iter.take_while(take_while).map(map) } #[inline] - fn screen_lines(&self) -> Line { - self.lines + pub fn display_offset(&self) -> usize { + self.display_offset } #[inline] - fn cols(&self) -> Column { - self.cols - } -} - -#[cfg(test)] -impl Dimensions for (Line, Column) { - fn total_lines(&self) -> usize { - *self.0 - } - - fn screen_lines(&self) -> Line { - self.0 - } - - fn cols(&self) -> Column { - self.1 - } -} - -pub struct GridIterator<'a, T> { - /// Immutable grid reference. - grid: &'a Grid<T>, - - /// Current position of the iterator within the grid. - cur: Point<usize>, -} - -impl<'a, T> GridIterator<'a, T> { - pub fn point(&self) -> Point<usize> { - self.cur - } - - pub fn cell(&self) -> &'a T { - &self.grid[self.cur] - } -} - -impl<'a, T> Iterator for GridIterator<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<Self::Item> { - let last_col = self.grid.cols() - 1; - - match self.cur { - Point { line, col } if line == 0 && col == last_col => return None, - Point { col, .. } if (col == last_col) => { - self.cur.line -= 1; - self.cur.col = Column(0); - }, - _ => self.cur.col += Column(1), - } - - Some(&self.grid[self.cur]) + pub fn cursor_cell(&mut self) -> &mut T { + let point = self.cursor.point; + &mut self[point.line][point.column] } } -impl<'a, T> BidirectionalIterator for GridIterator<'a, T> { - fn prev(&mut self) -> Option<Self::Item> { - let last_col = self.grid.cols() - 1; - - match self.cur { - Point { line, col: Column(0) } if line == self.grid.total_lines() - 1 => return None, - Point { col: Column(0), .. } => { - self.cur.line += 1; - self.cur.col = last_col; - }, - _ => self.cur.col -= Column(1), - } - - Some(&self.grid[self.cur]) +impl<T: PartialEq> PartialEq for Grid<T> { + fn eq(&self, other: &Self) -> bool { + // Compare struct fields and check result of grid comparison. + self.raw.eq(&other.raw) + && self.cols.eq(&other.cols) + && self.lines.eq(&other.lines) + && self.display_offset.eq(&other.display_offset) } } -/// Index active region by line. impl<T> Index<Line> for Grid<T> { type Output = Row<T>; @@ -588,16 +503,6 @@ impl<T> Index<Line> for Grid<T> { } } -/// Index with buffer offset. -impl<T> Index<usize> for Grid<T> { - type Output = Row<T>; - - #[inline] - fn index(&self, index: usize) -> &Row<T> { - &self.raw[index] - } -} - impl<T> IndexMut<Line> for Grid<T> { #[inline] fn index_mut(&mut self, index: Line) -> &mut Row<T> { @@ -605,26 +510,19 @@ impl<T> IndexMut<Line> for Grid<T> { } } -impl<T> IndexMut<usize> for Grid<T> { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Row<T> { - &mut self.raw[index] - } -} - -impl<'point, T> Index<&'point Point> for Grid<T> { - type Output = T; +impl<T> Index<usize> for Grid<T> { + type Output = Row<T>; #[inline] - fn index<'a>(&'a self, point: &Point) -> &'a T { - &self[point.line][point.col] + fn index(&self, index: usize) -> &Row<T> { + &self.raw[index] } } -impl<'point, T> IndexMut<&'point Point> for Grid<T> { +impl<T> IndexMut<usize> for Grid<T> { #[inline] - fn index_mut<'a, 'b>(&'a mut self, point: &'b Point) -> &'a mut T { - &mut self[point.line][point.col] + fn index_mut(&mut self, index: usize) -> &mut Row<T> { + &mut self.raw[index] } } @@ -633,216 +531,162 @@ impl<T> Index<Point<usize>> for Grid<T> { #[inline] fn index(&self, point: Point<usize>) -> &T { - &self[point.line][point.col] + &self[point.line][point.column] } } impl<T> IndexMut<Point<usize>> for Grid<T> { #[inline] fn index_mut(&mut self, point: Point<usize>) -> &mut T { - &mut self[point.line][point.col] + &mut self[point.line][point.column] } } -/// A subset of lines in the grid. -/// -/// May be constructed using Grid::region(..). -pub struct Region<'a, T> { - start: Line, - end: Line, - raw: &'a Storage<T>, -} +impl<T> Index<Point> for Grid<T> { + type Output = T; -/// A mutable subset of lines in the grid. -/// -/// May be constructed using Grid::region_mut(..). -pub struct RegionMut<'a, T> { - start: Line, - end: Line, - raw: &'a mut Storage<T>, + #[inline] + fn index(&self, point: Point) -> &T { + &self[point.line][point.column] + } } -impl<'a, T> RegionMut<'a, T> { - /// Call the provided function for every item in this region. - pub fn each<F: Fn(&mut T)>(self, func: F) { - for row in self { - for item in row { - func(item) - } - } +impl<T> IndexMut<Point> for Grid<T> { + #[inline] + fn index_mut(&mut self, point: Point) -> &mut T { + &mut self[point.line][point.column] } } -pub trait IndexRegion<I, T> { - /// Get an immutable region of Self. - fn region(&self, _: I) -> Region<'_, T>; +/// Grid dimensions. +pub trait Dimensions { + /// Total number of lines in the buffer, this includes scrollback and visible lines. + fn total_lines(&self) -> usize; - /// Get a mutable region of Self. - fn region_mut(&mut self, _: I) -> RegionMut<'_, T>; -} + /// Height of the viewport in lines. + fn screen_lines(&self) -> Line; -impl<T> IndexRegion<Range<Line>, T> for Grid<T> { - fn region(&self, index: Range<Line>) -> Region<'_, T> { - assert!(index.start < self.screen_lines()); - assert!(index.end <= self.screen_lines()); - assert!(index.start <= index.end); - Region { start: index.start, end: index.end, raw: &self.raw } - } + /// Width of the terminal in columns. + fn cols(&self) -> Column; - fn region_mut(&mut self, index: Range<Line>) -> RegionMut<'_, T> { - assert!(index.start < self.screen_lines()); - assert!(index.end <= self.screen_lines()); - assert!(index.start <= index.end); - RegionMut { start: index.start, end: index.end, raw: &mut self.raw } + /// Number of invisible lines part of the scrollback history. + #[inline] + fn history_size(&self) -> usize { + self.total_lines() - self.screen_lines().0 } } -impl<T> IndexRegion<RangeTo<Line>, T> for Grid<T> { - fn region(&self, index: RangeTo<Line>) -> Region<'_, T> { - assert!(index.end <= self.screen_lines()); - Region { start: Line(0), end: index.end, raw: &self.raw } - } - - fn region_mut(&mut self, index: RangeTo<Line>) -> RegionMut<'_, T> { - assert!(index.end <= self.screen_lines()); - RegionMut { start: Line(0), end: index.end, raw: &mut self.raw } +impl<G> Dimensions for Grid<G> { + #[inline] + fn total_lines(&self) -> usize { + self.raw.len() } -} -impl<T> IndexRegion<RangeFrom<Line>, T> for Grid<T> { - fn region(&self, index: RangeFrom<Line>) -> Region<'_, T> { - assert!(index.start < self.screen_lines()); - Region { start: index.start, end: self.screen_lines(), raw: &self.raw } + #[inline] + fn screen_lines(&self) -> Line { + self.lines } - fn region_mut(&mut self, index: RangeFrom<Line>) -> RegionMut<'_, T> { - assert!(index.start < self.screen_lines()); - RegionMut { start: index.start, end: self.screen_lines(), raw: &mut self.raw } + #[inline] + fn cols(&self) -> Column { + self.cols } } -impl<T> IndexRegion<RangeFull, T> for Grid<T> { - fn region(&self, _: RangeFull) -> Region<'_, T> { - Region { start: Line(0), end: self.screen_lines(), raw: &self.raw } - } - - fn region_mut(&mut self, _: RangeFull) -> RegionMut<'_, T> { - RegionMut { start: Line(0), end: self.screen_lines(), raw: &mut self.raw } +#[cfg(test)] +impl Dimensions for (Line, Column) { + fn total_lines(&self) -> usize { + *self.0 } -} - -pub struct RegionIter<'a, T> { - end: Line, - cur: Line, - raw: &'a Storage<T>, -} -pub struct RegionIterMut<'a, T> { - end: Line, - cur: Line, - raw: &'a mut Storage<T>, -} - -impl<'a, T> IntoIterator for Region<'a, T> { - type IntoIter = RegionIter<'a, T>; - type Item = &'a Row<T>; - - fn into_iter(self) -> Self::IntoIter { - RegionIter { end: self.end, cur: self.start, raw: self.raw } + fn screen_lines(&self) -> Line { + self.0 } -} -impl<'a, T> IntoIterator for RegionMut<'a, T> { - type IntoIter = RegionIterMut<'a, T>; - type Item = &'a mut Row<T>; - - fn into_iter(self) -> Self::IntoIter { - RegionIterMut { end: self.end, cur: self.start, raw: self.raw } + fn cols(&self) -> Column { + self.1 } } -impl<'a, T> Iterator for RegionIter<'a, T> { - type Item = &'a Row<T>; - - fn next(&mut self) -> Option<Self::Item> { - if self.cur < self.end { - let index = self.cur; - self.cur += 1; - Some(&self.raw[index]) - } else { - None - } - } +#[derive(Debug, PartialEq)] +pub struct Indexed<T, L = usize> { + pub point: Point<L>, + pub cell: T, } -impl<'a, T> Iterator for RegionIterMut<'a, T> { - type Item = &'a mut Row<T>; +impl<T, L> Deref for Indexed<T, L> { + type Target = T; - fn next(&mut self) -> Option<Self::Item> { - if self.cur < self.end { - let index = self.cur; - self.cur += 1; - unsafe { Some(&mut *(&mut self.raw[index] as *mut _)) } - } else { - None - } + #[inline] + fn deref(&self) -> &T { + &self.cell } } -/// Iterates over the visible area accounting for buffer transform. -pub struct DisplayIter<'a, T> { +/// Grid cell iterator. +pub struct GridIterator<'a, T> { + /// Immutable grid reference. grid: &'a Grid<T>, - offset: usize, - limit: usize, - col: Column, - line: Line, -} -impl<'a, T: 'a> DisplayIter<'a, T> { - pub fn new(grid: &'a Grid<T>) -> DisplayIter<'a, T> { - let offset = grid.display_offset + *grid.screen_lines() - 1; - let limit = grid.display_offset; - let col = Column(0); - let line = Line(0); - - DisplayIter { grid, offset, col, limit, line } - } + /// Current position of the iterator within the grid. + point: Point<usize>, +} - pub fn offset(&self) -> usize { - self.offset +impl<'a, T> GridIterator<'a, T> { + /// Current iteratior position. + pub fn point(&self) -> Point<usize> { + self.point } - pub fn point(&self) -> Point { - Point::new(self.line, self.col) + /// Cell at the current iteratior position. + pub fn cell(&self) -> &'a T { + &self.grid[self.point] } } -impl<'a, T: 'a> Iterator for DisplayIter<'a, T> { +impl<'a, T> Iterator for GridIterator<'a, T> { type Item = Indexed<&'a T>; - #[inline] fn next(&mut self) -> Option<Self::Item> { - // Return None if we've reached the end. - if self.offset == self.limit && self.grid.cols() == self.col { - return None; + let last_col = self.grid.cols() - 1; + match self.point { + Point { line, column: col } if line == 0 && col == last_col => return None, + Point { column: col, .. } if (col == last_col) => { + self.point.line -= 1; + self.point.column = Column(0); + }, + _ => self.point.column += Column(1), } - // Get the next item. - let item = Some(Indexed { - inner: &self.grid.raw[self.offset][self.col], - line: self.line, - column: self.col, - }); + Some(Indexed { cell: &self.grid[self.point], point: self.point }) + } +} + +/// Bidirectional iterator. +pub trait BidirectionalIterator: Iterator { + fn prev(&mut self) -> Option<Self::Item>; +} - // Update line/col to point to next item. - self.col += 1; - if self.col == self.grid.cols() && self.offset != self.limit { - self.offset -= 1; +impl<'a, T> BidirectionalIterator for GridIterator<'a, T> { + fn prev(&mut self) -> Option<Self::Item> { + let last_col = self.grid.cols() - 1; - self.col = Column(0); - self.line = Line(*self.grid.lines - 1 - (self.offset - self.limit)); + match self.point { + Point { line, column: Column(0) } if line == self.grid.total_lines() - 1 => { + return None + }, + Point { column: Column(0), .. } => { + self.point.line += 1; + self.point.column = last_col; + }, + _ => self.point.column -= Column(1), } - item + Some(Indexed { cell: &self.grid[self.point], point: self.point }) } } + +pub type DisplayIter<'a, T> = + Map<TakeWhile<GridIterator<'a, T>, DisplayIterTakeFun<'a, T>>, DisplayIterMapFun<'a, T>>; +type DisplayIterTakeFun<'a, T> = Box<dyn Fn(&Indexed<&'a T>) -> bool>; +type DisplayIterMapFun<'a, T> = Box<dyn FnMut(Indexed<&'a T>) -> Indexed<&'a T, Line>>; diff --git a/alacritty_terminal/src/grid/resize.rs b/alacritty_terminal/src/grid/resize.rs index 1a16e09e..40492c3a 100644 --- a/alacritty_terminal/src/grid/resize.rs +++ b/alacritty_terminal/src/grid/resize.rs @@ -113,7 +113,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // Remove the linewrap special case, by moving the cursor outside of the grid. if self.cursor.input_needs_wrap && reflow { self.cursor.input_needs_wrap = false; - self.cursor.point.col += 1; + self.cursor.point.column += 1; } let mut rows = self.raw.take_all(); @@ -171,11 +171,11 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { let mut target = self.cursor.point.sub(cols, num_wrapped); // Clamp to the last column, if no content was reflown with the cursor. - if target.col.0 == 0 && row.is_clear() { + if target.column.0 == 0 && row.is_clear() { self.cursor.input_needs_wrap = true; target = target.sub(cols, 1); } - self.cursor.point.col = target.col; + self.cursor.point.column = target.column; // Get required cursor line changes. Since `num_wrapped` is smaller than `cols` // this will always be either `0` or `1`. @@ -248,7 +248,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // Remove the linewrap special case, by moving the cursor outside of the grid. if self.cursor.input_needs_wrap && reflow { self.cursor.input_needs_wrap = false; - self.cursor.point.col += 1; + self.cursor.point.column += 1; } let mut new_raw = Vec::with_capacity(self.raw.len()); @@ -262,7 +262,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // width it is then later reflown. let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; if i == cursor_buffer_line { - self.cursor.point.col += buffered.len(); + self.cursor.point.column += buffered.len(); } row.append_front(buffered); @@ -274,7 +274,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { Some(wrapped) if reflow => wrapped, _ => { let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - if reflow && i == cursor_buffer_line && self.cursor.point.col > cols { + if reflow && i == cursor_buffer_line && self.cursor.point.column > cols { // If there are empty cells before the cursor, we assume it is explicit // whitespace and need to wrap it like normal content. Vec::new() @@ -333,17 +333,17 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { } else { // Reflow cursor if a line below it is deleted. let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - if (i == cursor_buffer_line && self.cursor.point.col < cols) + if (i == cursor_buffer_line && self.cursor.point.column < cols) || i < cursor_buffer_line { self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(1); } // Reflow the cursor if it is on this line beyond the width. - if i == cursor_buffer_line && self.cursor.point.col >= cols { + if i == cursor_buffer_line && self.cursor.point.column >= cols { // Since only a single new line is created, we subtract only `cols` // from the cursor instead of reflowing it completely. - self.cursor.point.col -= cols; + self.cursor.point.column -= cols; } // Make sure new row is at least as long as new width. @@ -363,17 +363,17 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // Reflow the primary cursor, or clamp it if reflow is disabled. if !reflow { - self.cursor.point.col = min(self.cursor.point.col, cols - 1); - } else if self.cursor.point.col == cols + self.cursor.point.column = min(self.cursor.point.column, cols - 1); + } else if self.cursor.point.column == cols && !self[self.cursor.point.line][cols - 1].flags().contains(Flags::WRAPLINE) { self.cursor.input_needs_wrap = true; - self.cursor.point.col -= 1; + self.cursor.point.column -= 1; } else { self.cursor.point = self.cursor.point.add(cols, 0); } // Clamp the saved cursor to the grid. - self.saved_cursor.point.col = min(self.saved_cursor.point.col, cols - 1); + self.saved_cursor.point.column = min(self.saved_cursor.point.column, cols - 1); } } diff --git a/alacritty_terminal/src/grid/tests.rs b/alacritty_terminal/src/grid/tests.rs index f178226c..269ab636 100644 --- a/alacritty_terminal/src/grid/tests.rs +++ b/alacritty_terminal/src/grid/tests.rs @@ -123,6 +123,10 @@ fn scroll_down() { // Test that GridIterator works. #[test] fn test_iter() { + let assert_indexed = |value: usize, indexed: Option<Indexed<&usize>>| { + assert_eq!(Some(&value), indexed.map(|indexed| indexed.cell)); + }; + let mut grid = Grid::<usize>::new(Line(5), Column(5), 0); for i in 0..5 { for j in 0..5 { @@ -130,33 +134,33 @@ fn test_iter() { } } - let mut iter = grid.iter_from(Point { line: 4, col: Column(0) }); + let mut iter = grid.iter_from(Point::new(4, Column(0))); assert_eq!(None, iter.prev()); - assert_eq!(Some(&1), iter.next()); - assert_eq!(Column(1), iter.point().col); + assert_indexed(1, iter.next()); + assert_eq!(Column(1), iter.point().column); assert_eq!(4, iter.point().line); - assert_eq!(Some(&2), iter.next()); - assert_eq!(Some(&3), iter.next()); - assert_eq!(Some(&4), iter.next()); + assert_indexed(2, iter.next()); + assert_indexed(3, iter.next()); + assert_indexed(4, iter.next()); // Test line-wrapping. - assert_eq!(Some(&5), iter.next()); - assert_eq!(Column(0), iter.point().col); + assert_indexed(5, iter.next()); + assert_eq!(Column(0), iter.point().column); assert_eq!(3, iter.point().line); - assert_eq!(Some(&4), iter.prev()); - assert_eq!(Column(4), iter.point().col); + assert_indexed(4, iter.prev()); + assert_eq!(Column(4), iter.point().column); assert_eq!(4, iter.point().line); // Make sure iter.cell() returns the current iterator position. assert_eq!(&4, iter.cell()); // Test that iter ends at end of grid. - let mut final_iter = grid.iter_from(Point { line: 0, col: Column(4) }); + let mut final_iter = grid.iter_from(Point { line: 0, column: Column(4) }); assert_eq!(None, final_iter.next()); - assert_eq!(Some(&23), final_iter.prev()); + assert_indexed(23, final_iter.prev()); } #[test] |