Files
galaxy/app/src/terminal/model/grid/indexing.rs
T

286 lines
6.8 KiB
Rust

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<usize> for GridStorage {
type Output = Row;
#[inline]
fn index(&self, index: usize) -> &Row {
&self.raw[index]
}
}
impl IndexMut<usize> 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<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<VisibleRow> for GridStorage {
type Output = Row;
#[inline]
fn index(&self, index: VisibleRow) -> &Row {
&self.raw[index]
}
}
impl IndexMut<VisibleRow> 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<F: Fn(&mut Cell)>(self, func: F) {
for row in self {
for item in row {
func(item)
}
}
}
}
pub trait IndexRegion<I> {
/// 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<Range<VisibleRow>> for GridStorage {
fn region(&self, index: Range<VisibleRow>) -> 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<VisibleRow>) -> 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<RangeTo<VisibleRow>> for GridStorage {
fn region(&self, index: RangeTo<VisibleRow>) -> Region<'_> {
assert!(index.end <= VisibleRow(self.visible_rows()));
Region {
start: VisibleRow(0),
end: index.end,
grid: self,
}
}
fn region_mut(&mut self, index: RangeTo<VisibleRow>) -> RegionMut<'_> {
assert!(index.end <= VisibleRow(self.visible_rows()));
RegionMut {
start: VisibleRow(0),
end: index.end,
grid: self,
}
}
}
impl IndexRegion<RangeFrom<VisibleRow>> for GridStorage {
fn region(&self, index: RangeFrom<VisibleRow>) -> 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<VisibleRow>) -> RegionMut<'_> {
assert!(index.start < VisibleRow(self.visible_rows()));
RegionMut {
start: index.start,
end: VisibleRow(self.visible_rows()),
grid: self,
}
}
}
impl IndexRegion<RangeFull> 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<Self::Item> {
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<Self::Item> {
if self.cur < self.end {
let index = self.cur;
self.cur += 1;
unsafe { Some(&mut *(&mut self.grid[index] as *mut _)) }
} else {
None
}
}
}