diff options
Diffstat (limited to 'alacritty_terminal/src/index.rs')
-rw-r--r-- | alacritty_terminal/src/index.rs | 177 |
1 files changed, 143 insertions, 34 deletions
diff --git a/alacritty_terminal/src/index.rs b/alacritty_terminal/src/index.rs index 019de83b..baed323e 100644 --- a/alacritty_terminal/src/index.rs +++ b/alacritty_terminal/src/index.rs @@ -7,16 +7,20 @@ use std::ops::{self, Add, AddAssign, Deref, Range, Sub, SubAssign}; use serde::{Deserialize, Serialize}; +use crate::grid::Dimensions; use crate::term::RenderableCell; /// The side of a cell. +pub type Side = Direction; + +/// Horizontal direction. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Side { +pub enum Direction { Left, Right, } -impl Side { +impl Direction { pub fn opposite(self) -> Self { match self { Side::Right => Side::Left, @@ -25,8 +29,23 @@ impl Side { } } +/// Behavior for handling grid boundaries. +pub enum Boundary { + /// Clamp to grid boundaries. + /// + /// When an operation exceeds the grid boundaries, the last point will be returned no matter + /// how far the boundaries were exceeded. + Clamp, + + /// Wrap around grid bondaries. + /// + /// When an operation exceeds the grid boundaries, the point will wrap around the entire grid + /// history and continue at the other side. + Wrap, +} + /// Index in the grid using row, column notation. -#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize, PartialOrd)] +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct Point<L = Line> { pub line: L, pub col: Column, @@ -65,43 +84,84 @@ impl<L> Point<L> { self.col = Column((self.col.0 + rhs) % num_cols); self } +} +impl Point<usize> { #[inline] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn sub_absolute(mut self, num_cols: Column, rhs: usize) -> Point<L> + pub fn sub_absolute<D>(mut self, dimensions: &D, boundary: Boundary, rhs: usize) -> Point<usize> where - L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>, + D: Dimensions, { - let num_cols = num_cols.0; - self.line = self.line + ((rhs + num_cols - 1).saturating_sub(self.col.0) / num_cols); + let total_lines = dimensions.total_lines(); + let num_cols = dimensions.cols().0; + + self.line += (rhs + num_cols - 1).saturating_sub(self.col.0) / num_cols; self.col = Column((num_cols + self.col.0 - rhs % num_cols) % num_cols); - self + + if self.line >= total_lines { + match boundary { + Boundary::Clamp => Point::new(total_lines - 1, Column(0)), + Boundary::Wrap => Point::new(self.line - total_lines, self.col), + } + } else { + self + } } #[inline] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn add_absolute(mut self, num_cols: Column, rhs: usize) -> Point<L> + pub fn add_absolute<D>(mut self, dimensions: &D, boundary: Boundary, rhs: usize) -> Point<usize> where - L: Copy + Default + Into<Line> + Add<usize, Output = L> + Sub<usize, Output = L>, + D: Dimensions, { - let line_changes = (rhs + self.col.0) / num_cols.0; - if self.line.into() >= Line(line_changes) { - self.line = self.line - line_changes; + let num_cols = dimensions.cols(); + + let line_delta = (rhs + self.col.0) / num_cols.0; + + if self.line >= line_delta { + self.line -= line_delta; self.col = Column((self.col.0 + rhs) % num_cols.0); self } else { - Point::new(L::default(), num_cols - 1) + match boundary { + Boundary::Clamp => Point::new(0, num_cols - 1), + Boundary::Wrap => { + let col = Column((self.col.0 + rhs) % num_cols.0); + let line = dimensions.total_lines() + self.line - line_delta; + Point::new(line, col) + }, + } } } } +impl PartialOrd for Point { + fn partial_cmp(&self, other: &Point) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + impl Ord for Point { fn cmp(&self, other: &Point) -> Ordering { match (self.line.cmp(&other.line), self.col.cmp(&other.col)) { - (Ordering::Equal, Ordering::Equal) => Ordering::Equal, - (Ordering::Equal, ord) | (ord, Ordering::Equal) => ord, - (Ordering::Less, _) => Ordering::Less, - (Ordering::Greater, _) => Ordering::Greater, + (Ordering::Equal, ord) | (ord, _) => ord, + } + } +} + +impl PartialOrd for Point<usize> { + fn partial_cmp(&self, other: &Point<usize>) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Point<usize> { + fn cmp(&self, other: &Point<usize>) -> Ordering { + match (self.line.cmp(&other.line), self.col.cmp(&other.col)) { + (Ordering::Equal, ord) => ord, + (Ordering::Less, _) => Ordering::Greater, + (Ordering::Greater, _) => Ordering::Less, } } } @@ -429,7 +489,7 @@ ops!(Linear, Linear); #[cfg(test)] mod tests { - use super::{Column, Line, Point}; + use super::*; #[test] fn location_ordering() { @@ -493,51 +553,100 @@ mod tests { #[test] fn add_absolute() { - let num_cols = Column(42); let point = Point::new(0, Column(13)); - let result = point.add_absolute(num_cols, 1); + let result = point.add_absolute(&(Line(1), Column(42)), Boundary::Clamp, 1); assert_eq!(result, Point::new(0, point.col + 1)); } #[test] - fn add_absolute_wrap() { - let num_cols = Column(42); - let point = Point::new(1, num_cols - 1); + fn add_absolute_wrapline() { + let point = Point::new(1, Column(41)); - let result = point.add_absolute(num_cols, 1); + let result = point.add_absolute(&(Line(2), Column(42)), Boundary::Clamp, 1); + + assert_eq!(result, Point::new(0, Column(0))); + } + + #[test] + fn add_absolute_multiline_wrapline() { + let point = Point::new(2, Column(9)); + + let result = point.add_absolute(&(Line(3), Column(10)), Boundary::Clamp, 11); assert_eq!(result, Point::new(0, Column(0))); } #[test] fn add_absolute_clamp() { - let num_cols = Column(42); - let point = Point::new(0, num_cols - 1); + let point = Point::new(0, Column(41)); - let result = point.add_absolute(num_cols, 1); + let result = point.add_absolute(&(Line(1), Column(42)), Boundary::Clamp, 1); assert_eq!(result, point); } #[test] + fn add_absolute_wrap() { + let point = Point::new(0, Column(41)); + + let result = point.add_absolute(&(Line(3), Column(42)), Boundary::Wrap, 1); + + assert_eq!(result, Point::new(2, Column(0))); + } + + #[test] + fn add_absolute_multiline_wrap() { + let point = Point::new(0, Column(9)); + + let result = point.add_absolute(&(Line(3), Column(10)), Boundary::Wrap, 11); + + assert_eq!(result, Point::new(1, Column(0))); + } + + #[test] fn sub_absolute() { - let num_cols = Column(42); let point = Point::new(0, Column(13)); - let result = point.sub_absolute(num_cols, 1); + let result = point.sub_absolute(&(Line(1), Column(42)), Boundary::Clamp, 1); assert_eq!(result, Point::new(0, point.col - 1)); } #[test] - fn sub_absolute_wrap() { - let num_cols = Column(42); + fn sub_absolute_wrapline() { let point = Point::new(0, Column(0)); - let result = point.sub_absolute(num_cols, 1); + let result = point.sub_absolute(&(Line(2), Column(42)), Boundary::Clamp, 1); + + assert_eq!(result, Point::new(1, Column(41))); + } + + #[test] + fn sub_absolute_multiline_wrapline() { + let point = Point::new(0, Column(0)); + + let result = point.sub_absolute(&(Line(3), Column(10)), Boundary::Clamp, 11); + + assert_eq!(result, Point::new(2, Column(9))); + } + + #[test] + fn sub_absolute_wrap() { + let point = Point::new(2, Column(0)); + + let result = point.sub_absolute(&(Line(3), Column(42)), Boundary::Wrap, 1); + + assert_eq!(result, Point::new(0, Column(41))); + } + + #[test] + fn sub_absolute_multiline_wrap() { + let point = Point::new(2, Column(0)); + + let result = point.sub_absolute(&(Line(3), Column(10)), Boundary::Wrap, 11); - assert_eq!(result, Point::new(1, num_cols - 1)); + assert_eq!(result, Point::new(1, Column(9))); } } |