use std::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}; use galaxy_terminal::model::grid::cell::Cell; use galaxy_terminal::model::grid::row::Row; use crate::terminal::model::{ grid::Dimensions as _, index::{Point, VisiblePoint, VisibleRow}, }; use super::{grid_handler::GridHandler, GridStorage}; pub(in crate::terminal::model) trait ConvertToAbsolute { type Output; /// Transforms a value from the VisibleScreen coordinate space to the grid /// coordinate space. fn convert_to_absolute(&self, grid: &GridHandler) -> Self::Output; } impl ConvertToAbsolute for VisibleRow { type Output = usize; fn convert_to_absolute(&self, grid: &GridHandler) -> Self::Output { grid.history_size() + self.0 } } impl ConvertToAbsolute for VisiblePoint { type Output = Point; fn convert_to_absolute(&self, grid: &GridHandler) -> Self::Output { Point::new(self.row.convert_to_absolute(grid), self.col) } } /// Index with buffer offset. impl Index for GridStorage { type Output = Row; #[inline] fn index(&self, index: usize) -> &Row { &self.raw[index] } } impl IndexMut for GridStorage { #[inline] fn index_mut(&mut self, index: usize) -> &mut Row { &mut self.raw[index] } } impl Index<&Point> for GridStorage { type Output = Cell; #[inline] fn index(&self, point: &Point) -> &Cell { &self[point.row][point.col] } } impl IndexMut<&Point> for GridStorage { #[inline] fn index_mut(&mut self, point: &Point) -> &mut Cell { &mut self[point.row][point.col] } } impl Index for GridStorage { type Output = Cell; #[inline] fn index(&self, point: Point) -> &Cell { &self[point.row][point.col] } } impl IndexMut for GridStorage { #[inline] fn index_mut(&mut self, point: Point) -> &mut Cell { &mut self[point.row][point.col] } } impl Index for GridStorage { type Output = Row; #[inline] fn index(&self, index: VisibleRow) -> &Row { &self.raw[index] } } impl IndexMut for GridStorage { #[inline] fn index_mut(&mut self, index: VisibleRow) -> &mut Row { &mut self.raw[index] } } /// A subset of lines in the grid. /// /// May be constructed using Grid::region(..). pub struct Region<'a> { start: VisibleRow, end: VisibleRow, grid: &'a GridStorage, } /// A mutable subset of lines in the grid. /// /// May be constructed using Grid::region_mut(..). pub struct RegionMut<'a> { start: VisibleRow, end: VisibleRow, grid: &'a mut GridStorage, } impl RegionMut<'_> { /// Call the provided function for every item in this region. pub fn each(self, func: F) { for row in self { for item in row { func(item) } } } } pub trait IndexRegion { /// Get an immutable region of Self. fn region(&self, _: I) -> Region<'_>; /// Get a mutable region of Self. fn region_mut(&mut self, _: I) -> RegionMut<'_>; } impl IndexRegion> for GridStorage { fn region(&self, index: Range) -> Region<'_> { assert!(index.start < VisibleRow(self.visible_rows())); assert!(index.end <= VisibleRow(self.visible_rows())); assert!(index.start <= index.end); Region { start: index.start, end: index.end, grid: self, } } fn region_mut(&mut self, index: Range) -> RegionMut<'_> { assert!(index.start < VisibleRow(self.visible_rows())); assert!(index.end <= VisibleRow(self.visible_rows())); assert!(index.start <= index.end); RegionMut { start: index.start, end: index.end, grid: self, } } } impl IndexRegion> for GridStorage { fn region(&self, index: RangeTo) -> Region<'_> { assert!(index.end <= VisibleRow(self.visible_rows())); Region { start: VisibleRow(0), end: index.end, grid: self, } } fn region_mut(&mut self, index: RangeTo) -> RegionMut<'_> { assert!(index.end <= VisibleRow(self.visible_rows())); RegionMut { start: VisibleRow(0), end: index.end, grid: self, } } } impl IndexRegion> for GridStorage { fn region(&self, index: RangeFrom) -> Region<'_> { assert!(index.start < VisibleRow(self.visible_rows())); Region { start: index.start, end: VisibleRow(self.visible_rows()), grid: self, } } fn region_mut(&mut self, index: RangeFrom) -> RegionMut<'_> { assert!(index.start < VisibleRow(self.visible_rows())); RegionMut { start: index.start, end: VisibleRow(self.visible_rows()), grid: self, } } } impl IndexRegion for GridStorage { fn region(&self, _: RangeFull) -> Region<'_> { Region { start: VisibleRow(0), end: VisibleRow(self.visible_rows()), grid: self, } } fn region_mut(&mut self, _: RangeFull) -> RegionMut<'_> { RegionMut { start: VisibleRow(0), end: VisibleRow(self.visible_rows()), grid: self, } } } pub struct RegionIter<'a> { end: VisibleRow, cur: VisibleRow, grid: &'a GridStorage, } pub struct RegionIterMut<'a> { end: VisibleRow, cur: VisibleRow, grid: &'a mut GridStorage, } impl<'a> IntoIterator for Region<'a> { type IntoIter = RegionIter<'a>; type Item = &'a Row; fn into_iter(self) -> Self::IntoIter { RegionIter { end: self.end, cur: self.start, grid: self.grid, } } } impl<'a> IntoIterator for RegionMut<'a> { type IntoIter = RegionIterMut<'a>; type Item = &'a mut Row; fn into_iter(self) -> Self::IntoIter { RegionIterMut { end: self.end, cur: self.start, grid: self.grid, } } } impl<'a> Iterator for RegionIter<'a> { type Item = &'a Row; fn next(&mut self) -> Option { if self.cur < self.end { let index = self.cur; self.cur += 1; Some(&self.grid[index]) } else { None } } } impl<'a> Iterator for RegionIterMut<'a> { type Item = &'a mut Row; fn next(&mut self) -> Option { if self.cur < self.end { let index = self.cur; self.cur += 1; unsafe { Some(&mut *(&mut self.grid[index] as *mut _)) } } else { None } } }