pub mod draw;
pub mod region;
use std::{
io::{Stdout, Write},
iter,
};
use crossterm::{
cursor::MoveTo,
queue,
style::{Print, SetStyle},
};
use self::draw::Draw;
use crate::{
error::Result,
style::Style,
utils::geometry::{Position, Size},
};
pub struct Buffer {
size: Size,
data: Vec<Option<Cell>>,
}
impl Buffer {
pub fn new<S: Into<Size>>(size: S) -> Self {
let size = size.into();
let mut data = Vec::new();
data.resize_with((size.width * size.height) as usize, Option::default);
Self { size, data }
}
fn diffs(&self, other: &Self) -> Diffs {
let mut diffs = Vec::new();
for (index, (new, old)) in iter::zip(&self.data, &other.data).enumerate() {
if new != old {
#[allow(clippy::cast_possible_truncation)]
diffs.push((Position::from_idx(index as u16, self.size), new));
}
}
Diffs { cells: diffs }
}
pub(crate) fn paint_diffs(&self, other: &Self, stdout: &mut Stdout) -> Result<()> {
for (pos, cell) in self.diffs(other).cells {
queue!(stdout, MoveTo(pos.x, pos.y))?;
match cell {
None => queue!(stdout, Print(" "))?,
Some(Cell { chr: None, style }) => {
queue!(stdout, SetStyle((*style).into()))?;
queue!(stdout, Print(" "))?;
}
Some(Cell { chr: Some(c), style }) => {
queue!(stdout, SetStyle((*style).into()))?;
queue!(stdout, Print(c))?;
}
};
}
stdout.flush()?;
Ok(())
}
}
impl Draw for Buffer {
fn set_option_cell(&mut self, position: Position, cell: Option<Cell>) -> bool {
let idx = usize::from(position.into_idx(self.size));
let in_bounds = idx < self.data.len();
if in_bounds {
self.data[idx] = cell;
}
in_bounds
}
fn size(&self) -> Size {
self.size
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Cell {
chr: Option<char>,
style: Style,
}
struct Diffs<'a> {
cells: Vec<(Position, &'a Option<Cell>)>,
}