use crate::*;
use print::
{
InputExtract,
Context,
};
use core::fmt;
use std::sync::OnceLock;
#[ derive( Debug ) ]
pub struct Table
{
pub delimitting_header : bool,
pub cell_prefix : String,
pub cell_postfix : String,
pub cell_separator : String,
pub row_prefix : String,
pub row_postfix : String,
pub row_separator : String,
pub h : char,
pub v : char,
pub t_l : char,
pub t_r : char,
pub t_t : char,
pub t_b : char,
pub cross : char,
pub corner_lt : char,
pub corner_rt : char,
pub corner_lb : char,
pub corner_rb : char,
pub max_width: usize,
}
impl Default for Table
{
fn default() -> Self
{
let delimitting_header = true;
let cell_prefix = "".to_string();
let cell_postfix = "".to_string();
let cell_separator = " │ ".to_string();
let row_prefix = "│ ".to_string();
let row_postfix = " │".to_string();
let row_separator = "\n".to_string();
let h = '─';
let v = '|';
let t_l = '├';
let t_r = '┤';
let t_t = '┬';
let t_b = '┴';
let cross = '┼';
let corner_lt = '┌';
let corner_rt = '┐';
let corner_lb = '└';
let corner_rb = '┘';
let max_width = 0;
Self
{
delimitting_header,
cell_prefix,
cell_postfix,
cell_separator,
row_prefix,
row_postfix,
row_separator,
h,
v,
t_l,
t_r,
t_t,
t_b,
cross,
corner_lt,
corner_rt,
corner_lb,
corner_rb,
max_width
}
}
}
impl Default for &'static Table
{
fn default() -> Self
{
static STYLES : OnceLock< Table > = OnceLock::new();
STYLES.get_or_init( ||
{
Table::default()
})
}
}
impl Table
{
pub fn instance() -> & 'static dyn TableOutputFormat
{
static INSTANCE : OnceLock< Table > = OnceLock::new();
INSTANCE.get_or_init( ||
{
Self::default()
})
}
pub fn min_width
(
&self,
column_count : usize,
) -> usize
{
self.row_prefix.chars().count()
+ self.row_postfix.chars().count()
+ column_count * ( self.cell_postfix.chars().count() + self.cell_prefix.chars().count() )
+ if column_count == 0 { 0 } else { ( column_count - 1 ) * self.cell_separator.chars().count() }
+ column_count
}
}
impl TableOutputFormat for Table
{
fn extract_write< 'buf, 'data >( &self, x : &InputExtract< 'data >, c : &mut Context< 'buf > ) -> fmt::Result
{
use format::text_wrap::text_wrap;
let cell_prefix = &self.cell_prefix;
let cell_postfix = &self.cell_postfix;
let cell_separator = &self.cell_separator;
let row_prefix = &self.row_prefix;
let row_postfix = &self.row_postfix;
let row_separator = &self.row_separator;
let h = self.h.to_string();
let column_count = x.col_descriptors.len();
if self.max_width != 0 && ( self.min_width( column_count ) > self.max_width )
{
return Err( fmt::Error );
}
let columns_nowrap_width = x.col_descriptors.iter().map( |c| c.width ).sum::<usize>();
let visual_elements_width = self.min_width( column_count ) - column_count;
let filtered_data = x.row_descriptors.iter().filter_map( | r |
{
if r.vis
{
Some( &x.data[ r.irow ] )
}
else
{
None
}
});
let wrapped_text = text_wrap
(
filtered_data,
x.col_descriptors.iter().map( | c | c.width ).collect::< Vec< usize > >(),
if self.max_width == 0 { 0 } else { self.max_width - visual_elements_width },
columns_nowrap_width
);
let new_columns_widthes = wrapped_text.column_widthes.iter().sum::<usize>();
let new_row_width = new_columns_widthes + visual_elements_width;
let mut printed_row_count = 0;
for row in wrapped_text.data.iter()
{
if printed_row_count == wrapped_text.first_row_height && x.has_header && self.delimitting_header
{
write!( c.buf, "{}", row_separator )?;
write!( c.buf, "{}", h.repeat( new_row_width ) )?;
}
if printed_row_count > 0
{
write!( c.buf, "{}", row_separator )?;
}
printed_row_count += 1;
write!( c.buf, "{}", row_prefix )?;
for ( icol, col ) in row.iter().enumerate()
{
let cell_wrapped_width = col.wrap_width;
let column_width = wrapped_text.column_widthes[ icol ];
let slice_width = col.content.chars().count();
if icol > 0
{
write!( c.buf, "{}", cell_separator )?;
}
write!( c.buf, "{}", cell_prefix )?;
let lspaces = column_width.saturating_sub( cell_wrapped_width ) / 2;
let rspaces = ( ( column_width.saturating_sub( cell_wrapped_width ) as f32 / 2 as f32 ) ).round() as usize + cell_wrapped_width.saturating_sub(slice_width);
if lspaces > 0
{
write!( c.buf, "{:<width$}", " ", width = lspaces )?;
}
write!( c.buf, "{}", col.content )?;
if rspaces > 0
{
write!( c.buf, "{:>width$}", " ", width = rspaces )?;
}
write!( c.buf, "{}", cell_postfix )?;
}
write!( c.buf, "{}", row_postfix )?;
}
Ok(())
}
}