use ratatui_core::{
buffer::Cell,
layout::{Position, Rect},
};
use crate::CellFilter;
pub struct CellPredicate<'a> {
filter_area: Rect,
strategy: &'a CellFilter,
}
impl<'a> CellPredicate<'a> {
pub(crate) fn new(area: Rect, strategy: &'a CellFilter) -> Self {
let filter_area = Self::resolve_area(area, strategy);
Self { filter_area, strategy }
}
fn resolve_area(area: Rect, mode: &CellFilter) -> Rect {
match mode {
CellFilter::All => area,
CellFilter::Area(r) => area.intersection(*r),
CellFilter::RefArea(ref_rect) => area.intersection(ref_rect.get()),
CellFilter::Inner(margin) => area.inner(*margin),
CellFilter::Outer(margin) => area.inner(*margin),
CellFilter::Text => area,
CellFilter::NonEmpty => area,
CellFilter::AllOf(_) => area,
CellFilter::AnyOf(_) => area,
CellFilter::NoneOf(_) => area,
CellFilter::Not(m) => Self::resolve_area(area, m.as_ref()),
CellFilter::FgColor(_) => area,
CellFilter::BgColor(_) => area,
CellFilter::Layout(layout, idx) => layout.split(area)[*idx as usize],
CellFilter::PositionFn(_) => area,
CellFilter::EvalCell(_) => area,
CellFilter::Static(filter) => Self::resolve_area(area, filter.as_ref()),
}
}
pub fn is_valid(&self, pos: Position, cell: &Cell) -> bool {
match &self.strategy {
CellFilter::All => true,
CellFilter::Area(_) => self.filter_area.contains(pos),
CellFilter::RefArea(_) => self.filter_area.contains(pos),
CellFilter::Layout(_, _) => self.filter_area.contains(pos),
CellFilter::Inner(_) => self.filter_area.contains(pos),
CellFilter::Outer(_) => !self.filter_area.contains(pos),
CellFilter::Text => {
let ch = cell.symbol().chars().next().unwrap();
ch.is_alphabetic() || ch.is_numeric() || " ?!.,:;()".contains(ch)
},
CellFilter::NonEmpty => cell.symbol() != " ",
CellFilter::AllOf(s) => s.iter().all(|mode| {
mode.predicate(self.filter_area)
.is_valid(pos, cell)
}),
CellFilter::AnyOf(s) => s.iter().any(|mode| {
mode.predicate(self.filter_area)
.is_valid(pos, cell)
}),
CellFilter::NoneOf(s) => s.iter().all(|mode| {
!mode
.predicate(self.filter_area)
.is_valid(pos, cell)
}),
CellFilter::Not(m) => !m.predicate(self.filter_area).is_valid(pos, cell),
CellFilter::FgColor(c) => cell.fg == *c,
CellFilter::BgColor(c) => cell.bg == *c,
CellFilter::PositionFn(f) => {
#[cfg(not(feature = "sendable"))]
return f.borrow()(pos);
#[cfg(feature = "sendable")]
return f.lock().unwrap()(pos);
},
CellFilter::EvalCell(f) => {
#[cfg(not(feature = "sendable"))]
return f.borrow()(cell);
#[cfg(feature = "sendable")]
return f.lock().unwrap()(cell);
},
CellFilter::Static(f) => f.predicate(self.filter_area).is_valid(pos, cell),
}
}
}