summaryrefslogtreecommitdiffstats
path: root/vendor/tabled/src/settings/themes
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tabled/src/settings/themes')
-rw-r--r--vendor/tabled/src/settings/themes/colorization.rs388
-rw-r--r--vendor/tabled/src/settings/themes/column_names.rs355
-rw-r--r--vendor/tabled/src/settings/themes/mod.rs9
3 files changed, 752 insertions, 0 deletions
diff --git a/vendor/tabled/src/settings/themes/colorization.rs b/vendor/tabled/src/settings/themes/colorization.rs
new file mode 100644
index 000000000..41c721330
--- /dev/null
+++ b/vendor/tabled/src/settings/themes/colorization.rs
@@ -0,0 +1,388 @@
+use papergrid::{
+ color::AnsiColor,
+ config::{Entity, Sides},
+};
+
+use crate::{
+ grid::{
+ config::ColoredConfig,
+ records::{ExactRecords, Records},
+ },
+ settings::{object::Object, Color, TableOption},
+};
+
+/// [`Colorization`] sets a color for the whole table data (so it's not include the borders).
+///
+/// You can colorize borders in a different round using [`BorderColor`] or [`RawStyle`]
+///
+/// # Examples
+///
+/// ```
+/// use std::iter::FromIterator;
+///
+/// use tabled::builder::Builder;
+/// use tabled::settings::{style::BorderColor, themes::Colorization, Color, Style};
+///
+/// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+///
+/// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+/// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+/// let color3 = Color::FG_RED | Color::BG_RED;
+///
+/// let mut table = Builder::from_iter(data).build();
+/// table
+/// .with(Colorization::chess(color1, color2))
+/// .with(Style::modern())
+/// .with(BorderColor::filled(color3));
+///
+/// println!("{table}");
+/// ```
+///
+/// [`RawStyle`]: crate::settings::style::RawStyle
+/// [`BorderColor`]: crate::settings::style::BorderColor
+#[derive(Debug, Clone)]
+pub struct Colorization {
+ pattern: ColorizationPattern,
+ colors: Vec<Color>,
+}
+
+#[derive(Debug, Clone)]
+enum ColorizationPattern {
+ Column,
+ Row,
+ ByRow,
+ ByColumn,
+ Chess,
+}
+
+impl Colorization {
+ /// Creates a [`Colorization`] with a chess pattern.
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::chess(color1, color2))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn chess(white: Color, black: Color) -> Self {
+ Self::new(vec![white, black], ColorizationPattern::Chess)
+ }
+
+ /// Creates a [`Colorization`] with a target [`Object`].
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::object::Rows;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::exact([color1, color2], Rows::first()))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn exact<I, O>(colors: I, target: O) -> ExactColorization<O>
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ let colors = colors.into_iter().map(Into::into).collect();
+ ExactColorization::new(colors, target)
+ }
+
+ /// Creates a [`Colorization`] with a pattern which changes row by row.
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::object::Rows;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::rows([color1, color2]))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn rows<I>(colors: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ Self::new(colors, ColorizationPattern::Row)
+ }
+
+ /// Creates a [`Colorization`] with a pattern which changes column by column.
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::object::Rows;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::columns([color1, color2]))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn columns<I>(colors: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ Self::new(colors, ColorizationPattern::Column)
+ }
+
+ /// Creates a [`Colorization`] with a pattern which peaks cells one by one iterating over rows.
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::object::Rows;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::by_row([color1, color2]))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn by_row<I>(colors: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ Self::new(colors, ColorizationPattern::ByRow)
+ }
+
+ /// Creates a [`Colorization`] with a pattern which peaks cells one by one iterating over columns.
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ ///
+ /// use tabled::builder::Builder;
+ /// use tabled::settings::object::Rows;
+ /// use tabled::settings::{themes::Colorization, Color, Style};
+ ///
+ /// let data = [["Hello", "World"], ["Hi", "World"], ["Halo", "World"]];
+ ///
+ /// let color1 = Color::FG_BLACK | Color::BG_WHITE;
+ /// let color2 = Color::BG_BLACK | Color::FG_WHITE;
+ ///
+ /// let mut table = Builder::from_iter(data).build();
+ /// table
+ /// .with(Colorization::by_column([color1, color2]))
+ /// .with(Style::empty());
+ ///
+ /// println!("{table}");
+ /// ```
+ pub fn by_column<I>(colors: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ Self::new(colors, ColorizationPattern::ByColumn)
+ }
+
+ fn new<I>(colors: I, pattern: ColorizationPattern) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Color>,
+ {
+ let colors = colors.into_iter().map(Into::into).collect();
+ Self { colors, pattern }
+ }
+}
+
+impl<R, D> TableOption<R, D, ColoredConfig> for Colorization
+where
+ R: Records + ExactRecords,
+{
+ fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+ if self.colors.is_empty() {
+ return;
+ }
+
+ let count_columns = records.count_columns();
+ let count_rows = records.count_rows();
+
+ match self.pattern {
+ ColorizationPattern::Column => colorize_columns(&self.colors, count_columns, cfg),
+ ColorizationPattern::Row => colorize_rows(&self.colors, count_rows, cfg),
+ ColorizationPattern::ByRow => {
+ colorize_by_row(&self.colors, count_rows, count_columns, cfg)
+ }
+ ColorizationPattern::ByColumn => {
+ colorize_by_column(&self.colors, count_rows, count_columns, cfg)
+ }
+ ColorizationPattern::Chess => {
+ colorize_diogonals(&self.colors, count_rows, count_columns, cfg)
+ }
+ }
+ }
+}
+
+fn colorize_columns(colors: &[Color], count_columns: usize, cfg: &mut ColoredConfig) {
+ for (col, color) in (0..count_columns).zip(colors.iter().cycle()) {
+ colorize_entity(color, Entity::Column(col), cfg);
+ }
+}
+
+fn colorize_rows(colors: &[Color], count_rows: usize, cfg: &mut ColoredConfig) {
+ for (row, color) in (0..count_rows).zip(colors.iter().cycle()) {
+ colorize_entity(color, Entity::Row(row), cfg);
+ }
+}
+
+fn colorize_by_row(
+ colors: &[Color],
+ count_rows: usize,
+ count_columns: usize,
+ cfg: &mut ColoredConfig,
+) {
+ let mut color_peek = colors.iter().cycle();
+ for row in 0..count_rows {
+ for col in 0..count_columns {
+ let color = color_peek.next().unwrap();
+ colorize_entity(color, Entity::Cell(row, col), cfg);
+ }
+ }
+}
+
+fn colorize_by_column(
+ colors: &[Color],
+ count_rows: usize,
+ count_columns: usize,
+ cfg: &mut ColoredConfig,
+) {
+ let mut color_peek = colors.iter().cycle();
+ for col in 0..count_columns {
+ for row in 0..count_rows {
+ let color = color_peek.next().unwrap();
+ colorize_entity(color, Entity::Cell(row, col), cfg);
+ }
+ }
+}
+
+fn colorize_diogonals(
+ colors: &[Color],
+ count_rows: usize,
+ count_columns: usize,
+ cfg: &mut ColoredConfig,
+) {
+ let mut color_peek = colors.iter().cycle();
+ for mut row in 0..count_rows {
+ let color = color_peek.next().unwrap();
+ for col in 0..count_columns {
+ colorize_entity(color, Entity::Cell(row, col), cfg);
+
+ row += 1;
+ if row == count_rows {
+ break;
+ }
+ }
+ }
+
+ let _ = color_peek.next().unwrap();
+
+ for mut col in 1..count_columns {
+ let color = color_peek.next().unwrap();
+ for row in 0..count_rows {
+ colorize_entity(color, Entity::Cell(row, col), cfg);
+
+ col += 1;
+ if col == count_columns {
+ break;
+ }
+ }
+ }
+}
+
+fn colorize_entity(color: &Color, pos: Entity, cfg: &mut ColoredConfig) {
+ let ansi_color = AnsiColor::from(color.clone());
+ let _ = cfg.set_color(pos, ansi_color.clone());
+ cfg.set_justification_color(pos, Some(ansi_color.clone()));
+ cfg.set_padding_color(
+ pos,
+ Sides::new(
+ Some(ansi_color.clone()),
+ Some(ansi_color.clone()),
+ Some(ansi_color.clone()),
+ Some(ansi_color),
+ ),
+ );
+}
+
+/// A colorization of a target [`Object`].
+///
+/// Can be created by [`Colorization::exact`].
+#[derive(Debug, Clone)]
+pub struct ExactColorization<O> {
+ colors: Vec<Color>,
+ target: O,
+}
+
+impl<O> ExactColorization<O> {
+ fn new(colors: Vec<Color>, target: O) -> Self {
+ Self { colors, target }
+ }
+}
+
+impl<R, D, O> TableOption<R, D, ColoredConfig> for ExactColorization<O>
+where
+ O: Object<R>,
+{
+ fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
+ if self.colors.is_empty() {
+ return;
+ }
+
+ let mut color_peek = self.colors.iter().cycle();
+ for pos in self.target.cells(records) {
+ let color = color_peek.next().unwrap();
+ colorize_entity(color, pos, cfg);
+ }
+ }
+}
diff --git a/vendor/tabled/src/settings/themes/column_names.rs b/vendor/tabled/src/settings/themes/column_names.rs
new file mode 100644
index 000000000..02848166d
--- /dev/null
+++ b/vendor/tabled/src/settings/themes/column_names.rs
@@ -0,0 +1,355 @@
+use crate::{
+ grid::{
+ config::{AlignmentHorizontal, ColoredConfig},
+ dimension::{CompleteDimensionVecRecords, Dimension, Estimate},
+ records::{
+ vec_records::{CellInfo, VecRecords},
+ ExactRecords, PeekableRecords, Records, Resizable,
+ },
+ util::string::string_width,
+ },
+ settings::{
+ style::{BorderText, Offset},
+ Color, TableOption,
+ },
+};
+
+/// [`ColumnNames`] sets strings on horizontal lines for the columns.
+///
+/// Notice that using a [`Default`] would reuse a names from the first row.
+///
+/// # Examples
+///
+/// ```
+/// use std::iter::FromIterator;
+/// use tabled::{Table, settings::themes::ColumnNames};
+///
+/// let data = vec![
+/// vec!["Hello", "World"],
+/// vec!["Hello", "World"],
+/// ];
+///
+/// let mut table = Table::from_iter(data);
+/// table.with(ColumnNames::new(["head1", "head2"]).set_offset(3).set_line(2));
+///
+/// assert_eq!(
+/// table.to_string(),
+/// "+--------+--------+\n\
+/// | Hello | World |\n\
+/// +--------+--------+\n\
+/// | Hello | World |\n\
+/// +---head1+---head2+"
+/// );
+/// ```
+///
+/// [`Default`] usage.
+///
+/// ```
+/// use std::iter::FromIterator;
+/// use tabled::{Table, settings::themes::ColumnNames};
+///
+/// let data = vec![
+/// vec!["Hello", "World"],
+/// vec!["Hello", "World"],
+/// ];
+///
+/// let mut table = Table::from_iter(data);
+/// table.with(ColumnNames::default());
+///
+/// assert_eq!(
+/// table.to_string(),
+/// "+Hello--+World--+\n\
+/// | Hello | World |\n\
+/// +-------+-------+"
+/// );
+/// ```
+#[derive(Debug, Clone)]
+pub struct ColumnNames {
+ names: Option<Vec<String>>,
+ colors: Vec<Option<Color>>,
+ offset: usize,
+ line: usize,
+ alignment: AlignmentHorizontal,
+}
+
+impl Default for ColumnNames {
+ fn default() -> Self {
+ Self {
+ names: Default::default(),
+ colors: Default::default(),
+ offset: Default::default(),
+ line: Default::default(),
+ alignment: AlignmentHorizontal::Left,
+ }
+ }
+}
+
+impl ColumnNames {
+ /// Creates a [`ColumnNames`] with a given names.
+ ///
+ /// Using a [`Default`] would reuse a names from the first row.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ /// use tabled::{Table, settings::themes::ColumnNames};
+ ///
+ /// let mut table = Table::from_iter(vec![vec!["Hello", "World"]]);
+ /// table.with(ColumnNames::new(["head1", "head2"]));
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+head1--+head2--+\n\
+ /// | Hello | World |\n\
+ /// +-------+-------+"
+ /// );
+ /// ```
+ pub fn new<I>(names: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<String>,
+ {
+ let names = names.into_iter().map(Into::into).collect::<Vec<_>>();
+ Self {
+ names: Some(names),
+ colors: Vec::new(),
+ offset: 0,
+ line: 0,
+ alignment: AlignmentHorizontal::Left,
+ }
+ }
+
+ /// Set color for the column names.
+ ///
+ /// By default there's no colors.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ /// use tabled::Table;
+ /// use tabled::settings::{Color, themes::ColumnNames};
+ ///
+ /// let mut table = Table::from_iter(vec![vec!["Hello", "World"]]);
+ /// table.with(ColumnNames::new(["head1", "head2"]).set_colors([Color::FG_RED]));
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+\u{1b}[31mh\u{1b}[39m\u{1b}[31me\u{1b}[39m\u{1b}[31ma\u{1b}[39m\u{1b}[31md\u{1b}[39m\u{1b}[31m1\u{1b}[39m--+head2--+\n\
+ /// | Hello | World |\n\
+ /// +-------+-------+"
+ /// );
+ /// ```
+ pub fn set_colors<I>(self, colors: I) -> Self
+ where
+ I: IntoIterator,
+ I::Item: Into<Option<Color>>,
+ {
+ let colors = colors.into_iter().map(Into::into).collect::<Vec<_>>();
+ Self {
+ names: self.names,
+ offset: self.offset,
+ line: self.line,
+ alignment: self.alignment,
+ colors,
+ }
+ }
+
+ /// Set a left offset after which the names will be used.
+ ///
+ /// By default there's no offset.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ /// use tabled::{Table, settings::themes::ColumnNames};
+ ///
+ /// let mut table = Table::from_iter(vec![vec!["Hello", "World"]]);
+ /// table.with(ColumnNames::new(["head1", "head2"]).set_offset(1));
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+-head1-+-head2-+\n\
+ /// | Hello | World |\n\
+ /// +-------+-------+"
+ /// );
+ /// ```
+ pub fn set_offset(self, i: usize) -> Self {
+ Self {
+ names: self.names,
+ colors: self.colors,
+ line: self.line,
+ alignment: self.alignment,
+ offset: i,
+ }
+ }
+
+ /// Set a horizontal line the names will be applied to.
+ ///
+ /// The default value is 0 (the top horizontal line).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ /// use tabled::{Table, settings::themes::ColumnNames};
+ ///
+ /// let mut table = Table::from_iter(vec![vec!["Hello", "World"]]);
+ /// table.with(ColumnNames::new(["head1", "head2"]).set_line(1));
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+-------+-------+\n\
+ /// | Hello | World |\n\
+ /// +head1--+head2--+"
+ /// );
+ /// ```
+ pub fn set_line(self, i: usize) -> Self {
+ Self {
+ names: self.names,
+ colors: self.colors,
+ offset: self.offset,
+ alignment: self.alignment,
+ line: i,
+ }
+ }
+
+ /// Set an alignment for the names.
+ ///
+ /// By default it's left aligned.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::iter::FromIterator;
+ /// use tabled::{
+ /// Table,
+ /// settings::themes::ColumnNames,
+ /// grid::config::AlignmentHorizontal,
+ /// };
+ ///
+ /// let mut table = Table::from_iter(vec![vec!["Hello", "World"]]);
+ /// table.with(ColumnNames::new(["head1", "head2"]).set_alignment(AlignmentHorizontal::Right));
+ ///
+ /// assert_eq!(
+ /// table.to_string(),
+ /// "+--head1+--head2+\n\
+ /// | Hello | World |\n\
+ /// +-------+-------+"
+ /// );
+ /// ```
+ pub fn set_alignment(self, alignment: AlignmentHorizontal) -> Self {
+ Self {
+ names: self.names,
+ colors: self.colors,
+ offset: self.offset,
+ line: self.line,
+ alignment,
+ }
+ }
+}
+
+impl TableOption<VecRecords<CellInfo<String>>, CompleteDimensionVecRecords<'static>, ColoredConfig>
+ for ColumnNames
+{
+ fn change(
+ self,
+ records: &mut VecRecords<CellInfo<String>>,
+ cfg: &mut ColoredConfig,
+ dims: &mut CompleteDimensionVecRecords<'static>,
+ ) {
+ let names = match self.names {
+ Some(names) => names,
+ None => {
+ if records.count_rows() == 0 || records.count_columns() == 0 {
+ return;
+ }
+
+ let names = (0..records.count_columns())
+ .map(|column| records.get_text((0, column)))
+ .map(ToString::to_string)
+ .collect::<Vec<_>>();
+
+ records.remove_row(0);
+
+ names
+ }
+ };
+
+ let names = names.iter().map(|name| name.lines().next().unwrap_or(""));
+
+ dims.estimate(&*records, cfg);
+
+ let mut widths = (0..records.count_columns())
+ .map(|column| dims.get_width(column))
+ .collect::<Vec<_>>();
+
+ let names = names.take(widths.len());
+
+ let offset = self.offset;
+ widths
+ .iter_mut()
+ .zip(names.clone())
+ .for_each(|(width, text)| {
+ let name_width = string_width(text) + offset;
+ *width = std::cmp::max(name_width, *width);
+ });
+
+ let _ = dims.set_widths(widths.clone());
+
+ let mut total_width = 0;
+ for (i, (width, name)) in widths.iter().zip(names).enumerate() {
+ let color = get_color(&self.colors, i);
+ let offset = total_width + 1;
+ let btext = get_border_text(
+ name,
+ offset,
+ *width,
+ self.alignment,
+ self.offset,
+ self.line,
+ color,
+ );
+ btext.change(records, cfg, dims);
+
+ total_width += width + 1;
+ }
+ }
+}
+
+fn get_border_text(
+ text: &str,
+ offset: usize,
+ available: usize,
+ alignment: AlignmentHorizontal,
+ alignment_offset: usize,
+ line: usize,
+ color: Option<&Color>,
+) -> BorderText<usize> {
+ let name = text.to_string();
+ let left_indent = get_indent(text, alignment, alignment_offset, available);
+ let left_offset = Offset::Begin(offset + left_indent);
+ let mut btext = BorderText::new(name).horizontal(line).offset(left_offset);
+ if let Some(color) = color {
+ btext = btext.color(color.clone());
+ }
+
+ btext
+}
+
+fn get_color(colors: &[Option<Color>], i: usize) -> Option<&Color> {
+ colors.get(i).and_then(|color| match color {
+ Some(color) => Some(color),
+ None => None,
+ })
+}
+
+fn get_indent(text: &str, align: AlignmentHorizontal, offset: usize, available: usize) -> usize {
+ match align {
+ AlignmentHorizontal::Left => offset,
+ AlignmentHorizontal::Right => available - string_width(text) - offset,
+ AlignmentHorizontal::Center => (available - string_width(text)) / 2,
+ }
+}
diff --git a/vendor/tabled/src/settings/themes/mod.rs b/vendor/tabled/src/settings/themes/mod.rs
new file mode 100644
index 000000000..75cf458cc
--- /dev/null
+++ b/vendor/tabled/src/settings/themes/mod.rs
@@ -0,0 +1,9 @@
+//! The module contains a varieity of configurations of table, which often
+//! changes not a single setting.
+//! As such they are making relatively big changes to the configuration.
+
+mod colorization;
+mod column_names;
+
+pub use colorization::{Colorization, ExactColorization};
+pub use column_names::ColumnNames;