use std::marker::PhantomData;
use papergrid::{records::Records, Borders};
use crate::{style::StyleCorrectSpan, Border, Table, TableOption};
use super::{HorizontalLine, Line, VerticalLine};
#[derive(Debug, Clone)]
pub struct Style<T, B, L, R, H, V, HLines = HLineArray<0>, VLines = VLineArray<0>> {
pub(crate) borders: Borders<char>,
pub(crate) horizontals: HLines,
pub(crate) verticals: VLines,
_top: PhantomData<T>,
_bottom: PhantomData<B>,
_left: PhantomData<L>,
_right: PhantomData<R>,
_horizontal: PhantomData<H>,
_vertical: PhantomData<V>,
}
type HLineArray<const N: usize> = [HorizontalLine; N];
type VLineArray<const N: usize> = [VerticalLine; N];
#[derive(Debug, Clone)]
pub struct On;
impl Style<(), (), (), (), (), (), (), ()> {
pub const fn empty() -> Style<(), (), (), (), (), ()> {
Style::new(
create_borders(
Line::empty(),
Line::empty(),
Line::empty(),
None,
None,
None,
),
[],
[],
)
}
pub const fn blank() -> Style<(), (), (), (), (), On> {
Style::new(
create_borders(
Line::empty(),
Line::empty(),
Line::empty(),
None,
None,
Some(' '),
),
[],
[],
)
}
pub const fn ascii() -> Style<On, On, On, On, On, On> {
Style::new(
create_borders(
Line::full('-', '+', '+', '+'),
Line::full('-', '+', '+', '+'),
Line::full('-', '+', '+', '+'),
Some('|'),
Some('|'),
Some('|'),
),
[],
[],
)
}
pub const fn psql() -> Style<(), (), (), (), (), On, HLineArray<1>> {
Style::new(
create_borders(
Line::empty(),
Line::empty(),
Line::empty(),
None,
None,
Some('|'),
),
[HorizontalLine::new(1, Line::empty())
.main(Some('-'))
.intersection(Some('+'))],
[],
)
}
pub const fn markdown() -> Style<(), (), On, On, (), On, HLineArray<1>> {
Style::new(
create_borders(
Line::empty(),
Line::empty(),
Line::empty(),
Some('|'),
Some('|'),
Some('|'),
),
[HorizontalLine::new(1, Line::full('-', '|', '|', '|'))],
[],
)
}
pub const fn modern() -> Style<On, On, On, On, On, On> {
Style::new(
create_borders(
Line::full('─', '┬', '┌', '┐'),
Line::full('─', '┴', '└', '┘'),
Line::full('─', '┼', '├', '┤'),
Some('│'),
Some('│'),
Some('│'),
),
[],
[],
)
}
pub const fn rounded() -> Style<On, On, On, On, (), On, HLineArray<1>> {
Style::new(
create_borders(
Line::full('─', '┬', '╭', '╮'),
Line::full('─', '┴', '╰', '╯'),
Line::empty(),
Some('│'),
Some('│'),
Some('│'),
),
[HorizontalLine::new(1, Line::full('─', '┼', '├', '┤'))],
[],
)
}
pub const fn extended() -> Style<On, On, On, On, On, On> {
Style::new(
create_borders(
Line::full('═', '╦', '╔', '╗'),
Line::full('═', '╩', '╚', '╝'),
Line::full('═', '╬', '╠', '╣'),
Some('║'),
Some('║'),
Some('║'),
),
[],
[],
)
}
pub const fn dots() -> Style<On, On, On, On, On, On> {
Style::new(
create_borders(
Line::full('.', '.', '.', '.'),
Line::full('.', ':', ':', ':'),
Line::full('.', ':', ':', ':'),
Some(':'),
Some(':'),
Some(':'),
),
[],
[],
)
}
pub const fn re_structured_text() -> Style<On, On, (), (), (), On, HLineArray<1>> {
Style::new(
create_borders(
Line::new(Some('='), Some(' '), None, None),
Line::new(Some('='), Some(' '), None, None),
Line::empty(),
None,
None,
Some(' '),
),
[HorizontalLine::new(
1,
Line::new(Some('='), Some(' '), None, None),
)],
[],
)
}
pub const fn ascii_rounded() -> Style<On, On, On, On, (), On> {
Style::new(
create_borders(
Line::full('-', '-', '.', '.'),
Line::full('-', '-', '\'', '\''),
Line::empty(),
Some('|'),
Some('|'),
Some('|'),
),
[],
[],
)
}
pub const fn correct_spans() -> StyleCorrectSpan {
StyleCorrectSpan
}
}
impl<T, B, L, R, H, V, HLines, VLines> Style<T, B, L, R, H, V, HLines, VLines> {
pub const fn get_frame(&self) -> Border {
Border::new_raw(Some(papergrid::Border {
top: self.borders.top,
bottom: self.borders.bottom,
left: self.borders.vertical_left,
right: self.borders.vertical_right,
left_top_corner: self.borders.top_left,
right_top_corner: self.borders.top_right,
left_bottom_corner: self.borders.bottom_left,
right_bottom_corner: self.borders.bottom_right,
}))
}
pub const fn get_horizontal(&self) -> Line {
Line::new(
self.borders.horizontal,
self.borders.intersection,
self.borders.horizontal_left,
self.borders.horizontal_right,
)
}
pub const fn get_vertical(&self) -> Line {
Line::new(
self.borders.vertical,
self.borders.intersection,
self.borders.top_intersection,
self.borders.bottom_intersection,
)
}
pub fn top(mut self, c: char) -> Style<On, B, L, R, H, V, HLines, VLines>
where
for<'a> &'a mut VLines: IntoIterator<Item = &'a mut VerticalLine>,
{
self.borders.top = Some(c);
if self.borders.has_left() {
self.borders.top_left = Some(c);
}
if self.borders.has_right() {
self.borders.top_right = Some(c);
}
if self.borders.has_vertical() {
self.borders.top_intersection = Some(c);
}
for vl in &mut self.verticals {
if let Some(line) = &mut vl.line {
line.connector1 = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn bottom(mut self, c: char) -> Style<T, On, L, R, H, V, HLines, VLines>
where
for<'a> &'a mut VLines: IntoIterator<Item = &'a mut VerticalLine>,
{
self.borders.bottom = Some(c);
if self.borders.has_left() {
self.borders.bottom_left = Some(c);
}
if self.borders.has_right() {
self.borders.bottom_right = Some(c);
}
if self.borders.has_vertical() {
self.borders.bottom_intersection = Some(c);
}
for vl in &mut self.verticals {
if let Some(line) = &mut vl.line {
line.connector2 = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn left(mut self, c: char) -> Style<T, B, On, R, H, V, HLines, VLines>
where
for<'a> &'a mut HLines: IntoIterator<Item = &'a mut HorizontalLine>,
{
self.borders.vertical_left = Some(c);
if self.borders.has_top() {
self.borders.top_left = Some(c);
}
if self.borders.has_bottom() {
self.borders.bottom_left = Some(c);
}
if self.borders.has_horizontal() {
self.borders.horizontal_left = Some(c);
}
for hl in &mut self.horizontals {
if let Some(line) = &mut hl.line {
line.connector1 = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn right(mut self, c: char) -> Style<T, B, L, On, H, V, HLines, VLines>
where
for<'a> &'a mut HLines: IntoIterator<Item = &'a mut HorizontalLine>,
{
self.borders.vertical_right = Some(c);
if self.borders.has_top() {
self.borders.top_right = Some(c);
}
if self.borders.has_bottom() {
self.borders.bottom_right = Some(c);
}
if self.borders.has_horizontal() {
self.borders.horizontal_right = Some(c);
}
for hl in &mut self.horizontals {
if let Some(line) = &mut hl.line {
line.connector2 = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn horizontal(mut self, c: char) -> Style<T, B, L, R, On, V, HLines, VLines>
where
for<'a> &'a mut VLines: IntoIterator<Item = &'a mut VerticalLine>,
{
self.borders.horizontal = Some(c);
if self.borders.has_vertical() {
self.borders.intersection = Some(c);
}
if self.borders.has_left() {
self.borders.horizontal_left = Some(c);
}
if self.borders.has_right() {
self.borders.horizontal_right = Some(c);
}
for vl in &mut self.verticals {
if let Some(line) = &mut vl.line {
line.intersection = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn vertical(mut self, c: char) -> Style<T, B, L, R, H, On, HLines, VLines>
where
for<'a> &'a mut HLines: IntoIterator<Item = &'a mut HorizontalLine>,
{
self.borders.vertical = Some(c);
if self.borders.has_horizontal() {
self.borders.intersection = Some(c);
}
if self.borders.has_top() {
self.borders.top_intersection = Some(c);
}
if self.borders.has_bottom() {
self.borders.bottom_intersection = Some(c);
}
for hl in &mut self.horizontals {
if let Some(line) = &mut hl.line {
line.intersection = Some(c);
}
}
Style::new(self.borders, self.horizontals, self.verticals)
}
pub fn horizontals<NewLines>(self, lines: NewLines) -> Style<T, B, L, R, H, V, NewLines, VLines>
where
NewLines: IntoIterator<Item = HorizontalLine> + Clone,
{
Style::new(self.borders, lines, self.verticals)
}
pub fn verticals<NewLines>(self, lines: NewLines) -> Style<T, B, L, R, H, V, HLines, NewLines>
where
NewLines: IntoIterator<Item = VerticalLine> + Clone,
{
Style::new(self.borders, self.horizontals, lines)
}
pub fn off_horizontals(self) -> Style<T, B, L, R, H, V, HLineArray<0>, VLines> {
Style::new(self.borders, [], self.verticals)
}
pub fn off_verticals(self) -> Style<T, B, L, R, H, V, HLines, VLineArray<0>> {
Style::new(self.borders, self.horizontals, [])
}
}
impl<B, R, H, V, HLines, VLines> Style<On, B, On, R, H, V, HLines, VLines> {
pub fn top_left_corner(mut self, c: char) -> Self {
self.borders.top_left = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<B, L, H, V, HLines, VLines> Style<On, B, L, On, H, V, HLines, VLines> {
pub fn top_right_corner(mut self, c: char) -> Self {
self.borders.top_right = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, L, H, V, HLines, VLines> Style<T, On, L, On, H, V, HLines, VLines> {
pub fn bottom_right_corner(mut self, c: char) -> Self {
self.borders.bottom_right = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, R, H, V, HLines, VLines> Style<T, On, On, R, H, V, HLines, VLines> {
pub fn bottom_left_corner(mut self, c: char) -> Self {
self.borders.bottom_left = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, B, R, V, HLines, VLines> Style<T, B, On, R, On, V, HLines, VLines> {
pub fn left_intersection(mut self, c: char) -> Self {
self.borders.horizontal_left = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, B, L, V, HLines, VLines> Style<T, B, L, On, On, V, HLines, VLines> {
pub fn right_intersection(mut self, c: char) -> Self {
self.borders.horizontal_right = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<B, L, R, H, HLines, VLines> Style<On, B, L, R, H, On, HLines, VLines> {
pub fn top_intersection(mut self, c: char) -> Self {
self.borders.top_intersection = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, L, R, H, HLines, VLines> Style<T, On, L, R, H, On, HLines, VLines> {
pub fn bottom_intersection(mut self, c: char) -> Self {
self.borders.bottom_intersection = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<T, B, L, R, HLines, VLines> Style<T, B, L, R, On, On, HLines, VLines> {
pub fn inner_intersection(mut self, c: char) -> Self {
self.borders.intersection = Some(c);
Style::new(self.borders, self.horizontals, self.verticals)
}
}
impl<B, L, R, H, V, HLines, VLines> Style<On, B, L, R, H, V, HLines, VLines> {
pub fn off_top(mut self) -> Style<(), B, L, R, H, V, HLines, VerticalLineIter<VLines::IntoIter>>
where
VLines: IntoIterator<Item = VerticalLine> + Clone,
{
self.borders.top = None;
self.borders.top_intersection = None;
self.borders.top_left = None;
self.borders.top_right = None;
let iter = VerticalLineIter::new(self.verticals.into_iter(), false, true, false);
Style::new(self.borders, self.horizontals, iter)
}
}
impl<T, L, R, H, V, HLines, VLines> Style<T, On, L, R, H, V, HLines, VLines> {
pub fn off_bottom(
mut self,
) -> Style<T, (), L, R, H, V, HLines, VerticalLineIter<VLines::IntoIter>>
where
VLines: IntoIterator<Item = VerticalLine> + Clone,
{
self.borders.bottom = None;
self.borders.bottom_intersection = None;
self.borders.bottom_left = None;
self.borders.bottom_right = None;
let iter = VerticalLineIter::new(self.verticals.into_iter(), false, false, true);
Style::new(self.borders, self.horizontals, iter)
}
}
impl<T, B, R, H, V, HLines, VLines> Style<T, B, On, R, H, V, HLines, VLines> {
pub fn off_left(
mut self,
) -> Style<T, B, (), R, H, V, HorizontalLineIter<HLines::IntoIter>, VLines>
where
HLines: IntoIterator<Item = HorizontalLine> + Clone,
{
self.borders.vertical_left = None;
self.borders.horizontal_left = None;
self.borders.top_left = None;
self.borders.bottom_left = None;
let iter = HorizontalLineIter::new(self.horizontals.into_iter(), false, true, false);
Style::new(self.borders, iter, self.verticals)
}
}
impl<T, B, L, H, V, HLines, VLines> Style<T, B, L, On, H, V, HLines, VLines> {
pub fn off_right(
mut self,
) -> Style<T, B, L, (), H, V, HorizontalLineIter<HLines::IntoIter>, VLines>
where
HLines: IntoIterator<Item = HorizontalLine> + Clone,
{
self.borders.vertical_right = None;
self.borders.horizontal_right = None;
self.borders.top_right = None;
self.borders.bottom_right = None;
let iter = HorizontalLineIter::new(self.horizontals.into_iter(), false, false, true);
Style::new(self.borders, iter, self.verticals)
}
}
impl<T, B, L, R, V, HLines, VLines> Style<T, B, L, R, On, V, HLines, VLines> {
pub fn off_horizontal(
mut self,
) -> Style<T, B, L, R, (), V, HLines, VerticalLineIter<VLines::IntoIter>>
where
VLines: IntoIterator<Item = VerticalLine> + Clone,
{
self.borders.horizontal = None;
self.borders.horizontal_left = None;
self.borders.horizontal_right = None;
self.borders.intersection = None;
let iter = VerticalLineIter::new(self.verticals.into_iter(), true, false, false);
Style::new(self.borders, self.horizontals, iter)
}
}
impl<T, B, L, R, H, HLines, VLines> Style<T, B, L, R, H, On, HLines, VLines> {
pub fn off_vertical(
mut self,
) -> Style<T, B, L, R, H, (), HorizontalLineIter<HLines::IntoIter>, VLines>
where
HLines: IntoIterator<Item = HorizontalLine> + Clone,
{
self.borders.vertical = None;
self.borders.top_intersection = None;
self.borders.bottom_intersection = None;
self.borders.intersection = None;
let iter = HorizontalLineIter::new(self.horizontals.into_iter(), true, false, false);
Style::new(self.borders, iter, self.verticals)
}
}
impl<T, B, L, R, H, V, HLines, VLines> Style<T, B, L, R, H, V, HLines, VLines> {
const fn new(borders: Borders, horizontals: HLines, verticals: VLines) -> Self {
Self {
borders,
horizontals,
verticals,
_top: PhantomData,
_bottom: PhantomData,
_left: PhantomData,
_right: PhantomData,
_horizontal: PhantomData,
_vertical: PhantomData,
}
}
}
impl<T, B, L, R, H, V, HLines, VLines, I> TableOption<I> for Style<T, B, L, R, H, V, HLines, VLines>
where
I: Records,
HLines: IntoIterator<Item = HorizontalLine> + Clone,
VLines: IntoIterator<Item = VerticalLine> + Clone,
{
fn change(&mut self, table: &mut Table<I>) {
table.get_config_mut().clear_theme();
table.get_config_mut().set_borders(self.borders.clone());
if table.shape().0 > 1 {
for mut hl in self.horizontals.clone() {
hl.change(table);
}
}
if table.shape().1 > 1 {
for mut vl in self.verticals.clone() {
vl.change(table);
}
}
table.destroy_width_cache();
table.destroy_height_cache();
}
}
const fn create_borders(
top: Line,
bottom: Line,
horizontal: Line,
left: Option<char>,
right: Option<char>,
vertical: Option<char>,
) -> Borders {
Borders {
top: top.main,
bottom: bottom.main,
top_left: top.connector1,
top_right: top.connector2,
bottom_left: bottom.connector1,
bottom_right: bottom.connector2,
top_intersection: top.intersection,
bottom_intersection: bottom.intersection,
horizontal_left: horizontal.connector1,
horizontal_right: horizontal.connector2,
horizontal: horizontal.main,
intersection: horizontal.intersection,
vertical_left: left,
vertical_right: right,
vertical,
}
}
#[derive(Debug, Clone)]
pub struct HorizontalLineIter<I> {
iter: I,
intersection: bool,
left: bool,
right: bool,
}
impl<I> HorizontalLineIter<I> {
fn new(iter: I, intersection: bool, left: bool, right: bool) -> Self {
Self {
iter,
intersection,
left,
right,
}
}
}
impl<I> Iterator for HorizontalLineIter<I>
where
I: Iterator<Item = HorizontalLine>,
{
type Item = HorizontalLine;
fn next(&mut self) -> Option<Self::Item> {
let mut hl = self.iter.next()?;
if let Some(mut line) = hl.line {
if self.intersection {
line.intersection = None;
}
if self.left {
line.connector1 = None;
}
if self.right {
line.connector2 = None;
}
hl.line = Some(line);
}
Some(hl)
}
}
#[derive(Debug, Clone)]
pub struct VerticalLineIter<I> {
iter: I,
intersection: bool,
top: bool,
bottom: bool,
}
impl<I> VerticalLineIter<I> {
fn new(iter: I, intersection: bool, top: bool, bottom: bool) -> Self {
Self {
iter,
intersection,
top,
bottom,
}
}
}
impl<I> Iterator for VerticalLineIter<I>
where
I: Iterator<Item = VerticalLine>,
{
type Item = VerticalLine;
fn next(&mut self) -> Option<Self::Item> {
let mut hl = self.iter.next()?;
if let Some(mut line) = hl.line {
if self.intersection {
line.intersection = None;
}
if self.top {
line.connector1 = None;
}
if self.bottom {
line.connector2 = None;
}
hl.line = Some(line);
}
Some(hl)
}
}