From 2f7fc335f8113b75e8ce88e6f369b22b51044ed2 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Fri, 19 Jul 2024 16:15:05 +0300 Subject: [PATCH 01/20] Move Color back to its own setting PaddingColor --- papergrid/src/ansi/ansi_str.rs | 4 +- papergrid/src/config/sides.rs | 20 +++- tabled/Cargo.toml | 4 +- tabled/examples/colored_padding.rs | 65 +++-------- tabled/src/settings/color/mod.rs | 33 ++++-- tabled/src/settings/mod.rs | 5 +- tabled/src/settings/padding/mod.rs | 64 ++-------- tabled/src/settings/padding_color/mod.rs | 143 +++++++++++++++++++++++ tabled/tests/core/pool_table.rs | 18 ++- tabled/tests/settings/padding_test.rs | 25 ++-- 10 files changed, 233 insertions(+), 148 deletions(-) create mode 100644 tabled/src/settings/padding_color/mod.rs diff --git a/papergrid/src/ansi/ansi_str.rs b/papergrid/src/ansi/ansi_str.rs index 58b32d42..4f7a7c4a 100644 --- a/papergrid/src/ansi/ansi_str.rs +++ b/papergrid/src/ansi/ansi_str.rs @@ -26,12 +26,12 @@ impl<'a> ANSIStr<'a> { } /// Gets a reference to a prefix. - pub fn get_prefix(&self) -> &'a str { + pub const fn get_prefix(&self) -> &'a str { self.prefix } /// Gets a reference to a suffix. - pub fn get_suffix(&self) -> &'a str { + pub const fn get_suffix(&self) -> &'a str { self.suffix } } diff --git a/papergrid/src/config/sides.rs b/papergrid/src/config/sides.rs index 7aa0fb49..214145ed 100644 --- a/papergrid/src/config/sides.rs +++ b/papergrid/src/config/sides.rs @@ -27,11 +27,19 @@ impl Sides { where T: Copy, { - Self { - top: value, - bottom: value, - left: value, - right: value, - } + Self::new(value, value, value, value) + } + + /// Creates a new object. + pub fn convert_into(self) -> Sides + where + T: Into, + { + Sides::new( + self.left.into(), + self.right.into(), + self.top.into(), + self.bottom.into(), + ) } } diff --git a/tabled/Cargo.toml b/tabled/Cargo.toml index 10835f90..c2bb1200 100644 --- a/tabled/Cargo.toml +++ b/tabled/Cargo.toml @@ -304,14 +304,14 @@ path = "examples/theme.rs" required-features = ["derive", "std"] [features] -default = ["derive", "macros"] +default = ["derive", "macros", "ansi"] std = ["papergrid/std"] derive = ["tabled_derive", "std"] ansi = ["papergrid/ansi", "ansi-str", "ansitok", "std"] macros = ["std"] [dependencies] -papergrid = { path="../papergrid", default-features = false } +papergrid = { path = "../papergrid", default-features = false } tabled_derive = { path = "../tabled_derive", optional = true } ansi-str = { version = "0.8", optional = true } ansitok = { version = "0.2", optional = true } diff --git a/tabled/examples/colored_padding.rs b/tabled/examples/colored_padding.rs index 86b589ed..c68d7e51 100644 --- a/tabled/examples/colored_padding.rs +++ b/tabled/examples/colored_padding.rs @@ -24,7 +24,7 @@ use tabled::{ }, settings::{ object::{Columns, Object, Rows, Segment}, - Alignment, CellOption, Color, Format, Margin, Modify, Padding, Style, + Alignment, CellOption, Color, Format, Margin, Modify, Padding, PaddingColor, Style, }, Table, Tabled, }; @@ -32,61 +32,32 @@ use tabled::{ #[derive(Tabled)] #[tabled(rename_all = "PascalCase")] struct Fundamental { - quantity: &'static str, - symbol: &'static str, - value: &'static str, - unit: &'static str, + quantity: String, + symbol: char, + value: String, + unit: String, } impl Fundamental { - fn new( - quantity: &'static str, - symbol: &'static str, - value: &'static str, - unit: &'static str, - ) -> Self { + fn new(quantity: &str, symbol: char, value: &str, unit: &str) -> Self { Self { - quantity, symbol, - value, - unit, + quantity: quantity.to_string(), + value: value.to_string(), + unit: unit.to_string(), } } } fn main() { // data source: https://www.britannica.com/science/physical-constant + #[rustfmt::skip] let data = [ - Fundamental::new( - "constant of gravitation", - "G", - "6.67384 × 10⁻¹¹", - "cubic metre per second squared per kilogram", - ), - Fundamental::new( - "speed of light (in a vacuum)", - "c", - "2.99792458 × 10⁻⁸", - "metres per second", - ), - Fundamental::new( - "Planck's constant", - "h", - "6.626070040 × 10⁻³⁴", - "joule second", - ), - Fundamental::new( - "Boltzmann constant", - "k", - "1.38064852 × 10⁻²³", - "joule per kelvin", - ), - Fundamental::new( - "Faraday constant", - "F", - "9.648533289 × 10⁴", - "coulombs per mole", - ), + Fundamental::new("constant of gravitation", 'G', "6.67384 × 10⁻¹¹", "cubic metre per second squared per kilogram"), + Fundamental::new("speed of light (in a vacuum)", 'c', "2.99792458 × 10⁻⁸", "metres per second"), + Fundamental::new("Planck's constant", 'h', "6.626070040 × 10⁻³⁴", "joule second"), + Fundamental::new("Boltzmann constant", 'k', "1.38064852 × 10⁻²³", "joule per kelvin"), + Fundamental::new("Faraday constant", 'F', "9.648533289 × 10⁴", "coulombs per mole"), ]; let pane_color = Color::try_from(' '.bg_rgb::<220, 220, 220>().to_string()).unwrap(); @@ -94,7 +65,8 @@ fn main() { let data_color = Color::try_from(' '.bg_rgb::<200, 200, 220>().to_string()).unwrap(); let header_settings = Modify::new(Rows::first()) - .with(Padding::new(1, 1, 2, 2).colorize( + .with(Padding::new(1, 1, 2, 2)) + .with(PaddingColor::new( Color::BG_GREEN, Color::BG_YELLOW, Color::BG_MAGENTA, @@ -106,7 +78,8 @@ fn main() { let data_settings = Modify::new(Rows::first().inverse()) .with(Alignment::left()) .with(MakeMaxPadding) - .with(Padding::new(1, 1, 0, 0).colorize( + .with(Padding::new(1, 1, 0, 0)) + .with(PaddingColor::new( Color::default(), Color::default(), data_color.clone(), diff --git a/tabled/src/settings/color/mod.rs b/tabled/src/settings/color/mod.rs index 5e7b8dbb..9569345a 100644 --- a/tabled/src/settings/color/mod.rs +++ b/tabled/src/settings/color/mod.rs @@ -43,7 +43,7 @@ pub struct Color { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] enum ColorInner { Static(StaticColor<'static>), - Allocated(ANSIBuf), + Buf(ANSIBuf), } #[rustfmt::skip] @@ -192,13 +192,13 @@ impl Color { S: Into, { let color = ANSIBuf::new(prefix, suffix); - let inner = ColorInner::Allocated(color); + let inner = ColorInner::Buf(color); Self { inner } } /// Creates a new empty [`Color`]`. - pub fn empty() -> Self { + pub const fn empty() -> Self { Self::new_static("", "") } @@ -213,7 +213,7 @@ impl Color { pub fn get_prefix(&self) -> &str { match &self.inner { ColorInner::Static(color) => color.get_prefix(), - ColorInner::Allocated(color) => color.get_prefix(), + ColorInner::Buf(color) => color.get_prefix(), } } @@ -221,9 +221,20 @@ impl Color { pub fn get_suffix(&self) -> &str { match &self.inner { ColorInner::Static(color) => color.get_suffix(), - ColorInner::Allocated(color) => color.get_suffix(), + ColorInner::Buf(color) => color.get_suffix(), } } + + /// Parses the string, + /// + /// PANICS if it's incorrectly built. + #[cfg(feature = "ansi")] + pub fn parse(text: S) -> Self + where + S: AsRef, + { + std::convert::TryFrom::try_from(text.as_ref()).unwrap() + } } impl Default for Color { @@ -238,7 +249,7 @@ impl From for ANSIBuf { fn from(color: Color) -> Self { match color.inner { ColorInner::Static(color) => ANSIBuf::from(color), - ColorInner::Allocated(color) => color, + ColorInner::Buf(color) => color, } } } @@ -246,7 +257,7 @@ impl From for ANSIBuf { impl From for Color { fn from(color: ANSIBuf) -> Self { Self { - inner: ColorInner::Allocated(color), + inner: ColorInner::Buf(color), } } } @@ -282,7 +293,7 @@ impl std::convert::TryFrom<&str> for Color { let buf = ANSIBuf::try_from(value)?; Ok(Color { - inner: ColorInner::Allocated(buf), + inner: ColorInner::Buf(buf), }) } } @@ -295,7 +306,7 @@ impl std::convert::TryFrom for Color { let buf = ANSIBuf::try_from(value)?; Ok(Color { - inner: ColorInner::Allocated(buf), + inner: ColorInner::Buf(buf), }) } } @@ -337,14 +348,14 @@ impl ANSIFmt for Color { fn fmt_ansi_prefix(&self, f: &mut W) -> fmt::Result { match &self.inner { ColorInner::Static(color) => color.fmt_ansi_prefix(f), - ColorInner::Allocated(color) => color.fmt_ansi_prefix(f), + ColorInner::Buf(color) => color.fmt_ansi_prefix(f), } } fn fmt_ansi_suffix(&self, f: &mut W) -> fmt::Result { match &self.inner { ColorInner::Static(color) => color.fmt_ansi_suffix(f), - ColorInner::Allocated(color) => color.fmt_ansi_suffix(f), + ColorInner::Buf(color) => color.fmt_ansi_suffix(f), } } } diff --git a/tabled/src/settings/mod.rs b/tabled/src/settings/mod.rs index c2285da5..ca52c8c7 100644 --- a/tabled/src/settings/mod.rs +++ b/tabled/src/settings/mod.rs @@ -49,6 +49,7 @@ mod alignment; mod extract; mod margin; mod padding; +mod padding_color; mod reverse; mod rotate; @@ -119,8 +120,8 @@ pub use settings_list::{EmptySettings, Settings}; pub use table_option::TableOption; pub use self::{ - alignment::Alignment, extract::Extract, margin::Margin, padding::Padding, reverse::Reverse, - rotate::Rotate, style::Border, style::Style, + alignment::Alignment, extract::Extract, margin::Margin, padding::Padding, + padding_color::PaddingColor, reverse::Reverse, rotate::Rotate, style::Border, style::Style, }; #[cfg(feature = "std")] diff --git a/tabled/src/settings/padding/mod.rs b/tabled/src/settings/padding/mod.rs index fb9144c7..8357e4c1 100644 --- a/tabled/src/settings/padding/mod.rs +++ b/tabled/src/settings/padding/mod.rs @@ -37,7 +37,6 @@ use crate::{ grid::{ - ansi::ANSIStr, config::{CompactConfig, CompactMultilineConfig}, config::{Indent, Sides}, }, @@ -45,9 +44,10 @@ use crate::{ }; #[cfg(feature = "std")] -use crate::grid::{ansi::ANSIBuf, config::ColoredConfig, config::Entity}; -#[cfg(feature = "std")] -use crate::settings::CellOption; +use crate::{ + grid::{config::ColoredConfig, config::Entity}, + settings::CellOption, +}; /// Padding is responsible for a left/right/top/bottom inner indent of a particular cell. /// @@ -58,9 +58,8 @@ use crate::settings::CellOption; /// let table = Table::new(&data).with(Modify::new(Rows::single(0)).with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V'))); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Padding> { +pub struct Padding { indent: Sides, - colors: Option>, } impl Padding { @@ -76,7 +75,6 @@ impl Padding { Indent::spaced(top), Indent::spaced(bottom), ), - colors: None, } } @@ -87,9 +85,7 @@ impl Padding { pub const fn zero() -> Self { Self::new(0, 0, 0, 0) } -} -impl Padding { /// The function, sets a characters for the padding on an each side. pub const fn fill(mut self, left: char, right: char, top: char, bottom: char) -> Self { self.indent.left.fill = left; @@ -98,72 +94,30 @@ impl Padding { self.indent.bottom.fill = bottom; self } - - /// The function, sets a characters for the padding on an each side. - pub fn colorize(self, left: C, right: C, top: C, bottom: C) -> Padding { - Padding { - indent: self.indent, - colors: Some(Sides::new(left, right, top, bottom)), - } - } } -#[cfg(feature = "std")] -impl CellOption for Padding -where - C: Into + Clone, -{ +impl CellOption for Padding { fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { let indent = self.indent; let pad = Sides::new(indent.left, indent.right, indent.top, indent.bottom); cfg.set_padding(entity, pad); - - if let Some(colors) = &self.colors { - let pad = Sides::new( - Some(colors.left.clone().into()), - Some(colors.right.clone().into()), - Some(colors.top.clone().into()), - Some(colors.bottom.clone().into()), - ); - cfg.set_padding_color(entity, pad); - } } } -#[cfg(feature = "std")] -impl TableOption for Padding -where - C: Into + Clone, -{ +impl TableOption for Padding { fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { >::change(self, records, cfg, Entity::Global) } } -impl TableOption for Padding -where - C: Into> + Clone, -{ +impl TableOption for Padding { fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { *cfg = cfg.set_padding(self.indent); - - if let Some(c) = self.colors { - let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); - *cfg = cfg.set_padding_color(colors); - } } } -impl TableOption for Padding -where - C: Into> + Clone, -{ +impl TableOption for Padding { fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { cfg.set_padding(self.indent); - - if let Some(c) = self.colors { - let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); - cfg.set_padding_color(colors); - } } } diff --git a/tabled/src/settings/padding_color/mod.rs b/tabled/src/settings/padding_color/mod.rs new file mode 100644 index 00000000..ea710bc7 --- /dev/null +++ b/tabled/src/settings/padding_color/mod.rs @@ -0,0 +1,143 @@ +//! This module contains a [`Padding`] setting of a cell on a [`Table`]. +//! +//! # Example +//! +#![cfg_attr(feature = "ansi", doc = "```")] +#![cfg_attr(not(feature = "ansi"), doc = "```ignore")] +//! use tabled::{ +//! Table, +//! settings::{Padding, PaddingColor, Color, Style}, +//! }; +//! +//! let table = Table::new("2024".chars()) +//! .with(Style::modern()) +//! .modify((2, 0), Padding::new(2, 4, 0, 0)) +//! .modify((2, 0), PaddingColor::filled(Color::FG_RED)) +//! .to_string(); +//! +//! assert_eq!( +//! table, +//! concat!( +//! "┌───────┐\n", +//! "│ char │\n", +//! "├───────┤\n", +//! "│ 2 │\n", +//! "├───────┤\n", +//! "│\u{1b}[31m \u{1b}[39m0\u{1b}[31m \u{1b}[39m│\n", +//! "├───────┤\n", +//! "│ 2 │\n", +//! "├───────┤\n", +//! "│ 4 │\n", +//! "└───────┘", +//! ), +//! ); +//! ``` +//! +//! [`Table`]: crate::Table + +use crate::{ + grid::{ + ansi::ANSIStr, + config::Sides, + config::{CompactConfig, CompactMultilineConfig}, + }, + settings::TableOption, +}; + +#[cfg(feature = "std")] +use crate::grid::{ansi::ANSIBuf, config::ColoredConfig, config::Entity}; +#[cfg(feature = "std")] +use crate::settings::CellOption; + +use super::Color; + +/// PaddingColor is responsible for a left/right/top/bottom inner color of a particular cell. +/// +#[cfg_attr(feature = "std", doc = "```")] +#[cfg_attr(not(feature = "std"), doc = "```ignore")] +/// # use tabled::{settings::{Style, Padding, object::Rows, Modify}, Table}; +/// # let data: Vec<&'static str> = Vec::new(); +/// let table = Table::new(&data).with(Modify::new(Rows::single(0)).with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V'))); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct PaddingColor { + colors: Sides, +} + +impl PaddingColor { + /// Construct's an Padding object. + pub const fn new(left: C, right: C, top: C, bottom: C) -> Self { + Self { + colors: Sides::new(left, right, top, bottom), + } + } + + /// The function, sets a color for all sides. + pub fn filled(color: C) -> Self + where + C: Clone, + { + Self::new(color.clone(), color.clone(), color.clone(), color) + } +} + +impl PaddingColor { + /// Construct's an Padding object with no color. + pub const fn none() -> Self { + Self::new( + Color::empty(), + Color::empty(), + Color::empty(), + Color::empty(), + ) + } +} + +#[cfg(feature = "std")] +impl CellOption for PaddingColor +where + C: Into + Clone, +{ + fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let colors = self.colors.clone(); + let pad = Sides::new( + Some(colors.left.into()), + Some(colors.right.into()), + Some(colors.top.into()), + Some(colors.bottom.into()), + ); + cfg.set_padding_color(entity, pad); + } +} + +#[cfg(feature = "std")] +impl TableOption for PaddingColor +where + C: Into + Clone, +{ + fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + >::change(self, records, cfg, Entity::Global) + } +} + +impl TableOption for PaddingColor +where + C: Into> + Clone, +{ + fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { + let c = self.colors.clone(); + let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); + *cfg = cfg.set_padding_color(colors); + } +} + +impl TableOption for PaddingColor +where + C: Into> + Clone, +{ + fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { + let c = self.colors.clone(); + let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); + cfg.set_padding_color(colors); + } +} diff --git a/tabled/tests/core/pool_table.rs b/tabled/tests/core/pool_table.rs index 01a145f0..3fa536b1 100644 --- a/tabled/tests/core/pool_table.rs +++ b/tabled/tests/core/pool_table.rs @@ -2,7 +2,7 @@ use tabled::{ grid::dimension::{DimensionPriority, PoolTableDimension}, - settings::{formatting::AlignmentStrategy, Alignment, Margin, Padding, Style}, + settings::{formatting::AlignmentStrategy, Alignment, Margin, Padding, PaddingColor, Style}, tables::{PoolTable, TableValue}, }; @@ -313,15 +313,13 @@ test_table!( test_table!( pool_table_padding_2, PoolTable::new(Matrix::with_no_frame(3, 3).to_vec()) - .with(Padding::new(1, 2, 3, 4) - .fill('!', '@', '#', '$') - .colorize( - ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), - ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), - ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), - ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), - ) - ), + .with(Padding::new(1, 2, 3, 4).fill('!', '@', '#', '$')) + .with(PaddingColor::new( + ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), + ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), + ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), + ANSIStr::new("\u{1b}[34m", "\u{1b}[39m"), + )), "+------+------+------+" "|\u{1b}[34m######\u{1b}[39m|\u{1b}[34m######\u{1b}[39m|\u{1b}[34m######\u{1b}[39m|" "|\u{1b}[34m######\u{1b}[39m|\u{1b}[34m######\u{1b}[39m|\u{1b}[34m######\u{1b}[39m|" diff --git a/tabled/tests/settings/padding_test.rs b/tabled/tests/settings/padding_test.rs index 7777769e..cd4ad1bb 100644 --- a/tabled/tests/settings/padding_test.rs +++ b/tabled/tests/settings/padding_test.rs @@ -2,14 +2,14 @@ use tabled::settings::{ object::{Rows, Segment}, - Alignment, Modify, Padding, Style, + Alignment, Modify, Padding, PaddingColor, Style, }; use crate::matrix::Matrix; use testing_table::test_table; #[cfg(feature = "ansi")] -use ::{owo_colors::OwoColorize, std::convert::TryFrom, tabled::settings::Color}; +use ::{owo_colors::OwoColorize, tabled::settings::Color}; test_table!( padding, @@ -102,18 +102,15 @@ test_table!( #[cfg(feature = "ansi")] test_table!( padding_color, - { - let padding = Padding::new(2, 2, 2, 2).colorize( - Color::try_from(' '.on_yellow().to_string()).unwrap(), - Color::try_from(' '.on_blue().to_string()).unwrap(), - Color::try_from(' '.on_red().to_string()).unwrap(), - Color::try_from(' '.on_green().to_string()).unwrap(), - ); - - Matrix::new(3, 3) - .with(Style::psql()) - .with(Modify::new(Rows::new(1..)).with(padding)) - }, + Matrix::new(3, 3) + .with(Style::psql()) + .modify(Rows::new(1..), Padding::new(2, 2, 2, 2)) + .modify(Rows::new(1..), PaddingColor::new( + Color::parse(' '.on_yellow().to_string()), + Color::parse(' '.on_blue().to_string()), + Color::parse(' '.on_red().to_string()), + Color::parse(' '.on_green().to_string()), + )), " N | column 0 | column 1 | column 2 \n-----+----------+----------+----------\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[43m \u{1b}[49m0\u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 0-0 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 0-1 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 0-2 \u{1b}[44m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[43m \u{1b}[49m1\u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 1-0 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 1-1 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 1-2 \u{1b}[44m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m|\u{1b}[41m \u{1b}[49m\n\u{1b}[43m \u{1b}[49m2\u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 2-0 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 2-1 \u{1b}[44m \u{1b}[49m|\u{1b}[43m \u{1b}[49m 2-2 \u{1b}[44m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m\n\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m|\u{1b}[42m \u{1b}[49m" ); From 2d82644c5f2e7b93da503ca5f64ce1f8181f719e Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Fri, 19 Jul 2024 16:42:42 +0300 Subject: [PATCH 02/20] Move back MarginColor to its own setting --- papergrid/src/ansi/ansi_str.rs | 5 + tabled/examples/colored_padding.rs | 11 +-- tabled/src/settings/color/mod.rs | 5 +- tabled/src/settings/margin/mod.rs | 102 ++++++-------------- tabled/src/settings/margin_color/mod.rs | 118 +++++++++++++++++++++++ tabled/src/settings/mod.rs | 6 +- tabled/src/settings/padding/mod.rs | 67 +++++++------ tabled/src/settings/padding_color/mod.rs | 89 ++++++++--------- tabled/tests/settings/margin_test.rs | 10 +- 9 files changed, 256 insertions(+), 157 deletions(-) create mode 100644 tabled/src/settings/margin_color/mod.rs diff --git a/papergrid/src/ansi/ansi_str.rs b/papergrid/src/ansi/ansi_str.rs index 4f7a7c4a..6c89489f 100644 --- a/papergrid/src/ansi/ansi_str.rs +++ b/papergrid/src/ansi/ansi_str.rs @@ -20,6 +20,11 @@ impl<'a> ANSIStr<'a> { Self { prefix, suffix } } + /// Constructs a new instance with suffix and prefix set to empty strings. + pub const fn empty() -> Self { + Self::new("", "") + } + /// Verifies if anything was actually set. pub const fn is_empty(&self) -> bool { self.prefix.is_empty() && self.suffix.is_empty() diff --git a/tabled/examples/colored_padding.rs b/tabled/examples/colored_padding.rs index c68d7e51..93040df5 100644 --- a/tabled/examples/colored_padding.rs +++ b/tabled/examples/colored_padding.rs @@ -24,7 +24,8 @@ use tabled::{ }, settings::{ object::{Columns, Object, Rows, Segment}, - Alignment, CellOption, Color, Format, Margin, Modify, Padding, PaddingColor, Style, + Alignment, CellOption, Color, Format, Margin, MarginColor, Modify, Padding, PaddingColor, + Style, }, Table, Tabled, }; @@ -94,12 +95,8 @@ fn main() { let table = Table::new(data) .with(Style::rounded()) - .with(Margin::new(1, 2, 1, 1).colorize( - pane_color.clone(), - pane_color.clone(), - pane_color.clone(), - pane_color, - )) + .with(Margin::new(1, 2, 1, 1)) + .with(MarginColor::filled(pane_color)) .with(border_color) .with(Modify::new(Segment::all()).with(data_color)) .with(header_settings) diff --git a/tabled/src/settings/color/mod.rs b/tabled/src/settings/color/mod.rs index 9569345a..f482e63f 100644 --- a/tabled/src/settings/color/mod.rs +++ b/tabled/src/settings/color/mod.rs @@ -227,7 +227,10 @@ impl Color { /// Parses the string, /// - /// PANICS if it's incorrectly built. + /// # Panics + /// + /// PANICS if the input string incorrectly built. + /// Use [`TryFrom`] instead if you are not sure about the input. #[cfg(feature = "ansi")] pub fn parse(text: S) -> Self where diff --git a/tabled/src/settings/margin/mod.rs b/tabled/src/settings/margin/mod.rs index 6dcc48ee..32e6bb92 100644 --- a/tabled/src/settings/margin/mod.rs +++ b/tabled/src/settings/margin/mod.rs @@ -4,31 +4,16 @@ //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] -//! use tabled::{settings::{Margin, Style}, Table}; -//! -//! let data = vec!["Hello", "World", "!"]; -//! -//! let mut table = Table::new(data); -//! table.with(Style::markdown()).with(Margin::new(3, 3, 1, 0)); -//! -//! assert_eq!( -//! table.to_string(), -//! concat!( -//! " \n", -//! " | &str | \n", -//! " |-------| \n", -//! " | Hello | \n", -//! " | World | \n", -//! " | ! | ", -//! ) -//! ); +//! # use tabled::{settings::Margin, Table}; +//! # let data: Vec<&'static str> = Vec::new(); +//! let table = Table::new(&data) +//! .with(Margin::new(1, 1, 1, 1).fill('>', '<', 'V', '^')); //! ``` //! //! [`Table`]: crate::Table use crate::{ grid::{ - ansi::ANSIStr, config::{CompactConfig, CompactMultilineConfig}, config::{Indent, Sides}, }, @@ -36,21 +21,38 @@ use crate::{ }; #[cfg(feature = "std")] -use crate::grid::{ansi::ANSIBuf, config::ColoredConfig}; +use crate::grid::config::ColoredConfig; /// Margin is responsible for a left/right/top/bottom outer indent of a grid. /// +/// # Example +/// #[cfg_attr(feature = "std", doc = "```")] #[cfg_attr(not(feature = "std"), doc = "```ignore")] -/// # use tabled::{settings::Margin, Table}; -/// # let data: Vec<&'static str> = Vec::new(); -/// let table = Table::new(&data) -/// .with(Margin::new(1, 1, 1, 1).fill('>', '<', 'V', '^')); +/// use tabled::{settings::{Margin, Style}, Table}; +/// +/// let data = vec!["Hello", "World", "!"]; +/// +/// let mut table = Table::new(data); +/// table +/// .with(Style::markdown()) +/// .with(Margin::new(3, 3, 1, 0)); +/// +/// assert_eq!( +/// table.to_string(), +/// concat!( +/// " \n", +/// " | &str | \n", +/// " |-------| \n", +/// " | Hello | \n", +/// " | World | \n", +/// " | ! | ", +/// ) +/// ); /// ``` #[derive(Debug, Clone)] -pub struct Margin> { +pub struct Margin { indent: Sides, - colors: Option>, } impl Margin { @@ -66,12 +68,9 @@ impl Margin { Indent::spaced(top), Indent::spaced(bottom), ), - colors: None, } } -} -impl Margin { /// The function, sets a characters for the margin on an each side. pub const fn fill(mut self, left: char, right: char, top: char, bottom: char) -> Self { self.indent.left.fill = left; @@ -80,64 +79,25 @@ impl Margin { self.indent.bottom.fill = bottom; self } - - /// The function, sets a characters for the margin on an each side. - pub fn colorize(self, left: C, right: C, top: C, bottom: C) -> Margin { - Margin { - indent: self.indent, - colors: Some(Sides::new(left, right, top, bottom)), - } - } } #[cfg(feature = "std")] -impl TableOption for Margin -where - C: Into + Clone, -{ +impl TableOption for Margin { fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { let indent = self.indent; let margin = Sides::new(indent.left, indent.right, indent.top, indent.bottom); cfg.set_margin(margin); - - if let Some(colors) = &self.colors { - let margin = Sides::new( - Some(colors.left.clone().into()), - Some(colors.right.clone().into()), - Some(colors.top.clone().into()), - Some(colors.bottom.clone().into()), - ); - cfg.set_margin_color(margin); - } } } -impl TableOption for Margin -where - C: Into> + Clone, -{ +impl TableOption for Margin { fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { *cfg = cfg.set_margin(self.indent); - - if let Some(c) = self.colors { - // todo: make a new method (BECAUSE INTO doesn't work) try_into(); - let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); - *cfg = cfg.set_margin_color(colors); - } } } -impl TableOption for Margin -where - C: Into> + Clone, -{ +impl TableOption for Margin { fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { cfg.set_margin(self.indent); - - if let Some(c) = self.colors { - // todo: make a new method (BECAUSE INTO doesn't work) try_into(); - let colors = Sides::new(c.left.into(), c.right.into(), c.top.into(), c.bottom.into()); - cfg.set_margin_color(colors); - } } } diff --git a/tabled/src/settings/margin_color/mod.rs b/tabled/src/settings/margin_color/mod.rs new file mode 100644 index 00000000..6b811054 --- /dev/null +++ b/tabled/src/settings/margin_color/mod.rs @@ -0,0 +1,118 @@ +//! This module contains a Margin settings of a [`Table`]. +//! +//! [`Table`]: crate::Table + +use crate::{ + grid::{ + ansi::ANSIStr, + config::Sides, + config::{CompactConfig, CompactMultilineConfig}, + }, + settings::TableOption, +}; + +#[cfg(feature = "std")] +use crate::grid::{ansi::ANSIBuf, config::ColoredConfig}; + +/// MarginColor is responsible for a left/right/top/bottom outer color of a grid. +/// +/// # Example +/// +#[cfg_attr(feature = "ansi", doc = "```")] +#[cfg_attr(not(feature = "ansi"), doc = "```ignore")] +/// use tabled::{ +/// settings::{Margin, MarginColor, Style, Color}, +/// Table, +/// }; +/// +/// let data = vec!["Hello", "World", "!"]; +/// +/// let mut table = Table::new(data); +/// table +/// .with(Style::markdown()) +/// .with(Margin::new(3, 3, 1, 0)) +/// .with(MarginColor::filled(Color::BG_RED)); +/// +/// assert_eq!( +/// table.to_string(), +/// concat!( +/// "\u{1b}[41m \u{1b}[49m\n", +/// "\u{1b}[41m \u{1b}[49m| &str |\u{1b}[41m \u{1b}[49m\n", +/// "\u{1b}[41m \u{1b}[49m|-------|\u{1b}[41m \u{1b}[49m\n", +/// "\u{1b}[41m \u{1b}[49m| Hello |\u{1b}[41m \u{1b}[49m\n", +/// "\u{1b}[41m \u{1b}[49m| World |\u{1b}[41m \u{1b}[49m\n", +/// "\u{1b}[41m \u{1b}[49m| ! |\u{1b}[41m \u{1b}[49m", +/// ) +/// ); +/// ``` +#[derive(Debug, Clone)] +pub struct MarginColor { + colors: Sides, +} + +impl MarginColor { + /// Construct's an Margin object. + pub const fn new(left: C, right: C, top: C, bottom: C) -> Self { + Self { + colors: Sides::new(left, right, top, bottom), + } + } + + /// The function, sets a color for the margin on an each side. + pub fn filled(color: C) -> Self + where + C: Clone, + { + Self::new(color.clone(), color.clone(), color.clone(), color) + } +} + +impl MarginColor> { + /// Construct's an Padding object with no color. + pub const fn empty() -> Self { + Self::new( + ANSIStr::empty(), + ANSIStr::empty(), + ANSIStr::empty(), + ANSIStr::empty(), + ) + } +} + +#[cfg(feature = "std")] +impl TableOption for MarginColor +where + C: Into + Clone, +{ + fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + let c = self.colors.clone(); + let margin = Sides::new( + Some(c.left.into()), + Some(c.right.into()), + Some(c.top.into()), + Some(c.bottom.into()), + ); + + cfg.set_margin_color(margin); + } +} + +impl TableOption for MarginColor +where + C: Into> + Clone, +{ + fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { + let colors = self.colors.convert_into(); + *cfg = cfg.set_margin_color(colors); + } +} + +impl TableOption for MarginColor +where + C: Into> + Clone, +{ + fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { + let colors = self.colors.convert_into(); + cfg.set_margin_color(colors); + } +} diff --git a/tabled/src/settings/mod.rs b/tabled/src/settings/mod.rs index ca52c8c7..e54f0e7c 100644 --- a/tabled/src/settings/mod.rs +++ b/tabled/src/settings/mod.rs @@ -48,6 +48,7 @@ mod table_option; mod alignment; mod extract; mod margin; +mod margin_color; mod padding; mod padding_color; mod reverse; @@ -120,8 +121,9 @@ pub use settings_list::{EmptySettings, Settings}; pub use table_option::TableOption; pub use self::{ - alignment::Alignment, extract::Extract, margin::Margin, padding::Padding, - padding_color::PaddingColor, reverse::Reverse, rotate::Rotate, style::Border, style::Style, + alignment::Alignment, extract::Extract, margin::Margin, margin_color::MarginColor, + padding::Padding, padding_color::PaddingColor, reverse::Reverse, rotate::Rotate, style::Border, + style::Style, }; #[cfg(feature = "std")] diff --git a/tabled/src/settings/padding/mod.rs b/tabled/src/settings/padding/mod.rs index 8357e4c1..2808727a 100644 --- a/tabled/src/settings/padding/mod.rs +++ b/tabled/src/settings/padding/mod.rs @@ -2,35 +2,13 @@ //! //! # Example //! +//! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] -//! use tabled::{Table, settings::{Padding, Style, Modify, object::Cell}}; -//! -//! let table = Table::new("2022".chars()) -//! .with(Style::modern()) -//! .with(Modify::new((2, 0)).with(Padding::new(1, 1, 2, 2))) -//! .to_string(); -//! -//! assert_eq!( -//! table, -//! concat!( -//! "┌──────┐\n", -//! "│ char │\n", -//! "├──────┤\n", -//! "│ 2 │\n", -//! "├──────┤\n", -//! "│ │\n", -//! "│ │\n", -//! "│ 0 │\n", -//! "│ │\n", -//! "│ │\n", -//! "├──────┤\n", -//! "│ 2 │\n", -//! "├──────┤\n", -//! "│ 2 │\n", -//! "└──────┘", -//! ), -//! ); +//! # use tabled::{settings::{Style, Padding, object::Rows, Modify}, Table}; +//! # let data: Vec<&'static str> = Vec::new(); +//! let table = Table::new(&data) +//! .with(Modify::new(Rows::single(0)).with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V'))); //! ``` //! //! [`Table`]: crate::Table @@ -51,11 +29,40 @@ use crate::{ /// Padding is responsible for a left/right/top/bottom inner indent of a particular cell. /// +/// # Example +/// #[cfg_attr(feature = "std", doc = "```")] #[cfg_attr(not(feature = "std"), doc = "```ignore")] -/// # use tabled::{settings::{Style, Padding, object::Rows, Modify}, Table}; -/// # let data: Vec<&'static str> = Vec::new(); -/// let table = Table::new(&data).with(Modify::new(Rows::single(0)).with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V'))); +/// use tabled::{ +/// Table, +/// settings::{Padding, Style, Modify, object::Cell}, +/// }; +/// +/// let table = Table::new("2022".chars()) +/// .with(Style::modern()) +/// .with(Modify::new((2, 0)).with(Padding::new(1, 1, 2, 2))) +/// .to_string(); +/// +/// assert_eq!( +/// table, +/// concat!( +/// "┌──────┐\n", +/// "│ char │\n", +/// "├──────┤\n", +/// "│ 2 │\n", +/// "├──────┤\n", +/// "│ │\n", +/// "│ │\n", +/// "│ 0 │\n", +/// "│ │\n", +/// "│ │\n", +/// "├──────┤\n", +/// "│ 2 │\n", +/// "├──────┤\n", +/// "│ 2 │\n", +/// "└──────┘", +/// ), +/// ); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Padding { diff --git a/tabled/src/settings/padding_color/mod.rs b/tabled/src/settings/padding_color/mod.rs index ea710bc7..4331c084 100644 --- a/tabled/src/settings/padding_color/mod.rs +++ b/tabled/src/settings/padding_color/mod.rs @@ -1,36 +1,15 @@ -//! This module contains a [`Padding`] setting of a cell on a [`Table`]. +//! This module contains a [`PaddingColor`] setting of a cell on a [`Table`]. //! //! # Example //! -#![cfg_attr(feature = "ansi", doc = "```")] -#![cfg_attr(not(feature = "ansi"), doc = "```ignore")] -//! use tabled::{ -//! Table, -//! settings::{Padding, PaddingColor, Color, Style}, -//! }; -//! -//! let table = Table::new("2024".chars()) -//! .with(Style::modern()) -//! .modify((2, 0), Padding::new(2, 4, 0, 0)) -//! .modify((2, 0), PaddingColor::filled(Color::FG_RED)) -//! .to_string(); -//! -//! assert_eq!( -//! table, -//! concat!( -//! "┌───────┐\n", -//! "│ char │\n", -//! "├───────┤\n", -//! "│ 2 │\n", -//! "├───────┤\n", -//! "│\u{1b}[31m \u{1b}[39m0\u{1b}[31m \u{1b}[39m│\n", -//! "├───────┤\n", -//! "│ 2 │\n", -//! "├───────┤\n", -//! "│ 4 │\n", -//! "└───────┘", -//! ), -//! ); +#![cfg_attr(feature = "std", doc = "```")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +//! # use tabled::{settings::{Style, Padding, object::Rows, Modify}, Table}; +//! # let data: Vec<&'static str> = Vec::new(); +//! let table = Table::new(&data) +//! .with(Modify::new(Rows::single(0)) +//! .with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V')) +//! ); //! ``` //! //! [`Table`]: crate::Table @@ -49,15 +28,39 @@ use crate::grid::{ansi::ANSIBuf, config::ColoredConfig, config::Entity}; #[cfg(feature = "std")] use crate::settings::CellOption; -use super::Color; - /// PaddingColor is responsible for a left/right/top/bottom inner color of a particular cell. /// -#[cfg_attr(feature = "std", doc = "```")] -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -/// # use tabled::{settings::{Style, Padding, object::Rows, Modify}, Table}; -/// # let data: Vec<&'static str> = Vec::new(); -/// let table = Table::new(&data).with(Modify::new(Rows::single(0)).with(Padding::new(0, 0, 1, 1).fill('>', '<', '^', 'V'))); +/// # Example +/// +#[cfg_attr(feature = "ansi", doc = "```")] +#[cfg_attr(not(feature = "ansi"), doc = "```ignore")] +/// use tabled::{ +/// Table, +/// settings::{Padding, PaddingColor, Color, Style}, +/// }; +/// +/// let table = Table::new("2024".chars()) +/// .with(Style::modern()) +/// .modify((2, 0), Padding::new(2, 4, 0, 0)) +/// .modify((2, 0), PaddingColor::filled(Color::FG_RED)) +/// .to_string(); +/// +/// assert_eq!( +/// table, +/// concat!( +/// "┌───────┐\n", +/// "│ char │\n", +/// "├───────┤\n", +/// "│ 2 │\n", +/// "├───────┤\n", +/// "│\u{1b}[31m \u{1b}[39m0\u{1b}[31m \u{1b}[39m│\n", +/// "├───────┤\n", +/// "│ 2 │\n", +/// "├───────┤\n", +/// "│ 4 │\n", +/// "└───────┘", +/// ), +/// ); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct PaddingColor { @@ -81,14 +84,14 @@ impl PaddingColor { } } -impl PaddingColor { +impl PaddingColor> { /// Construct's an Padding object with no color. - pub const fn none() -> Self { + pub const fn empty() -> Self { Self::new( - Color::empty(), - Color::empty(), - Color::empty(), - Color::empty(), + ANSIStr::empty(), + ANSIStr::empty(), + ANSIStr::empty(), + ANSIStr::empty(), ) } } diff --git a/tabled/tests/settings/margin_test.rs b/tabled/tests/settings/margin_test.rs index 0e2e53a1..f103ed8e 100644 --- a/tabled/tests/settings/margin_test.rs +++ b/tabled/tests/settings/margin_test.rs @@ -1,6 +1,8 @@ #![cfg(feature = "std")] -use tabled::settings::{object::Cell, Border, Highlight, Margin, Modify, Span, Style, Width}; +use tabled::settings::{ + object::Cell, Border, Highlight, Margin, MarginColor, Modify, Span, Style, Width, +}; use crate::matrix::Matrix; use testing_table::{is_lines_equal, static_table, test_table}; @@ -144,7 +146,8 @@ fn margin_color_test_not_colored_feature() { let table = Matrix::new(3, 3) .with(Style::psql()) - .with(Margin::new(2, 2, 2, 2).fill('>', '<', 'V', '^').colorize( + .with(Margin::new(2, 2, 2, 2).fill('>', '<', 'V', '^')) + .with(MarginColor::new( Color::BG_GREEN, Color::BG_YELLOW, Color::BG_RED, @@ -173,7 +176,8 @@ fn margin_color_test_not_colored_feature() { fn margin_color_test() { let table = Matrix::new(3, 3) .with(Style::psql()) - .with(Margin::new(2, 2, 2, 2).fill('>', '<', 'V', '^').colorize( + .with(Margin::new(2, 2, 2, 2).fill('>', '<', 'V', '^')) + .with(MarginColor::new( Color::try_from(" ".red().bold().to_string()).unwrap(), Color::try_from(" ".green().to_string()).unwrap(), Color::try_from(" ".on_blue().red().bold().to_string()).unwrap(), From 090157c27b21a0730ece66829937af4b0a74bf12 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Fri, 19 Jul 2024 17:37:13 +0300 Subject: [PATCH 03/20] Add PaddingExpand setting to expand Padding to set Color --- tabled/examples/colored_padding.rs | 64 +------- tabled/src/settings/mod.rs | 3 + tabled/src/settings/padding/mod.rs | 15 ++ tabled/src/settings/padding_expand/mod.rs | 187 ++++++++++++++++++++++ 4 files changed, 213 insertions(+), 56 deletions(-) create mode 100644 tabled/src/settings/padding_expand/mod.rs diff --git a/tabled/examples/colored_padding.rs b/tabled/examples/colored_padding.rs index 93040df5..ed612ecb 100644 --- a/tabled/examples/colored_padding.rs +++ b/tabled/examples/colored_padding.rs @@ -13,19 +13,10 @@ use std::convert::TryFrom; use owo_colors::OwoColorize; use tabled::{ - grid::{ - config::{ColoredConfig, Entity}, - dimension::SpannedGridDimension, - records::{ - vec_records::{Cell, VecRecords}, - ExactRecords, PeekableRecords, Records, - }, - util::string::string_width_multiline, - }, settings::{ object::{Columns, Object, Rows, Segment}, - Alignment, CellOption, Color, Format, Margin, MarginColor, Modify, Padding, PaddingColor, - Style, + style::BorderColor, + Alignment, Color, Format, Margin, MarginColor, Modify, Padding, PaddingColor, Style, }, Table, Tabled, }; @@ -73,19 +64,14 @@ fn main() { Color::BG_MAGENTA, Color::BG_CYAN, )) - .with(MakeMaxPadding) + .with(Alignment::center()) + .with(Padding::expand(true)) .with(Format::content(|s| s.on_black().white().to_string())); let data_settings = Modify::new(Rows::first().inverse()) - .with(Alignment::left()) - .with(MakeMaxPadding) - .with(Padding::new(1, 1, 0, 0)) - .with(PaddingColor::new( - Color::default(), - Color::default(), - data_color.clone(), - data_color.clone(), - )); + .with(Alignment::center()) + .with(Padding::expand(true)) + .with(PaddingColor::filled(data_color.clone())); let symbol_settings = Modify::new(Columns::single(1).not(Rows::first())) .with(Format::content(|s| s.bold().to_string())); @@ -97,7 +83,7 @@ fn main() { .with(Style::rounded()) .with(Margin::new(1, 2, 1, 1)) .with(MarginColor::filled(pane_color)) - .with(border_color) + .with(BorderColor::filled(border_color)) .with(Modify::new(Segment::all()).with(data_color)) .with(header_settings) .with(data_settings) @@ -107,37 +93,3 @@ fn main() { println!("\n\n{table}\n\n"); } - -#[derive(Debug, Clone)] -struct MakeMaxPadding; - -impl CellOption, ColoredConfig> for MakeMaxPadding -where - T: Cell + AsRef, -{ - fn change(self, records: &mut VecRecords, cfg: &mut ColoredConfig, entity: Entity) { - let widths = SpannedGridDimension::width(&*records, cfg); - - let count_rows = records.count_rows(); - let count_cols = records.count_columns(); - - for (row, col) in entity.iter(count_rows, count_cols) { - let column_width = widths[col]; - let text = records.get_text((row, col)); - let width = string_width_multiline(text); - - if width < column_width { - let available_width = column_width - width; - let left = available_width / 2; - let right = available_width - left; - - let pos = (row, col).into(); - let mut pad = cfg.get_padding(pos); - pad.left.size = left; - pad.right.size = right; - - cfg.set_padding(pos, pad); - } - } - } -} diff --git a/tabled/src/settings/mod.rs b/tabled/src/settings/mod.rs index e54f0e7c..242a3518 100644 --- a/tabled/src/settings/mod.rs +++ b/tabled/src/settings/mod.rs @@ -96,6 +96,9 @@ pub mod measurement; pub mod merge; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub mod padding_expand; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub mod panel; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] diff --git a/tabled/src/settings/padding/mod.rs b/tabled/src/settings/padding/mod.rs index 2808727a..42675c39 100644 --- a/tabled/src/settings/padding/mod.rs +++ b/tabled/src/settings/padding/mod.rs @@ -27,6 +27,9 @@ use crate::{ settings::CellOption, }; +#[cfg(feature = "std")] +use super::padding_expand::PaddingExpand; + /// Padding is responsible for a left/right/top/bottom inner indent of a particular cell. /// /// # Example @@ -101,8 +104,19 @@ impl Padding { self.indent.bottom.fill = bottom; self } + + #[cfg(feature = "std")] + /// Construct's an PaddingExpand object. + pub const fn expand(horizontal: bool) -> PaddingExpand { + if horizontal { + PaddingExpand::Horizontal + } else { + PaddingExpand::Vertical + } + } } +#[cfg(feature = "std")] impl CellOption for Padding { fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { let indent = self.indent; @@ -111,6 +125,7 @@ impl CellOption for Padding { } } +#[cfg(feature = "std")] impl TableOption for Padding { fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { >::change(self, records, cfg, Entity::Global) diff --git a/tabled/src/settings/padding_expand/mod.rs b/tabled/src/settings/padding_expand/mod.rs new file mode 100644 index 00000000..8d1f2472 --- /dev/null +++ b/tabled/src/settings/padding_expand/mod.rs @@ -0,0 +1,187 @@ +//! This module contains a [`PaddingExpand`] setting to expand cells padding to its limit a cell. + +use papergrid::{ + config::{AlignmentHorizontal, AlignmentVertical}, + dimension::spanned::SpannedGridDimension, + records::{ExactRecords, IntoRecords, PeekableRecords, Records}, +}; + +#[cfg(feature = "std")] +use crate::{ + grid::{config::ColoredConfig, config::Entity}, + settings::CellOption, +}; + +use super::TableOption; + +/// PaddingExpand is able to expand padding to its limit a cell. +/// Maybe usefull in cases were its colorization is supposed to be used next. +/// +/// # Example +/// +#[cfg_attr(feature = "ansi", doc = "```")] +#[cfg_attr(not(feature = "ansi"), doc = "```ignore")] +/// use std::iter::FromIterator; +/// +/// use tabled::{ +/// settings::{Padding, Style, Color, PaddingColor}, +/// Table, +/// }; +/// +/// let char_split = |s: &str| s.chars().map(|c| c.to_string()).collect::>(); +/// let data = vec![ +/// char_split("2021"), +/// char_split("2022"), +/// char_split("2023"), +/// char_split("2024"), +/// ]; +/// +/// let table = Table::from_iter(&data) +/// .with(Style::ascii()) +/// .with(PaddingColor::filled(Color::BG_BLUE)) +/// .modify((2, 1), Padding::new(2, 2, 3, 3)) +/// .with(Padding::expand(true)) +/// .with(Padding::expand(false)) +/// .to_string(); +/// +/// assert_eq!( +/// table, +/// concat!( +/// "+---+-----+---+---+\n", +/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|1\u{1b}[44m \u{1b}[49m|\n", +/// "+---+-----+---+---+\n", +/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|\n", +/// "+---+-----+---+---+\n", +/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|3\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n", +/// "+---+-----+---+---+\n", +/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|4\u{1b}[44m \u{1b}[49m|\n", +/// "+---+-----+---+---+", +/// ), +/// ); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum PaddingExpand { + /// Horizontal expansion of padding (LEFT and RIGHT) + Horizontal, + /// Vertical expansion of padding (TOP and BOTTOM) + Vertical, +} + +impl TableOption for PaddingExpand +where + R: Records + ExactRecords + PeekableRecords, + for<'a> &'a R: Records, + for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef, +{ + fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + >::change(self, records, cfg, Entity::Global) + } +} + +impl CellOption for PaddingExpand +where + R: Records + ExactRecords + PeekableRecords, + for<'a> &'a R: Records, + for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef, +{ + fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + match self { + PaddingExpand::Vertical => expand_vertical(records, cfg, entity), + PaddingExpand::Horizontal => expand_horizontal(records, cfg, entity), + } + } +} + +fn expand_horizontal(records: &mut R, cfg: &mut ColoredConfig, entity: Entity) +where + R: Records + ExactRecords + PeekableRecords, + for<'a> &'a R: Records, + for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef, +{ + let widths = SpannedGridDimension::width(&*records, cfg); + + let count_rows = records.count_rows(); + let count_cols = records.count_columns(); + + for (row, col) in entity.iter(count_rows, count_cols) { + let pos = Entity::Cell(row, col); + + let column_width = widths[col]; + let width = records.get_width((row, col)); + + if width < column_width { + let alignment = *cfg.get_alignment_horizontal(pos); + + let available_width = column_width - width; + let (left, right) = split_horizontal_space(alignment, available_width); + + let mut pad = cfg.get_padding(pos); + pad.left.size = left; + pad.right.size = right; + + cfg.set_padding(pos, pad); + } + } +} + +fn expand_vertical(records: &mut R, cfg: &mut ColoredConfig, entity: Entity) +where + R: Records + ExactRecords + PeekableRecords, + for<'a> &'a R: Records, + for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef, +{ + let heights = SpannedGridDimension::height(&*records, cfg); + + let count_rows = records.count_rows(); + let count_cols = records.count_columns(); + + for (row, col) in entity.iter(count_rows, count_cols) { + let pos = Entity::Cell(row, col); + + let row_height = heights[row]; + let cell_height = records.count_lines((row, col)); + + if cell_height < row_height { + let alignment = *cfg.get_alignment_vertical(pos); + + let available_width = row_height - cell_height; + let (top, bottom) = split_vertical_space(alignment, available_width); + + let mut pad = cfg.get_padding(pos); + pad.top.size = top; + pad.bottom.size = bottom; + + cfg.set_padding(pos, pad); + } + } +} + +fn split_horizontal_space(al: AlignmentHorizontal, space: usize) -> (usize, usize) { + match al { + AlignmentHorizontal::Center => { + let left = space / 2; + let right = space - left; + (left, right) + } + AlignmentHorizontal::Left => (0, space), + AlignmentHorizontal::Right => (space, 0), + } +} + +fn split_vertical_space(al: AlignmentVertical, space: usize) -> (usize, usize) { + match al { + AlignmentVertical::Center => { + let left = space / 2; + let right = space - left; + (left, right) + } + AlignmentVertical::Top => (0, space), + AlignmentVertical::Bottom => (space, 0), + } +} From 3e991ceef8a58dacd3d4ba4ffd30b7be3b5f1b82 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 00:06:04 +0300 Subject: [PATCH 04/20] Remove colorization from Theme --- tabled/src/settings/padding/mod.rs | 4 +--- tabled/src/settings/themes/theme.rs | 15 ++------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/tabled/src/settings/padding/mod.rs b/tabled/src/settings/padding/mod.rs index 42675c39..e6a7e09e 100644 --- a/tabled/src/settings/padding/mod.rs +++ b/tabled/src/settings/padding/mod.rs @@ -24,12 +24,10 @@ use crate::{ #[cfg(feature = "std")] use crate::{ grid::{config::ColoredConfig, config::Entity}, + settings::padding_expand::PaddingExpand, settings::CellOption, }; -#[cfg(feature = "std")] -use super::padding_expand::PaddingExpand; - /// Padding is responsible for a left/right/top/bottom inner indent of a particular cell. /// /// # Example diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index 48153aa5..1b9fcc3e 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -20,7 +20,7 @@ use crate::{ }, records::{ExactRecords, PeekableRecords, Records, RecordsMut, Resizable}, }, - settings::{style::Style, themes::Colorization, Alignment, Color, Rotate, TableOption}, + settings::{style::Style, Alignment, Color, Rotate, TableOption}, }; /// A raw style data, which can be produced safely from [`Style`]. @@ -31,7 +31,6 @@ pub struct Theme { border: TableBorders, lines: BorderLines, layout: Layout, - colorization: Option, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -77,7 +76,6 @@ impl Theme { TableBorders::new(chars, Borders::empty()), BorderLines::new(horizontal1, None, None), Layout::new(HeadPosition::Top, false, false, false, false), - None, ) } } @@ -91,7 +89,6 @@ impl Theme { TableBorders::new(Borders::empty(), Borders::empty()), BorderLines::new(None, None, None), Layout::new(HeadPosition::Top, false, false, false, false), - None, ) } } @@ -472,17 +469,11 @@ impl Theme { } impl Theme { - const fn _new( - border: TableBorders, - lines: BorderLines, - layout: Layout, - colorization: Option, - ) -> Self { + const fn _new(border: TableBorders, lines: BorderLines, layout: Layout) -> Self { Self { border, lines, layout, - colorization, } } } @@ -493,7 +484,6 @@ impl From> for Theme { TableBorders::new(borders, Borders::empty()), BorderLines::new(None, None, None), Layout::new(HeadPosition::Top, false, false, false, false), - None, ) } } @@ -554,7 +544,6 @@ impl From for Theme { TableBorders::new(borders, colors), BorderLines::new(None, Some(horizontals), Some(verticals)), Layout::new(HeadPosition::Top, false, false, false, false), - None, ) } } From 9fcda1b9c20573d64b80f0acc7deab75496f1688 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 01:55:02 +0300 Subject: [PATCH 05/20] Redo `Theme` into `Theme/Layout/Reverse` --- tabled/Cargo.toml | 2 +- tabled/examples/reverse.rs | 4 +- tabled/examples/theme.rs | 15 +- tabled/src/settings/alignment/mod.rs | 16 ++ tabled/src/settings/reverse/mod.rs | 68 +++++-- tabled/src/settings/themes/layout.rs | 164 +++++++++++++++ tabled/src/settings/themes/mod.rs | 2 + tabled/src/settings/themes/theme.rs | 281 ++------------------------ tabled/tests/core/pool_table.rs | 4 +- tabled/tests/settings/layout_test.rs | 122 +++++++++++ tabled/tests/settings/mod.rs | 2 + tabled/tests/settings/padding_test.rs | 7 +- tabled/tests/settings/reverse_test.rs | 116 +++++++++++ tabled/tests/settings/theme_test.rs | 278 +------------------------ 14 files changed, 510 insertions(+), 571 deletions(-) create mode 100644 tabled/src/settings/themes/layout.rs create mode 100644 tabled/tests/settings/layout_test.rs create mode 100644 tabled/tests/settings/reverse_test.rs diff --git a/tabled/Cargo.toml b/tabled/Cargo.toml index c2bb1200..b1532d1a 100644 --- a/tabled/Cargo.toml +++ b/tabled/Cargo.toml @@ -304,7 +304,7 @@ path = "examples/theme.rs" required-features = ["derive", "std"] [features] -default = ["derive", "macros", "ansi"] +default = ["derive", "macros"] std = ["papergrid/std"] derive = ["tabled_derive", "std"] ansi = ["papergrid/ansi", "ansi-str", "ansitok", "std"] diff --git a/tabled/examples/reverse.rs b/tabled/examples/reverse.rs index 0fca6795..f3df8c2f 100644 --- a/tabled/examples/reverse.rs +++ b/tabled/examples/reverse.rs @@ -20,8 +20,8 @@ fn main() { table.with(Style::rounded().remove_horizontals().remove_vertical()); table.with(Padding::new(2, 2, 0, 0)); table.with(Shadow::new(3).set_offset(6)); - table.with(Reverse::rows()); - table.with(Reverse::columns()); + table.with(Reverse::rows(1, 0)); + table.with(Reverse::columns(0, 0)); println!("{table}"); } diff --git a/tabled/examples/theme.rs b/tabled/examples/theme.rs index 3ecb7cd1..6b8e6da7 100644 --- a/tabled/examples/theme.rs +++ b/tabled/examples/theme.rs @@ -1,5 +1,8 @@ use tabled::{ - settings::{themes::Theme, Style}, + settings::{ + themes::{Layout, Theme}, + Alignment, Reverse, Style, + }, Table, Tabled, }; @@ -32,13 +35,11 @@ fn main() { Concept::new("VOP_STRATEGY", "VOP_STRATEGY method fulfills an I/O request described by given struct buf object"), ]; - let mut theme = Theme::from_style(Style::ascii()); - theme.reverse_rows(true); - theme.reverse_columns(true); - theme.set_footer(true); - let mut table = Table::new(data); - table.with(theme); + table.with(Theme::from_style(Style::ascii())); + table.with(Reverse::rows(1, 0)); + table.with(Reverse::columns(0, 0)); + table.with(Layout::new(Alignment::top(), true)); println!("{table}"); } diff --git a/tabled/src/settings/alignment/mod.rs b/tabled/src/settings/alignment/mod.rs index e254571c..1603c647 100644 --- a/tabled/src/settings/alignment/mod.rs +++ b/tabled/src/settings/alignment/mod.rs @@ -137,6 +137,22 @@ impl Alignment { Self::vertical(AlignmentVertical::Center) } + /// Convert alignment to horizontal. + pub const fn get_horizontal(self) -> Option { + match self.inner { + Horizontal(alignment) => Some(alignment), + Vertical(_) => None, + } + } + + /// Convert alignment to vertical. + pub const fn get_vertical(self) -> Option { + match self.inner { + Horizontal(_) => None, + Vertical(alignment) => Some(alignment), + } + } + /// Returns an alignment with the given horizontal alignment. const fn horizontal(alignment: AlignmentHorizontal) -> Self { Self::new(Horizontal(alignment)) diff --git a/tabled/src/settings/reverse/mod.rs b/tabled/src/settings/reverse/mod.rs index 849a7e86..d0c6f8fd 100644 --- a/tabled/src/settings/reverse/mod.rs +++ b/tabled/src/settings/reverse/mod.rs @@ -7,17 +7,27 @@ use crate::{ #[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Reverse { columns: bool, + skip: usize, + skip_from_end: usize, } impl Reverse { /// Reverse columns. - pub const fn columns() -> Self { - Self { columns: true } + pub const fn columns(start: usize, end: usize) -> Self { + Self::new(true, start, end) } /// Reverse rows. - pub const fn rows() -> Self { - Self { columns: false } + pub const fn rows(start: usize, end: usize) -> Self { + Self::new(false, start, end) + } + + const fn new(columns: bool, skip: usize, skip_from_end: usize) -> Self { + Self { + columns, + skip, + skip_from_end, + } } } @@ -26,45 +36,65 @@ where R: Resizable + Records + ExactRecords, { fn change(self, records: &mut R, _: &mut C, _: &mut D) { - match self.columns { - true => reverse_columns(records), - false => reverse_rows(records), + let count_rows = records.count_rows(); + let count_columns = records.count_columns(); + + let skip = self.skip_from_end + self.skip; + + if self.columns { + if count_columns <= skip { + return; + } + + let start = self.skip; + let end = count_columns - self.skip_from_end; + + reverse_columns(records, start, end); + } else { + if count_rows <= skip { + return; + } + + let start = self.skip; + let end = count_rows - self.skip_from_end; + + reverse_rows(records, start, end); } } } -fn reverse_rows(data: &mut R) +fn reverse_rows(data: &mut R, start: usize, end: usize) where R: Resizable + ExactRecords, { - let count_rows = data.count_rows(); + let count_rows = end - start; if count_rows < 2 { return; } - for row in 0..count_rows / 2 { - data.swap_row(row, count_rows - row - 1); + for (i, row) in (start..end / 2).enumerate() { + data.swap_row(row, end - i - 1); } } -fn reverse_columns(data: &mut R) +fn reverse_columns(data: &mut R, start: usize, end: usize) where R: Resizable + Records, { - let count_columns = data.count_columns(); + let count_columns = end - start; if count_columns < 2 { return; } - for col in 0..count_columns / 2 { - data.swap_column(col, count_columns - col - 1); + for (i, col) in (start..end / 2).enumerate() { + data.swap_column(col, end - i - 1); } } #[cfg(test)] #[cfg(feature = "std")] mod tests { - use crate::grid::records::vec_records::VecRecords; + use crate::grid::records::{vec_records::VecRecords, Records}; use super::{reverse_columns, reverse_rows}; @@ -85,13 +115,15 @@ mod tests { } fn rev_rows(mut data: Vec>) -> Vec> { - reverse_rows(&mut data); + let end = data.len(); + reverse_rows(&mut data, 0, end); data } fn rev_cols(data: Vec>) -> Vec> { let mut records = VecRecords::new(data); - reverse_columns(&mut records); + let end = records.count_columns(); + reverse_columns(&mut records, 0, end); records.into() } diff --git a/tabled/src/settings/themes/layout.rs b/tabled/src/settings/themes/layout.rs new file mode 100644 index 00000000..7ccba3de --- /dev/null +++ b/tabled/src/settings/themes/layout.rs @@ -0,0 +1,164 @@ +//! Module contains [`Layout`] setting. + +use papergrid::records::{ExactRecords, PeekableRecords, Records}; + +use crate::{ + grid::{ + config::{AlignmentHorizontal, AlignmentVertical}, + records::{RecordsMut, Resizable}, + }, + settings::{Alignment, Rotate, TableOption}, +}; + +/// Layout can be used to move header to a specific corner. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Layout { + orientation: HeadPosition, + footer: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum HeadPosition { + Top, + Bottom, + Left, + Right, +} + +impl Layout { + /// Construct a new layout setting. + pub fn new(stick: Alignment, footer: bool) -> Self { + let orientation = convert_orientation(stick); + + Self { + footer, + orientation, + } + } +} + +impl TableOption for Layout +where + R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, +{ + fn change(self, records: &mut R, _: &mut C, _: &mut D) { + move_head_if(records, self.orientation); + + if self.footer { + copy_head(records, self.orientation); + } + } +} + +const fn convert_orientation(position: Alignment) -> HeadPosition { + match (position.get_horizontal(), position.get_vertical()) { + (None, Some(AlignmentVertical::Top)) => HeadPosition::Top, + (None, Some(AlignmentVertical::Bottom)) => HeadPosition::Bottom, + (Some(AlignmentHorizontal::Left), None) => HeadPosition::Left, + (Some(AlignmentHorizontal::Right), None) => HeadPosition::Right, + (None, Some(AlignmentVertical::Center)) => HeadPosition::Top, + (Some(AlignmentHorizontal::Center), None) => HeadPosition::Top, + (None, None) | (Some(_), Some(_)) => HeadPosition::Top, + } +} + +fn copy_head(records: &mut R, orientation: HeadPosition) +where + R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, +{ + let head = collect_head_by(records, orientation); + match orientation { + HeadPosition::Top => cp_row(records, head, records.count_rows()), + HeadPosition::Bottom => cp_row(records, head, 0), + HeadPosition::Left => cp_column(records, head, records.count_columns()), + HeadPosition::Right => cp_column(records, head, 0), + } +} + +fn collect_head_by(records: &mut R, orientation: HeadPosition) -> Vec +where + R: Records + PeekableRecords + ExactRecords, +{ + match orientation { + HeadPosition::Top => collect_head(records, 0), + HeadPosition::Bottom => collect_head(records, records.count_rows() - 1), + HeadPosition::Left => collect_head_vertical(records, 0), + HeadPosition::Right => collect_head_vertical(records, records.count_columns() - 1), + } +} + +fn cp_row(records: &mut R, row: Vec, pos: usize) +where + R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, +{ + records.insert_row(pos); + + for (col, text) in row.into_iter().enumerate() { + records.set((pos, col), text); + } +} + +fn cp_column(records: &mut R, column: Vec, pos: usize) +where + R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, +{ + records.insert_column(pos); + + for (row, text) in column.into_iter().enumerate() { + records.set((row, pos), text); + } +} + +fn move_head_if(records: &mut R, orientation: HeadPosition) +where + R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, +{ + match orientation { + HeadPosition::Top => {} + HeadPosition::Bottom => { + let head = collect_head(records, 0); + push_row(records, head); + records.remove_row(0); + } + HeadPosition::Left => { + Rotate::Left.change(records, &mut (), &mut ()); + Rotate::Bottom.change(records, &mut (), &mut ()); + } + HeadPosition::Right => { + Rotate::Right.change(records, &mut (), &mut ()); + } + } +} + +fn collect_head(records: &mut R, row: usize) -> Vec +where + R: Records + PeekableRecords, +{ + (0..records.count_columns()) + .map(|column| records.get_text((row, column))) + .map(ToString::to_string) + .collect() +} + +fn collect_head_vertical(records: &mut R, column: usize) -> Vec +where + R: Records + PeekableRecords + ExactRecords, +{ + (0..records.count_rows()) + .map(|row| records.get_text((row, column))) + .map(ToString::to_string) + .collect() +} + +fn push_row(records: &mut R, row: Vec) +where + R: Records + ExactRecords + Resizable + RecordsMut, +{ + records.push_row(); + + let last_row = records.count_rows() - 1; + + for (col, text) in row.into_iter().enumerate() { + records.set((last_row, col), text); + } +} diff --git a/tabled/src/settings/themes/mod.rs b/tabled/src/settings/themes/mod.rs index 74376d6e..fc4f86ca 100644 --- a/tabled/src/settings/themes/mod.rs +++ b/tabled/src/settings/themes/mod.rs @@ -4,8 +4,10 @@ mod colorization; mod column_names; +mod layout; mod theme; pub use colorization::{Colorization, ExactColorization}; pub use column_names::ColumnNames; +pub use layout::Layout; pub use theme::Theme; diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index 1b9fcc3e..acb54c88 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -13,14 +13,11 @@ use std::collections::HashMap; use std::iter::FromIterator; use crate::{ - grid::{ - config::{ - AlignmentHorizontal, AlignmentVertical, Border, Borders, ColoredConfig, CompactConfig, - CompactMultilineConfig, HorizontalLine, VerticalLine, - }, - records::{ExactRecords, PeekableRecords, Records, RecordsMut, Resizable}, + grid::config::{ + Border, Borders, ColoredConfig, CompactConfig, CompactMultilineConfig, HorizontalLine, + VerticalLine, }, - settings::{style::Style, Alignment, Color, Rotate, TableOption}, + settings::{style::Style, Color, TableOption}, }; /// A raw style data, which can be produced safely from [`Style`]. @@ -30,7 +27,6 @@ use crate::{ pub struct Theme { border: TableBorders, lines: BorderLines, - layout: Layout, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -39,30 +35,13 @@ struct TableBorders { colors: Borders, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] struct BorderLines { horizontal1: Option>, horizontals: Option>>, verticals: Option>>, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct Layout { - orientation: HeadPosition, - footer: bool, - reverse_rows: bool, - reverse_column: bool, - move_header_on_borders: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum HeadPosition { - Top, - Bottom, - Left, - Right, -} - impl Theme { /// Build a theme out of a style builder. pub const fn from_style( @@ -75,7 +54,6 @@ impl Theme { Self::_new( TableBorders::new(chars, Borders::empty()), BorderLines::new(horizontal1, None, None), - Layout::new(HeadPosition::Top, false, false, false, false), ) } } @@ -88,7 +66,6 @@ impl Theme { Self::_new( TableBorders::new(Borders::empty(), Borders::empty()), BorderLines::new(None, None, None), - Layout::new(HeadPosition::Top, false, false, false, false), ) } } @@ -445,36 +422,8 @@ impl Theme { } impl Theme { - /// Reverse rows. - pub fn reverse_rows(&mut self, reverse: bool) { - self.layout.reverse_rows = reverse; - } - - /// Reverse columns. - pub fn reverse_columns(&mut self, reverse: bool) { - self.layout.reverse_column = reverse; - } - - /// Set a footer. - /// - /// Copy columns names to an apposite side of a table. - pub fn set_footer(&mut self, footer: bool) { - self.layout.footer = footer; - } - - /// Set column alignment - pub fn align_columns(&mut self, position: Alignment) { - self.layout.orientation = convert_orientation(position); - } -} - -impl Theme { - const fn _new(border: TableBorders, lines: BorderLines, layout: Layout) -> Self { - Self { - border, - lines, - layout, - } + const fn _new(border: TableBorders, lines: BorderLines) -> Self { + Self { border, lines } } } @@ -483,33 +432,15 @@ impl From> for Theme { Self::_new( TableBorders::new(borders, Borders::empty()), BorderLines::new(None, None, None), - Layout::new(HeadPosition::Top, false, false, false, false), ) } } -impl TableOption for Theme -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { +impl TableOption for Theme { + fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { cfg_clear_borders(cfg); cfg_set_custom_lines(cfg, self.lines); cfg_set_borders(cfg, self.border); - - move_head_if(records, self.layout.orientation); - - if self.layout.reverse_column { - reverse_head(records, self.layout.orientation); - } - - if self.layout.reverse_rows { - reverse_data(records, self.layout.orientation); - } - - if self.layout.footer { - copy_head(records, self.layout.orientation); - } } } @@ -540,11 +471,9 @@ impl From for Theme { let horizontals = cfg.get_horizontal_lines().into_iter().collect(); let verticals = cfg.get_vertical_lines().into_iter().collect(); - Self::_new( - TableBorders::new(borders, colors), - BorderLines::new(None, Some(horizontals), Some(verticals)), - Layout::new(HeadPosition::Top, false, false, false, false), - ) + let borders = TableBorders::new(borders, colors); + let lines = BorderLines::new(None, Some(horizontals), Some(verticals)); + Self::_new(borders, lines) } } @@ -568,24 +497,6 @@ impl BorderLines { } } -impl Layout { - const fn new( - orientation: HeadPosition, - footer: bool, - reverse_rows: bool, - reverse_column: bool, - move_header_on_borders: bool, - ) -> Self { - Self { - orientation, - footer, - reverse_rows, - reverse_column, - move_header_on_borders, - } - } -} - fn cfg_clear_borders(cfg: &mut ColoredConfig) { cfg.remove_borders(); cfg.remove_borders_colors(); @@ -639,171 +550,3 @@ const fn hlines_find( line } - -fn reverse_data(records: &mut R, orientation: HeadPosition) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - let count_rows = records.count_rows(); - let count_columns = records.count_columns(); - if count_columns < 2 || count_rows < 2 { - return; - } - - match orientation { - HeadPosition::Top => reverse_rows(records, 1, count_rows), - HeadPosition::Bottom => reverse_rows(records, 0, count_rows - 1), - HeadPosition::Left => reverse_columns(records, 1, count_columns), - HeadPosition::Right => reverse_columns(records, 0, count_columns - 1), - } -} - -fn reverse_head(data: &mut R, orientation: HeadPosition) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - match orientation { - HeadPosition::Top | HeadPosition::Bottom => reverse_columns(data, 0, data.count_columns()), - HeadPosition::Left | HeadPosition::Right => reverse_rows(data, 0, data.count_rows()), - } -} - -fn reverse_rows(data: &mut R, from: usize, to: usize) -where - R: Resizable, -{ - let end = to / 2; - let mut to = to - 1; - for row in from..end { - data.swap_row(row, to); - to -= 1; - } -} - -fn reverse_columns(data: &mut R, from: usize, to: usize) -where - R: Resizable, -{ - let end = to / 2; - let mut to = to - 1; - for row in from..end { - data.swap_column(row, to); - to -= 1; - } -} - -fn copy_head(records: &mut R, orientation: HeadPosition) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - let head = collect_head_by(records, orientation); - match orientation { - HeadPosition::Top => cp_row(records, head, records.count_rows()), - HeadPosition::Bottom => cp_row(records, head, 0), - HeadPosition::Left => cp_column(records, head, records.count_columns()), - HeadPosition::Right => cp_column(records, head, 0), - } -} - -fn collect_head_by(records: &mut R, orientation: HeadPosition) -> Vec -where - R: Records + PeekableRecords + ExactRecords, -{ - match orientation { - HeadPosition::Top => collect_head(records, 0), - HeadPosition::Bottom => collect_head(records, records.count_rows() - 1), - HeadPosition::Left => collect_head_vertical(records, 0), - HeadPosition::Right => collect_head_vertical(records, records.count_columns() - 1), - } -} - -fn cp_row(records: &mut R, row: Vec, pos: usize) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - records.insert_row(pos); - - for (col, text) in row.into_iter().enumerate() { - records.set((pos, col), text); - } -} - -fn cp_column(records: &mut R, column: Vec, pos: usize) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - records.insert_column(pos); - - for (row, text) in column.into_iter().enumerate() { - records.set((row, pos), text); - } -} - -fn move_head_if(records: &mut R, orientation: HeadPosition) -where - R: Records + Resizable + ExactRecords + PeekableRecords + RecordsMut, -{ - match orientation { - HeadPosition::Top => {} - HeadPosition::Bottom => { - let head = collect_head(records, 0); - push_row(records, head); - records.remove_row(0); - } - HeadPosition::Left => { - Rotate::Left.change(records, &mut (), &mut ()); - Rotate::Bottom.change(records, &mut (), &mut ()); - } - HeadPosition::Right => { - Rotate::Right.change(records, &mut (), &mut ()); - } - } -} - -fn collect_head(records: &mut R, row: usize) -> Vec -where - R: Records + PeekableRecords, -{ - (0..records.count_columns()) - .map(|column| records.get_text((row, column))) - .map(ToString::to_string) - .collect() -} - -fn collect_head_vertical(records: &mut R, column: usize) -> Vec -where - R: Records + PeekableRecords + ExactRecords, -{ - (0..records.count_rows()) - .map(|row| records.get_text((row, column))) - .map(ToString::to_string) - .collect() -} - -fn push_row(records: &mut R, row: Vec) -where - R: Records + ExactRecords + Resizable + RecordsMut, -{ - records.push_row(); - - let last_row = records.count_rows() - 1; - - for (col, text) in row.into_iter().enumerate() { - records.set((last_row, col), text); - } -} - -fn convert_orientation(position: Alignment) -> HeadPosition { - let h = Option::from(position); - let v = Option::from(position); - - match (h, v) { - (None, Some(AlignmentVertical::Top)) => HeadPosition::Top, - (None, Some(AlignmentVertical::Bottom)) => HeadPosition::Bottom, - (Some(AlignmentHorizontal::Left), None) => HeadPosition::Left, - (Some(AlignmentHorizontal::Right), None) => HeadPosition::Right, - (None, Some(AlignmentVertical::Center)) => HeadPosition::Top, - (Some(AlignmentHorizontal::Center), None) => HeadPosition::Top, - (None, None) | (Some(_), Some(_)) => HeadPosition::Top, - } -} diff --git a/tabled/tests/core/pool_table.rs b/tabled/tests/core/pool_table.rs index 3fa536b1..0385d64c 100644 --- a/tabled/tests/core/pool_table.rs +++ b/tabled/tests/core/pool_table.rs @@ -2,7 +2,7 @@ use tabled::{ grid::dimension::{DimensionPriority, PoolTableDimension}, - settings::{formatting::AlignmentStrategy, Alignment, Margin, Padding, PaddingColor, Style}, + settings::{formatting::AlignmentStrategy, Alignment, Margin, Padding, Style}, tables::{PoolTable, TableValue}, }; @@ -10,7 +10,7 @@ use crate::matrix::Matrix; use testing_table::test_table; #[cfg(feature = "ansi")] -use tabled::grid::ansi::ANSIStr; +use tabled::{grid::ansi::ANSIStr, settings::PaddingColor}; test_table!( pool_table, diff --git a/tabled/tests/settings/layout_test.rs b/tabled/tests/settings/layout_test.rs new file mode 100644 index 00000000..a888df47 --- /dev/null +++ b/tabled/tests/settings/layout_test.rs @@ -0,0 +1,122 @@ +#![cfg(feature = "std")] + +use tabled::settings::{themes::Layout, Alignment, Style}; + +use crate::matrix::Matrix; +use testing_table::test_table; + +test_table!( + theme_stick_left, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::left(), false)), + "┌──────────┬─────┬─────┬─────┐" + "│ N │ 0 │ 1 │ 2 │" + "├──────────┼─────┼─────┼─────┤" + "│ column 0 │ 0-0 │ 1-0 │ 2-0 │" + "├──────────┼─────┼─────┼─────┤" + "│ column 1 │ 0-1 │ 1-1 │ 2-1 │" + "├──────────┼─────┼─────┼─────┤" + "│ column 2 │ 0-2 │ 1-2 │ 2-2 │" + "└──────────┴─────┴─────┴─────┘" +); + +test_table!( + theme_stick_right, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::right(), false)), + "┌─────┬─────┬─────┬──────────┐" + "│ 2 │ 1 │ 0 │ N │" + "├─────┼─────┼─────┼──────────┤" + "│ 2-0 │ 1-0 │ 0-0 │ column 0 │" + "├─────┼─────┼─────┼──────────┤" + "│ 2-1 │ 1-1 │ 0-1 │ column 1 │" + "├─────┼─────┼─────┼──────────┤" + "│ 2-2 │ 1-2 │ 0-2 │ column 2 │" + "└─────┴─────┴─────┴──────────┘" +); + +test_table!( + theme_stick_bottom, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::bottom(), false)), + "┌───┬──────────┬──────────┬──────────┐" + "│ 0 │ 0-0 │ 0-1 │ 0-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 1 │ 1-0 │ 1-1 │ 1-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 2 │ 2-0 │ 2-1 │ 2-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ N │ column 0 │ column 1 │ column 2 │" + "└───┴──────────┴──────────┴──────────┘" +); + +test_table!( + theme_footer, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::top(), true)), + "┌───┬──────────┬──────────┬──────────┐" + "│ N │ column 0 │ column 1 │ column 2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 0 │ 0-0 │ 0-1 │ 0-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 1 │ 1-0 │ 1-1 │ 1-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 2 │ 2-0 │ 2-1 │ 2-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ N │ column 0 │ column 1 │ column 2 │" + "└───┴──────────┴──────────┴──────────┘" +); + +test_table!( + theme_stick_left_with_footer, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::left(), true)), + "┌──────────┬─────┬─────┬─────┬──────────┐" + "│ N │ 0 │ 1 │ 2 │ N │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 0 │ 0-0 │ 1-0 │ 2-0 │ column 0 │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 1 │ 0-1 │ 1-1 │ 2-1 │ column 1 │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 2 │ 0-2 │ 1-2 │ 2-2 │ column 2 │" + "└──────────┴─────┴─────┴─────┴──────────┘" +); + +test_table!( + theme_stick_right_with_footer, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::right(), true)), + "┌──────────┬─────┬─────┬─────┬──────────┐" + "│ N │ 2 │ 1 │ 0 │ N │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 0 │ 2-0 │ 1-0 │ 0-0 │ column 0 │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 1 │ 2-1 │ 1-1 │ 0-1 │ column 1 │" + "├──────────┼─────┼─────┼─────┼──────────┤" + "│ column 2 │ 2-2 │ 1-2 │ 0-2 │ column 2 │" + "└──────────┴─────┴─────┴─────┴──────────┘" +); + +test_table!( + theme_stick_bottom_with_footer, + Matrix::new(3, 3).with(Style::modern()).with(Layout::new(Alignment::bottom(), true)), + "┌───┬──────────┬──────────┬──────────┐" + "│ N │ column 0 │ column 1 │ column 2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 0 │ 0-0 │ 0-1 │ 0-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 1 │ 1-0 │ 1-1 │ 1-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ 2 │ 2-0 │ 2-1 │ 2-2 │" + "├───┼──────────┼──────────┼──────────┤" + "│ N │ column 0 │ column 1 │ column 2 │" + "└───┴──────────┴──────────┴──────────┘" +); + +test_table!( + theme_stick_1x1, + Matrix::new(0, 0).with(Layout::new(Alignment::left(), false)), + "+---+" + "| N |" + "+---+" +); + +test_table!( + theme_stick_empty, + Matrix::empty().with(Layout::new(Alignment::left(), false)), + "" +); diff --git a/tabled/tests/settings/mod.rs b/tabled/tests/settings/mod.rs index 1038db21..7c4f3a35 100644 --- a/tabled/tests/settings/mod.rs +++ b/tabled/tests/settings/mod.rs @@ -10,11 +10,13 @@ mod format_test; mod formatting_test; mod height_test; mod highlingt_test; +mod layout_test; mod margin_test; mod merge_test; mod padding_test; mod panel_test; mod render_settings; +mod reverse_test; mod rotate_test; mod shadow_test; mod span_test; diff --git a/tabled/tests/settings/padding_test.rs b/tabled/tests/settings/padding_test.rs index cd4ad1bb..2a926f6d 100644 --- a/tabled/tests/settings/padding_test.rs +++ b/tabled/tests/settings/padding_test.rs @@ -2,14 +2,17 @@ use tabled::settings::{ object::{Rows, Segment}, - Alignment, Modify, Padding, PaddingColor, Style, + Alignment, Modify, Padding, Style, }; use crate::matrix::Matrix; use testing_table::test_table; #[cfg(feature = "ansi")] -use ::{owo_colors::OwoColorize, tabled::settings::Color}; +use ::{ + owo_colors::OwoColorize, + tabled::settings::{Color, PaddingColor}, +}; test_table!( padding, diff --git a/tabled/tests/settings/reverse_test.rs b/tabled/tests/settings/reverse_test.rs new file mode 100644 index 00000000..124c5ce6 --- /dev/null +++ b/tabled/tests/settings/reverse_test.rs @@ -0,0 +1,116 @@ +#![cfg(feature = "std")] + +use tabled::settings::Reverse; + +use crate::matrix::Matrix; +use testing_table::test_table; + +test_table!( + test_0x0_reverse_rows, + Matrix::empty().with(Reverse::rows(0, 0)), + "" +); + +test_table!( + test_0x0_reverse_columns, + Matrix::empty().with(Reverse::columns(0, 0)), + "" +); + +test_table!( + test_3x3_reverse_rows, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::rows(0, 0)), + "+-----+-----+-----+" + "| 234 | 567 | 891 |" + "+-----+-----+-----+" + "| 123 | 456 | 789 |" + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" +); + +test_table!( + test_3x3_reverse_rows_skip_start, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::rows(1, 0)), + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 123 | 456 | 789 |" + "+-----+-----+-----+" + "| 234 | 567 | 891 |" + "+-----+-----+-----+" +); + +test_table!( + test_3x3_reverse_rows_skip_end, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::rows(0, 1)), + "+-----+-----+-----+" + "| 123 | 456 | 789 |" + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 234 | 567 | 891 |" + "+-----+-----+-----+" +); + +test_table!( + test_4x4_reverse_rows_skip_start_and_end, + Matrix::iter([(123, 456, 789), (234, 567, 891), (345, 678, 901)]).with(Reverse::rows(1, 1)), + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 123 | 456 | 789 |" + "+-----+-----+-----+" + "| 234 | 567 | 891 |" + "+-----+-----+-----+" + "| 345 | 678 | 901 |" + "+-----+-----+-----+" +); + +test_table!( + test_3x3_reverse_columns, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::columns(0, 0)), + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 789 | 456 | 123 |" + "+-----+-----+-----+" + "| 891 | 567 | 234 |" + "+-----+-----+-----+" +); + +test_table!( + test_3x3_reverse_columns_skip_start, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::columns(1, 0)), + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 123 | 456 | 789 |" + "+-----+-----+-----+" + "| 234 | 567 | 891 |" + "+-----+-----+-----+" +); + +test_table!( + test_3x3_reverse_columns_skip_end, + Matrix::iter([(123, 456, 789), (234, 567, 891)]).with(Reverse::columns(0, 1)), + "+-----+-----+-----+" + "| i32 | i32 | i32 |" + "+-----+-----+-----+" + "| 456 | 123 | 789 |" + "+-----+-----+-----+" + "| 567 | 234 | 891 |" + "+-----+-----+-----+" +); + +test_table!( + test_4x3_reverse_columns_skip_start_and_end, + Matrix::iter([(123, 456, 789, 123), (234, 567, 891, 234)]).with(Reverse::columns(1, 1)), + "+-----+-----+-----+-----+" + "| i32 | i32 | i32 | i32 |" + "+-----+-----+-----+-----+" + "| 123 | 456 | 789 | 123 |" + "+-----+-----+-----+-----+" + "| 234 | 567 | 891 | 234 |" + "+-----+-----+-----+-----+" +); diff --git a/tabled/tests/settings/theme_test.rs b/tabled/tests/settings/theme_test.rs index aa0b894a..5b37d985 100644 --- a/tabled/tests/settings/theme_test.rs +++ b/tabled/tests/settings/theme_test.rs @@ -1,6 +1,6 @@ #![cfg(feature = "std")] -use tabled::settings::{themes::Theme, Alignment, Style}; +use tabled::settings::{themes::Theme, Style}; use crate::matrix::Matrix; use testing_table::test_table; @@ -20,273 +20,11 @@ test_table!( ); test_table!( - theme_reverse_data, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.reverse_rows(true); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ N │ column 0 │ column 1 │ column 2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "└───┴──────────┴──────────┴──────────┘" -); - -test_table!( - theme_reverse_columns, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.reverse_columns(true); - theme - }), - "┌──────────┬──────────┬──────────┬───┐" - "│ column 2 │ column 1 │ column 0 │ N │" - "├──────────┼──────────┼──────────┼───┤" - "│ 0-2 │ 0-1 │ 0-0 │ 0 │" - "├──────────┼──────────┼──────────┼───┤" - "│ 1-2 │ 1-1 │ 1-0 │ 1 │" - "├──────────┼──────────┼──────────┼───┤" - "│ 2-2 │ 2-1 │ 2-0 │ 2 │" - "└──────────┴──────────┴──────────┴───┘" -); - -test_table!( - theme_reverse_columns_and_data, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.reverse_rows(true); - theme.reverse_columns(true); - theme - }), - "┌──────────┬──────────┬──────────┬───┐" - "│ column 2 │ column 1 │ column 0 │ N │" - "├──────────┼──────────┼──────────┼───┤" - "│ 2-2 │ 2-1 │ 2-0 │ 2 │" - "├──────────┼──────────┼──────────┼───┤" - "│ 1-2 │ 1-1 │ 1-0 │ 1 │" - "├──────────┼──────────┼──────────┼───┤" - "│ 0-2 │ 0-1 │ 0-0 │ 0 │" - "└──────────┴──────────┴──────────┴───┘" -); - -test_table!( - theme_stick_left, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::left()); - theme - }), - "┌──────────┬─────┬─────┬─────┐" - "│ N │ 0 │ 1 │ 2 │" - "├──────────┼─────┼─────┼─────┤" - "│ column 0 │ 0-0 │ 1-0 │ 2-0 │" - "├──────────┼─────┼─────┼─────┤" - "│ column 1 │ 0-1 │ 1-1 │ 2-1 │" - "├──────────┼─────┼─────┼─────┤" - "│ column 2 │ 0-2 │ 1-2 │ 2-2 │" - "└──────────┴─────┴─────┴─────┘" -); - -test_table!( - theme_stick_right, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::right()); - theme - }), - "┌─────┬─────┬─────┬──────────┐" - "│ 2 │ 1 │ 0 │ N │" - "├─────┼─────┼─────┼──────────┤" - "│ 2-0 │ 1-0 │ 0-0 │ column 0 │" - "├─────┼─────┼─────┼──────────┤" - "│ 2-1 │ 1-1 │ 0-1 │ column 1 │" - "├─────┼─────┼─────┼──────────┤" - "│ 2-2 │ 1-2 │ 0-2 │ column 2 │" - "└─────┴─────┴─────┴──────────┘" -); - -test_table!( - theme_stick_bottom, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::bottom()); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ N │ column 0 │ column 1 │ column 2 │" - "└───┴──────────┴──────────┴──────────┘" -); - -test_table!( - theme_footer, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.set_footer(true); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ N │ column 0 │ column 1 │ column 2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ N │ column 0 │ column 1 │ column 2 │" - "└───┴──────────┴──────────┴──────────┘" -); - -test_table!( - theme_stick_left_with_footer, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::left()); - theme.set_footer(true); - theme - }), - "┌──────────┬─────┬─────┬─────┬──────────┐" - "│ N │ 0 │ 1 │ 2 │ N │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 0 │ 0-0 │ 1-0 │ 2-0 │ column 0 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 1 │ 0-1 │ 1-1 │ 2-1 │ column 1 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 2 │ 0-2 │ 1-2 │ 2-2 │ column 2 │" - "└──────────┴─────┴─────┴─────┴──────────┘" -); - -test_table!( - theme_stick_right_with_footer, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::right()); - theme.set_footer(true); - theme - }), - "┌──────────┬─────┬─────┬─────┬──────────┐" - "│ N │ 2 │ 1 │ 0 │ N │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 0 │ 2-0 │ 1-0 │ 0-0 │ column 0 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 1 │ 2-1 │ 1-1 │ 0-1 │ column 1 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 2 │ 2-2 │ 1-2 │ 0-2 │ column 2 │" - "└──────────┴─────┴─────┴─────┴──────────┘" -); - -test_table!( - theme_stick_bottom_with_footer, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::bottom()); - theme.set_footer(true); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ N │ column 0 │ column 1 │ column 2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ N │ column 0 │ column 1 │ column 2 │" - "└───┴──────────┴──────────┴──────────┘" -); - -test_table!( - theme_footer_with_reverse, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.set_footer(true); - theme.reverse_rows(true); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ N │ column 0 │ column 1 │ column 2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ N │ column 0 │ column 1 │ column 2 │" - "└───┴──────────┴──────────┴──────────┘" - -); - -test_table!( - theme_stick_left_with_footer_with_reverse, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::left()); - theme.set_footer(true); - theme.reverse_rows(true); - theme - }), - "┌──────────┬─────┬─────┬─────┬──────────┐" - "│ N │ 2 │ 1 │ 0 │ N │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 0 │ 2-0 │ 1-0 │ 0-0 │ column 0 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 1 │ 2-1 │ 1-1 │ 0-1 │ column 1 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 2 │ 2-2 │ 1-2 │ 0-2 │ column 2 │" - "└──────────┴─────┴─────┴─────┴──────────┘" -); - -test_table!( - theme_stick_right_with_footer_with_reverse, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::right()); - theme.set_footer(true); - theme.reverse_rows(true); - theme - }), - "┌──────────┬─────┬─────┬─────┬──────────┐" - "│ N │ 0 │ 1 │ 2 │ N │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 0 │ 0-0 │ 1-0 │ 2-0 │ column 0 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 1 │ 0-1 │ 1-1 │ 2-1 │ column 1 │" - "├──────────┼─────┼─────┼─────┼──────────┤" - "│ column 2 │ 0-2 │ 1-2 │ 2-2 │ column 2 │" - "└──────────┴─────┴─────┴─────┴──────────┘" -); - -test_table!( - theme_stick_bottom_with_footer_with_reverse, - Matrix::new(3, 3).with({ - let mut theme = Theme::from_style(Style::modern()); - theme.align_columns(Alignment::bottom()); - theme.set_footer(true); - theme.reverse_rows(true); - theme - }), - "┌───┬──────────┬──────────┬──────────┐" - "│ N │ column 0 │ column 1 │ column 2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 2 │ 2-0 │ 2-1 │ 2-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 1 │ 1-0 │ 1-1 │ 1-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ 0 │ 0-0 │ 0-1 │ 0-2 │" - "├───┼──────────┼──────────┼──────────┤" - "│ N │ column 0 │ column 1 │ column 2 │" - "└───┴──────────┴──────────┴──────────┘" + theme_1, + Matrix::new(3, 3).with(Theme::from_style(Style::markdown())), + "| N | column 0 | column 1 | column 2 |" + "|---|----------|----------|----------|" + "| 0 | 0-0 | 0-1 | 0-2 |" + "| 1 | 1-0 | 1-1 | 1-2 |" + "| 2 | 2-0 | 2-1 | 2-2 |" ); From b4c1105e158e53c62b899e4fbef37798dc1fd13a Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 01:59:10 +0300 Subject: [PATCH 06/20] Refactorings theme --- tabled/src/settings/themes/theme.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index acb54c88..10008ad2 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -270,15 +270,25 @@ impl Theme { } /// Set borders structure. - pub fn set_border(&mut self, borders: Borders) { + pub fn set_borders(&mut self, borders: Borders) { self.border.chars = borders; } /// Set borders structure. - pub fn set_border_color(&mut self, borders: Borders) { + pub fn set_borders_colors(&mut self, borders: Borders) { self.border.colors = borders; } + /// Set borders structure. + pub const fn get_borders(&self) -> Borders { + self.border.chars + } + + /// Set borders structure. + pub fn get_borders_colors(&self) -> Borders { + self.border.colors.clone() + } + /// Set an outer border. pub const fn get_border_frame(&self) -> Border { Border { From 6986731415c2655e29a77fed04405a966d8e54f5 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 02:17:33 +0300 Subject: [PATCH 07/20] Make Priority not static --- tabled/examples/height.rs | 4 +- tabled/examples/hyperlink.rs | 6 +- tabled/examples/table_width_2.rs | 2 +- .../settings/height/cell_height_increase.rs | 4 +- .../src/settings/height/cell_height_limit.rs | 4 +- .../settings/height/table_height_increase.rs | 4 +- .../src/settings/height/table_height_limit.rs | 4 +- tabled/src/settings/peaker/mod.rs | 19 ++-- tabled/src/settings/width/min_width.rs | 14 ++- tabled/src/settings/width/truncate.rs | 34 +++--- tabled/src/settings/width/wrap.rs | 16 ++- tabled/tests/settings/width_test.rs | 100 +++++++++--------- 12 files changed, 104 insertions(+), 107 deletions(-) diff --git a/tabled/examples/height.rs b/tabled/examples/height.rs index 2da0f36d..2a268460 100644 --- a/tabled/examples/height.rs +++ b/tabled/examples/height.rs @@ -33,7 +33,7 @@ fn main() { let table_ = table .clone() - .with(Height::limit(4).priority::()) + .with(Height::limit(4).priority(PriorityMax)) .to_string(); println!("Table decrease height to 4\n"); @@ -41,7 +41,7 @@ fn main() { let table_ = table .clone() - .with(Height::limit(0).priority::()) + .with(Height::limit(0).priority(PriorityMax)) .to_string(); println!("Table decrease height to 0\n"); diff --git a/tabled/examples/hyperlink.rs b/tabled/examples/hyperlink.rs index 9fda7a04..6c717ed5 100644 --- a/tabled/examples/hyperlink.rs +++ b/tabled/examples/hyperlink.rs @@ -9,7 +9,7 @@ //! [`tabled`] doesn't have the final say on whether a link is clickable or not. use tabled::{ - settings::{object::Segment, Alignment, Modify, Style, Width}, + settings::{object::Segment, Alignment, Style, Width}, Table, Tabled, }; @@ -53,7 +53,7 @@ fn main() { table .with(Style::ascii_rounded()) .with(Alignment::left()) - .with(Modify::new(Segment::all()).with(Width::wrap(16).keep_words())); + .modify(Segment::all(), Width::wrap(16).keep_words(true)); println!("{table}"); @@ -61,7 +61,7 @@ fn main() { table .with(Style::ascii_rounded()) .with(Alignment::left()) - .with(Modify::new(Segment::all()).with(Width::wrap(16))); + .modify(Segment::all(), Width::wrap(16)); println!("{table}"); } diff --git a/tabled/examples/table_width_2.rs b/tabled/examples/table_width_2.rs index d2601fc8..d4ed9be3 100644 --- a/tabled/examples/table_width_2.rs +++ b/tabled/examples/table_width_2.rs @@ -15,7 +15,7 @@ fn main() { let mut table = Table::new(lines); table.with(Style::ascii_rounded()).with( Modify::new(Segment::all()) - .with(Width::wrap(30).keep_words()) + .with(Width::wrap(30).keep_words(true)) .with(Alignment::left()), ); diff --git a/tabled/src/settings/height/cell_height_increase.rs b/tabled/src/settings/height/cell_height_increase.rs index e78c127d..d4d5ff77 100644 --- a/tabled/src/settings/height/cell_height_increase.rs +++ b/tabled/src/settings/height/cell_height_increase.rs @@ -31,12 +31,12 @@ impl CellHeightIncrease { /// The priority makes sense only for table, so the function /// converts it to [`TableHeightIncrease`] with a given priority. - pub fn priority

(self) -> TableHeightIncrease + pub fn priority

(self, priority: P) -> TableHeightIncrease where P: Peaker, W: Measurement, { - TableHeightIncrease::new(self.height).priority::

() + TableHeightIncrease::new(self.height).priority(priority) } } diff --git a/tabled/src/settings/height/cell_height_limit.rs b/tabled/src/settings/height/cell_height_limit.rs index 609386e5..1bd52361 100644 --- a/tabled/src/settings/height/cell_height_limit.rs +++ b/tabled/src/settings/height/cell_height_limit.rs @@ -31,12 +31,12 @@ impl CellHeightLimit { } /// Set's a priority by which the limit logic will be applied. - pub fn priority

(self) -> TableHeightLimit + pub fn priority

(self, priority: P) -> TableHeightLimit where P: Peaker, W: Measurement, { - TableHeightLimit::new(self.height).priority::

() + TableHeightLimit::new(self.height).priority(priority) } } diff --git a/tabled/src/settings/height/table_height_increase.rs b/tabled/src/settings/height/table_height_increase.rs index 5b503414..7a0706de 100644 --- a/tabled/src/settings/height/table_height_increase.rs +++ b/tabled/src/settings/height/table_height_increase.rs @@ -33,12 +33,12 @@ impl TableHeightIncrease { } /// Sets a different priority logic. - pub fn priority

(self) -> TableHeightIncrease + pub fn priority

(self, priority: P) -> TableHeightIncrease where P: Peaker, { TableHeightIncrease { - priority: P::create(), + priority, height: self.height, } } diff --git a/tabled/src/settings/height/table_height_limit.rs b/tabled/src/settings/height/table_height_limit.rs index ff33f78d..2115fc07 100644 --- a/tabled/src/settings/height/table_height_limit.rs +++ b/tabled/src/settings/height/table_height_limit.rs @@ -34,12 +34,12 @@ impl TableHeightLimit { } /// Sets a different priority logic. - pub fn priority

(self) -> TableHeightLimit + pub fn priority

(self, priority: P) -> TableHeightLimit where P: Peaker, { TableHeightLimit { - priority: P::create(), + priority, height: self.height, } } diff --git a/tabled/src/settings/peaker/mod.rs b/tabled/src/settings/peaker/mod.rs index a49796b0..6a21b06c 100644 --- a/tabled/src/settings/peaker/mod.rs +++ b/tabled/src/settings/peaker/mod.rs @@ -6,24 +6,27 @@ /// A strategy of width function. /// It determines the order how the function is applied. pub trait Peaker { - /// Creates a new instance. - fn create() -> Self; /// This function returns a column index which will be changed. /// Or `None` if no changes are necessary. fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option; } +// todo: Add PriorityLeft, PriorityRight + /// A Peaker which goes over column 1 by 1. #[derive(Debug, Default, Clone)] pub struct PriorityNone { i: usize, } -impl Peaker for PriorityNone { - fn create() -> Self { +impl PriorityNone { + /// Creates a new priority which does not target anything. + pub const fn new() -> Self { Self { i: 0 } } +} +impl Peaker for PriorityNone { fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { let mut i = self.i; let mut count_empty = 0; @@ -57,10 +60,6 @@ impl Peaker for PriorityNone { pub struct PriorityMax; impl Peaker for PriorityMax { - fn create() -> Self { - Self - } - fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { let col = (0..widths.len()).max_by_key(|&i| widths[i]).unwrap(); if widths[col] == 0 { @@ -76,10 +75,6 @@ impl Peaker for PriorityMax { pub struct PriorityMin; impl Peaker for PriorityMin { - fn create() -> Self { - Self - } - fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option { let col = (0..widths.len()) .filter(|&i| min_widths.is_empty() || widths[i] > min_widths[i]) diff --git a/tabled/src/settings/width/min_width.rs b/tabled/src/settings/width/min_width.rs index cd3764f9..31faed6a 100644 --- a/tabled/src/settings/width/min_width.rs +++ b/tabled/src/settings/width/min_width.rs @@ -2,8 +2,6 @@ //! //! [`Table`]: crate::Table -use std::marker::PhantomData; - use crate::{ grid::config::{ColoredConfig, Entity}, grid::dimension::CompleteDimensionVecRecords, @@ -57,7 +55,7 @@ use super::util::get_table_widths_with_total; pub struct MinWidth { width: W, fill: char, - _priority: PhantomData

, + priority: P, } impl MinWidth @@ -65,11 +63,11 @@ where W: Measurement, { /// Creates a new instance of [`MinWidth`]. - pub fn new(width: W) -> Self { + pub const fn new(width: W) -> Self { Self { width, fill: ' ', - _priority: PhantomData, + priority: PriorityNone::new(), } } } @@ -92,11 +90,11 @@ impl MinWidth { /// /// [`PriorityMax`]: crate::settings::peaker::PriorityMax /// [`PriorityMin`]: crate::settings::peaker::PriorityMin - pub fn priority(self) -> MinWidth { + pub fn priority(self, peacker: PP) -> MinWidth { MinWidth { fill: self.fill, width: self.width, - _priority: PhantomData, + priority: peacker, } } } @@ -161,7 +159,7 @@ where return; } - let widths = get_increase_list(widths, necessary_width, total_width, P::create()); + let widths = get_increase_list(widths, necessary_width, total_width, self.priority); dims.set_widths(widths); } diff --git a/tabled/src/settings/width/truncate.rs b/tabled/src/settings/width/truncate.rs index ef3159b4..5ca02fee 100644 --- a/tabled/src/settings/width/truncate.rs +++ b/tabled/src/settings/width/truncate.rs @@ -2,7 +2,7 @@ //! //! [`Table`]: crate::Table -use std::{borrow::Cow, iter, marker::PhantomData}; +use std::{borrow::Cow, iter}; use crate::{ grid::{ @@ -44,7 +44,7 @@ pub struct Truncate<'a, W = usize, P = PriorityNone> { width: W, suffix: Option>, multiline: bool, - _priority: PhantomData

, + priority: P, } #[cfg(feature = "ansi")] @@ -89,12 +89,12 @@ where W: Measurement, { /// Creates a [`Truncate`] object - pub fn new(width: W) -> Truncate<'static, W> { + pub const fn new(width: W) -> Truncate<'static, W> { Self { width, multiline: false, suffix: None, - _priority: PhantomData, + priority: PriorityNone::new(), } } } @@ -115,8 +115,8 @@ impl<'a, W, P> Truncate<'a, W, P> { Truncate { width: self.width, multiline: self.multiline, + priority: self.priority, suffix: Some(suff), - _priority: PhantomData, } } @@ -128,18 +128,18 @@ impl<'a, W, P> Truncate<'a, W, P> { Truncate { width: self.width, multiline: self.multiline, + priority: self.priority, suffix: Some(suff), - _priority: PhantomData, } } /// Use trancate logic per line, not as a string as a whole. - pub fn multiline(self) -> Truncate<'a, W, P> { + pub fn multiline(self, on: bool) -> Truncate<'a, W, P> { Truncate { width: self.width, - multiline: true, + multiline: on, suffix: self.suffix, - _priority: self._priority, + priority: self.priority, } } @@ -152,8 +152,8 @@ impl<'a, W, P> Truncate<'a, W, P> { Truncate { width: self.width, multiline: self.multiline, + priority: self.priority, suffix: Some(suff), - _priority: PhantomData, } } } @@ -167,12 +167,12 @@ impl<'a, W, P> Truncate<'a, W, P> { /// /// [`PriorityMax`]: crate::settings::peaker::PriorityMax /// [`PriorityMin`]: crate::settings::peaker::PriorityMin - pub fn priority(self) -> Truncate<'a, W, PP> { + pub fn priority(self, priority: PP) -> Truncate<'a, W, PP> { Truncate { width: self.width, multiline: self.multiline, suffix: self.suffix, - _priority: PhantomData, + priority, } } } @@ -333,10 +333,16 @@ where try_color: s.try_color, }); - let priority = P::create(); let multiline = self.multiline; let widths = truncate_total_width( - records, cfg, widths, total, width, priority, suffix, multiline, + records, + cfg, + widths, + total, + width, + self.priority, + suffix, + multiline, ); dims.set_widths(widths); diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs index a871c105..7a3efa1b 100644 --- a/tabled/src/settings/width/wrap.rs +++ b/tabled/src/settings/width/wrap.rs @@ -3,8 +3,6 @@ //! //! [`Table`]: crate::Table -use std::marker::PhantomData; - use crate::{ grid::{ config::SpannedConfig, @@ -46,7 +44,7 @@ use crate::util::string::split_at_width; pub struct Wrap { width: W, keep_words: bool, - _priority: PhantomData

, + priority: P, } impl Wrap { @@ -58,7 +56,7 @@ impl Wrap { Wrap { width, keep_words: false, - _priority: PhantomData, + priority: PriorityNone::new(), } } } @@ -76,11 +74,11 @@ impl Wrap { /// [`Padding`]: crate::settings::Padding /// [`PriorityMax`]: crate::settings::peaker::PriorityMax /// [`PriorityMin`]: crate::settings::peaker::PriorityMin - pub fn priority(self) -> Wrap { + pub fn priority(self, priority: PP) -> Wrap { Wrap { width: self.width, keep_words: self.keep_words, - _priority: PhantomData, + priority, } } @@ -88,8 +86,8 @@ impl Wrap { /// /// If a wrapping point will be in a word, [`Wrap`] will /// preserve a word (if possible) and wrap the string before it. - pub fn keep_words(mut self) -> Self { - self.keep_words = true; + pub fn keep_words(mut self, on: bool) -> Self { + self.keep_words = on; self } } @@ -125,7 +123,7 @@ where return; } - let priority = P::create(); + let priority = self.priority; let keep_words = self.keep_words; let widths = wrap_total_width(records, cfg, widths, total, width, keep_words, priority); diff --git a/tabled/tests/settings/width_test.rs b/tabled/tests/settings/width_test.rs index 1dc6c7e9..53ef7257 100644 --- a/tabled/tests/settings/width_test.rs +++ b/tabled/tests/settings/width_test.rs @@ -92,7 +92,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 17 + 2 + 2)); @@ -111,7 +111,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 17 + 2 + 2)); @@ -130,7 +130,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 17 + 2 + 2)); @@ -150,7 +150,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 17 + 2 + 2)); @@ -171,7 +171,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 17 + 2 + 2)); @@ -190,7 +190,7 @@ test_table!( { let table = Matrix::iter(vec!["this"]) .with(Style::markdown()) - .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words(true))) .to_string(); assert!(is_lines_equal(&table, 8)); @@ -209,7 +209,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); AnsiStr::ansi_strip(&table).to_string() @@ -226,7 +226,7 @@ test_table!( Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))), "| String |" "|-------------------|" "| \u{1b}[32m\u{1b}[40mthis is a long \u{1b}[39m\u{1b}[49m |" @@ -240,7 +240,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); AnsiStr::ansi_strip(&table).to_string() @@ -257,7 +257,7 @@ test_table!( Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))), "| String |" "|-------------------|" "| \u{1b}[32m\u{1b}[40mthis is a long \u{1b}[39m\u{1b}[49m |" @@ -271,7 +271,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); AnsiStr::ansi_strip(&table).to_string() @@ -288,7 +288,7 @@ test_table!( Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))), "| String |" "|-------------------|" "| \u{1b}[32m\u{1b}[40mthis is a long \u{1b}[39m\u{1b}[49m |" @@ -302,7 +302,7 @@ test_table!( let table = Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); AnsiStr::ansi_strip(&table).to_string() @@ -319,7 +319,7 @@ test_table!( Matrix::iter(vec!["this is a long sentence".on_black().green().to_string()]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))), "| String |" "|-------------------|" "| \u{1b}[32m\u{1b}[40mthis is a long \u{1b}[39m\u{1b}[49m |" @@ -332,7 +332,7 @@ test_table!( { let table = Matrix::iter(vec!["this".on_black().green().to_string()]) .with(Style::markdown()) - .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words(true))) .to_string(); AnsiStr::ansi_strip(&table).to_string() @@ -347,7 +347,7 @@ test_table!( max_width_wrapped_keep_words_color_4_1, Matrix::iter(vec!["this".on_black().green().to_string()]) .with(Style::markdown()) - .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(10).keep_words(true))), "| String |" "|--------|" "| \u{1b}[32;40mthis\u{1b}[0m |" @@ -358,7 +358,7 @@ test_table!( Matrix::iter(["this is a long sentencesentencesentence"]) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())), + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))), "| &str |" "|-------------------|" "| this is a long se |" @@ -376,7 +376,7 @@ fn max_width_wrapped_keep_words_long_word_color() { let table = Matrix::iter(data) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words())) + .with(Modify::new(Segment::all()).with(Width::wrap(17).keep_words(true))) .to_string(); assert_eq!( @@ -406,7 +406,7 @@ fn max_width_wrapped_keep_words_long_word_color() { #[test] fn max_width_keep_words_1() { let table = Matrix::iter(["asdf"]) - .with(Width::wrap(7).keep_words()) + .with(Width::wrap(7).keep_words(true)) .to_string(); assert_eq!( @@ -423,7 +423,7 @@ fn max_width_keep_words_1() { ); let table = Matrix::iter(["qweqw eqwe"]) - .with(Width::wrap(8).keep_words()) + .with(Width::wrap(8).keep_words(true)) .to_string(); assert_eq!( @@ -449,7 +449,7 @@ fn max_width_keep_words_1() { .remove_horizontal() .horizontals([(1, HorizontalLine::inherit(Style::modern()))]), ) - .with(Width::wrap(21).keep_words().priority::()) + .with(Width::wrap(21).keep_words(true).priority(PriorityMax)) .with(Alignment::center()) .to_string(); @@ -1172,7 +1172,7 @@ fn total_width_wrapping() { .insert((3, 2), "some loong string") .with(Modify::new(Segment::all()).with(Alignment::center())) .with(Style::markdown()) - .with(Width::wrap(20).keep_words()) + .with(Width::wrap(20).keep_words(true)) .with(MinWidth::new(20)) .to_string(); @@ -1822,7 +1822,7 @@ fn max_width_truncate_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(35).priority::()) + .with(Width::truncate(35).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 35)); @@ -1840,7 +1840,7 @@ fn max_width_truncate_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(20).priority::()) + .with(Width::truncate(20).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 20)); @@ -1858,7 +1858,7 @@ fn max_width_truncate_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(0).priority::()) + .with(Width::truncate(0).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 13)); @@ -1880,7 +1880,7 @@ fn max_width_truncate_priority_max_with_span() { .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) .with(Modify::new((2, 1)).with(Span::column(2))) - .with(Width::truncate(15).priority::()) + .with(Width::truncate(15).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 15)); @@ -1901,7 +1901,7 @@ fn max_width_wrap_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(35).priority::()) + .with(Width::wrap(35).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 35)); @@ -1923,7 +1923,7 @@ fn max_width_wrap_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(20).priority::()) + .with(Width::wrap(20).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 20)); @@ -1958,7 +1958,7 @@ fn max_width_wrap_priority_max() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(0).priority::()) + .with(Width::wrap(0).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 13)); @@ -1980,7 +1980,7 @@ fn max_width_wrap_priority_max_with_span() { .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) .with(Modify::new((2, 1)).with(Span::column(2))) - .with(Width::wrap(15).priority::()) + .with(Width::wrap(15).priority(PriorityMax)) .to_string(); assert!(is_lines_equal(&table, 15)); @@ -2018,7 +2018,7 @@ fn max_width_truncate_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(35).priority::()) + .with(Width::truncate(35).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 35)); @@ -2036,7 +2036,7 @@ fn max_width_truncate_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(20).priority::()) + .with(Width::truncate(20).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 20)); @@ -2054,7 +2054,7 @@ fn max_width_truncate_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::truncate(0).priority::()) + .with(Width::truncate(0).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 13)); @@ -2076,7 +2076,7 @@ fn max_width_truncate_priority_min_with_span() { .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) .with(Modify::new((2, 1)).with(Span::column(2))) - .with(Width::truncate(15).priority::()) + .with(Width::truncate(15).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 15)); @@ -2095,7 +2095,7 @@ fn max_width_truncate_priority_min_with_span() { .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) .with(Modify::new((2, 1)).with(Span::column(2))) - .with(Width::truncate(17).priority::()) + .with(Width::truncate(17).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 17)); @@ -2116,7 +2116,7 @@ fn max_width_wrap_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(35).priority::()) + .with(Width::wrap(35).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 35)); @@ -2135,7 +2135,7 @@ fn max_width_wrap_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(20).priority::()) + .with(Width::wrap(20).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 20)); @@ -2157,7 +2157,7 @@ fn max_width_wrap_priority_min() { let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) - .with(Width::wrap(0).priority::()) + .with(Width::wrap(0).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 13)); @@ -2179,7 +2179,7 @@ fn max_width_wrap_priority_min_with_span() { .insert((2, 1), "Hello World With Big Line") .with(Style::markdown()) .with(Modify::new((2, 1)).with(Span::column(2))) - .with(Width::wrap(15).priority::()) + .with(Width::wrap(15).priority(PriorityMin)) .to_string(); assert!(is_lines_equal(&table, 15)); @@ -2208,7 +2208,7 @@ fn max_width_wrap_priority_min_with_span() { fn min_width_priority_max() { let table = Matrix::new(3, 3) .with(Style::markdown()) - .with(MinWidth::new(60).priority::()) + .with(MinWidth::new(60).priority(PriorityMax)) .to_string(); assert_eq!(string_width_multiline(&table), 60); @@ -2228,7 +2228,7 @@ fn min_width_priority_max() { fn min_width_priority_min() { let table = Matrix::new(3, 3) .with(Style::markdown()) - .with(MinWidth::new(60).priority::()) + .with(MinWidth::new(60).priority(PriorityMin)) .to_string(); assert_eq!(string_width_multiline(&table), 60); @@ -2313,7 +2313,7 @@ fn min_width_is_used_after_margin() { fn wrap_keeping_words_0() { let data = vec![["Hello world"]]; let table = tabled::Table::new(data) - .with(Width::wrap(8).keep_words()) + .with(Width::wrap(8).keep_words(true)) .to_string(); assert_eq!( @@ -2343,7 +2343,7 @@ fn cell_truncate_multiline() { .with(Style::markdown()) .with( Modify::new(Columns::new(1..2).not(Rows::single(0))) - .with(Width::truncate(1).multiline()), + .with(Width::truncate(1).multiline(true)), ) .to_string(); @@ -2371,7 +2371,7 @@ fn cell_truncate_multiline_with_suffix() { .with(Style::markdown()) .with( Modify::new(Columns::new(1..2).not(Rows::single(0))) - .with(Width::truncate(1).multiline().suffix(".")), + .with(Width::truncate(1).multiline(true).suffix(".")), ) .to_string(); @@ -2397,7 +2397,7 @@ fn table_truncate_multiline() { .insert((1, 1), "H\nel\nlo World") .insert((3, 2), "multi\nline string\n") .with(Style::markdown()) - .with(Width::truncate(20).multiline()) + .with(Width::truncate(20).multiline(true)) .to_string(); assert_eq!( @@ -2422,7 +2422,7 @@ fn table_truncate_multiline_with_suffix() { .insert((1, 1), "H\nel\nlo World") .insert((3, 2), "multi\nline string\n") .with(Style::markdown()) - .with(Width::truncate(20).suffix(".").multiline()) + .with(Width::truncate(20).suffix(".").multiline(true)) .to_string(); assert_eq!( @@ -2489,7 +2489,7 @@ mod derived { let table = Matrix::iter(&data) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Width::wrap(57).keep_words()) + .with(Width::wrap(57).keep_words(true)) .to_string(); assert_eq!( @@ -2574,7 +2574,7 @@ mod derived { let table = Matrix::iter(&data) .with(Style::markdown()) .with(Modify::new(Segment::all()).with(Alignment::left())) - .with(Width::wrap(57).keep_words()) + .with(Width::wrap(57).keep_words(true)) .to_string(); assert_eq!( @@ -2685,7 +2685,7 @@ mod derived { tabled::Table::new(data) .with( Modify::new(Segment::all()) - .with(Width::wrap(5).keep_words()) + .with(Width::wrap(5).keep_words(true)) .with(Alignment::left()), ) .to_string() @@ -2767,7 +2767,7 @@ mod derived { tabled::Table::new(data) .with( Modify::new(Segment::all()) - .with(Width::wrap(6).keep_words()) + .with(Width::wrap(6).keep_words(true)) .with(Alignment::left()), ) .to_string() From c7e5c1ff6d12219ef254dd66c834b8d01d4ec6b5 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 02:43:42 +0300 Subject: [PATCH 08/20] Add PriorityLeft and PriorityRight --- tabled/src/settings/peaker/left.rs | 38 +++++++++++++ tabled/src/settings/peaker/max.rs | 16 ++++++ tabled/src/settings/peaker/min.rs | 19 +++++++ tabled/src/settings/peaker/mod.rs | 87 ++++------------------------- tabled/src/settings/peaker/none.rs | 43 ++++++++++++++ tabled/src/settings/peaker/right.rs | 46 +++++++++++++++ tabled/tests/settings/width_test.rs | 45 ++++++++++++++- 7 files changed, 217 insertions(+), 77 deletions(-) create mode 100644 tabled/src/settings/peaker/left.rs create mode 100644 tabled/src/settings/peaker/max.rs create mode 100644 tabled/src/settings/peaker/min.rs create mode 100644 tabled/src/settings/peaker/none.rs create mode 100644 tabled/src/settings/peaker/right.rs diff --git a/tabled/src/settings/peaker/left.rs b/tabled/src/settings/peaker/left.rs new file mode 100644 index 00000000..c94b6e40 --- /dev/null +++ b/tabled/src/settings/peaker/left.rs @@ -0,0 +1,38 @@ +use super::Peaker; + +/// A Peaker which goes over column 1 by 1, but truncates as much as possible left side. +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)] +pub struct PriorityLeft { + i: usize, +} + +impl PriorityLeft { + /// Creates a new priority which does not target anything. + pub const fn new() -> Self { + Self { i: 0 } + } +} + +impl Peaker for PriorityLeft { + fn peak(&mut self, min: &[usize], widths: &[usize]) -> Option { + let col = self.i; + if widths[col] > min[col] { + return Some(col); + } + + if col + 1 == widths.len() { + return None; + } + + let mut col = col + 1; + while widths[col] == min[col] { + if col + 1 == widths.len() { + return None; + } + + col += 1; + } + + Some(col) + } +} diff --git a/tabled/src/settings/peaker/max.rs b/tabled/src/settings/peaker/max.rs new file mode 100644 index 00000000..c488c0b1 --- /dev/null +++ b/tabled/src/settings/peaker/max.rs @@ -0,0 +1,16 @@ +use super::Peaker; + +/// A Peaker which goes over the biggest column first. +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)] +pub struct PriorityMax; + +impl Peaker for PriorityMax { + fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { + let col = (0..widths.len()).max_by_key(|&i| widths[i]).unwrap(); + if widths[col] == 0 { + None + } else { + Some(col) + } + } +} diff --git a/tabled/src/settings/peaker/min.rs b/tabled/src/settings/peaker/min.rs new file mode 100644 index 00000000..4a4b04cd --- /dev/null +++ b/tabled/src/settings/peaker/min.rs @@ -0,0 +1,19 @@ +use super::Peaker; + +/// A Peaker which goes over the smallest column first. +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)] +pub struct PriorityMin; + +impl Peaker for PriorityMin { + fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option { + let col = (0..widths.len()) + .filter(|&i| min_widths.is_empty() || widths[i] > min_widths[i]) + .min_by_key(|&i| widths[i]) + .unwrap(); + if widths[col] == 0 { + None + } else { + Some(col) + } + } +} diff --git a/tabled/src/settings/peaker/mod.rs b/tabled/src/settings/peaker/mod.rs index 6a21b06c..741a6f42 100644 --- a/tabled/src/settings/peaker/mod.rs +++ b/tabled/src/settings/peaker/mod.rs @@ -3,6 +3,12 @@ //! [`Width`]: crate::settings::width::Width //! [`Height`]: crate::settings::height::Height +mod left; +mod max; +mod min; +mod none; +mod right; + /// A strategy of width function. /// It determines the order how the function is applied. pub trait Peaker { @@ -11,79 +17,8 @@ pub trait Peaker { fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option; } -// todo: Add PriorityLeft, PriorityRight - -/// A Peaker which goes over column 1 by 1. -#[derive(Debug, Default, Clone)] -pub struct PriorityNone { - i: usize, -} - -impl PriorityNone { - /// Creates a new priority which does not target anything. - pub const fn new() -> Self { - Self { i: 0 } - } -} - -impl Peaker for PriorityNone { - fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { - let mut i = self.i; - let mut count_empty = 0; - while widths[i] == 0 { - i += 1; - if i >= widths.len() { - i = 0; - } - - count_empty += 1; - if count_empty == widths.len() { - return None; - } - } - - let col = i; - - i += 1; - if i >= widths.len() { - i = 0; - } - - self.i = i; - - Some(col) - } -} - -/// A Peaker which goes over the biggest column first. -#[derive(Debug, Default, Clone)] -pub struct PriorityMax; - -impl Peaker for PriorityMax { - fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { - let col = (0..widths.len()).max_by_key(|&i| widths[i]).unwrap(); - if widths[col] == 0 { - None - } else { - Some(col) - } - } -} - -/// A Peaker which goes over the smallest column first. -#[derive(Debug, Default, Clone)] -pub struct PriorityMin; - -impl Peaker for PriorityMin { - fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option { - let col = (0..widths.len()) - .filter(|&i| min_widths.is_empty() || widths[i] > min_widths[i]) - .min_by_key(|&i| widths[i]) - .unwrap(); - if widths[col] == 0 { - None - } else { - Some(col) - } - } -} +pub use left::PriorityLeft; +pub use max::PriorityMax; +pub use min::PriorityMin; +pub use none::PriorityNone; +pub use right::PriorityRight; diff --git a/tabled/src/settings/peaker/none.rs b/tabled/src/settings/peaker/none.rs new file mode 100644 index 00000000..d661d94a --- /dev/null +++ b/tabled/src/settings/peaker/none.rs @@ -0,0 +1,43 @@ +use super::Peaker; + +/// A Peaker which goes over column 1 by 1. +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)] +pub struct PriorityNone { + i: usize, +} + +impl PriorityNone { + /// Creates a new priority which does not target anything. + pub const fn new() -> Self { + Self { i: 0 } + } +} + +impl Peaker for PriorityNone { + fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option { + let mut i = self.i; + let mut count_empty = 0; + while widths[i] == 0 { + i += 1; + if i >= widths.len() { + i = 0; + } + + count_empty += 1; + if count_empty == widths.len() { + return None; + } + } + + let col = i; + + i += 1; + if i >= widths.len() { + i = 0; + } + + self.i = i; + + Some(col) + } +} diff --git a/tabled/src/settings/peaker/right.rs b/tabled/src/settings/peaker/right.rs new file mode 100644 index 00000000..590424c8 --- /dev/null +++ b/tabled/src/settings/peaker/right.rs @@ -0,0 +1,46 @@ +use super::Peaker; + +/// A Peaker which goes over column 1 by 1, from right side, but truncates as much as possible right side. +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)] +pub struct PriorityRight { + i: Option, +} + +impl PriorityRight { + /// Creates a new priority which does not target anything. + pub const fn new() -> Self { + Self { i: None } + } +} + +impl Peaker for PriorityRight { + fn peak(&mut self, min: &[usize], widths: &[usize]) -> Option { + if widths.is_empty() { + return None; + } + + if self.i.is_none() { + self.i = Some(widths.len() - 1); + } + + let col = self.i.expect("checked"); + if widths[col] > min[col] { + return Some(col); + } + + if col == 0 { + return None; + } + + let mut col = col - 1; + while widths[col] == min[col] { + if col == 0 { + return None; + } + + col -= 1; + } + + Some(col) + } +} diff --git a/tabled/tests/settings/width_test.rs b/tabled/tests/settings/width_test.rs index 53ef7257..f26610ad 100644 --- a/tabled/tests/settings/width_test.rs +++ b/tabled/tests/settings/width_test.rs @@ -5,7 +5,7 @@ use tabled::{ settings::{ formatting::{TabSize, TrimStrategy}, object::{Columns, Object, Rows, Segment}, - peaker::{PriorityMax, PriorityMin}, + peaker::{PriorityLeft, PriorityMax, PriorityMin, PriorityRight}, width::{Justify, MinWidth, SuffixLimit, Width}, Alignment, Margin, Modify, Padding, Panel, Settings, Span, Style, }, @@ -2441,6 +2441,49 @@ fn table_truncate_multiline_with_suffix() { ); } +test_table!( + test_priority_left, + Matrix::new(3, 10) + .with(Style::markdown()) + .with(Width::wrap(60).priority(PriorityLeft::default())), + "| | | | | | | | co | column 7 | column 8 | column 9 |" + "| | | | | | | | lu | | | |" + "| | | | | | | | mn | | | |" + "| | | | | | | | 6 | | | |" + "|--|--|--|--|--|--|--|----|----------|----------|----------|" + "| | | | | | | | 0- | 0-7 | 0-8 | 0-9 |" + "| | | | | | | | 6 | | | |" + "| | | | | | | | 1- | 1-7 | 1-8 | 1-9 |" + "| | | | | | | | 6 | | | |" + "| | | | | | | | 2- | 2-7 | 2-8 | 2-9 |" + "| | | | | | | | 6 | | | |" +); + +test_table!( + test_priority_right, + Matrix::new(3, 10) + .with(Style::markdown()) + .with(Width::wrap(60).priority(PriorityRight::default())), + "| N | column 0 | column 1 | column 2 | c | | | | | | |" + "| | | | | o | | | | | | |" + "| | | | | l | | | | | | |" + "| | | | | u | | | | | | |" + "| | | | | m | | | | | | |" + "| | | | | n | | | | | | |" + "| | | | | | | | | | | |" + "| | | | | 3 | | | | | | |" + "|---|----------|----------|----------|---|--|--|--|--|--|--|" + "| 0 | 0-0 | 0-1 | 0-2 | 0 | | | | | | |" + "| | | | | - | | | | | | |" + "| | | | | 3 | | | | | | |" + "| 1 | 1-0 | 1-1 | 1-2 | 1 | | | | | | |" + "| | | | | - | | | | | | |" + "| | | | | 3 | | | | | | |" + "| 2 | 2-0 | 2-1 | 2-2 | 2 | | | | | | |" + "| | | | | - | | | | | | |" + "| | | | | 3 | | | | | | |" +); + #[cfg(feature = "derive")] mod derived { use super::*; From 481d86543fb046a6af1ea33ea8116de371f61da0 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 03:19:01 +0300 Subject: [PATCH 09/20] Add tuple implementation of TableOption and CellOption --- tabled/src/settings/cell_option.rs | 63 ++++++++++++++++++++++++++++ tabled/src/settings/settings_list.rs | 22 +++++----- tabled/src/settings/table_option.rs | 63 ++++++++++++++++++++++++++++ tabled/tests/core/table_test.rs | 49 +++++++++++++++++++++- 4 files changed, 184 insertions(+), 13 deletions(-) diff --git a/tabled/src/settings/cell_option.rs b/tabled/src/settings/cell_option.rs index 0951c1bf..af167c89 100644 --- a/tabled/src/settings/cell_option.rs +++ b/tabled/src/settings/cell_option.rs @@ -73,3 +73,66 @@ where } } } + +macro_rules! tuple_trait_impl { + ( $($name:ident)+ ) => { + impl),+> CellOption for ($($name,)+) { + fn change(self, records: &mut R, cfg: &mut C, entity: Entity) { + #![allow(non_snake_case)] + let ($($name,)+) = self; + $( + $name::change($name, records, cfg, entity); + )+ + } + + fn hint_change(&self) -> Option { + #![allow(non_snake_case)] + let ($($name,)+) = &self; + let list = [ + $( + $name::hint_change($name), + )+ + ]; + + hint_change_list(&list) + } + } + }; +} + +tuple_trait_impl!(T0 T1); +tuple_trait_impl!(T0 T1 T2); +tuple_trait_impl!(T0 T1 T2 T3); +tuple_trait_impl!(T0 T1 T2 T3 T4); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9); + +pub(crate) fn hint_change_list(list: &[Option]) -> Option { + let mut entries = vec![]; + for e in list.iter().flatten() { + entries.push(*e); + } + + if entries.is_empty() { + return None; + } + + Some(combine_entity_list(&entries)) +} + +pub(crate) fn combine_entity_list(list: &[Entity]) -> Entity { + if list.is_empty() { + // must never happen + return Entity::Global; + } + + let mut entity = list[0]; + for e in &list[1..] { + entity = crate::settings::settings_list::combine_entity(entity, *e); + } + + entity +} diff --git a/tabled/src/settings/settings_list.rs b/tabled/src/settings/settings_list.rs index fc2d9a77..36d068d0 100644 --- a/tabled/src/settings/settings_list.rs +++ b/tabled/src/settings/settings_list.rs @@ -86,19 +86,17 @@ impl TableOption for EmptySettings { fn change(self, _: &mut R, _: &mut C, _: &mut D) {} } -fn combine_entity(x1: Entity, x2: Entity) -> Entity { +pub(crate) fn combine_entity(x1: Entity, x2: Entity) -> Entity { use Entity::*; + match (x1, x2) { - (_, Global) => Global, - (Global, _) => Global, - (Column(_), Row(_)) => Global, - (Column(a), Column(_)) => Column(a), - (Column(a), Cell(_, _)) => Column(a), - (Row(_), Column(_)) => Global, - (Row(a), Row(_)) => Row(a), - (Row(a), Cell(_, _)) => Row(a), - (Cell(_, _), Column(a)) => Column(a), - (Cell(_, _), Row(a)) => Row(a), - (Cell(a, b), Cell(_, _)) => Cell(a, b), + (Column(a), Column(b)) if a == b => Column(a), + (Column(a), Cell(_, b)) if a == b => Column(a), + (Row(a), Row(b)) if a == b => Row(a), + (Row(a), Cell(b, _)) if a == b => Row(a), + (Cell(_, a), Column(b)) if a == b => Column(a), + (Cell(a, _), Row(b)) if a == b => Row(a), + (Cell(a, b), Cell(a1, b1)) if a == a1 && b == b1 => Cell(a, b), + _ => Global, } } diff --git a/tabled/src/settings/table_option.rs b/tabled/src/settings/table_option.rs index 04a97654..18545896 100644 --- a/tabled/src/settings/table_option.rs +++ b/tabled/src/settings/table_option.rs @@ -69,3 +69,66 @@ where } } } + +macro_rules! tuple_trait_impl { + ( $($name:ident)+ ) => { + impl),+> TableOption for ($($name,)+) { + fn change(self, records: &mut R, cfg: &mut C, dimension: &mut D) { + #![allow(non_snake_case)] + let ($($name,)+) = self; + $( + $name::change($name, records, cfg, dimension); + )+ + } + + fn hint_change(&self) -> Option { + #![allow(non_snake_case)] + let ($($name,)+) = &self; + let list = [ + $( + $name::hint_change($name), + )+ + ]; + + hint_change_list(&list) + } + } + }; +} + +tuple_trait_impl!(T0 T1); +tuple_trait_impl!(T0 T1 T2); +tuple_trait_impl!(T0 T1 T2 T3); +tuple_trait_impl!(T0 T1 T2 T3 T4); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8); +tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9); + +pub(crate) fn hint_change_list(list: &[Option]) -> Option { + let mut entries = vec![]; + for e in list.iter().flatten() { + entries.push(*e); + } + + if entries.is_empty() { + return None; + } + + Some(combine_entity_list(&entries)) +} + +pub(crate) fn combine_entity_list(list: &[Entity]) -> Entity { + if list.is_empty() { + // must never happen + return Entity::Global; + } + + let mut entity = list[0]; + for e in &list[1..] { + entity = crate::settings::settings_list::combine_entity(entity, *e); + } + + entity +} diff --git a/tabled/tests/core/table_test.rs b/tabled/tests/core/table_test.rs index a3ac80ba..c75b0f30 100644 --- a/tabled/tests/core/table_test.rs +++ b/tabled/tests/core/table_test.rs @@ -4,7 +4,10 @@ use std::iter::FromIterator; use tabled::{ builder::Builder, - settings::{formatting::Charset, Height, Modify, Padding, Settings, Style, Width}, + settings::{ + formatting::Charset, Border, Height, Highlight, Modify, Padding, Settings, Shadow, Style, + Width, + }, Table, }; @@ -860,3 +863,47 @@ test_table!( "| 1 | 1-0 | 1-1 | 1-2 |" "| 2 | 2-0 | 2-1 | 2-2 |" ); + +test_table!( + table_tuple_settings_list_0_test, + Matrix::new(3, 3) + .with(Style::markdown()) + .modify((1, 0), ("Hello World", "Hello World 2")), + "| N | column 0 | column 1 | column 2 |" + "|---------------|----------|----------|----------|" + "| Hello World 2 | 0-0 | 0-1 | 0-2 |" + "| 1 | 1-0 | 1-1 | 1-2 |" + "| 2 | 2-0 | 2-1 | 2-2 |" +); + +test_table!( + table_tuple_settings_list_1_test, + Matrix::new(3, 3) + .with(Style::markdown()) + .modify((1, 0), ("Hello World", Padding::new(2, 2, 1, 1), "1")), + "| N | column 0 | column 1 | column 2 |" + "|-----|----------|----------|----------|" + "| | 0-0 | 0-1 | 0-2 |" + "| 1 | | | |" + "| | | | |" + "| 1 | 1-0 | 1-1 | 1-2 |" + "| 2 | 2-0 | 2-1 | 2-2 |" +); + +test_table!( + table_tuple_settings_list_2_test, + Matrix::new(3, 3) + .with(Style::markdown()) + .with((Padding::new(2, 2, 0, 0), Highlight::border((0, 0), Border::filled('*')), Shadow::new(5))), + "******* " + "* N * column 0 | column 1 | column 2 |▒▒▒▒▒" + "*******------------|------------|------------|▒▒▒▒▒" + "| 0 | 0-0 | 0-1 | 0-2 |▒▒▒▒▒" + "| 1 | 1-0 | 1-1 | 1-2 |▒▒▒▒▒" + "| 2 | 2-0 | 2-1 | 2-2 |▒▒▒▒▒" + " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" + " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" + " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" + " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" + " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" +); From 9a6bd75f3d63a5a23ae1d59ce92c9b693c78b1fb Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 03:23:45 +0300 Subject: [PATCH 10/20] Fix --- tabled/src/settings/cell_option.rs | 39 ++++++++--------------------- tabled/src/settings/table_option.rs | 12 +++++++++ 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/tabled/src/settings/cell_option.rs b/tabled/src/settings/cell_option.rs index af167c89..f9ca393e 100644 --- a/tabled/src/settings/cell_option.rs +++ b/tabled/src/settings/cell_option.rs @@ -74,6 +74,7 @@ where } } +#[cfg(feature = "std")] macro_rules! tuple_trait_impl { ( $($name:ident)+ ) => { impl),+> CellOption for ($($name,)+) { @@ -94,45 +95,27 @@ macro_rules! tuple_trait_impl { )+ ]; - hint_change_list(&list) + crate::settings::table_option::hint_change_list(&list) } } }; } +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9); - -pub(crate) fn hint_change_list(list: &[Option]) -> Option { - let mut entries = vec![]; - for e in list.iter().flatten() { - entries.push(*e); - } - - if entries.is_empty() { - return None; - } - - Some(combine_entity_list(&entries)) -} - -pub(crate) fn combine_entity_list(list: &[Entity]) -> Entity { - if list.is_empty() { - // must never happen - return Entity::Global; - } - - let mut entity = list[0]; - for e in &list[1..] { - entity = crate::settings::settings_list::combine_entity(entity, *e); - } - - entity -} diff --git a/tabled/src/settings/table_option.rs b/tabled/src/settings/table_option.rs index 18545896..243590bc 100644 --- a/tabled/src/settings/table_option.rs +++ b/tabled/src/settings/table_option.rs @@ -70,6 +70,7 @@ where } } +#[cfg(feature = "std")] macro_rules! tuple_trait_impl { ( $($name:ident)+ ) => { impl),+> TableOption for ($($name,)+) { @@ -96,16 +97,26 @@ macro_rules! tuple_trait_impl { }; } +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8); +#[cfg(feature = "std")] tuple_trait_impl!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9); +#[cfg(feature = "std")] pub(crate) fn hint_change_list(list: &[Option]) -> Option { let mut entries = vec![]; for e in list.iter().flatten() { @@ -119,6 +130,7 @@ pub(crate) fn hint_change_list(list: &[Option]) -> Option { Some(combine_entity_list(&entries)) } +#[cfg(feature = "std")] pub(crate) fn combine_entity_list(list: &[Entity]) -> Entity { if list.is_empty() { // must never happen From cfc078e1e63da65e5189cf3aae173e23d3b028ec Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 21:17:37 +0300 Subject: [PATCH 11/20] Rename CellInfo into Text --- papergrid/examples/span_usage.rs | 4 +- .../src/records/vec_records/cell_info.rs | 24 +++++++--- papergrid/src/records/vec_records/mod.rs | 2 +- papergrid/tests/grid/peekable_grid.rs | 6 +-- tabled/src/builder/index_builder.rs | 18 +++---- tabled/src/builder/table_builder.rs | 48 +++++++++---------- .../src/grid/dimension/peekable_dimension.rs | 22 ++++----- tabled/src/grid/records/records_mut.rs | 10 ++-- tabled/src/settings/location/mod.rs | 11 ++--- tabled/src/settings/themes/column_names.rs | 14 +++--- tabled/src/tables/table.rs | 25 +++++----- tabled/tests/matrix/matrix.rs | 9 ++-- 12 files changed, 93 insertions(+), 100 deletions(-) diff --git a/papergrid/examples/span_usage.rs b/papergrid/examples/span_usage.rs index d5f96376..f0a31804 100644 --- a/papergrid/examples/span_usage.rs +++ b/papergrid/examples/span_usage.rs @@ -6,7 +6,7 @@ use papergrid::{ }, dimension::{spanned::SpannedGridDimension, Estimate}, grid::peekable::PeekableGrid, - records::vec_records::{CellInfo, VecRecords}, + records::vec_records::{Text, VecRecords}, }; fn main() { @@ -49,7 +49,7 @@ fn main() { let data = data .iter() - .map(|row| row.iter().map(CellInfo::new).collect()) + .map(|row| row.iter().map(Text::new).collect()) .collect(); let records = VecRecords::new(data); diff --git a/papergrid/src/records/vec_records/cell_info.rs b/papergrid/src/records/vec_records/cell_info.rs index d9b0ed71..7c41bdc5 100644 --- a/papergrid/src/records/vec_records/cell_info.rs +++ b/papergrid/src/records/vec_records/cell_info.rs @@ -1,3 +1,4 @@ +use core::fmt::Display; use std::{borrow::Cow, cmp::max}; use crate::{ @@ -7,13 +8,13 @@ use crate::{ /// The struct is a [Cell] implementation which keeps width information pre allocated. #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)] -pub struct CellInfo { +pub struct Text { text: S, width: usize, lines: Vec>, } -impl CellInfo { +impl Text { /// Creates a new instance of the structure. pub fn new(text: S) -> Self where @@ -33,7 +34,7 @@ impl CellInfo { } } -impl AsRef for CellInfo +impl AsRef for Text where S: AsRef, { @@ -42,7 +43,16 @@ where } } -impl Cell for CellInfo +impl Display for Text +where + S: Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.text.fmt(f) + } +} + +impl Cell for Text where S: AsRef, { @@ -75,7 +85,7 @@ where } } -impl Clone for CellInfo +impl Clone for Text where S: Clone + AsRef, { @@ -128,8 +138,8 @@ impl<'a> StrWithWidth<'a> { } } -fn create_cell_info>(text: S) -> CellInfo { - let mut info = CellInfo { +fn create_cell_info>(text: S) -> Text { + let mut info = Text { text, lines: vec![], width: 0, diff --git a/papergrid/src/records/vec_records/mod.rs b/papergrid/src/records/vec_records/mod.rs index 15d3bb4b..12cb4796 100644 --- a/papergrid/src/records/vec_records/mod.rs +++ b/papergrid/src/records/vec_records/mod.rs @@ -12,7 +12,7 @@ use std::ops::{Deref, DerefMut}; use super::PeekableRecords; pub use cell::Cell; -pub use cell_info::{CellInfo, StrWithWidth}; +pub use cell_info::{StrWithWidth, Text}; /// A [Records] implementation based on allocated buffers. #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] diff --git a/papergrid/tests/grid/peekable_grid.rs b/papergrid/tests/grid/peekable_grid.rs index cb207bf4..6b3501dd 100644 --- a/papergrid/tests/grid/peekable_grid.rs +++ b/papergrid/tests/grid/peekable_grid.rs @@ -8,7 +8,7 @@ use papergrid::{ }, dimension::{spanned::SpannedGridDimension, Dimension}, grid::peekable::PeekableGrid, - records::vec_records::{CellInfo, VecRecords}, + records::vec_records::{Text, VecRecords}, }; use testing_table::test_table; @@ -73,7 +73,7 @@ test_table!( let data = data .iter() - .map(|row| row.iter().map(CellInfo::new).collect()) + .map(|row| row.iter().map(Text::new).collect()) .collect(); let records = VecRecords::new(data); @@ -145,7 +145,7 @@ test_table!( let data = data .iter() - .map(|row| row.iter().map(CellInfo::new).collect()) + .map(|row| row.iter().map(Text::new).collect()) .collect(); let records = VecRecords::new(data); diff --git a/tabled/src/builder/index_builder.rs b/tabled/src/builder/index_builder.rs index b4f317bf..3422cec0 100644 --- a/tabled/src/builder/index_builder.rs +++ b/tabled/src/builder/index_builder.rs @@ -1,4 +1,4 @@ -use crate::{grid::records::vec_records::CellInfo, Table}; +use crate::{grid::records::vec_records::Text, Table}; use super::Builder; @@ -47,9 +47,9 @@ use super::Builder; pub struct IndexBuilder { /// Index is an index data. /// It's always set. - index: Vec>, + index: Vec>, /// Name of an index - name: Option>, + name: Option>, /// A flag which checks if we need to actually use index. /// /// It might happen when it's only necessary to [`Self::transpose`] table. @@ -57,7 +57,7 @@ pub struct IndexBuilder { /// A flag which checks if table was transposed. transposed: bool, /// Data originated in [`Builder`]. - data: Vec>>, + data: Vec>>, /// A size of columns count_columns: usize, } @@ -123,7 +123,7 @@ impl IndexBuilder { /// ) /// ``` pub fn name(mut self, name: Option) -> Self { - self.name = name.map(CellInfo::new); + self.name = name.map(Text::new); self } @@ -257,7 +257,7 @@ fn build_index(mut b: IndexBuilder) -> Builder { // add index column if b.print_index { - b.index.insert(0, CellInfo::default()); + b.index.insert(0, Text::default()); insert_column(&mut b.data, b.index, 0); } @@ -266,7 +266,7 @@ fn build_index(mut b: IndexBuilder) -> Builder { b.data[0][0] = name; } else { let count_columns = b.data[0].len(); - let mut name_row = vec![CellInfo::default(); count_columns]; + let mut name_row = vec![Text::default(); count_columns]; name_row[0] = name; b.data.insert(1, name_row); @@ -276,8 +276,8 @@ fn build_index(mut b: IndexBuilder) -> Builder { Builder::from_vec(b.data) } -fn build_range_index(n: usize) -> Vec> { - (0..n).map(|i| i.to_string()).map(CellInfo::new).collect() +fn build_range_index(n: usize) -> Vec> { + (0..n).map(|i| i.to_string()).map(Text::new).collect() } fn get_column(v: &mut [Vec], col: usize) -> Vec diff --git a/tabled/src/builder/table_builder.rs b/tabled/src/builder/table_builder.rs index 019180d7..24d02492 100644 --- a/tabled/src/builder/table_builder.rs +++ b/tabled/src/builder/table_builder.rs @@ -1,6 +1,6 @@ use std::iter::FromIterator; -use crate::{grid::records::vec_records::CellInfo, Table}; +use crate::{grid::records::vec_records::Text, Table}; use super::IndexBuilder; @@ -39,11 +39,11 @@ use super::IndexBuilder; #[derive(Debug, Default, Clone)] pub struct Builder { /// A list of rows. - data: Vec>>, + data: Vec>>, /// A number of columns. count_columns: usize, /// A content of cells which are created in case rows has different length. - empty_text: CellInfo, + empty_text: Text, } impl Builder { @@ -87,13 +87,13 @@ impl Builder { /// let data = vec![]; /// let builder = Builder::from_vec(data); /// ``` - pub fn from_vec(data: Vec>>) -> Self { + pub fn from_vec(data: Vec>>) -> Self { let count_columns = if data.is_empty() { 0 } else { data[0].len() }; Self { data, count_columns, - empty_text: CellInfo::default(), + empty_text: Text::default(), } } @@ -112,7 +112,7 @@ impl Builder { where T: Into, { - self.empty_text = CellInfo::new(text.into()); + self.empty_text = Text::new(text.into()); } /// Build creates a [`Table`] instance. @@ -272,14 +272,14 @@ impl Builder { let text = iter .next() .map(Into::into) - .map(CellInfo::new) + .map(Text::new) .unwrap_or(self.empty_text.clone()); row.push(text); } for text in iter { - let text = CellInfo::new(text.into()); + let text = Text::new(text.into()); let mut row = Vec::with_capacity(self.count_columns + 1); for _ in 0..self.count_columns { @@ -311,14 +311,14 @@ impl Builder { let text = iter .next() .map(Into::into) - .map(CellInfo::new) + .map(Text::new) .unwrap_or(self.empty_text.clone()); row.insert(index, text); } for text in iter { - let text = CellInfo::new(text.into()); + let text = Text::new(text.into()); let mut row = Vec::with_capacity(self.count_columns + 1); for _ in 0..index { @@ -360,12 +360,12 @@ impl From for Vec> { builder .data .into_iter() - .map(|row| row.into_iter().map(CellInfo::into_inner).collect()) + .map(|row| row.into_iter().map(Text::into_inner).collect()) .collect() } } -impl From for Vec>> { +impl From for Vec>> { fn from(builder: Builder) -> Self { builder.data } @@ -399,7 +399,7 @@ impl From>> for Builder { fn from(data: Vec>) -> Self { let mut data = data .into_iter() - .map(|row| row.into_iter().map(CellInfo::new).collect()) + .map(|row| row.into_iter().map(Text::new).collect()) .collect(); let count_columns = equalize_row_length(&mut data); @@ -407,24 +407,24 @@ impl From>> for Builder { Self { data, count_columns, - empty_text: CellInfo::default(), + empty_text: Text::default(), } } } -impl From>>> for Builder { - fn from(mut data: Vec>>) -> Self { +impl From>>> for Builder { + fn from(mut data: Vec>>) -> Self { let count_columns = equalize_row_length(&mut data); Self { data, count_columns, - empty_text: CellInfo::default(), + empty_text: Text::default(), } } } -fn create_row(row: R, size: usize, default: &CellInfo) -> Vec> +fn create_row(row: R, size: usize, default: &Text) -> Vec> where R: IntoIterator, R::Item: Into, @@ -432,7 +432,7 @@ where let mut list = Vec::with_capacity(size); for text in row { let text = text.into(); - let text = CellInfo::new(text); + let text = Text::new(text); list.push(text); } @@ -446,7 +446,7 @@ where list } -fn remove_empty_columns(data: &mut [Vec>], count_columns: usize) -> usize { +fn remove_empty_columns(data: &mut [Vec>], count_columns: usize) -> usize { let mut deleted = 0; for col in 0..count_columns { let col = col - deleted; @@ -472,7 +472,7 @@ fn remove_empty_columns(data: &mut [Vec>], count_columns: usize deleted } -fn remove_empty_rows(data: &mut Vec>>, count_columns: usize) { +fn remove_empty_rows(data: &mut Vec>>, count_columns: usize) { let mut deleted = 0; for row in 0..data.len() { @@ -494,7 +494,7 @@ fn remove_empty_rows(data: &mut Vec>>, count_columns: usize } } -fn resize_rows(data: &mut Vec>>, size: usize, empty_text: &CellInfo) { +fn resize_rows(data: &mut Vec>>, size: usize, empty_text: &Text) { for row in data { append_vec(row, empty_text.clone(), size); } @@ -521,7 +521,7 @@ fn is_size_eq(expected: usize, new: usize) -> bool { } } -fn equalize_row_length(data: &mut Vec>>) -> usize { +fn equalize_row_length(data: &mut Vec>>) -> usize { if data.is_empty() { return 0; } @@ -536,7 +536,7 @@ fn equalize_row_length(data: &mut Vec>>) -> usize { }); if !is_consistent { - let empty_text = CellInfo::default(); + let empty_text = Text::default(); for row in data { let size = count_columns - row.len(); append_vec(row, empty_text.clone(), size); diff --git a/tabled/src/grid/dimension/peekable_dimension.rs b/tabled/src/grid/dimension/peekable_dimension.rs index d4480e8e..ec63349d 100644 --- a/tabled/src/grid/dimension/peekable_dimension.rs +++ b/tabled/src/grid/dimension/peekable_dimension.rs @@ -1,7 +1,7 @@ use crate::grid::{ config::SpannedConfig, dimension::{Dimension, Estimate}, - records::vec_records::{CellInfo, VecRecords}, + records::vec_records::{Text, VecRecords}, records::Records, }; @@ -16,18 +16,12 @@ pub struct PeekableDimension { impl PeekableDimension { /// Calculates height of rows. - pub fn height>( - records: &VecRecords>, - cfg: &SpannedConfig, - ) -> Vec { + pub fn height>(records: &VecRecords>, cfg: &SpannedConfig) -> Vec { estimation::build_height(records, cfg) } /// Calculates width of columns. - pub fn width>( - records: &VecRecords>, - cfg: &SpannedConfig, - ) -> Vec { + pub fn width>(records: &VecRecords>, cfg: &SpannedConfig) -> Vec { estimation::build_width(records, cfg) } @@ -47,11 +41,11 @@ impl Dimension for PeekableDimension { } } -impl Estimate<&VecRecords>, SpannedConfig> for PeekableDimension +impl Estimate<&VecRecords>, SpannedConfig> for PeekableDimension where T: AsRef, { - fn estimate(&mut self, records: &VecRecords>, cfg: &SpannedConfig) { + fn estimate(&mut self, records: &VecRecords>, cfg: &SpannedConfig) { let (width, height) = estimation::build_dimensions(records, cfg); self.width = width; self.height = height; @@ -67,7 +61,7 @@ mod estimation { use super::*; pub(super) fn build_dimensions>( - records: &VecRecords>, + records: &VecRecords>, cfg: &SpannedConfig, ) -> (Vec, Vec) { let count_columns = records.count_columns(); @@ -267,7 +261,7 @@ mod estimation { } pub(super) fn build_height>( - records: &VecRecords>, + records: &VecRecords>, cfg: &SpannedConfig, ) -> Vec { let mut heights = vec![]; @@ -299,7 +293,7 @@ mod estimation { } pub(super) fn build_width>( - records: &VecRecords>, + records: &VecRecords>, cfg: &SpannedConfig, ) -> Vec { let count_columns = records.count_columns(); diff --git a/tabled/src/grid/records/records_mut.rs b/tabled/src/grid/records/records_mut.rs index 38c42d2c..6017b732 100644 --- a/tabled/src/grid/records/records_mut.rs +++ b/tabled/src/grid/records/records_mut.rs @@ -1,6 +1,6 @@ use crate::grid::config::Position; #[cfg(feature = "std")] -use crate::grid::records::vec_records::{CellInfo, VecRecords}; +use crate::grid::records::vec_records::{Text, VecRecords}; /// A [`Records`] representation which can modify cell by (row, column) index. /// @@ -20,15 +20,15 @@ where } #[cfg(feature = "std")] -impl RecordsMut for VecRecords> { +impl RecordsMut for VecRecords> { fn set(&mut self, (row, col): Position, text: String) { - self[row][col] = CellInfo::new(text); + self[row][col] = Text::new(text); } } #[cfg(feature = "std")] -impl RecordsMut<&str> for VecRecords> { +impl RecordsMut<&str> for VecRecords> { fn set(&mut self, (row, col): Position, text: &str) { - self[row][col] = CellInfo::new(text.to_string()); + self[row][col] = Text::new(text.to_string()); } } diff --git a/tabled/src/settings/location/mod.rs b/tabled/src/settings/location/mod.rs index 28d0716e..3f6340bc 100644 --- a/tabled/src/settings/location/mod.rs +++ b/tabled/src/settings/location/mod.rs @@ -219,7 +219,7 @@ fn bounds_to_usize( mod tests { use crate::{ grid::config::Entity, - grid::records::vec_records::CellInfo, + grid::records::vec_records::Text, grid::records::vec_records::VecRecords, settings::location::{ByColumnName, ByCondition, ByContent}, settings::object::Object, @@ -391,16 +391,11 @@ mod tests { fn cells(o: O, data: &[Vec]) -> Vec where - O: Object>>, + O: Object>>, { let data = data .iter() - .map(|row| { - row.iter() - .map(|n| n.to_string()) - .map(CellInfo::new) - .collect() - }) + .map(|row| row.iter().map(|n| n.to_string()).map(Text::new).collect()) .collect(); let records = VecRecords::new(data); diff --git a/tabled/src/settings/themes/column_names.rs b/tabled/src/settings/themes/column_names.rs index d0f7cd27..510f15c5 100644 --- a/tabled/src/settings/themes/column_names.rs +++ b/tabled/src/settings/themes/column_names.rs @@ -5,7 +5,7 @@ use crate::{ config::{AlignmentHorizontal, AlignmentVertical, ColoredConfig, Position}, dimension::{CompleteDimensionVecRecords, Dimension, Estimate}, records::{ - vec_records::{CellInfo, VecRecords}, + vec_records::{Text, VecRecords}, ExactRecords, PeekableRecords, Records, Resizable, }, util::string::string_width, @@ -223,12 +223,12 @@ impl ColumnNames { } } -impl TableOption>, ColoredConfig, CompleteDimensionVecRecords<'_>> +impl TableOption>, ColoredConfig, CompleteDimensionVecRecords<'_>> for ColumnNames { fn change( self, - records: &mut VecRecords>, + records: &mut VecRecords>, cfg: &mut ColoredConfig, dims: &mut CompleteDimensionVecRecords<'_>, ) { @@ -268,7 +268,7 @@ fn set_column_text( target_line: usize, alignments: ListValue, colors: Option>, - records: &mut VecRecords>, + records: &mut VecRecords>, dims: &mut CompleteDimensionVecRecords<'_>, cfg: &mut ColoredConfig, ) { @@ -304,7 +304,7 @@ fn set_row_text( target_line: usize, alignments: ListValue, colors: Option>, - records: &mut VecRecords>, + records: &mut VecRecords>, dims: &mut CompleteDimensionVecRecords<'_>, cfg: &mut ColoredConfig, ) { @@ -336,7 +336,7 @@ fn set_row_text( } fn get_column_names( - records: &mut VecRecords>, + records: &mut VecRecords>, opt: Option>, ) -> Vec { match opt { @@ -363,7 +363,7 @@ fn vec_set_size(mut data: Vec, size: usize) -> Vec { data } -fn collect_head(records: &mut VecRecords>) -> Vec { +fn collect_head(records: &mut VecRecords>) -> Vec { if records.count_rows() == 0 || records.count_columns() == 0 { return Vec::new(); } diff --git a/tabled/src/tables/table.rs b/tabled/src/tables/table.rs index 42b36601..1f72aa7b 100644 --- a/tabled/src/tables/table.rs +++ b/tabled/src/tables/table.rs @@ -13,7 +13,7 @@ use crate::{ }, dimension::{CompleteDimensionVecRecords, Dimension, Estimate, PeekableDimension}, records::{ - vec_records::{CellInfo, VecRecords}, + vec_records::{Text, VecRecords}, ExactRecords, Records, }, PeekableGrid, @@ -57,7 +57,7 @@ use crate::{ /// [`Style::ascii`]: crate::settings::Style::ascii #[derive(Debug, Clone, PartialEq, Eq)] pub struct Table { - records: VecRecords>, + records: VecRecords>, config: ColoredConfig, dimension: CompleteDimensionVecRecords<'static>, } @@ -75,7 +75,7 @@ impl Table { let mut header = Vec::with_capacity(T::LENGTH); for text in T::headers() { let text = text.into_owned(); - let cell = CellInfo::new(text); + let cell = Text::new(text); header.push(cell); } @@ -84,7 +84,7 @@ impl Table { let mut list = Vec::with_capacity(T::LENGTH); for text in row.fields().into_iter() { let text = text.into_owned(); - let cell = CellInfo::new(text); + let cell = Text::new(text); list.push(cell); } @@ -171,11 +171,8 @@ impl Table { /// It applies settings immediately. pub fn with(&mut self, option: O) -> &mut Self where - for<'a> O: TableOption< - VecRecords>, - ColoredConfig, - CompleteDimensionVecRecords<'a>, - >, + for<'a> O: + TableOption>, ColoredConfig, CompleteDimensionVecRecords<'a>>, { let reastimation_hint = option.hint_change(); let mut dims = self.dimension.from_origin(); @@ -198,8 +195,8 @@ impl Table { /// [`Location`]: crate::settings::location::Locator pub fn modify(&mut self, target: T, option: O) -> &mut Self where - T: Object>>, - O: CellOption>, ColoredConfig> + Clone, + T: Object>>, + O: CellOption>, ColoredConfig> + Clone, { for entity in target.cells(&self.records) { let opt = option.clone(); @@ -274,12 +271,12 @@ impl Table { } /// Returns a used records. - pub fn get_records(&self) -> &VecRecords> { + pub fn get_records(&self) -> &VecRecords> { &self.records } /// Returns a used records. - pub fn get_records_mut(&mut self) -> &mut VecRecords> { + pub fn get_records_mut(&mut self) -> &mut VecRecords> { &mut self.records } } @@ -469,7 +466,7 @@ fn set_width_table(f: &fmt::Formatter<'_>, cfg: &mut SpannedConfig, table: &Tabl fn print_grid( f: &mut F, - records: &VecRecords>, + records: &VecRecords>, cfg: &SpannedConfig, dims: D, colors: &ColorMap, diff --git a/tabled/tests/matrix/matrix.rs b/tabled/tests/matrix/matrix.rs index dcc73703..a99ee48d 100644 --- a/tabled/tests/matrix/matrix.rs +++ b/tabled/tests/matrix/matrix.rs @@ -7,7 +7,7 @@ use std::{ use tabled::{ grid::config::ColoredConfig, grid::dimension::CompleteDimensionVecRecords, - grid::records::vec_records::{CellInfo, VecRecords}, + grid::records::vec_records::{Text, VecRecords}, settings::{object::Segment, Alignment, Modify, TableOption}, Table, Tabled, }; @@ -93,11 +93,8 @@ impl Matrix { pub fn with(self, opt: O) -> Table where - for<'a> O: TableOption< - VecRecords>, - ColoredConfig, - CompleteDimensionVecRecords<'a>, - >, + for<'a> O: + TableOption>, ColoredConfig, CompleteDimensionVecRecords<'a>>, { let mut table = self.to_table(); table.with(opt); From 144bb0e383308a3876301e5eeb387cc951adbb0c Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 21:26:27 +0300 Subject: [PATCH 12/20] rename string_width_multiline into get_string_width --- papergrid/src/dimension/compact.rs | 4 +- papergrid/src/dimension/spanned.rs | 6 +-- papergrid/src/grid/compact.rs | 4 +- papergrid/src/grid/iterable.rs | 12 +++--- papergrid/src/grid/peekable.rs | 14 +++---- papergrid/src/records/peekable_records.rs | 4 +- .../src/records/vec_records/cell_info.rs | 6 +-- papergrid/src/util/string.rs | 41 +++++++++---------- tabled/examples/shadow.rs | 2 +- .../records/into_records/truncate_records.rs | 5 +-- tabled/src/settings/measurement/mod.rs | 4 +- tabled/src/settings/themes/column_names.rs | 14 +++---- tabled/src/settings/width/min_width.rs | 8 ++-- tabled/src/settings/width/truncate.rs | 6 +-- tabled/src/settings/width/wrap.rs | 4 +- tabled/src/tables/compact.rs | 4 +- tabled/src/tables/extended.rs | 10 ++--- tabled/src/tables/table_pool.rs | 12 +++--- tabled/src/util/string.rs | 8 ++-- tabled/tests/settings/margin_test.rs | 5 +-- tabled/tests/settings/width_test.rs | 39 ++++++++---------- 21 files changed, 102 insertions(+), 110 deletions(-) diff --git a/papergrid/src/dimension/compact.rs b/papergrid/src/dimension/compact.rs index dc3835fa..a2a2148c 100644 --- a/papergrid/src/dimension/compact.rs +++ b/papergrid/src/dimension/compact.rs @@ -7,7 +7,7 @@ use core::cmp::max; use crate::{ dimension::{Dimension, Estimate}, records::{IntoRecords, Records}, - util::string::{count_lines, string_width_multiline}, + util::string::{count_lines, get_string_width}, }; use crate::config::compact::CompactConfig; @@ -139,7 +139,7 @@ fn get_cell_height(cell: &str, cfg: &CompactConfig) -> usize { } fn get_cell_width(text: &str, cfg: &CompactConfig) -> usize { - let width = string_width_multiline(text); + let width = get_string_width(text); let pad = cfg.get_padding(); width + pad.left.size + pad.right.size diff --git a/papergrid/src/dimension/spanned.rs b/papergrid/src/dimension/spanned.rs index 249104f7..3a9ec315 100644 --- a/papergrid/src/dimension/spanned.rs +++ b/papergrid/src/dimension/spanned.rs @@ -11,7 +11,7 @@ use crate::{ config::Position, dimension::{Dimension, Estimate}, records::{IntoRecords, Records}, - util::string::{count_lines, string_dimension, string_width_multiline}, + util::string::{count_lines, get_string_dimension, get_string_width}, }; use crate::config::spanned::SpannedConfig; @@ -112,7 +112,7 @@ where } let text = cell.as_ref(); - let (height, width) = string_dimension(text); + let (height, width) = get_string_dimension(text); let pad = cfg.get_padding(pos.into()); let width = width + pad.left.size + pad.right.size; let height = height + pad.top.size + pad.bottom.size; @@ -274,7 +274,7 @@ fn adjust_column_range( fn get_cell_width(text: &str, cfg: &SpannedConfig, pos: Position) -> usize { let padding = get_cell_padding(cfg, pos); - let width = string_width_multiline(text); + let width = get_string_width(text); width + padding } diff --git a/papergrid/src/grid/compact.rs b/papergrid/src/grid/compact.rs index f2bdd3e2..9f1814ee 100644 --- a/papergrid/src/grid/compact.rs +++ b/papergrid/src/grid/compact.rs @@ -12,7 +12,7 @@ use crate::{ config::{AlignmentHorizontal, Borders, HorizontalLine, Indent, Sides}, dimension::Dimension, records::{IntoRecords, Records}, - util::string::string_width, + util::string::get_line_width, }; use crate::config::compact::CompactConfig; @@ -563,7 +563,7 @@ where { let available = width - (padding.left.space.size + padding.right.space.size); - let text_width = string_width(text); + let text_width = get_line_width(text); let (left, right) = if available > text_width { calculate_indent(alignment, text_width, available) } else { diff --git a/papergrid/src/grid/iterable.rs b/papergrid/src/grid/iterable.rs index cdc07842..a2c07cfd 100644 --- a/papergrid/src/grid/iterable.rs +++ b/papergrid/src/grid/iterable.rs @@ -14,7 +14,7 @@ use crate::{ config::{AlignmentHorizontal, AlignmentVertical, Formatting, Indent, Position, Sides}, dimension::Dimension, records::{IntoRecords, Records}, - util::string::{count_lines, get_lines, string_width, string_width_multiline, Lines}, + util::string::{count_lines, get_line_width, get_lines, get_string_width, Lines}, }; /// Grid provides a set of methods for building a text-based table. @@ -301,12 +301,12 @@ fn print_single_line_column( let (text, text_width) = if fmt.horizontal_trim && !text.is_empty() { let text = string_trim(text); - let width = string_width(&text); + let width = get_line_width(&text); (text, width) } else { let text = Cow::Borrowed(text); - let width = string_width_multiline(&text); + let width = get_string_width(&text); (text, width) }; @@ -854,7 +854,7 @@ where line }; - let line_width = string_width(&line); + let line_width = get_line_width(&line); let available_width = self.width - self.pad.left.size - self.pad.right.size; let (left, right) = if self.fmt.allow_lines_alignment { @@ -1303,11 +1303,11 @@ fn count_empty_lines(cell: &str) -> (usize, usize, usize) { fn get_text_width(text: &str, trim: bool) -> usize { if trim { get_lines(text) - .map(|line| string_width(line.trim())) + .map(|line| get_line_width(line.trim())) .max() .unwrap_or(0) } else { - string_width_multiline(text) + get_string_width(text) } } diff --git a/papergrid/src/grid/peekable.rs b/papergrid/src/grid/peekable.rs index 5ba26140..27b5a470 100644 --- a/papergrid/src/grid/peekable.rs +++ b/papergrid/src/grid/peekable.rs @@ -17,7 +17,7 @@ use crate::{ config::{AlignmentHorizontal, AlignmentVertical, Entity, Indent, Position, Sides}, dimension::Dimension, records::{ExactRecords, PeekableRecords, Records}, - util::string::string_width, + util::string::get_line_width, }; /// Grid provides a set of methods for building a text-based table. @@ -390,7 +390,7 @@ mod grid_basic { let line = records.get_line(pos, index); let (line, line_width) = if cfg.formatting.horizontal_trim { let line = string_trim(line); - let width = string_width(&line); + let width = get_line_width(&line); (line, width) } else { let width = records.get_line_width(pos, index); @@ -405,7 +405,7 @@ mod grid_basic { let cell_width = if cfg.formatting.horizontal_trim { (0..records.count_lines(pos)) .map(|i| records.get_line(pos, i)) - .map(|line| string_width(line.trim())) + .map(|line| get_line_width(line.trim())) .max() .unwrap_or_default() } else { @@ -909,7 +909,7 @@ mod grid_not_spanned { let line = records.get_line(pos, index); let (line, line_width) = if cfg.formatting.horizontal_trim { let line = string_trim(line); - let width = string_width(&line); + let width = get_line_width(&line); (line, width) } else { let width = records.get_line_width(pos, index); @@ -925,7 +925,7 @@ mod grid_not_spanned { let cell_width = if cfg.formatting.horizontal_trim { (0..records.count_lines(pos)) .map(|i| records.get_line(pos, i)) - .map(|line| string_width(line.trim())) + .map(|line| get_line_width(line.trim())) .max() .unwrap_or_default() } else { @@ -1775,7 +1775,7 @@ mod grid_spanned { let line = records.get_line(pos, index); let (line, line_width) = if text_cfg.formatting.horizontal_trim { let line = string_trim(line); - let width = string_width(&line); + let width = get_line_width(&line); (line, width) } else { let width = records.get_line_width(pos, index); @@ -1791,7 +1791,7 @@ mod grid_spanned { let cell_width = if text_cfg.formatting.horizontal_trim { (0..records.count_lines(pos)) .map(|i| records.get_line(pos, i)) - .map(|line| string_width(line.trim())) + .map(|line| get_line_width(line.trim())) .max() .unwrap_or_default() } else { diff --git a/papergrid/src/records/peekable_records.rs b/papergrid/src/records/peekable_records.rs index 528ba5f0..b8726f4f 100644 --- a/papergrid/src/records/peekable_records.rs +++ b/papergrid/src/records/peekable_records.rs @@ -17,12 +17,12 @@ pub trait PeekableRecords { /// Returns a width of a text of a cell by an index. fn get_width(&self, pos: Position) -> usize { - crate::util::string::string_width_multiline(self.get_text(pos)) + crate::util::string::get_string_width(self.get_text(pos)) } /// Returns a width of line of a text of a cell by an index. fn get_line_width(&self, pos: Position, line: usize) -> usize { - crate::util::string::string_width(self.get_line(pos, line)) + crate::util::string::get_line_width(self.get_line(pos, line)) } } diff --git a/papergrid/src/records/vec_records/cell_info.rs b/papergrid/src/records/vec_records/cell_info.rs index 7c41bdc5..a3495338 100644 --- a/papergrid/src/records/vec_records/cell_info.rs +++ b/papergrid/src/records/vec_records/cell_info.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, cmp::max}; use crate::{ records::vec_records::Cell, - util::string::{self, count_lines, get_lines, string_width}, + util::string::{self, count_lines, get_line_width, get_lines}, }; /// The struct is a [Cell] implementation which keeps width information pre allocated. @@ -149,7 +149,7 @@ fn create_cell_info>(text: S) -> Text { // We check if there's only 1 line in which case we don't allocate lines Vec let count_lines = count_lines(info.text.as_ref()); if count_lines < 2 { - info.width = string::string_width_multiline(info.text.as_ref()); + info.width = string::get_string_width(info.text.as_ref()); return info; } @@ -171,7 +171,7 @@ fn create_cell_info>(text: S) -> Text { info.lines = vec![StrWithWidth::new(Cow::Borrowed(""), 0); count_lines]; for (line, i) in get_lines(text).zip(info.lines.iter_mut()) { - i.width = string_width(&line); + i.width = get_line_width(&line); i.text = line; info.width = max(info.width, i.width); } diff --git a/papergrid/src/util/string.rs b/papergrid/src/util/string.rs index 7e7f4a88..a0b8cf32 100644 --- a/papergrid/src/util/string.rs +++ b/papergrid/src/util/string.rs @@ -6,7 +6,7 @@ /// Returns string width and count lines of a string. It's a combination of [`string_width_multiline`] and [`count_lines`]. #[cfg(feature = "std")] -pub fn string_dimension(text: &str) -> (usize, usize) { +pub fn get_string_dimension(text: &str) -> (usize, usize) { #[cfg(not(feature = "ansi"))] { let (lines, acc, max) = text.chars().fold((1, 0, 0), |(lines, acc, max), c| { @@ -24,13 +24,13 @@ pub fn string_dimension(text: &str) -> (usize, usize) { #[cfg(feature = "ansi")] { get_lines(text) - .map(|line| string_width(&line)) + .map(|line| get_line_width(&line)) .fold((0, 0), |(i, acc), width| (i + 1, acc.max(width))) } } /// Returns a string width. -pub fn string_width(text: &str) -> usize { +pub fn get_line_width(text: &str) -> usize { #[cfg(not(feature = "ansi"))] { unicode_width::UnicodeWidthStr::width(text) @@ -50,7 +50,7 @@ pub fn string_width(text: &str) -> usize { } /// Returns a max string width of a line. -pub fn string_width_multiline(text: &str) -> usize { +pub fn get_string_width(text: &str) -> usize { #[cfg(not(feature = "ansi"))] { text.lines() @@ -61,7 +61,7 @@ pub fn string_width_multiline(text: &str) -> usize { #[cfg(feature = "ansi")] { - text.lines().map(string_width).max().unwrap_or(0) + text.lines().map(get_line_width).max().unwrap_or(0) } } @@ -181,22 +181,19 @@ mod tests { fn string_width_emojie_test() { // ...emojis such as “joy”, which normally take up two columns when printed in a terminal // https://github.com/mgeisler/textwrap/pull/276 - assert_eq!(string_width("🎩"), 2); - assert_eq!(string_width("Rust 💕"), 7); - assert_eq!(string_width_multiline("Go 👍\nC 😎"), 5); + assert_eq!(get_line_width("🎩"), 2); + assert_eq!(get_line_width("Rust 💕"), 7); + assert_eq!(get_string_width("Go 👍\nC 😎"), 5); } #[cfg(feature = "ansi")] #[test] fn colored_string_width_test() { use owo_colors::OwoColorize; - assert_eq!(string_width(&"hello world".red().to_string()), 11); - assert_eq!( - string_width_multiline(&"hello\nworld".blue().to_string()), - 5 - ); - assert_eq!(string_width("\u{1b}[34m0\u{1b}[0m"), 1); - assert_eq!(string_width(&"0".red().to_string()), 1); + assert_eq!(get_line_width(&"hello world".red().to_string()), 11); + assert_eq!(get_string_width(&"hello\nworld".blue().to_string()), 5); + assert_eq!(get_line_width("\u{1b}[34m0\u{1b}[0m"), 1); + assert_eq!(get_line_width(&"0".red().to_string()), 1); } #[test] @@ -212,7 +209,7 @@ mod tests { #[test] fn string_width_multinline_for_link() { assert_eq!( - string_width_multiline( + get_string_width( "\u{1b}]8;;file:///home/nushell/asd.zip\u{1b}\\asd.zip\u{1b}]8;;\u{1b}\\" ), 7 @@ -223,7 +220,9 @@ mod tests { #[test] fn string_width_for_link() { assert_eq!( - string_width("\u{1b}]8;;file:///home/nushell/asd.zip\u{1b}\\asd.zip\u{1b}]8;;\u{1b}\\"), + get_line_width( + "\u{1b}]8;;file:///home/nushell/asd.zip\u{1b}\\asd.zip\u{1b}]8;;\u{1b}\\" + ), 7 ); } @@ -232,7 +231,7 @@ mod tests { #[test] fn string_dimension_test() { assert_eq!( - string_dimension("\u{1b}[37mnow is the time for all good men\n\u{1b}[0m"), + get_string_dimension("\u{1b}[37mnow is the time for all good men\n\u{1b}[0m"), { #[cfg(feature = "ansi")] { @@ -245,11 +244,11 @@ mod tests { } ); assert_eq!( - string_dimension("now is the time for all good men\n"), + get_string_dimension("now is the time for all good men\n"), (2, 32) ); - assert_eq!(string_dimension("asd"), (1, 3)); - assert_eq!(string_dimension(""), (1, 0)); + assert_eq!(get_string_dimension("asd"), (1, 3)); + assert_eq!(get_string_dimension(""), (1, 0)); } #[cfg(feature = "std")] diff --git a/tabled/examples/shadow.rs b/tabled/examples/shadow.rs index bde2cfeb..33637f0a 100644 --- a/tabled/examples/shadow.rs +++ b/tabled/examples/shadow.rs @@ -129,7 +129,7 @@ fn create_small_table(style: Borders) -> Table { // todo: very likely can be simplified fn create_main_table(message: &str) -> Table { - let (count_lines, message_width) = string::string_dimension(message); + let (count_lines, message_width) = string::get_string_dimension(message); let count_additional_separators = if count_lines > 2 { count_lines - 2 } else { 0 }; let left_table_space = (0..count_additional_separators) .map(|_| " ║ \n") diff --git a/tabled/src/grid/records/into_records/truncate_records.rs b/tabled/src/grid/records/into_records/truncate_records.rs index 1bdc6ac3..19f83f6c 100644 --- a/tabled/src/grid/records/into_records/truncate_records.rs +++ b/tabled/src/grid/records/into_records/truncate_records.rs @@ -2,8 +2,7 @@ use crate::{ grid::dimension::Dimension, grid::records::into_records::either_string::EitherString, - grid::records::IntoRecords, grid::util::string::string_width_multiline, - settings::width::Truncate, + grid::records::IntoRecords, grid::util::string::get_string_width, settings::width::Truncate, }; /// A records iterator which truncates all cells to a given width. @@ -88,7 +87,7 @@ where let width = self.dimension.get_width(self.iter_column); self.iter_column += 1; - let text_width = string_width_multiline(text_ref); + let text_width = get_string_width(text_ref); let is_small = text_width <= width; if is_small { Some(EitherString::Some(text)) diff --git a/tabled/src/settings/measurement/mod.rs b/tabled/src/settings/measurement/mod.rs index a5bdf1de..e0c5cfc6 100644 --- a/tabled/src/settings/measurement/mod.rs +++ b/tabled/src/settings/measurement/mod.rs @@ -4,7 +4,7 @@ use crate::{ grid::config::SpannedConfig, grid::dimension::SpannedGridDimension, grid::records::{ExactRecords, IntoRecords, PeekableRecords, Records}, - grid::util::string::{self, string_width_multiline}, + grid::util::string::{self, get_string_width}, settings::{Height, Width}, }; @@ -119,7 +119,7 @@ where { let (count_rows, count_cols) = (records.count_rows(), records.count_columns()); (0..count_rows).map(move |row| { - (0..count_cols).map(move |col| string_width_multiline(records.get_text((row, col)))) + (0..count_cols).map(move |col| get_string_width(records.get_text((row, col)))) }) } diff --git a/tabled/src/settings/themes/column_names.rs b/tabled/src/settings/themes/column_names.rs index 510f15c5..698abc82 100644 --- a/tabled/src/settings/themes/column_names.rs +++ b/tabled/src/settings/themes/column_names.rs @@ -8,7 +8,7 @@ use crate::{ vec_records::{Text, VecRecords}, ExactRecords, PeekableRecords, Records, Resizable, }, - util::string::string_width, + util::string::get_line_width, }, settings::{ object::{Column, Row}, @@ -278,7 +278,7 @@ fn set_column_text( let widths = names .iter() .enumerate() - .map(|(col, name)| (cmp::max(string_width(name), dims.get_width(col)))) + .map(|(col, name)| (cmp::max(get_line_width(name), dims.get_width(col)))) .collect::>(); dims.set_widths(widths.clone()); @@ -314,7 +314,7 @@ fn set_row_text( let heights = names .iter() .enumerate() - .map(|(row, name)| (cmp::max(string_width(name), dims.get_height(row)))) + .map(|(row, name)| (cmp::max(get_line_width(name), dims.get_height(row)))) .collect::>(); dims.set_heights(heights.clone()); @@ -399,16 +399,16 @@ fn get_color(colors: &Option>, i: usize) -> Option<&Color> { fn get_horizontal_indent(text: &str, align: AlignmentHorizontal, available: usize) -> usize { match align { AlignmentHorizontal::Left => 0, - AlignmentHorizontal::Right => available - string_width(text), - AlignmentHorizontal::Center => (available - string_width(text)) / 2, + AlignmentHorizontal::Right => available - get_line_width(text), + AlignmentHorizontal::Center => (available - get_line_width(text)) / 2, } } fn get_vertical_indent(text: &str, align: AlignmentVertical, available: usize) -> usize { match align { AlignmentVertical::Top => 0, - AlignmentVertical::Bottom => available - string_width(text), - AlignmentVertical::Center => (available - string_width(text)) / 2, + AlignmentVertical::Bottom => available - get_line_width(text), + AlignmentVertical::Center => (available - get_line_width(text)) / 2, } } diff --git a/tabled/src/settings/width/min_width.rs b/tabled/src/settings/width/min_width.rs index 31faed6a..7e7ac5ce 100644 --- a/tabled/src/settings/width/min_width.rs +++ b/tabled/src/settings/width/min_width.rs @@ -6,7 +6,7 @@ use crate::{ grid::config::{ColoredConfig, Entity}, grid::dimension::CompleteDimensionVecRecords, grid::records::{ExactRecords, IntoRecords, PeekableRecords, Records, RecordsMut}, - grid::util::string::{get_lines, string_width_multiline}, + grid::util::string::{get_lines, get_string_width}, settings::{ measurement::Measurement, peaker::{Peaker, PriorityNone}, @@ -119,7 +119,7 @@ where } let cell = records.get_text(pos); - let cell_width = string_width_multiline(cell); + let cell_width = get_string_width(cell); if cell_width >= width { continue; } @@ -191,12 +191,12 @@ where } fn increase_width(s: &str, width: usize, fill_with: char) -> String { - use crate::grid::util::string::string_width; + use crate::grid::util::string::get_line_width; use std::{borrow::Cow, iter::repeat}; get_lines(s) .map(|line| { - let length = string_width(&line); + let length = get_line_width(&line); if length < width { let mut line = line.into_owned(); diff --git a/tabled/src/settings/width/truncate.rs b/tabled/src/settings/width/truncate.rs index 5ca02fee..1b3e7fc4 100644 --- a/tabled/src/settings/width/truncate.rs +++ b/tabled/src/settings/width/truncate.rs @@ -9,7 +9,7 @@ use crate::{ config::{ColoredConfig, Entity, SpannedConfig}, dimension::CompleteDimensionVecRecords, records::{EmptyRecords, ExactRecords, IntoRecords, PeekableRecords, Records, RecordsMut}, - util::string::{string_width, string_width_multiline}, + util::string::{get_line_width, get_string_width}, }, settings::{ measurement::Measurement, @@ -216,7 +216,7 @@ where let text = records.get_text(pos); - let cell_width = string_width_multiline(text); + let cell_width = get_string_width(text); if available >= cell_width { continue; } @@ -284,7 +284,7 @@ fn need_suffix_color_preservation(_suffix: &Option>) -> bool } fn make_suffix<'a>(suffix: &'a TruncateSuffix<'_>, width: usize) -> (Cow<'a, str>, usize) { - let suffix_length = string_width(&suffix.text); + let suffix_length = get_line_width(&suffix.text); if width > suffix_length { return (Cow::Borrowed(suffix.text.as_ref()), width - suffix_length); } diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs index 7a3efa1b..1b537474 100644 --- a/tabled/src/settings/width/wrap.rs +++ b/tabled/src/settings/width/wrap.rs @@ -9,7 +9,7 @@ use crate::{ config::{ColoredConfig, Entity}, dimension::CompleteDimensionVecRecords, records::{EmptyRecords, ExactRecords, IntoRecords, PeekableRecords, Records, RecordsMut}, - util::string::string_width_multiline, + util::string::get_string_width, }, settings::{ measurement::Measurement, @@ -151,7 +151,7 @@ where } let text = records.get_text(pos); - let cell_width = string_width_multiline(text); + let cell_width = get_string_width(text); if cell_width <= width { continue; } diff --git a/tabled/src/tables/compact.rs b/tabled/src/tables/compact.rs index 231ca078..a28a6547 100644 --- a/tabled/src/tables/compact.rs +++ b/tabled/src/tables/compact.rs @@ -76,7 +76,7 @@ use crate::{ into_records::{LimitColumns, LimitRows}, IntoRecords, IterRecords, }, - util::string::string_width, + util::string::get_line_width, CompactGrid, }, settings::{style::Style, TableOption}, @@ -256,7 +256,7 @@ where for row in mat.iter() { for (col, text) in row.iter().enumerate() { let text = text.as_ref(); - let text_width = string_width(text); + let text_width = get_line_width(text); width[col] = max(width[col], text_width); } } diff --git a/tabled/src/tables/extended.rs b/tabled/src/tables/extended.rs index 7a806e9a..ffc7bd83 100644 --- a/tabled/src/tables/extended.rs +++ b/tabled/src/tables/extended.rs @@ -48,7 +48,7 @@ //! assert_eq!(table, expected); //! ``` -use crate::grid::util::string::string_width; +use crate::grid::util::string::get_line_width; use crate::Tabled; use std::cell::RefCell; use std::fmt::{self, Debug, Display}; @@ -127,7 +127,7 @@ impl ExtendedTable { return false; } - let suffix_width = string_width(suffix); + let suffix_width = get_line_width(suffix); if max < suffix_width { return false; } @@ -137,7 +137,7 @@ impl ExtendedTable { let fields_max_width = self .fields .iter() - .map(|s| string_width(s)) + .map(|s| get_line_width(s)) .max() .unwrap_or_default(); @@ -208,14 +208,14 @@ impl Display for ExtendedTable { let max_field_width = fields .iter() - .map(|s| string_width(s)) + .map(|s| get_line_width(s)) .max() .unwrap_or_default(); let max_values_length = self .records .iter() - .map(|record| record.iter().map(|s| string_width(s)).max()) + .map(|record| record.iter().map(|s| get_line_width(s)).max()) .max() .unwrap_or_default() .unwrap_or_default(); diff --git a/tabled/src/tables/table_pool.rs b/tabled/src/tables/table_pool.rs index b1ee328c..991a98f9 100644 --- a/tabled/src/tables/table_pool.rs +++ b/tabled/src/tables/table_pool.rs @@ -251,7 +251,7 @@ mod print { dimension::{Dimension, DimensionPriority, Estimate, PoolTableDimension}, records::Records, util::string::{ - count_lines, get_lines, string_dimension, string_width, string_width_multiline, + count_lines, get_line_width, get_lines, get_string_dimension, get_string_width, }, }, settings::{Padding, Style, TableOption}, @@ -631,7 +631,7 @@ mod print { if lines_alignment { for line in get_lines(text) { - let line_width = string_width(&line); + let line_width = get_line_width(&line); let (left, right) = indent_horizontal(halignment, width, line_width); if border.has_left() { @@ -659,11 +659,11 @@ mod print { line_index += 1; } } else { - let text_width = string_width_multiline(text); + let text_width = get_string_width(text); let (left, _) = indent_horizontal(halignment, width, text_width); for line in get_lines(text) { - let line_width = string_width(&line); + let line_width = get_line_width(&line); let right = width - line_width - left; if border.has_left() { @@ -1465,7 +1465,7 @@ mod print { } fn str_dimension(text: &str, cfg: &CompactMultilineConfig) -> Dim { - let (count_lines, width) = string_dimension(text); + let (count_lines, width) = get_string_dimension(text); let w = width + get_padding_horizontal(cfg); let h = count_lines + get_padding_vertical(cfg); Dim::new(w, h) @@ -1590,7 +1590,7 @@ mod print { } let mut buf = String::new(); - let width = string_width_multiline(table); + let width = get_string_width(table); let top_color = color.top; let bottom_color = color.bottom; let left_color = color.left; diff --git a/tabled/src/util/string.rs b/tabled/src/util/string.rs index 7eadea8b..da632d68 100644 --- a/tabled/src/util/string.rs +++ b/tabled/src/util/string.rs @@ -180,7 +180,7 @@ pub(crate) fn strip_osc(text: &str) -> (String, Option) { mod tests { use super::*; - use crate::grid::util::string::string_width; + use crate::grid::util::string::get_line_width; #[cfg(feature = "ansi")] use owo_colors::{colors::Yellow, OwoColorize}; @@ -201,7 +201,7 @@ mod tests { assert_eq!(cut_str("🏳️🏳️", 0), ""); assert_eq!(cut_str("🏳️🏳️", 1), "🏳"); assert_eq!(cut_str("🏳️🏳️", 2), "🏳\u{fe0f}🏳"); - assert_eq!(string_width("🏳️🏳️"), string_width("🏳\u{fe0f}🏳\u{fe0f}")); + assert_eq!(get_line_width("🏳️🏳️"), get_line_width("🏳\u{fe0f}🏳\u{fe0f}")); assert_eq!(cut_str("🎓", 1), "�"); assert_eq!(cut_str("🎓", 2), "🎓"); @@ -257,8 +257,8 @@ mod tests { "\u{1b}[31;100m🏳\u{fe0f}🏳\u{1b}[39m\u{1b}[49m" ); assert_eq!( - string_width(&emojies), - string_width("\u{1b}[31;100m🏳\u{fe0f}🏳\u{fe0f}\u{1b}[39m\u{1b}[49m") + get_line_width(&emojies), + get_line_width("\u{1b}[31;100m🏳\u{fe0f}🏳\u{fe0f}\u{1b}[39m\u{1b}[49m") ); } diff --git a/tabled/tests/settings/margin_test.rs b/tabled/tests/settings/margin_test.rs index f103ed8e..3a29d02d 100644 --- a/tabled/tests/settings/margin_test.rs +++ b/tabled/tests/settings/margin_test.rs @@ -104,10 +104,7 @@ fn table_with_margin_and_max_width() { .with(Width::increase(50)) .to_string(); - assert_eq!( - tabled::grid::util::string::string_width_multiline(&table), - 50 - ); + assert_eq!(tabled::grid::util::string::get_string_width(&table), 50); assert_eq!( table, static_table!( diff --git a/tabled/tests/settings/width_test.rs b/tabled/tests/settings/width_test.rs index f26610ad..c06fd892 100644 --- a/tabled/tests/settings/width_test.rs +++ b/tabled/tests/settings/width_test.rs @@ -1,7 +1,7 @@ #![cfg(feature = "std")] use tabled::{ - grid::util::string::string_width_multiline, + grid::util::string::get_string_width, settings::{ formatting::{TabSize, TrimStrategy}, object::{Columns, Object, Rows, Segment}, @@ -877,7 +877,7 @@ fn total_width_big() { .with(MinWidth::new(80)) .to_string(); - assert_eq!(string_width_multiline(&table), 80); + assert_eq!(get_string_width(&table), 80); assert_eq!( table, static_table!( @@ -895,7 +895,7 @@ fn total_width_big() { .with(Settings::new(Width::truncate(80), Width::increase(80))) .to_string(); - assert_eq!(string_width_multiline(&table), 80); + assert_eq!(get_string_width(&table), 80); assert_eq!( table, static_table!( @@ -1366,7 +1366,7 @@ fn min_width_works_with_right_alignment() { ) .with(MinWidth::new(50)); - assert_eq!(string_width_multiline(&table.to_string()), 50); + assert_eq!(get_string_width(&table.to_string()), 50); assert_eq!( table.to_string(), static_table!( @@ -1458,7 +1458,7 @@ fn min_width_works_with_right_alignment() { "| |" ) ); - assert_eq!(string_width_multiline(&table.to_string()), 50); + assert_eq!(get_string_width(&table.to_string()), 50); table .with(Modify::new(Segment::all()).with(TrimStrategy::Horizontal)) @@ -1521,7 +1521,7 @@ fn min_width_with_span_1() { .with(MinWidth::new(100)) .to_string(); - assert_eq!(string_width_multiline(&table), 100); + assert_eq!(get_string_width(&table), 100); assert_eq!( table, static_table!( @@ -1549,7 +1549,7 @@ fn min_width_with_span_2() { .with(MinWidth::new(100)) .to_string(); - assert_eq!(string_width_multiline(&table), 100); + assert_eq!(get_string_width(&table), 100); assert_eq!( table, static_table!( @@ -1724,7 +1724,7 @@ fn max_width_truncate_with_big_span() { .with(Width::truncate(40)) .to_string(); - assert_eq!(string_width_multiline(&table), 40); + assert_eq!(get_string_width(&table), 40); assert_eq!( table, static_table!( @@ -1774,7 +1774,7 @@ fn max_width_truncate_with_big_span() { "| | 2-0 | Hello World With Big Line |" ) ); - assert_eq!(string_width_multiline(&table), 40); + assert_eq!(get_string_width(&table), 40); let table = Matrix::new(3, 3) .insert((2, 1), "Hello World With Big Line; Here we gooooooo") @@ -1785,7 +1785,7 @@ fn max_width_truncate_with_big_span() { .with(Width::truncate(40)) .to_string(); - assert_eq!(string_width_multiline(&table), 40); + assert_eq!(get_string_width(&table), 40); assert_eq!( table, static_table!( @@ -2211,7 +2211,7 @@ fn min_width_priority_max() { .with(MinWidth::new(60).priority(PriorityMax)) .to_string(); - assert_eq!(string_width_multiline(&table), 60); + assert_eq!(get_string_width(&table), 60); assert_eq!( table, static_table!( @@ -2231,7 +2231,7 @@ fn min_width_priority_min() { .with(MinWidth::new(60).priority(PriorityMin)) .to_string(); - assert_eq!(string_width_multiline(&table), 60); + assert_eq!(get_string_width(&table), 60); assert_eq!( table, static_table!( @@ -2273,7 +2273,7 @@ fn min_width_is_not_used_after_padding() { .with(Modify::new((0, 0)).with(Padding::new(2, 2, 0, 0))) .to_string(); - assert_eq!(string_width_multiline(&table), 40); + assert_eq!(get_string_width(&table), 40); assert_eq!( table, static_table!( @@ -2294,7 +2294,7 @@ fn min_width_is_used_after_margin() { .with(Width::increase(60)) .to_string(); - assert_eq!(string_width_multiline(&table), 60); + assert_eq!(get_string_width(&table), 60); assert_eq!( table, static_table!( @@ -2316,10 +2316,7 @@ fn wrap_keeping_words_0() { .with(Width::wrap(8).keep_words(true)) .to_string(); - assert_eq!( - tabled::grid::util::string::string_width_multiline(&table), - 8 - ); + assert_eq!(tabled::grid::util::string::get_string_width(&table), 8); assert_eq!( table, @@ -2612,7 +2609,7 @@ mod derived { "| \u{1b}[37m.4\u{1b}[39m | | | |" ) ); - assert_eq!(string_width_multiline(&table), 57); + assert_eq!(get_string_width(&table), 57); let table = Matrix::iter(&data) .with(Style::markdown()) @@ -2635,7 +2632,7 @@ mod derived { "| \u{1b}[37m.4\u{1b}[39m | | | |" ) ); - assert_eq!(string_width_multiline(&table), 57); + assert_eq!(get_string_width(&table), 57); } #[cfg(feature = "ansi")] @@ -2697,7 +2694,7 @@ mod derived { table, "| ver | published_d | is_act | major_feature |\n|-----|-------------|--------|--------------------------|\n| \u{1b}[31m0.2\u{1b}[39m | \u{1b}[48;2;8;10;30m\u{1b}[31m2021-06-23\u{1b}[39m\u{1b}[49m | true | \u{1b}[34;42m#[header(inline)] attrib\u{1b}[39m\u{1b}[49m |\n| \u{1b}[31m0.2\u{1b}[39m | \u{1b}[48;2;8;100;30m\u{1b}[32m2021-06-19\u{1b}[39m\u{1b}[49m | false | \u{1b}[33mAPI changes\u{1b}[39m |\n| \u{1b}[37m0.1\u{1b}[39m | \u{1b}[48;2;8;10;30m\u{1b}[31m2021-06-07\u{1b}[39m\u{1b}[49m | false | \u{1b}[31;40mdisplay_with attribute\u{1b}[0m |" ); - assert_eq!(string_width_multiline(&table), 57); + assert_eq!(get_string_width(&table), 57); } #[cfg(feature = "ansi")] From 1be84a40f974b016362b998023a0f41df9bd85cf Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 21:47:42 +0300 Subject: [PATCH 13/20] Refactorings theme --- tabled/src/settings/themes/theme.rs | 219 +++++++++++++--------------- 1 file changed, 98 insertions(+), 121 deletions(-) diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index 10008ad2..f7ec825b 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -25,48 +25,48 @@ use crate::{ /// It can be useful in order to not have a generics and be able to use it as a variable more conveniently. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Theme { - border: TableBorders, - lines: BorderLines, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct TableBorders { chars: Borders, colors: Borders, -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -struct BorderLines { - horizontal1: Option>, - horizontals: Option>>, - verticals: Option>>, + lines_horizontals: Option>>, + lines_verticals: Option>>, + lines_horizontal1: Option>, } impl Theme { + const fn gen( + chars: Borders, + colors: Borders, + lines_horizontals: Option>>, + lines_verticals: Option>>, + lines_horizontal1: Option>, + ) -> Self { + Self { + chars, + colors, + lines_horizontals, + lines_verticals, + lines_horizontal1, + } + } + /// Build a theme out of a style builder. pub const fn from_style( style: Style, ) -> Self { let chars = style.get_borders(); - let horizontals = style.get_horizontals(); - let horizontal1 = hlines_find(horizontals, 1); + let hlines = style.get_horizontals(); + let hlines1 = hlines_find(hlines, 1); - Self::_new( - TableBorders::new(chars, Borders::empty()), - BorderLines::new(horizontal1, None, None), - ) + Self::gen(chars, Borders::empty(), None, None, hlines1) } } impl Theme { /// Creates a new empty style. /// - /// It's quite an analog of [`Style::empty`] + /// It's an analog of [`Style::empty`] pub const fn new() -> Self { - Self::_new( - TableBorders::new(Borders::empty(), Borders::empty()), - BorderLines::new(None, None, None), - ) + Self::gen(Borders::empty(), Borders::empty(), None, None, None) } } @@ -80,7 +80,7 @@ macro_rules! func_set_chars { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Set a border character", " ", "", $desc, "", " ", ".")] pub fn $name(&mut self, c: char) { - self.border.chars.$arg = Some(c); + self.chars.$arg = Some(c); } }; } @@ -89,7 +89,7 @@ macro_rules! func_remove_chars { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Remove a border character", " ", "", $desc, "", " ", ".")] pub fn $name(&mut self) { - self.border.chars.$arg = None; + self.chars.$arg = None; } }; } @@ -98,7 +98,7 @@ macro_rules! func_get_chars { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Get a border character", " ", "", $desc, "", " ", ".")] pub const fn $name(&self) -> Option { - self.border.chars.$arg + self.chars.$arg } }; } @@ -107,7 +107,7 @@ macro_rules! func_set_colors { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Set a border color", " ", "", $desc, "", " ", ".")] pub fn $name(&mut self, color: Color) { - self.border.colors.$arg = Some(color); + self.colors.$arg = Some(color); } }; } @@ -116,7 +116,7 @@ macro_rules! func_remove_colors { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Remove a border color", " ", "", $desc, "", " ", ".")] pub fn $name(&mut self) { - self.border.colors.$arg = None; + self.colors.$arg = None; } }; } @@ -125,7 +125,7 @@ macro_rules! func_get_colors { ($name:ident, $arg:ident, $desc:expr) => { #[doc = concat!("Get a border color", " ", "", $desc, "", " ", ".")] pub fn $name(&self) -> Option<&Color> { - self.border.colors.$arg.as_ref() + self.colors.$arg.as_ref() } }; } @@ -247,73 +247,73 @@ impl Theme { impl Theme { /// Returns an outer border of the style. pub fn set_border_frame(&mut self, frame: Border) { - self.border.chars.top = frame.top; - self.border.chars.bottom = frame.bottom; - self.border.chars.left = frame.left; - self.border.chars.right = frame.right; - self.border.chars.top_left = frame.left_top_corner; - self.border.chars.top_right = frame.right_top_corner; - self.border.chars.bottom_left = frame.left_bottom_corner; - self.border.chars.bottom_right = frame.right_bottom_corner; + self.chars.top = frame.top; + self.chars.bottom = frame.bottom; + self.chars.left = frame.left; + self.chars.right = frame.right; + self.chars.top_left = frame.left_top_corner; + self.chars.top_right = frame.right_top_corner; + self.chars.bottom_left = frame.left_bottom_corner; + self.chars.bottom_right = frame.right_bottom_corner; } /// Returns an outer border of the style. pub fn set_border_color_frame(&mut self, frame: Border) { - self.border.colors.top = frame.top; - self.border.colors.bottom = frame.bottom; - self.border.colors.left = frame.left; - self.border.colors.right = frame.right; - self.border.colors.top_left = frame.left_top_corner; - self.border.colors.top_right = frame.right_top_corner; - self.border.colors.bottom_left = frame.left_bottom_corner; - self.border.colors.bottom_right = frame.right_bottom_corner; + self.colors.top = frame.top; + self.colors.bottom = frame.bottom; + self.colors.left = frame.left; + self.colors.right = frame.right; + self.colors.top_left = frame.left_top_corner; + self.colors.top_right = frame.right_top_corner; + self.colors.bottom_left = frame.left_bottom_corner; + self.colors.bottom_right = frame.right_bottom_corner; } /// Set borders structure. pub fn set_borders(&mut self, borders: Borders) { - self.border.chars = borders; + self.chars = borders; } /// Set borders structure. pub fn set_borders_colors(&mut self, borders: Borders) { - self.border.colors = borders; + self.colors = borders; } /// Set borders structure. pub const fn get_borders(&self) -> Borders { - self.border.chars + self.chars } /// Set borders structure. pub fn get_borders_colors(&self) -> Borders { - self.border.colors.clone() + self.colors.clone() } /// Set an outer border. pub const fn get_border_frame(&self) -> Border { Border { - top: self.border.chars.top, - bottom: self.border.chars.bottom, - left: self.border.chars.left, - right: self.border.chars.right, - left_top_corner: self.border.chars.top_left, - right_top_corner: self.border.chars.top_right, - left_bottom_corner: self.border.chars.bottom_left, - right_bottom_corner: self.border.chars.bottom_right, + top: self.chars.top, + bottom: self.chars.bottom, + left: self.chars.left, + right: self.chars.right, + left_top_corner: self.chars.top_left, + right_top_corner: self.chars.top_right, + left_bottom_corner: self.chars.bottom_left, + right_bottom_corner: self.chars.bottom_right, } } /// Set an outer border. pub const fn get_border_color_frame(&self) -> Border<&Color> { Border { - top: self.border.colors.top.as_ref(), - bottom: self.border.colors.bottom.as_ref(), - left: self.border.colors.left.as_ref(), - right: self.border.colors.right.as_ref(), - left_top_corner: self.border.colors.top_left.as_ref(), - right_top_corner: self.border.colors.top_right.as_ref(), - left_bottom_corner: self.border.colors.bottom_left.as_ref(), - right_bottom_corner: self.border.colors.bottom_right.as_ref(), + top: self.colors.top.as_ref(), + bottom: self.colors.bottom.as_ref(), + left: self.colors.left.as_ref(), + right: self.colors.right.as_ref(), + left_top_corner: self.colors.top_left.as_ref(), + right_top_corner: self.colors.top_right.as_ref(), + left_bottom_corner: self.colors.bottom_left.as_ref(), + right_bottom_corner: self.colors.bottom_right.as_ref(), } } } @@ -351,7 +351,7 @@ impl Theme { /// ) /// ``` pub fn set_lines_horizontal(&mut self, lines: HashMap>) { - self.lines.horizontals = Some(lines); + self.lines_horizontals = Some(lines); } /// Set vertical border lines. @@ -391,78 +391,72 @@ impl Theme { /// ) /// ``` pub fn set_lines_vertical(&mut self, lines: HashMap>) { - self.lines.verticals = Some(lines); + self.lines_verticals = Some(lines); } /// Insert a vertical line into specific column location. pub fn insert_line_vertical(&mut self, line: usize, vertical: VerticalLine) { - match &mut self.lines.verticals { + match &mut self.lines_verticals { Some(verticals) => { let _ = verticals.insert(line, vertical); } - None => self.lines.verticals = Some(HashMap::from_iter([(line, vertical)])), + None => self.lines_verticals = Some(HashMap::from_iter([(line, vertical)])), } } /// Insert a horizontal line to a specific row location. pub fn insert_line_horizontal(&mut self, line: usize, horizontal: HorizontalLine) { - match &mut self.lines.horizontals { + match &mut self.lines_horizontals { Some(horizontals) => { let _ = horizontals.insert(line, horizontal); } - None => self.lines.horizontals = Some(HashMap::from_iter([(line, horizontal)])), + None => self.lines_horizontals = Some(HashMap::from_iter([(line, horizontal)])), } } /// Get a vertical line at the row if any set. pub fn get_line_vertical(&self, column: usize) -> Option> { - self.lines - .verticals + self.lines_verticals .as_ref() .and_then(|lines| lines.get(&column).cloned()) } /// Get a horizontal line at the row if any set. pub fn get_line_horizontal(&self, row: usize) -> Option> { - self.lines - .horizontals + self.lines_horizontals .as_ref() .and_then(|list| list.get(&row).cloned()) } } -impl Theme { - const fn _new(border: TableBorders, lines: BorderLines) -> Self { - Self { border, lines } - } -} - impl From> for Theme { fn from(borders: Borders) -> Self { - Self::_new( - TableBorders::new(borders, Borders::empty()), - BorderLines::new(None, None, None), - ) + Self::gen(borders, Borders::empty(), None, None, None) } } impl TableOption for Theme { fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { cfg_clear_borders(cfg); - cfg_set_custom_lines(cfg, self.lines); - cfg_set_borders(cfg, self.border); + cfg_set_custom_lines( + cfg, + self.lines_horizontals, + self.lines_verticals, + self.lines_horizontal1, + ); + cfg_set_borders(cfg, self.chars, self.colors); } } impl TableOption for Theme { fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { - *cfg = cfg.set_borders(self.border.chars); + *cfg = cfg.set_borders(self.chars); } } impl TableOption for Theme { fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { - cfg.set_borders(self.border.chars); + cfg.set_borders(self.chars); } } @@ -481,29 +475,7 @@ impl From for Theme { let horizontals = cfg.get_horizontal_lines().into_iter().collect(); let verticals = cfg.get_vertical_lines().into_iter().collect(); - let borders = TableBorders::new(borders, colors); - let lines = BorderLines::new(None, Some(horizontals), Some(verticals)); - Self::_new(borders, lines) - } -} - -impl TableBorders { - const fn new(chars: Borders, colors: Borders) -> Self { - Self { chars, colors } - } -} - -impl BorderLines { - const fn new( - horizontal1: Option>, - horizontals: Option>>, - verticals: Option>>, - ) -> Self { - Self { - horizontal1, - horizontals, - verticals, - } + Self::gen(borders, colors, Some(horizontals), Some(verticals), None) } } @@ -516,26 +488,31 @@ fn cfg_clear_borders(cfg: &mut ColoredConfig) { cfg.remove_color_line_vertical(); } -fn cfg_set_borders(cfg: &mut ColoredConfig, border: TableBorders) { - cfg.set_borders(border.chars); +fn cfg_set_borders(cfg: &mut ColoredConfig, borders: Borders, colors: Borders) { + cfg.set_borders(borders); - if !border.colors.is_empty() { - cfg.set_borders_color(border.colors.convert_into()); + if !colors.is_empty() { + cfg.set_borders_color(colors.convert_into()); } } -fn cfg_set_custom_lines(cfg: &mut ColoredConfig, lines: BorderLines) { - if let Some(line) = lines.horizontal1 { +fn cfg_set_custom_lines( + cfg: &mut ColoredConfig, + horizontals: Option>>, + verticals: Option>>, + horizontal1: Option>, +) { + if let Some(line) = horizontal1 { cfg.insert_horizontal_line(1, line); } - if let Some(lines) = lines.horizontals { + if let Some(lines) = horizontals { for (row, line) in lines { cfg.insert_horizontal_line(row, line); } } - if let Some(lines) = lines.verticals { + if let Some(lines) = verticals { for (col, line) in lines { cfg.insert_vertical_line(col, line); } From 8efc2f7a249f4c90d16809548206a1b35a194b27 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sat, 20 Jul 2024 23:07:15 +0300 Subject: [PATCH 14/20] Fix --- tabled/tests/qc/tests/builder.rs | 6 +++--- tabled/tests/qc/tests/span.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tabled/tests/qc/tests/builder.rs b/tabled/tests/qc/tests/builder.rs index 6f1822b7..cb9356d6 100644 --- a/tabled/tests/qc/tests/builder.rs +++ b/tabled/tests/qc/tests/builder.rs @@ -2,7 +2,7 @@ use quickcheck::Arbitrary; use quickcheck_macros::quickcheck; use tabled::{ builder::Builder, - grid::util::string::{string_width, string_width_multiline}, + grid::util::string::{get_line_width, get_string_width}, settings::Style, Table, }; @@ -20,7 +20,7 @@ fn qc_table_is_consistent(data: Vec>) -> bool { let lines = table.lines().collect::>(); let lines_has_the_same_length = lines .iter() - .map(|line| string_width(line)) + .map(|line| get_line_width(line)) .all(|line_width| line_width == lines[0].len()); lines_has_the_same_length } @@ -37,7 +37,7 @@ fn qc_table_is_consistent_with_borders(table_structure: TableStructure) { let output = table.to_string(); if let Some(line) = output.lines().next() { - assert_eq!(string_width(line), string_width_multiline(&output)); + assert_eq!(get_line_width(line), get_string_width(&output)); } } diff --git a/tabled/tests/qc/tests/span.rs b/tabled/tests/qc/tests/span.rs index 5a57b7dc..db28403f 100644 --- a/tabled/tests/qc/tests/span.rs +++ b/tabled/tests/qc/tests/span.rs @@ -3,13 +3,13 @@ use quickcheck_macros::quickcheck; use tabled::{ builder::Builder, - grid::util::string::{string_width, string_width_multiline}, + grid::util::string::{get_line_width, get_string_width}, settings::{Modify, Span, Style}, Table, }; #[quickcheck] -fn qc_table_is_consistent_with_hspan_and_vspan(table_structure: TableStructure) { +fn qc_tget_string_widthable_is_consistent_with_hspan_and_vspan(table_structure: TableStructure) { let mut table = create_table(table_structure.rows); set_theme(&mut table, table_structure.theme); set_span_hspan(&mut table, &table_structure.row_span); @@ -18,7 +18,7 @@ fn qc_table_is_consistent_with_hspan_and_vspan(table_structure: TableStructure) let output = table.to_string(); if let Some(line) = output.lines().next() { - assert_eq!(string_width(line), string_width_multiline(&output)); + assert_eq!(get_line_width(line), get_string_width(&output)); } } @@ -31,7 +31,7 @@ fn qc_table_is_consistent_with_hspan(table_structure: TableStructure) { let output = table.to_string(); if let Some(line) = output.lines().next() { - assert_eq!(string_width(line), string_width_multiline(&output)); + assert_eq!(get_line_width(line), get_string_width(&output)); } } @@ -44,7 +44,7 @@ fn qc_table_is_consistent_with_vspan(table_structure: TableStructure) { let output = table.to_string(); if let Some(line) = output.lines().next() { - assert_eq!(string_width(line), string_width_multiline(&output)); + assert_eq!(get_line_width(line), get_string_width(&output)); } } @@ -134,7 +134,7 @@ fn test_data_span_test() { let output = table.to_string(); if let Some(line) = output.lines().next() { - assert_eq!(string_width(line), string_width_multiline(&output)); + assert_eq!(get_line_width(line), get_string_width(&output)); } } From 481bdc32b04830d9998f6fff3956de6bbb0be274 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sun, 21 Jul 2024 00:04:59 +0300 Subject: [PATCH 15/20] Rename wrap::wrap_text and truncate::truncate_text --- tabled/src/grid/records/into_records/truncate_records.rs | 2 +- tabled/src/settings/width/truncate.rs | 2 +- tabled/src/settings/width/wrap.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tabled/src/grid/records/into_records/truncate_records.rs b/tabled/src/grid/records/into_records/truncate_records.rs index 19f83f6c..3a97ea77 100644 --- a/tabled/src/grid/records/into_records/truncate_records.rs +++ b/tabled/src/grid/records/into_records/truncate_records.rs @@ -92,7 +92,7 @@ where if is_small { Some(EitherString::Some(text)) } else { - let text = Truncate::truncate_text(text_ref, width); + let text = Truncate::truncate(text_ref, width); let text = text.into_owned(); Some(EitherString::Owned(text)) } diff --git a/tabled/src/settings/width/truncate.rs b/tabled/src/settings/width/truncate.rs index 1b3e7fc4..cfe01b76 100644 --- a/tabled/src/settings/width/truncate.rs +++ b/tabled/src/settings/width/truncate.rs @@ -179,7 +179,7 @@ impl<'a, W, P> Truncate<'a, W, P> { impl Truncate<'_, (), ()> { /// Truncate a given string - pub fn truncate_text(text: &str, width: usize) -> Cow<'_, str> { + pub fn truncate(text: &str, width: usize) -> Cow<'_, str> { truncate_text(text, width, "", false) } } diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs index 1b537474..91220de4 100644 --- a/tabled/src/settings/width/wrap.rs +++ b/tabled/src/settings/width/wrap.rs @@ -94,7 +94,7 @@ impl Wrap { impl Wrap<(), ()> { /// Wrap a given string - pub fn wrap_text(text: &str, width: usize, keeping_words: bool) -> String { + pub fn wrap(text: &str, width: usize, keeping_words: bool) -> String { wrap_text(text, width, keeping_words) } } From 1cabb32310e133e2e14ed694354c2d32453fa16e Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sun, 21 Jul 2024 03:23:45 +0300 Subject: [PATCH 16/20] Simplify examples && refactoring Theme --- tabled/Cargo.toml | 16 +- tabled/examples/border_text.rs | 12 +- tabled/examples/colored_borders.rs | 30 +- tabled/examples/derive/crate_override.rs | 22 +- tabled/examples/derive/display_with.rs | 54 +-- tabled/examples/derive/format.rs | 21 +- tabled/examples/derive/format2.rs | 61 --- tabled/examples/derive/format_enum.rs | 25 ++ tabled/examples/derive/inline.rs | 32 +- tabled/examples/derive/inline_enum.rs | 23 +- tabled/examples/derive/order.rs | 33 +- tabled/examples/derive/rename.rs | 33 +- tabled/examples/derive/rename_all.rs | 31 +- tabled/examples/derive/skip.rs | 33 +- tabled/src/settings/themes/theme.rs | 468 ++++++++++++----------- tabled/tests/derive/derive_test.rs | 67 ++++ tabled/tests/settings/panel_test.rs | 4 +- tabled/tests/settings/style_test.rs | 28 +- 18 files changed, 496 insertions(+), 497 deletions(-) delete mode 100644 tabled/examples/derive/format2.rs create mode 100644 tabled/examples/derive/format_enum.rs diff --git a/tabled/Cargo.toml b/tabled/Cargo.toml index b1532d1a..033fd38f 100644 --- a/tabled/Cargo.toml +++ b/tabled/Cargo.toml @@ -39,12 +39,12 @@ path = "examples/derive/rename_all.rs" required-features = ["derive"] [[example]] -name = "rename" +name = "derive_rename" path = "examples/derive/rename.rs" required-features = ["derive"] [[example]] -name = "order" +name = "derive_order" path = "examples/derive/order.rs" required-features = ["derive"] @@ -54,22 +54,22 @@ path = "examples/derive/skip.rs" required-features = ["derive"] [[example]] -name = "inline" +name = "derive_inline" path = "examples/derive/inline.rs" required-features = ["derive"] [[example]] -name = "inline_enum" +name = "derive_inline_enum" path = "examples/derive/inline_enum.rs" required-features = ["derive"] [[example]] -name = "display_with" +name = "derive_display_with" path = "examples/derive/display_with.rs" required-features = ["derive"] [[example]] -name = "crate_override" +name = "derive_crate_override" path = "examples/derive/crate_override.rs" required-features = ["derive"] @@ -79,8 +79,8 @@ path = "examples/derive/format.rs" required-features = ["derive"] [[example]] -name = "derive_format2" -path = "examples/derive/format2.rs" +name = "derive_format_enum" +path = "examples/derive/format_enum.rs" required-features = ["derive"] [[example]] diff --git a/tabled/examples/border_text.rs b/tabled/examples/border_text.rs index 52eb8592..99d9aa1a 100644 --- a/tabled/examples/border_text.rs +++ b/tabled/examples/border_text.rs @@ -22,6 +22,7 @@ use tabled::{ settings::{ object::Rows, style::{HorizontalLine, LineText, Style, VerticalLine}, + Theme, }, Table, }; @@ -29,15 +30,18 @@ use tabled::{ fn main() { let data = [[5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]; - let line = HorizontalLine::inherit(Style::modern()) + let hline = HorizontalLine::inherit(Style::modern()) .left(VerticalLine::inherit_left(Style::modern()).get_vertical()); - let style = Style::modern().remove_horizontal().horizontals([(1, line)]); + + let mut theme = Theme::from_style(Style::modern()); + theme.remove_horizontal_lines(); + theme.insert_horizontal_line(1, hline.into()); let table = Table::new(data) - .with(style) + .with(theme) .with(LineText::new("Numbers", Rows::first()).offset(1)) .with(LineText::new("More numbers", Rows::single(1)).offset(1)) - .with(LineText::new("end.", Rows::last()).offset(1)) + .with(LineText::new("end", Rows::last()).offset(1)) .to_string(); println!("{table}"); diff --git a/tabled/examples/colored_borders.rs b/tabled/examples/colored_borders.rs index 789ffaf1..6f6c5d6d 100644 --- a/tabled/examples/colored_borders.rs +++ b/tabled/examples/colored_borders.rs @@ -31,21 +31,21 @@ impl CodeEditor { fn main() { let mut style = Theme::from(Style::extended()); - style.set_border_color_top(Color::FG_RED); - style.set_border_color_bottom(Color::FG_CYAN); - style.set_border_color_left(Color::FG_BLUE); - style.set_border_color_right(Color::FG_GREEN); - style.set_border_color_corner_top_left(Color::FG_BLUE); - style.set_border_color_corner_top_right(Color::FG_RED); - style.set_border_color_corner_bottom_left(Color::FG_CYAN); - style.set_border_color_corner_bottom_right(Color::FG_GREEN); - style.set_border_color_intersection_bottom(Color::FG_CYAN); - style.set_border_color_intersection_top(Color::FG_RED); - style.set_border_color_intersection_right(Color::FG_GREEN); - style.set_border_color_intersection_left(Color::FG_BLUE); - style.set_border_color_intersection(Color::FG_MAGENTA); - style.set_border_color_horizontal(Color::FG_MAGENTA); - style.set_border_color_vertical(Color::FG_MAGENTA); + style.set_colors_top(Color::FG_RED); + style.set_colors_bottom(Color::FG_CYAN); + style.set_colors_left(Color::FG_BLUE); + style.set_colors_right(Color::FG_GREEN); + style.set_colors_corner_top_left(Color::FG_BLUE); + style.set_colors_corner_top_right(Color::FG_RED); + style.set_colors_corner_bottom_left(Color::FG_CYAN); + style.set_colors_corner_bottom_right(Color::FG_GREEN); + style.set_colors_intersection_bottom(Color::FG_CYAN); + style.set_colors_intersection_top(Color::FG_RED); + style.set_colors_intersection_right(Color::FG_GREEN); + style.set_colors_intersection_left(Color::FG_BLUE); + style.set_colors_intersection(Color::FG_MAGENTA); + style.set_colors_horizontal(Color::FG_MAGENTA); + style.set_colors_vertical(Color::FG_MAGENTA); let data = [ CodeEditor::new("Sublime Text 3", "2008", "Sublime HQ"), diff --git a/tabled/examples/derive/crate_override.rs b/tabled/examples/derive/crate_override.rs index ca37528e..ea96fc55 100644 --- a/tabled/examples/derive/crate_override.rs +++ b/tabled/examples/derive/crate_override.rs @@ -8,21 +8,23 @@ pub mod unknown_crate { pub use ::tabled::{Table, Tabled}; } +// make sure we are not using default 'tabled::*' path #[allow(non_camel_case_types, dead_code)] type tabled = usize; -use unknown_crate::{Table, Tabled}; - -#[derive(Tabled)] +#[derive(unknown_crate::Tabled)] #[tabled(crate = "unknown_crate")] -struct Country<'a> { - name: &'a str, - capital_city: &'a str, +struct Country { + name: String, + city: String, } -impl<'a> Country<'a> { - fn new(name: &'a str, capital_city: &'a str) -> Self { - Self { name, capital_city } +impl Country { + fn new(name: &str, city: &str) -> Self { + Self { + name: name.to_string(), + city: city.to_string(), + } } } @@ -33,7 +35,7 @@ fn main() { Country::new("Canada", "Ottawa"), ]; - let table = Table::new(data); + let table = unknown_crate::Table::new(data); println!("{table}"); } diff --git a/tabled/examples/derive/display_with.rs b/tabled/examples/derive/display_with.rs index c011801e..b66da8c1 100644 --- a/tabled/examples/derive/display_with.rs +++ b/tabled/examples/derive/display_with.rs @@ -15,53 +15,37 @@ use std::borrow::Cow; use tabled::{Table, Tabled}; #[derive(Tabled)] -#[tabled(rename_all = "camelCase")] struct Country { - name: &'static str, - #[tabled(display_with("display_capital", format!("CAPITAL {}", self.capital_city)))] - capital_city: &'static str, + name: String, + #[tabled(display_with = "str::to_uppercase")] + capital: String, #[tabled(display_with("display_perimeter", self))] - surface_area_km2: f32, - #[tabled(display_with = "str::to_lowercase")] - national_currency: &'static str, - national_currency_short: &'static str, -} - -fn display_perimeter(country: &Country) -> Cow<'_, str> { - if country.surface_area_km2 > 1_000_000.0 { - "Very Big Land".into() - } else { - "Big Land".into() - } -} - -fn display_capital(country: String) -> Cow<'static, str> { - format!("{country}!").into() + area_km2: f32, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, capital: &str, area_km2: f32) -> Self { Self { - name, - national_currency, - national_currency_short, - capital_city, - surface_area_km2, + name: name.to_string(), + capital: capital.to_string(), + area_km2, } } } +fn display_perimeter(country: &Country) -> Cow<'_, str> { + if country.area_km2 > 1_000_000.0 { + "BIG".into() + } else { + "small".into() + } +} + fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Kabul", 652867.0), + Country::new("Angola", "Luanda", 1246700.0), + Country::new("Canada", "Ottawa", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/examples/derive/format.rs b/tabled/examples/derive/format.rs index 0dc31cd4..6ddc3cf8 100644 --- a/tabled/examples/derive/format.rs +++ b/tabled/examples/derive/format.rs @@ -7,28 +7,31 @@ use tabled::{settings::Style, Table, Tabled}; struct Phone { #[tabled(format = "code {}")] code: String, - #[tabled(skip)] - alias: String, - #[tabled(format("{}/{}", str::to_lowercase(&self.alias), self.number))] + #[tabled(rename = "")] + #[tabled(format("{}/{}", self.alias.join(","), self.number))] number: String, + #[tabled(skip)] + alias: Vec, } impl Phone { - fn new(code: &str, alias: &str, number: &str) -> Self { + fn new(code: &str, number: &str, alias: &[&str]) -> Self { + let alias = alias.iter().map(ToString::to_string).collect(); + Self { code: code.to_string(), - alias: alias.to_string(), number: number.to_string(), + alias, } } } fn main() { let data = [ - Phone::new("AFN", "Mate", "11111111"), - Phone::new("CAD", "Sara", "22222222"), - Phone::new("RUS", "Cris", "33333333"), - Phone::new("BLR", "Ham", "44444444"), + Phone::new("AFN", "11111111", &["Mate"]), + Phone::new("CAD", "22222222", &["Sara", "Football", "meetup"]), + Phone::new("RUS", "33333333", &["Cris", "meetup"]), + Phone::new("BLR", "44444444", &["Ham", "meetup"]), ]; let mut table = Table::new(data); diff --git a/tabled/examples/derive/format2.rs b/tabled/examples/derive/format2.rs deleted file mode 100644 index 5550dd7c..00000000 --- a/tabled/examples/derive/format2.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! This example demonstrates using the [attribute macro](https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros) -//! [`format`] to beatifuly castomize the resulting values, be used for table contraction. - -use tabled::{settings::Style, Table, Tabled}; - -#[derive(Tabled)] -struct User { - #[tabled(format("{}.{}.{}.{}", self.ip[0], self.ip[1], self.ip[2], self.ip[3]))] - ip: [u8; 4], - #[tabled(inline)] - password: Password, -} - -#[derive(Tabled)] -enum Password { - #[tabled(inline)] - Mask { - #[tabled(format("T {}", str::to_uppercase(self.text)))] - text: String, - #[tabled(format = "F {}")] - factor: usize, - }, - #[tabled(inline)] - Plain(String), -} - -impl Password { - fn mask(s: &str, f: usize) -> Self { - Self::Mask { - text: s.to_string(), - factor: f, - } - } - - fn plain(s: &str) -> Self { - Self::Plain(s.to_string()) - } -} - -impl User { - fn new(ip: [u8; 4], password: Password) -> Self { - Self { ip, password } - } -} - -fn main() { - let data = [ - User::new([127, 0, 0, 1], Password::mask("11111111", 0)), - User::new([127, 0, 0, 1], Password::mask("1", 1000)), - User::new([127, 0, 0, 3], Password::plain("3333")), - ]; - - let mut table = Table::new(data); - table.with( - Style::modern_rounded() - .remove_horizontal() - .remove_vertical(), - ); - - println!("{table}"); -} diff --git a/tabled/examples/derive/format_enum.rs b/tabled/examples/derive/format_enum.rs new file mode 100644 index 00000000..684bcfb2 --- /dev/null +++ b/tabled/examples/derive/format_enum.rs @@ -0,0 +1,25 @@ +//! This example demonstrates using the [attribute macro](https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros) +//! [`format`] to beatifuly castomize the resulting values, be used for table contraction. + +use tabled::{Table, Tabled}; + +#[derive(Tabled)] +enum Vehicle { + #[tabled(inline)] + Car(#[tabled(format = "car->{}", rename = "cars")] String), + #[tabled(inline)] + Boat(#[tabled(format = "boat->{}", rename = "boats")] String), +} + +fn main() { + let data = [ + Vehicle::Car("bmw".into()), + Vehicle::Car("audi".into()), + Vehicle::Car("volkswagen".into()), + Vehicle::Boat("ford".into()), + ]; + + let table = Table::new(data); + + println!("{table}"); +} diff --git a/tabled/examples/derive/inline.rs b/tabled/examples/derive/inline.rs index 2ce07816..801bc5b7 100644 --- a/tabled/examples/derive/inline.rs +++ b/tabled/examples/derive/inline.rs @@ -9,34 +9,26 @@ use tabled::{Table, Tabled}; #[derive(Tabled)] struct Country { - name: &'static str, - capital_city: &'static str, - surface_area_km2: f32, + name: String, #[tabled(inline)] currency: Currency, + area_km2: f32, } #[derive(Tabled)] struct Currency { - str: &'static str, - short: &'static str, + currency: String, + currency_short: String, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, currency: &str, currency_short: &str, area_km2: f32) -> Self { Self { - name, - capital_city, - surface_area_km2, + name: name.to_string(), + area_km2, currency: Currency { - str: national_currency, - short: national_currency_short, + currency: currency.to_string(), + currency_short: currency_short.to_string(), }, } } @@ -44,9 +36,9 @@ impl Country { fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Afghani", "AFN", 652867.0), + Country::new("Angola", "Kwanza", "AOA", 1246700.0), + Country::new("Canada", "Canadian Dollar", "CAD", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/examples/derive/inline_enum.rs b/tabled/examples/derive/inline_enum.rs index 5557ae46..a6480ce2 100644 --- a/tabled/examples/derive/inline_enum.rs +++ b/tabled/examples/derive/inline_enum.rs @@ -12,26 +12,28 @@ use tabled::{Table, Tabled}; #[derive(Tabled)] -enum Contact<'a> { - #[tabled(inline("telegram::"))] +enum Contact { + #[tabled(inline)] Telegram { - username: &'a str, - #[tabled(inline("telegram::"))] - number: Number, + #[tabled(inline("tg::"))] + num: Number, }, #[tabled(inline)] Local(#[tabled(inline("local::"))] Number), } -#[derive(tabled::Tabled)] +#[derive(Tabled)] struct Number { - number: &'static str, + number: String, code: usize, } impl Number { - fn new(number: &'static str, code: usize) -> Self { - Self { number, code } + fn new(number: &str, code: usize) -> Self { + Self { + number: number.to_string(), + code, + } } } @@ -39,8 +41,7 @@ fn main() { let data = [ Contact::Local(Number::new("654321", 123)), Contact::Telegram { - username: "no2Presley", - number: Number::new("123456", 123), + num: Number::new("123456", 123), }, ]; diff --git a/tabled/examples/derive/order.rs b/tabled/examples/derive/order.rs index 44e036fa..078982a8 100644 --- a/tabled/examples/derive/order.rs +++ b/tabled/examples/derive/order.rs @@ -8,38 +8,27 @@ use tabled::{Table, Tabled}; #[derive(Tabled)] struct Country { - name: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - #[tabled(order = 1)] - national_currency: &'static str, - #[tabled(order = 2)] - national_currency_short: &'static str, + name: String, + capital: String, + #[tabled(order = 0)] + area_km2: f32, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, city: &str, area_km2: f32) -> Self { Self { - name, - national_currency, - national_currency_short, - capital_city, - surface_area_km2, + name: name.to_string(), + capital: city.to_string(), + area_km2, } } } fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Kabul", 652867.0), + Country::new("Angola", "Luanda", 1246700.0), + Country::new("Canada", "Ottawa", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/examples/derive/rename.rs b/tabled/examples/derive/rename.rs index 70941194..b2500645 100644 --- a/tabled/examples/derive/rename.rs +++ b/tabled/examples/derive/rename.rs @@ -5,38 +5,27 @@ use tabled::{Table, Tabled}; #[derive(Tabled)] struct Country { - name: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - #[tabled(rename = "Currency")] - national_currency: &'static str, - #[tabled(rename = "Currency-ISO")] - national_currency_short: &'static str, + name: String, + capital: String, + #[tabled(rename = "area")] + area_km2: f32, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, capital: &str, area: f32) -> Self { Self { - name, - national_currency, - national_currency_short, - capital_city, - surface_area_km2, + name: name.to_string(), + capital: capital.to_string(), + area_km2: area, } } } fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Kabul", 652867.0), + Country::new("Angola", "Luanda", 1246700.0), + Country::new("Canada", "Ottawa", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/examples/derive/rename_all.rs b/tabled/examples/derive/rename_all.rs index cd408e5b..8997244b 100644 --- a/tabled/examples/derive/rename_all.rs +++ b/tabled/examples/derive/rename_all.rs @@ -16,38 +16,27 @@ use tabled::{Table, Tabled}; #[derive(Tabled)] #[tabled(rename_all = "camelCase")] struct Country { - name: &'static str, - capital_city: &'static str, - surface_area_km2: f32, + name: String, #[tabled(rename_all = "kebab-case")] - national_currency: &'static str, - #[tabled(rename_all = "kebab-case")] - national_currency_short: &'static str, + capital_city: String, + area_km2: f32, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, city: &str, area_km2: f32) -> Self { Self { - name, - national_currency, - national_currency_short, - capital_city, - surface_area_km2, + name: name.to_string(), + capital_city: city.to_string(), + area_km2, } } } fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Kabul", 652867.0), + Country::new("Angola", "Luanda", 1246700.0), + Country::new("Canada", "Ottawa", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/examples/derive/skip.rs b/tabled/examples/derive/skip.rs index 86f7a9ba..e8292638 100644 --- a/tabled/examples/derive/skip.rs +++ b/tabled/examples/derive/skip.rs @@ -4,43 +4,34 @@ //! * Note how [`skip`] annoys [clippy](https://doc.rust-lang.org/clippy/) with `dead_code` //! warnings. This can be addressed with compiler overrides like `#[allow(dead_code)]`. +#![allow(dead_code)] + use tabled::{Table, Tabled}; -#[allow(dead_code)] #[derive(Tabled)] struct Country { - name: &'static str, - capital_city: &'static str, + name: String, #[tabled(skip)] - surface_area_km2: f32, - national_currency: &'static str, + capital: String, #[tabled(skip)] - national_currency_short: &'static str, + area_km2: f32, } impl Country { - fn new( - name: &'static str, - national_currency: &'static str, - national_currency_short: &'static str, - capital_city: &'static str, - surface_area_km2: f32, - ) -> Self { + fn new(name: &str, capital: &str, area: f32) -> Self { Self { - name, - national_currency, - national_currency_short, - capital_city, - surface_area_km2, + name: name.to_string(), + capital: capital.to_string(), + area_km2: area, } } } fn main() { let data = [ - Country::new("Afghanistan", "Afghani", "AFN", "Kabul", 652867.0), - Country::new("Angola", "Kwanza", "AOA", "Luanda", 1246700.0), - Country::new("Canada", "Canadian Dollar", "CAD", "Ottawa", 9984670.0), + Country::new("Afghanistan", "Kabul", 652867.0), + Country::new("Angola", "Luanda", 1246700.0), + Country::new("Canada", "Ottawa", 9984670.0), ]; let table = Table::new(data); diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index f7ec825b..cf1b9941 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -33,20 +33,11 @@ pub struct Theme { } impl Theme { - const fn gen( - chars: Borders, - colors: Borders, - lines_horizontals: Option>>, - lines_verticals: Option>>, - lines_horizontal1: Option>, - ) -> Self { - Self { - chars, - colors, - lines_horizontals, - lines_verticals, - lines_horizontal1, - } + /// Creates a new empty style. + /// + /// It's an analog of [`Style::empty`] + pub const fn new() -> Self { + Self::gen(Borders::empty(), Borders::empty(), None, None, None) } /// Build a theme out of a style builder. @@ -59,194 +50,9 @@ impl Theme { Self::gen(chars, Borders::empty(), None, None, hlines1) } -} - -impl Theme { - /// Creates a new empty style. - /// - /// It's an analog of [`Style::empty`] - pub const fn new() -> Self { - Self::gen(Borders::empty(), Borders::empty(), None, None, None) - } -} - -impl Default for Theme { - fn default() -> Self { - Self::new() - } -} - -macro_rules! func_set_chars { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Set a border character", " ", "", $desc, "", " ", ".")] - pub fn $name(&mut self, c: char) { - self.chars.$arg = Some(c); - } - }; -} -macro_rules! func_remove_chars { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Remove a border character", " ", "", $desc, "", " ", ".")] - pub fn $name(&mut self) { - self.chars.$arg = None; - } - }; -} - -macro_rules! func_get_chars { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Get a border character", " ", "", $desc, "", " ", ".")] - pub const fn $name(&self) -> Option { - self.chars.$arg - } - }; -} - -macro_rules! func_set_colors { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Set a border color", " ", "", $desc, "", " ", ".")] - pub fn $name(&mut self, color: Color) { - self.colors.$arg = Some(color); - } - }; -} - -macro_rules! func_remove_colors { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Remove a border color", " ", "", $desc, "", " ", ".")] - pub fn $name(&mut self) { - self.colors.$arg = None; - } - }; -} - -macro_rules! func_get_colors { - ($name:ident, $arg:ident, $desc:expr) => { - #[doc = concat!("Get a border color", " ", "", $desc, "", " ", ".")] - pub fn $name(&self) -> Option<&Color> { - self.colors.$arg.as_ref() - } - }; -} - -#[rustfmt::skip] -impl Theme { - func_set_chars!(set_border_top, top, "top"); - func_set_chars!(set_border_bottom, bottom, "bottom"); - func_set_chars!(set_border_left, left, "left"); - func_set_chars!(set_border_right, right, "right"); - func_set_chars!(set_border_corner_top_left, top_left, "top left corner"); - func_set_chars!(set_border_corner_top_right, top_right, "top right corner"); - func_set_chars!(set_border_corner_bottom_left, bottom_left, "bottom left corner"); - func_set_chars!(set_border_corner_bottom_right, bottom_right, "bottom right corner"); - func_set_chars!(set_border_intersection_top, top_intersection, "top intersection with a vertical line"); - func_set_chars!(set_border_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_set_chars!(set_border_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_set_chars!(set_border_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_set_chars!(set_border_intersection, intersection, "intersection of horizontal and vertical line"); - func_set_chars!(set_border_horizontal, horizontal, "horizontal"); - func_set_chars!(set_border_vertical, vertical, "vertical"); -} - -#[rustfmt::skip] -impl Theme { - func_get_chars!(get_border_top, top, "top"); - func_get_chars!(get_border_bottom, bottom, "bottom"); - func_get_chars!(get_border_left, left, "left"); - func_get_chars!(get_border_right, right, "right"); - func_get_chars!(get_border_corner_top_left, top_left, "top left corner"); - func_get_chars!(get_border_corner_top_right, top_right, "top right corner"); - func_get_chars!(get_border_corner_bottom_left, bottom_left, "bottom left corner"); - func_get_chars!(get_border_corner_bottom_right, bottom_right, "bottom right corner"); - func_get_chars!(get_border_intersection_top, top_intersection, "top intersection with a vertical line"); - func_get_chars!(get_border_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_get_chars!(get_border_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_get_chars!(get_border_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_get_chars!(get_border_intersection, intersection, "intersection of horizontal and vertical line"); - func_get_chars!(get_border_horizontal, horizontal, "horizontal"); - func_get_chars!(get_border_vertical, vertical, "vertical"); -} - -#[rustfmt::skip] -impl Theme { - func_remove_chars!(remove_border_top, top, "top"); - func_remove_chars!(remove_border_bottom, bottom, "bottom"); - func_remove_chars!(remove_border_left, left, "left"); - func_remove_chars!(remove_border_right, right, "right"); - func_remove_chars!(remove_border_corner_top_left, top_left, "top left corner"); - func_remove_chars!(remove_border_corner_top_right, top_right, "top right corner"); - func_remove_chars!(remove_border_corner_bottom_left, bottom_left, "bottom left corner"); - func_remove_chars!(remove_border_corner_bottom_right, bottom_right, "bottom right corner"); - func_remove_chars!(remove_border_intersection_top, top_intersection, "top intersection with a vertical line"); - func_remove_chars!(remove_border_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_remove_chars!(remove_border_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_remove_chars!(remove_border_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_remove_chars!(remove_border_intersection, intersection, "intersection of horizontal and vertical line"); - func_remove_chars!(remove_border_horizontal, horizontal, "horizontal"); - func_remove_chars!(remove_border_vertical, vertical, "vertical"); -} - -#[rustfmt::skip] -impl Theme { - func_set_colors!(set_border_color_top, top, "top"); - func_set_colors!(set_border_color_bottom, bottom, "bottom"); - func_set_colors!(set_border_color_left, left, "left"); - func_set_colors!(set_border_color_right, right, "right"); - func_set_colors!(set_border_color_corner_top_left, top_left, "top left corner"); - func_set_colors!(set_border_color_corner_top_right, top_right, "top right corner"); - func_set_colors!(set_border_color_corner_bottom_left, bottom_left, "bottom left corner"); - func_set_colors!(set_border_color_corner_bottom_right, bottom_right, "bottom right corner"); - func_set_colors!(set_border_color_intersection_top, top_intersection, "top intersection with a vertical line"); - func_set_colors!(set_border_color_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_set_colors!(set_border_color_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_set_colors!(set_border_color_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_set_colors!(set_border_color_intersection, intersection, "intersection of horizontal and vertical line"); - func_set_colors!(set_border_color_horizontal, horizontal, "horizontal"); - func_set_colors!(set_border_color_vertical, vertical, "vertical"); -} - -#[rustfmt::skip] -impl Theme { - func_remove_colors!(remove_border_color_top, top, "top"); - func_remove_colors!(remove_border_color_bottom, bottom, "bottom"); - func_remove_colors!(remove_border_color_left, left, "left"); - func_remove_colors!(remove_border_color_right, right, "right"); - func_remove_colors!(remove_border_color_corner_top_left, top_left, "top left corner"); - func_remove_colors!(remove_border_color_corner_top_right, top_right, "top right corner"); - func_remove_colors!(remove_border_color_corner_bottom_left, bottom_left, "bottom left corner"); - func_remove_colors!(remove_border_color_corner_bottom_right, bottom_right, "bottom right corner"); - func_remove_colors!(remove_border_color_intersection_top, top_intersection, "top intersection with a vertical line"); - func_remove_colors!(remove_border_color_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_remove_colors!(remove_border_color_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_remove_colors!(remove_border_color_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_remove_colors!(remove_border_color_intersection, intersection, "intersection of horizontal and vertical line"); - func_remove_colors!(remove_border_color_horizontal, horizontal, "horizontal"); - func_remove_colors!(remove_border_color_vertical, vertical, "vertical"); -} - -#[rustfmt::skip] -impl Theme { - func_get_colors!(get_border_color_top, top, "top"); - func_get_colors!(get_border_color_bottom, bottom, "bottom"); - func_get_colors!(get_border_color_left, left, "left"); - func_get_colors!(get_border_color_right, right, "right"); - func_get_colors!(get_border_color_corner_top_left, top_left, "top left corner"); - func_get_colors!(get_border_color_corner_top_right, top_right, "top right corner"); - func_get_colors!(get_border_color_corner_bottom_left, bottom_left, "bottom left corner"); - func_get_colors!(get_border_color_corner_bottom_right, bottom_right, "bottom right corner"); - func_get_colors!(get_border_color_intersection_top, top_intersection, "top intersection with a vertical line"); - func_get_colors!(get_border_color_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); - func_get_colors!(get_border_color_intersection_left, left_intersection, "left intersection with a horizontal line"); - func_get_colors!(get_border_color_intersection_right, right_intersection, "right intersection with a horizontal line"); - func_get_colors!(get_border_color_intersection, intersection, "intersection of horizontal and vertical line"); - func_get_colors!(get_border_color_horizontal, horizontal, "horizontal"); - func_get_colors!(get_border_color_vertical, vertical, "vertical"); -} - -impl Theme { /// Returns an outer border of the style. - pub fn set_border_frame(&mut self, frame: Border) { + pub fn set_frame(&mut self, frame: Border) { self.chars.top = frame.top; self.chars.bottom = frame.bottom; self.chars.left = frame.left; @@ -258,7 +64,7 @@ impl Theme { } /// Returns an outer border of the style. - pub fn set_border_color_frame(&mut self, frame: Border) { + pub fn set_frame_colors(&mut self, frame: Border) { self.colors.top = frame.top; self.colors.bottom = frame.bottom; self.colors.left = frame.left; @@ -275,22 +81,52 @@ impl Theme { } /// Set borders structure. - pub fn set_borders_colors(&mut self, borders: Borders) { + pub fn set_colors(&mut self, borders: Borders) { self.colors = borders; } - /// Set borders structure. - pub const fn get_borders(&self) -> Borders { - self.chars + /// Get borders structure. + pub const fn get_borders(&self) -> &Borders { + &self.chars } - /// Set borders structure. - pub fn get_borders_colors(&self) -> Borders { - self.colors.clone() + /// Get borders color structure. + pub const fn get_borders_colors(&self) -> &Borders { + &self.colors + } + + /// Get borders structure. + pub fn get_borders_mut(&mut self) -> &mut Borders { + &mut self.chars + } + + /// Get borders color structure. + pub fn get_colors_mut(&mut self) -> &mut Borders { + &mut self.colors + } + + /// Remove borders. + pub fn remove_borders(&mut self) { + self.set_borders(Borders::empty()); + } + + /// Remove colors. + pub fn remove_colors(&mut self) { + self.set_colors(Borders::empty()); + } + + /// Remove horizontal lines. + pub fn remove_horizontal_lines(&mut self) { + self.set_horizontal_lines(HashMap::new()); + } + + /// Remove vertical lines. + pub fn remove_vertical_lines(&mut self) { + self.set_vertical_lines(HashMap::new()); } /// Set an outer border. - pub const fn get_border_frame(&self) -> Border { + pub const fn get_frame(&self) -> Border { Border { top: self.chars.top, bottom: self.chars.bottom, @@ -304,7 +140,7 @@ impl Theme { } /// Set an outer border. - pub const fn get_border_color_frame(&self) -> Border<&Color> { + pub const fn get_frame_colors(&self) -> Border<&Color> { Border { top: self.colors.top.as_ref(), bottom: self.colors.bottom.as_ref(), @@ -316,9 +152,7 @@ impl Theme { right_bottom_corner: self.colors.bottom_right.as_ref(), } } -} -impl Theme { /// Set horizontal border lines. /// /// # Example @@ -332,7 +166,7 @@ impl Theme { /// let mut lines = HashMap::new(); /// lines.insert(1, HorizontalLine::inherit(Style::extended()).into()); /// - /// style.set_lines_horizontal(lines); + /// style.set_horizontal_lines(lines); /// /// let data = (0..3).map(|i| ("Hello", i)); /// let table = Table::new(data).with(style).to_string(); @@ -350,7 +184,7 @@ impl Theme { /// ), /// ) /// ``` - pub fn set_lines_horizontal(&mut self, lines: HashMap>) { + pub fn set_horizontal_lines(&mut self, lines: HashMap>) { self.lines_horizontals = Some(lines); } @@ -372,7 +206,7 @@ impl Theme { /// let mut lines = HashMap::new(); /// lines.insert(1, HorizontalLine::inherit(Style::extended()).into()); /// - /// style.set_lines_vertical(lines); + /// style.set_vertical_lines(lines); /// /// let data = (0..3).map(|i| ("Hello", i)); /// let table = Table::new(data).with(style).to_string(); @@ -390,12 +224,12 @@ impl Theme { /// ), /// ) /// ``` - pub fn set_lines_vertical(&mut self, lines: HashMap>) { + pub fn set_vertical_lines(&mut self, lines: HashMap>) { self.lines_verticals = Some(lines); } /// Insert a vertical line into specific column location. - pub fn insert_line_vertical(&mut self, line: usize, vertical: VerticalLine) { + pub fn insert_vertical_line(&mut self, line: usize, vertical: VerticalLine) { match &mut self.lines_verticals { Some(verticals) => { let _ = verticals.insert(line, vertical); @@ -405,7 +239,7 @@ impl Theme { } /// Insert a horizontal line to a specific row location. - pub fn insert_line_horizontal(&mut self, line: usize, horizontal: HorizontalLine) { + pub fn insert_horizontal_line(&mut self, line: usize, horizontal: HorizontalLine) { match &mut self.lines_horizontals { Some(horizontals) => { let _ = horizontals.insert(line, horizontal); @@ -415,17 +249,33 @@ impl Theme { } /// Get a vertical line at the row if any set. - pub fn get_line_vertical(&self, column: usize) -> Option> { + pub fn get_vertical_line(&self, column: usize) -> Option<&VerticalLine> { self.lines_verticals .as_ref() - .and_then(|lines| lines.get(&column).cloned()) + .and_then(|lines| lines.get(&column)) } /// Get a horizontal line at the row if any set. - pub fn get_line_horizontal(&self, row: usize) -> Option> { + pub fn get_horizontal_line(&self, row: usize) -> Option<&HorizontalLine> { self.lines_horizontals .as_ref() - .and_then(|list| list.get(&row).cloned()) + .and_then(|list| list.get(&row)) + } + + const fn gen( + chars: Borders, + colors: Borders, + lines_horizontals: Option>>, + lines_verticals: Option>>, + lines_horizontal1: Option>, + ) -> Self { + Self { + chars, + colors, + lines_horizontals, + lines_verticals, + lines_horizontal1, + } } } @@ -435,6 +285,12 @@ impl From> for Theme { } } +impl Default for Theme { + fn default() -> Self { + Self::new() + } +} + impl TableOption for Theme { fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { cfg_clear_borders(cfg); @@ -479,6 +335,174 @@ impl From for Theme { } } +macro_rules! func_set_chars { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Set a border character", " ", "", $desc, "", " ", ".")] + pub fn $name(&mut self, c: char) { + self.chars.$arg = Some(c); + } + }; +} + +macro_rules! func_remove_chars { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Remove a border character", " ", "", $desc, "", " ", ".")] + pub fn $name(&mut self) { + self.chars.$arg = None; + } + }; +} + +macro_rules! func_get_chars { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Get a border character", " ", "", $desc, "", " ", ".")] + pub const fn $name(&self) -> Option { + self.chars.$arg + } + }; +} + +macro_rules! func_set_colors { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Set a border color", " ", "", $desc, "", " ", ".")] + pub fn $name(&mut self, color: Color) { + self.colors.$arg = Some(color); + } + }; +} + +macro_rules! func_remove_colors { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Remove a border color", " ", "", $desc, "", " ", ".")] + pub fn $name(&mut self) { + self.colors.$arg = None; + } + }; +} + +macro_rules! func_get_colors { + ($name:ident, $arg:ident, $desc:expr) => { + #[doc = concat!("Get a border color", " ", "", $desc, "", " ", ".")] + pub fn $name(&self) -> Option<&Color> { + self.colors.$arg.as_ref() + } + }; +} + +#[rustfmt::skip] +impl Theme { + func_set_chars!(set_borders_top, top, "top"); + func_set_chars!(set_borders_bottom, bottom, "bottom"); + func_set_chars!(set_borders_left, left, "left"); + func_set_chars!(set_borders_right, right, "right"); + func_set_chars!(set_borders_corner_top_left, top_left, "top left corner"); + func_set_chars!(set_borders_corner_top_right, top_right, "top right corner"); + func_set_chars!(set_borders_corner_bottom_left, bottom_left, "bottom left corner"); + func_set_chars!(set_borders_corner_bottom_right, bottom_right, "bottom right corner"); + func_set_chars!(set_borders_intersection_top, top_intersection, "top intersection with a vertical line"); + func_set_chars!(set_borders_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_set_chars!(set_borders_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_set_chars!(set_borders_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_set_chars!(set_borders_intersection, intersection, "intersection of horizontal and vertical line"); + func_set_chars!(set_borders_horizontal, horizontal, "horizontal"); + func_set_chars!(set_borders_vertical, vertical, "vertical"); +} + +#[rustfmt::skip] +impl Theme { + func_get_chars!(get_borders_top, top, "top"); + func_get_chars!(get_borders_bottom, bottom, "bottom"); + func_get_chars!(get_borders_left, left, "left"); + func_get_chars!(get_borders_right, right, "right"); + func_get_chars!(get_borders_corner_top_left, top_left, "top left corner"); + func_get_chars!(get_borders_corner_top_right, top_right, "top right corner"); + func_get_chars!(get_borders_corner_bottom_left, bottom_left, "bottom left corner"); + func_get_chars!(get_borders_corner_bottom_right, bottom_right, "bottom right corner"); + func_get_chars!(get_borders_intersection_top, top_intersection, "top intersection with a vertical line"); + func_get_chars!(get_borders_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_get_chars!(get_borders_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_get_chars!(get_borders_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_get_chars!(get_borders_intersection, intersection, "intersection of horizontal and vertical line"); + func_get_chars!(get_borders_horizontal, horizontal, "horizontal"); + func_get_chars!(get_borders_vertical, vertical, "vertical"); +} + +#[rustfmt::skip] +impl Theme { + func_remove_chars!(remove_borders_top, top, "top"); + func_remove_chars!(remove_borders_bottom, bottom, "bottom"); + func_remove_chars!(remove_borders_left, left, "left"); + func_remove_chars!(remove_borders_right, right, "right"); + func_remove_chars!(remove_borders_corner_top_left, top_left, "top left corner"); + func_remove_chars!(remove_borders_corner_top_right, top_right, "top right corner"); + func_remove_chars!(remove_borders_corner_bottom_left, bottom_left, "bottom left corner"); + func_remove_chars!(remove_borders_corner_bottom_right, bottom_right, "bottom right corner"); + func_remove_chars!(remove_borders_intersection_top, top_intersection, "top intersection with a vertical line"); + func_remove_chars!(remove_borders_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_remove_chars!(remove_borders_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_remove_chars!(remove_borders_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_remove_chars!(remove_borders_intersection, intersection, "intersection of horizontal and vertical line"); + func_remove_chars!(remove_borders_horizontal, horizontal, "horizontal"); + func_remove_chars!(remove_borders_vertical, vertical, "vertical"); +} + +#[rustfmt::skip] +impl Theme { + func_set_colors!(set_colors_top, top, "top"); + func_set_colors!(set_colors_bottom, bottom, "bottom"); + func_set_colors!(set_colors_left, left, "left"); + func_set_colors!(set_colors_right, right, "right"); + func_set_colors!(set_colors_corner_top_left, top_left, "top left corner"); + func_set_colors!(set_colors_corner_top_right, top_right, "top right corner"); + func_set_colors!(set_colors_corner_bottom_left, bottom_left, "bottom left corner"); + func_set_colors!(set_colors_corner_bottom_right, bottom_right, "bottom right corner"); + func_set_colors!(set_colors_intersection_top, top_intersection, "top intersection with a vertical line"); + func_set_colors!(set_colors_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_set_colors!(set_colors_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_set_colors!(set_colors_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_set_colors!(set_colors_intersection, intersection, "intersection of horizontal and vertical line"); + func_set_colors!(set_colors_horizontal, horizontal, "horizontal"); + func_set_colors!(set_colors_vertical, vertical, "vertical"); +} + +#[rustfmt::skip] +impl Theme { + func_remove_colors!(remove_colors_top, top, "top"); + func_remove_colors!(remove_colors_bottom, bottom, "bottom"); + func_remove_colors!(remove_colors_left, left, "left"); + func_remove_colors!(remove_colors_right, right, "right"); + func_remove_colors!(remove_colors_corner_top_left, top_left, "top left corner"); + func_remove_colors!(remove_colors_corner_top_right, top_right, "top right corner"); + func_remove_colors!(remove_colors_corner_bottom_left, bottom_left, "bottom left corner"); + func_remove_colors!(remove_colors_corner_bottom_right, bottom_right, "bottom right corner"); + func_remove_colors!(remove_colors_intersection_top, top_intersection, "top intersection with a vertical line"); + func_remove_colors!(remove_colors_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_remove_colors!(remove_colors_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_remove_colors!(remove_colors_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_remove_colors!(remove_colors_intersection, intersection, "intersection of horizontal and vertical line"); + func_remove_colors!(remove_colors_horizontal, horizontal, "horizontal"); + func_remove_colors!(remove_colors_vertical, vertical, "vertical"); +} + +#[rustfmt::skip] +impl Theme { + func_get_colors!(get_colors_top, top, "top"); + func_get_colors!(get_colors_bottom, bottom, "bottom"); + func_get_colors!(get_colors_left, left, "left"); + func_get_colors!(get_colors_right, right, "right"); + func_get_colors!(get_colors_corner_top_left, top_left, "top left corner"); + func_get_colors!(get_colors_corner_top_right, top_right, "top right corner"); + func_get_colors!(get_colors_corner_bottom_left, bottom_left, "bottom left corner"); + func_get_colors!(get_colors_corner_bottom_right, bottom_right, "bottom right corner"); + func_get_colors!(get_colors_intersection_top, top_intersection, "top intersection with a vertical line"); + func_get_colors!(get_colors_intersection_bottom, bottom_intersection, "bottom intersection with a vertical line"); + func_get_colors!(get_colors_intersection_left, left_intersection, "left intersection with a horizontal line"); + func_get_colors!(get_colors_intersection_right, right_intersection, "right intersection with a horizontal line"); + func_get_colors!(get_colors_intersection, intersection, "intersection of horizontal and vertical line"); + func_get_colors!(get_colors_horizontal, horizontal, "horizontal"); + func_get_colors!(get_colors_vertical, vertical, "vertical"); +} + fn cfg_clear_borders(cfg: &mut ColoredConfig) { cfg.remove_borders(); cfg.remove_borders_colors(); diff --git a/tabled/tests/derive/derive_test.rs b/tabled/tests/derive/derive_test.rs index 5515e687..ece97781 100644 --- a/tabled/tests/derive/derive_test.rs +++ b/tabled/tests/derive/derive_test.rs @@ -1563,6 +1563,73 @@ fn test_format_enum_inline() { assert_eq!(Struct::Variant3.fields(), ["", "", "", "+"]); } +#[test] +#[allow(dead_code)] +fn test_macros_in_display_with() { + #[derive(Tabled)] + #[tabled(rename_all = "camelCase")] + struct Country { + name: String, + #[tabled(display_with("display_capital", format!(".{}", self.capital)))] + capital: String, + #[tabled(display_with("display_perimeter", self))] + area_km2: f32, + #[tabled(display_with = "str::to_lowercase")] + national_currency: String, + national_currency_short: String, + } + + fn display_perimeter(country: &Country) -> std::borrow::Cow<'_, str> { + if country.area_km2 > 1_000_000.0 { + "Very Big Land".into() + } else { + "Big Land".into() + } + } + + fn display_capital(country: String) -> std::borrow::Cow<'static, str> { + format!("{country}!").into() + } +} + +#[test] +#[allow(dead_code)] +fn test_macros_in_format() { + #[derive(Tabled)] + struct Country { + name: String, + #[tabled(format("{}", format!(".{}", self.capital)))] + capital: String, + #[tabled(format("{}", self.field1[0]))] + field1: [u8; 4], + } +} + +#[test] +#[allow(dead_code)] +fn test_enum_format_1() { + #[derive(Tabled)] + struct User { + #[tabled(format("{}.{}.{}.{}", self.ip[0], self.ip[1], self.ip[2], self.ip[3]))] + ip: [u8; 4], + #[tabled(inline)] + password: Password, + } + + #[derive(Tabled)] + enum Password { + #[tabled(inline)] + Mask { + #[tabled(format("t={}/{}", self.text, self.factor))] + text: String, + #[tabled(skip)] + factor: usize, + }, + #[tabled(inline)] + Plain(#[tabled(rename = "password")] String), + } +} + mod __ { #[test] fn dont_import_the_trait() { diff --git a/tabled/tests/settings/panel_test.rs b/tabled/tests/settings/panel_test.rs index d5cc0294..79d7c4a1 100644 --- a/tabled/tests/settings/panel_test.rs +++ b/tabled/tests/settings/panel_test.rs @@ -146,8 +146,8 @@ test_table!( .with(Panel::horizontal(0,"Numbers")) .with({ let mut style = Theme::from_style(Style::modern()); - style.set_border_intersection_top('─'); - style.set_lines_horizontal(HashMap::from_iter([(1, HorizontalLine::inherit(Style::modern()).intersection('┬').into_inner())])); + style.set_borders_intersection_top('─'); + style.set_horizontal_lines(HashMap::from_iter([(1, HorizontalLine::inherit(Style::modern()).intersection('┬').into_inner())])); style }) .with(Modify::new(Cell::new(0, 0)).with(Alignment::center())), diff --git a/tabled/tests/settings/style_test.rs b/tabled/tests/settings/style_test.rs index 949a8523..9f262139 100644 --- a/tabled/tests/settings/style_test.rs +++ b/tabled/tests/settings/style_test.rs @@ -657,14 +657,14 @@ test_table!( .insert((1, 1), "a longer string") .with({ let mut style = Theme::from_style(Style::modern()); - style.set_border_bottom('a'); - style.set_border_left('b'); - style.set_border_intersection('x'); - style.remove_border_right(); - style.remove_border_top(); - style.remove_border_intersection_top(); - style.remove_border_corner_top_left(); - style.remove_border_corner_top_right(); + style.set_borders_bottom('a'); + style.set_borders_left('b'); + style.set_borders_intersection('x'); + style.remove_borders_right(); + style.remove_borders_top(); + style.remove_borders_intersection_top(); + style.remove_borders_corner_top_left(); + style.remove_borders_corner_top_right(); style }), "b N │ column 0 │ column 1 │ column 2 " @@ -683,7 +683,7 @@ test_table!( .insert((1, 1), "a longer string") .with({ let mut style = Theme::from_style(Style::modern()); - style.remove_border_bottom(); + style.remove_borders_bottom(); style }), "┌───┬─────────────────┬──────────┬──────────┐" @@ -703,7 +703,7 @@ test_table!( .insert((1, 1), "a longer string") .with({ let mut style = Theme::from_style(Style::modern()); - style.remove_border_bottom(); + style.remove_borders_bottom(); style }) .with(Modify::new(Rows::last()).with(GridBorder { left_bottom_corner: Some('*'), ..Default::default() })), @@ -2232,7 +2232,7 @@ test_table!( { let verticals = (1..4).map(|i| (i, VerticalLine::filled('+').into())).collect(); let mut style = Theme::from_style(Style::rounded()); - style.set_lines_vertical(verticals); + style.set_vertical_lines(verticals); Matrix::new(3, 3).with(style) }, @@ -2276,7 +2276,7 @@ test_table!( { let mut style = Theme::from_style(Style::ascii()); let verticals = (0..10).map(|i| (i, VerticalLine::full('*', 'x', 'c', '2').into())).collect(); - style.set_lines_vertical(verticals); + style.set_vertical_lines(verticals); Matrix::new(3, 3).with(style) }, @@ -2297,8 +2297,8 @@ test_table!( let m = Matrix::new(3, 3); let mut style = Theme::from_style(Style::ascii()); - style.insert_line_horizontal(1, HorizontalLine::full('8', '8', '8', '8').into()); - style.insert_line_vertical(1, VerticalLine::full('*', 'x', 'c', '2').into()); + style.insert_horizontal_line(1, HorizontalLine::full('8', '8', '8', '8').into()); + style.insert_vertical_line(1, VerticalLine::full('*', 'x', 'c', '2').into()); m.with(style) }, From 5143ddcb99477b1139e5cfd84091a35f5d60e3e9 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Sun, 21 Jul 2024 17:23:49 +0300 Subject: [PATCH 17/20] Just refactorings of examples --- tabled/Cargo.toml | 8 +- tabled/examples/border_text.rs | 6 +- tabled/examples/builder.rs | 24 +--- tabled/examples/builder_index.rs | 14 +-- tabled/examples/chess.rs | 13 +- tabled/examples/col_row_macros.rs | 29 ++--- tabled/examples/color.rs | 40 +++--- tabled/examples/colored_borders.rs | 30 ++--- tabled/examples/colored_padding.rs | 10 +- tabled/examples/colorization.rs | 26 ++-- tabled/examples/column_names.rs | 3 +- tabled/examples/compact_table.rs | 6 +- tabled/examples/compact_table_2.rs | 6 +- tabled/examples/compact_table_3.rs | 6 +- tabled/examples/concat.rs | 4 +- tabled/examples/custom_style.rs | 24 ++-- tabled/examples/disable.rs | 21 ++-- tabled/examples/extended_display.rs | 10 +- tabled/examples/extract.rs | 79 +++--------- tabled/examples/format.rs | 17 +-- tabled/examples/formatting_settings.rs | 17 +-- tabled/examples/grid_colors.rs | 14 +-- tabled/examples/highlight.rs | 15 +-- tabled/examples/highlight_color.rs | 13 +- tabled/examples/iter_table.rs | 17 ++- ...es_2.rs => merge_duplicates_horizontal.rs} | 19 ++- ...icates.rs => merge_duplicates_vertical.rs} | 38 +++--- tabled/examples/nested_table_2.rs | 84 +++++-------- tabled/examples/nested_table_3.rs | 23 ++-- tabled/examples/panel.rs | 15 +-- tabled/examples/table.rs | 4 +- tabled/examples/table_width_2.rs | 9 +- tabled/src/settings/highlight/mod.rs | 4 +- tabled/src/settings/style/border_color.rs | 115 +++--------------- tabled/src/settings/themes/theme.rs | 8 ++ tabled/tests/settings/style_test.rs | 2 +- 36 files changed, 298 insertions(+), 475 deletions(-) rename tabled/examples/{merge_duplicates_2.rs => merge_duplicates_horizontal.rs} (84%) rename tabled/examples/{merge_duplicates.rs => merge_duplicates_vertical.rs} (87%) diff --git a/tabled/Cargo.toml b/tabled/Cargo.toml index 033fd38f..718cb21b 100644 --- a/tabled/Cargo.toml +++ b/tabled/Cargo.toml @@ -149,13 +149,13 @@ path = "examples/col_row_macros.rs" required-features = ["macros", "derive"] [[example]] -name = "merge_duplicates" -path = "examples/merge_duplicates.rs" +name = "merge_duplicates_horizontal" +path = "examples/merge_duplicates_horizontal.rs" required-features = ["derive"] [[example]] -name = "merge_duplicates_2" -path = "examples/merge_duplicates_2.rs" +name = "merge_duplicates_vertical" +path = "examples/merge_duplicates_vertical.rs" required-features = ["derive"] [[example]] diff --git a/tabled/examples/border_text.rs b/tabled/examples/border_text.rs index 99d9aa1a..8f5f6447 100644 --- a/tabled/examples/border_text.rs +++ b/tabled/examples/border_text.rs @@ -21,7 +21,7 @@ use tabled::{ settings::{ object::Rows, - style::{HorizontalLine, LineText, Style, VerticalLine}, + style::{Border, HorizontalLine, LineText, Style}, Theme, }, Table, @@ -30,8 +30,8 @@ use tabled::{ fn main() { let data = [[5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]; - let hline = HorizontalLine::inherit(Style::modern()) - .left(VerticalLine::inherit_left(Style::modern()).get_vertical()); + let hline = + HorizontalLine::inherit(Style::modern()).left(Border::inherit(Style::modern()).get_left()); let mut theme = Theme::from_style(Style::modern()); theme.remove_horizontal_lines(); diff --git a/tabled/examples/builder.rs b/tabled/examples/builder.rs index 434df793..dad9028e 100644 --- a/tabled/examples/builder.rs +++ b/tabled/examples/builder.rs @@ -8,32 +8,20 @@ //! and can be populated through iteration if it is mutable. This flexibility //! is useful when you don't have direct control over the datasets you intend to [table](tabled). -use tabled::{ - builder::Builder, - settings::{object::Rows, Modify, Panel, Style, Width}, -}; +use tabled::{builder::Builder, settings::Style}; fn main() { - let message = r#"The terms "the ocean" or "the sea" used without specification refer to the interconnected body of salt water covering the majority of the Earth's surface"#; - let link = r#"https://en.wikipedia.org/wiki/Ocean"#; - - let oceans = ["Atlantic", "Pacific", "Indian", "Southern", "Arctic"]; + let oceans = "Atlantic, Pacific, Indian, Southern, Arctic"; let mut builder = Builder::default(); - builder.push_record(["#", "Ocean"]); - for (i, ocean) in oceans.iter().enumerate() { + builder.push_record(["#", "Ocean"]); + for (i, ocean) in oceans.split(", ").enumerate() { builder.push_record([i.to_string(), ocean.to_string()]); } - let table = builder - .build() - .with(Panel::header(message)) - .with(Panel::header(link)) - .with(Panel::horizontal(2, "=".repeat(link.len()))) - .with(Modify::new(Rows::single(1)).with(Width::wrap(link.len()))) - .with(Style::markdown()) - .to_string(); + let mut table = builder.build(); + table.with(Style::markdown().remove_horizontals()); println!("{table}"); } diff --git a/tabled/examples/builder_index.rs b/tabled/examples/builder_index.rs index d7840367..7ed313ad 100644 --- a/tabled/examples/builder_index.rs +++ b/tabled/examples/builder_index.rs @@ -13,17 +13,17 @@ use tabled::{settings::Style, Table, Tabled}; #[derive(Tabled)] struct Distribution { - name: &'static str, - based_on: &'static str, + name: String, + based_on: String, is_active: bool, is_cool: bool, } impl Distribution { - fn new(name: &'static str, based_on: &'static str, is_active: bool, is_cool: bool) -> Self { + fn new(name: &str, based: &str, is_active: bool, is_cool: bool) -> Self { Self { - name, - based_on, + name: name.to_string(), + based_on: based.to_string(), is_active, is_cool, } @@ -31,7 +31,7 @@ impl Distribution { } fn main() { - let data = [ + let data = vec![ Distribution::new("Manjaro", "Arch", true, true), Distribution::new("Arch", "None", true, true), Distribution::new("Debian", "None", true, true), @@ -44,7 +44,7 @@ fn main() { .name(None) .build(); - table.with(Style::modern()); + table.with(Style::modern_rounded()); println!("{table}"); } diff --git a/tabled/examples/chess.rs b/tabled/examples/chess.rs index db83218c..8b87fb4b 100644 --- a/tabled/examples/chess.rs +++ b/tabled/examples/chess.rs @@ -17,21 +17,18 @@ fn main() { let board = [ ["♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"], ["♟", "♟", "♟", "♟", "♟", "♟", "♟", "♟"], - [" ", " ", " ", " ", " ", " ", " ", " "], - [" ", " ", " ", " ", " ", " ", " ", " "], - [" ", " ", " ", " ", " ", " ", " ", " "], - [" ", " ", " ", " ", " ", " ", " ", " "], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], ["♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"], ["♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"], ]; - let color_white = Color::BG_WHITE | Color::FG_BLACK; - let color_black = Color::FG_WHITE | Color::BG_BLACK; - let mut table = Builder::from_iter(board).build(); table .with(Style::empty()) - .with(Colorization::chess(color_white, color_black)); + .with(Colorization::chess(Color::BG_WHITE, Color::BG_BLACK)); println!("{table}"); } diff --git a/tabled/examples/col_row_macros.rs b/tabled/examples/col_row_macros.rs index c5757056..b5c74593 100644 --- a/tabled/examples/col_row_macros.rs +++ b/tabled/examples/col_row_macros.rs @@ -33,11 +33,15 @@ impl Person { } fn main() { - let validated = [Person::new("Sam", 31, true), Person::new("Sarah", 26, true)]; + let validated = [ + Person::new("Sam", 31, true), + Person::new("Sarah", 26, true), + Person::new("Sam", 31, true), + ]; let not_validated = [ Person::new("Jack Black", 51, false), - Person::new("Michelle Goldstein", 44, true), + Person::new("Michelle Goldstein", 44, false), ]; let unsure = [ @@ -47,21 +51,18 @@ fn main() { Person::new("Adam Blend", 17, true), ]; - let table_validated = Table::new(validated).with(Style::ascii()).to_string(); - let table_not_validated = Table::new(not_validated).with(Style::modern()).to_string(); - let table_unsure = Table::new(unsure).with(Style::ascii_rounded()).to_string(); - - let output1 = row![table_validated, table_not_validated]; - let output2 = col![table_unsure; 3]; + let validated = Table::new(validated).with(Style::ascii()).to_string(); + let not_validated = Table::new(not_validated).with(Style::modern()).to_string(); + let unsure = Table::new(unsure).with(Style::ascii_rounded()).to_string(); - let output3 = col![ - row![table_validated, table_not_validated].with(Style::empty()), - table_unsure + let output = col![ + row![validated, not_validated] + .with(Style::empty()) + .with(Alignment::center_vertical()), + row![unsure; 3].with(Style::empty()) ] .with(Alignment::center()) .to_string(); - println!("{output1}"); - println!("{output2}"); - println!("{output3}"); + println!("{output}"); } diff --git a/tabled/examples/color.rs b/tabled/examples/color.rs index 32aaf05f..8122353c 100644 --- a/tabled/examples/color.rs +++ b/tabled/examples/color.rs @@ -14,23 +14,23 @@ use tabled::{ settings::{ object::{Columns, Rows}, style::{BorderColor, Style}, - Color, Format, Modify, + Color, }, Table, Tabled, }; #[derive(Tabled)] struct Bsd { - distribution: &'static str, - year_of_first_release: usize, + distribution: String, + first_release: usize, is_active: bool, } impl Bsd { - fn new(distribution: &'static str, year_of_first_release: usize, is_active: bool) -> Self { + fn new(dist: &str, first_release: usize, is_active: bool) -> Self { Self { - distribution, - year_of_first_release, + distribution: dist.to_string(), + first_release, is_active, } } @@ -45,30 +45,24 @@ fn main() { Bsd::new("OpenBSD", 1995, true), ]; - let red = Format::content(|s| s.red().on_bright_white().to_string()); - let blue = Format::content(|s| s.blue().to_string()); - let green = Format::content(|s| s.green().to_string()); - - let color_red = Color::try_from(' '.red().to_string()).unwrap(); - let color_purple = Color::try_from(' '.purple().to_string()).unwrap(); - - let yellow_color = Color::try_from(' '.yellow().to_string()).unwrap(); + let clr_red = Color::try_from(' '.red().to_string()).unwrap(); + let clr_red_light = Color::try_from(' '.red().on_bright_white().to_string()).unwrap(); + let clr_blue = Color::try_from(' '.blue().to_string()).unwrap(); + let clr_green = Color::try_from(' '.green().to_string()).unwrap(); + let clr_purple = Color::try_from(' '.purple().to_string()).unwrap(); let border = BorderColor::new() - .set_bottom(color_red) - .set_left(Color::default()) - .set_right(Color::default()) - .set_corner_bottom_left(color_purple.clone()) - .set_corner_bottom_right(color_purple); + .bottom(clr_red) + .corner_bottom_left(clr_purple.clone()) + .corner_bottom_right(clr_purple); let mut table = Table::new(data); table .with(Style::psql()) - .with(yellow_color) .modify(Rows::first(), border) - .with(Modify::new(Columns::single(0)).with(red)) - .with(Modify::new(Columns::single(1)).with(green)) - .with(Modify::new(Columns::single(2)).with(blue)); + .modify(Columns::single(0), clr_red_light) + .modify(Columns::single(1), clr_green) + .modify(Columns::single(2), clr_blue); println!("{table}"); } diff --git a/tabled/examples/colored_borders.rs b/tabled/examples/colored_borders.rs index 6f6c5d6d..5dbadfe1 100644 --- a/tabled/examples/colored_borders.rs +++ b/tabled/examples/colored_borders.rs @@ -14,22 +14,30 @@ use tabled::{ #[derive(Tabled)] struct CodeEditor { - name: &'static str, - first_release: &'static str, - developer: &'static str, + name: String, + first_release: String, + developer: String, } impl CodeEditor { - fn new(name: &'static str, first_release: &'static str, developer: &'static str) -> Self { + fn new(name: &str, first_release: &str, developer: &str) -> Self { Self { - name, - first_release, - developer, + name: name.to_string(), + first_release: first_release.to_string(), + developer: developer.to_string(), } } } fn main() { + let data = [ + CodeEditor::new("Sublime Text 3", "2008", "Sublime HQ"), + CodeEditor::new("Visual Studio Code", "2015", "Microsoft"), + CodeEditor::new("Notepad++", "2003", "Don Ho"), + CodeEditor::new("GNU Emacs", "1984", "Richard Stallman"), + CodeEditor::new("Neovim", "2015", "Vim community"), + ]; + let mut style = Theme::from(Style::extended()); style.set_colors_top(Color::FG_RED); style.set_colors_bottom(Color::FG_CYAN); @@ -47,14 +55,6 @@ fn main() { style.set_colors_horizontal(Color::FG_MAGENTA); style.set_colors_vertical(Color::FG_MAGENTA); - let data = [ - CodeEditor::new("Sublime Text 3", "2008", "Sublime HQ"), - CodeEditor::new("Visual Studio Code", "2015", "Microsoft"), - CodeEditor::new("Notepad++", "2003", "Don Ho"), - CodeEditor::new("GNU Emacs", "1984", "Richard Stallman"), - CodeEditor::new("Neovim", "2015", "Vim community"), - ]; - let table = Table::new(data).with(style).to_string(); println!("{table}"); diff --git a/tabled/examples/colored_padding.rs b/tabled/examples/colored_padding.rs index ed612ecb..e776a731 100644 --- a/tabled/examples/colored_padding.rs +++ b/tabled/examples/colored_padding.rs @@ -8,8 +8,6 @@ //! //! * Note how a unique color can be set for each direction. -use std::convert::TryFrom; - use owo_colors::OwoColorize; use tabled::{ @@ -25,9 +23,9 @@ use tabled::{ #[tabled(rename_all = "PascalCase")] struct Fundamental { quantity: String, - symbol: char, value: String, unit: String, + symbol: char, } impl Fundamental { @@ -52,9 +50,9 @@ fn main() { Fundamental::new("Faraday constant", 'F', "9.648533289 × 10⁴", "coulombs per mole"), ]; - let pane_color = Color::try_from(' '.bg_rgb::<220, 220, 220>().to_string()).unwrap(); - let border_color = Color::try_from(' '.bg_rgb::<200, 200, 220>().bold().to_string()).unwrap(); - let data_color = Color::try_from(' '.bg_rgb::<200, 200, 220>().to_string()).unwrap(); + let pane_color = Color::parse(' '.bg_rgb::<220, 220, 220>().to_string()); + let border_color = Color::parse(' '.bg_rgb::<200, 200, 220>().bold().to_string()); + let data_color = Color::parse(' '.bg_rgb::<200, 200, 220>().to_string()); let header_settings = Modify::new(Rows::first()) .with(Padding::new(1, 1, 2, 2)) diff --git a/tabled/examples/colorization.rs b/tabled/examples/colorization.rs index a68ca93e..959c26e1 100644 --- a/tabled/examples/colorization.rs +++ b/tabled/examples/colorization.rs @@ -6,8 +6,9 @@ //! * Note how [`Format::content()`] is used to break out [`CellOption`] //! specifications. This is helpful for organizing extensive [`Table`] configurations. +use std::iter::FromIterator; + use tabled::{ - builder::Builder, settings::{object::Rows, style::Style, themes::Colorization, Color, Concat}, Table, Tabled, }; @@ -44,26 +45,25 @@ fn main() { ]; let total = data.iter().map(|e| e.salary).sum::(); - let total_row = Builder::from(vec![vec![ - String::from(""), - String::from(""), + let total_row = Table::from_iter([vec![ + String::default(), + String::default(), String::from("TOTAL"), total.to_string(), - ]]) - .build(); + ]]); - let color_data_primary = Color::BG_WHITE | Color::FG_BLACK; - let color_data_second = Color::BG_BRIGHT_WHITE | Color::FG_BLACK; - let color_head = Color::BOLD | Color::BG_CYAN | Color::FG_BLACK; - let color_footer = Color::BOLD | Color::BG_BLUE | Color::FG_BLACK; + let clr_data_primary = Color::BG_WHITE | Color::FG_BLACK; + let clr_data_second = Color::BG_BRIGHT_WHITE | Color::FG_BLACK; + let clr_head = Color::BOLD | Color::BG_CYAN | Color::FG_BLACK; + let clr_footer = Color::BOLD | Color::BG_BLUE | Color::FG_BLACK; let mut table = Table::new(data); table .with(Concat::vertical(total_row)) .with(Style::empty()) - .with(Colorization::rows([color_data_primary, color_data_second])) - .with(Colorization::exact([color_head], Rows::first())) - .with(Colorization::exact([color_footer], Rows::last())); + .with(Colorization::rows([clr_data_primary, clr_data_second])) + .with(Colorization::exact([clr_head], Rows::first())) + .with(Colorization::exact([clr_footer], Rows::last())); println!("{table}"); } diff --git a/tabled/examples/column_names.rs b/tabled/examples/column_names.rs index 7e0d6bc0..5cd23349 100644 --- a/tabled/examples/column_names.rs +++ b/tabled/examples/column_names.rs @@ -35,7 +35,8 @@ fn main() { let mut table = Table::new(data); - table.with(Style::modern().remove_horizontal()).with( + table.with(Style::modern().remove_horizontal()); + table.with( ColumnNames::default() .color(Color::BOLD | Color::BG_BLUE | Color::FG_WHITE) .alignment(Alignment::center()), diff --git a/tabled/examples/compact_table.rs b/tabled/examples/compact_table.rs index 9d278dae..6dc2ff03 100644 --- a/tabled/examples/compact_table.rs +++ b/tabled/examples/compact_table.rs @@ -4,6 +4,8 @@ //! * [`CompactTable`] is a [`Table`] alternative that trades off reduced //! flexibility for improved performance. +#![allow(dead_code)] + use tabled::{settings::style::Style, tables::CompactTable}; fn main() { @@ -13,11 +15,11 @@ fn main() { ["Manjaro", "Arch", "true"], ]; - let _table = CompactTable::new(data) + let table = CompactTable::new(data) .columns(3) .width([7, 5, 5]) .with(Style::markdown()); #[cfg(feature = "std")] - println!("{}", _table.to_string()); + println!("{}", table.to_string()); } diff --git a/tabled/examples/compact_table_2.rs b/tabled/examples/compact_table_2.rs index 50c9e7f6..ef543da2 100644 --- a/tabled/examples/compact_table_2.rs +++ b/tabled/examples/compact_table_2.rs @@ -4,6 +4,8 @@ //! * Note how [`CompactTable::from()`] inherits the lengths of the nested arrays //! as typed definitions through [const generics](https://practice.rs/generics-traits/const-generics.html). +#![allow(dead_code)] + use tabled::{settings::style::Style, tables::CompactTable}; fn main() { @@ -13,8 +15,8 @@ fn main() { ["Manjaro", "Arch", "true"], ]; - let _table = CompactTable::from(data).with(Style::psql()); + let table = CompactTable::from(data).with(Style::psql()); #[cfg(feature = "std")] - println!("{}", _table.to_string()); + println!("{}", table.to_string()); } diff --git a/tabled/examples/compact_table_3.rs b/tabled/examples/compact_table_3.rs index 951d6616..252eafd1 100644 --- a/tabled/examples/compact_table_3.rs +++ b/tabled/examples/compact_table_3.rs @@ -3,6 +3,8 @@ //! //! * Note how the multiline data is accepted, but then truncated in the display. +#![allow(dead_code)] + use tabled::{settings::style::Style, tables::CompactTable}; fn main() { @@ -12,8 +14,8 @@ fn main() { ["Manjaro", "A\nr\nc\nh", "true"], ]; - let _table = CompactTable::from(data).with(Style::psql()); + let table = CompactTable::from(data).with(Style::psql()); #[cfg(feature = "std")] - println!("{}", _table.to_string()); + println!("{}", table.to_string()); } diff --git a/tabled/examples/concat.rs b/tabled/examples/concat.rs index 09afeed7..95d0bcdc 100644 --- a/tabled/examples/concat.rs +++ b/tabled/examples/concat.rs @@ -7,7 +7,7 @@ //! If the two tables are of unequal shape, additional blank cells are added as needed. use tabled::{ - settings::{object::Segment, Alignment, Concat, Modify, Style}, + settings::{Alignment, Concat, Style}, Table, Tabled, }; @@ -52,7 +52,7 @@ fn main() { weather_table .with(Concat::horizontal(location_table)) .with(Style::empty()) - .with(Modify::new(Segment::all()).with(Alignment::left())); + .with(Alignment::right()); println!("{weather_table}"); } diff --git a/tabled/examples/custom_style.rs b/tabled/examples/custom_style.rs index 7158f333..431f51d9 100644 --- a/tabled/examples/custom_style.rs +++ b/tabled/examples/custom_style.rs @@ -17,28 +17,28 @@ use tabled::{ #[derive(Tabled)] struct CodeEditor { - name: &'static str, - first_release: &'static str, - developer: &'static str, + name: String, + developer: String, + first_release: usize, } impl CodeEditor { - fn new(name: &'static str, first_release: &'static str, developer: &'static str) -> Self { + fn new(name: &str, first_release: usize, developer: &str) -> Self { Self { - name, first_release, - developer, + name: name.to_string(), + developer: developer.to_string(), } } } fn main() { let data = [ - CodeEditor::new("Sublime Text 3", "2008", "Sublime HQ"), - CodeEditor::new("Visual Studio Code", "2015", "Microsoft"), - CodeEditor::new("Notepad++", "2003", "Don Ho"), - CodeEditor::new("GNU Emacs", "1984", "Richard Stallman"), - CodeEditor::new("Neovim", "2015", "Vim community"), + CodeEditor::new("Sublime Text 3", 2008, "Sublime HQ"), + CodeEditor::new("Visual Studio Code", 2015, "Microsoft"), + CodeEditor::new("Notepad++", 2003, "Don Ho"), + CodeEditor::new("GNU Emacs", 1984, "Richard Stallman"), + CodeEditor::new("Neovim", 2015, "Vim community"), ]; let theme = Style::modern() @@ -48,7 +48,7 @@ fn main() { .remove_vertical(); let mut table = Table::new(data); - table.with(theme).with(Alignment::left()); + table.with((theme, Alignment::center())); println!("{table}"); } diff --git a/tabled/examples/disable.rs b/tabled/examples/disable.rs index a9cade33..69117b30 100644 --- a/tabled/examples/disable.rs +++ b/tabled/examples/disable.rs @@ -5,27 +5,23 @@ //! It is safest to use [`Disable`] last in a chain of alterations. use tabled::{ - settings::{ - location::ByColumnName, - style::{Border, Style}, - Disable, - }, + settings::{location::ByColumnName, Disable}, Table, Tabled, }; #[derive(Tabled)] struct Distribution { - name: &'static str, - based_on: &'static str, + name: String, + based_on: String, is_active: bool, is_cool: bool, } impl Distribution { - fn new(name: &'static str, based_on: &'static str, is_active: bool, is_cool: bool) -> Self { + fn new(name: &str, based_on: &str, is_active: bool, is_cool: bool) -> Self { Self { - name, - based_on, + name: name.to_string(), + based_on: based_on.to_string(), is_active, is_cool, } @@ -40,10 +36,7 @@ fn main() { ]; let mut table = Table::new(data); - table - .with(Style::markdown()) - .with(Disable::column(ByColumnName::new("is_active"))) - .modify(ByColumnName::new("name"), Border::filled('#')); + table.with(Disable::column(ByColumnName::new("is_active"))); println!("{table}"); } diff --git a/tabled/examples/extended_display.rs b/tabled/examples/extended_display.rs index d3125788..94eb013f 100644 --- a/tabled/examples/extended_display.rs +++ b/tabled/examples/extended_display.rs @@ -5,17 +5,17 @@ use tabled::{tables::ExtendedTable, Tabled}; #[derive(Tabled)] struct Distribution { - name: &'static str, - based_on: &'static str, + name: String, + based_on: String, is_active: bool, is_cool: bool, } impl Distribution { - fn new(name: &'static str, based_on: &'static str, is_active: bool, is_cool: bool) -> Self { + fn new(name: &str, based_on: &str, is_active: bool, is_cool: bool) -> Self { Self { - name, - based_on, + name: name.to_string(), + based_on: based_on.to_string(), is_active, is_cool, } diff --git a/tabled/examples/extract.rs b/tabled/examples/extract.rs index 8d7d8643..fdd311bb 100644 --- a/tabled/examples/extract.rs +++ b/tabled/examples/extract.rs @@ -9,98 +9,59 @@ //! * Note how [`Extract`] methods accepts [`RangeBounds`] arguments, //! making subset specifications concise. -use std::fmt::{Display, Formatter}; - use tabled::{ - settings::{ - object::{Columns, Rows}, - Alignment, Extract, Format, Modify, Style, - }, + settings::{object::Rows, Alignment, Extract, Style}, Table, Tabled, }; #[derive(Tabled)] struct Album { - artist: &'static str, - name: &'static str, - released: &'static str, - level_of_greatness: LevelOfGreatness, + artist: String, + name: String, + released: String, + #[tabled(format = "{:?}")] + greatness: Greatness, } impl Album { - fn new( - artist: &'static str, - name: &'static str, - released: &'static str, - level_of_greatness: LevelOfGreatness, - ) -> Self { + fn new(artist: &str, name: &str, released: &str, greatness: Greatness) -> Self { Self { - artist, - name, - released, - level_of_greatness, + name: name.to_string(), + artist: artist.to_string(), + released: released.to_string(), + greatness, } } } #[derive(Debug)] -enum LevelOfGreatness { +enum Greatness { Supreme, Outstanding, Unparalleled, } -impl Display for LevelOfGreatness { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - std::fmt::Debug::fmt(&self, f) - } -} - fn main() { - use LevelOfGreatness::*; + use Greatness::*; + #[rustfmt::skip] let data = [ - Album::new( - "Pink Floyd", - "The Dark Side of the Moon", - "01 March 1973", - Unparalleled, - ), + Album::new("Pink Floyd", "The Dark Side of the Moon", "01 March 1973", Unparalleled), Album::new("Fleetwood Mac", "Rumours", "04 February 1977", Outstanding), - Album::new( - "Led Zeppelin", - "Led Zeppelin IV", - "08 November 1971", - Supreme, - ), + Album::new("Led Zeppelin", "Led Zeppelin IV", "08 November 1971", Supreme), ]; - println!("Full"); + println!("Full table"); let mut table = Table::new(data); table .with(Style::modern()) - .with(Modify::new(Rows::first()).with(Alignment::center())) - .with(Modify::new(Rows::new(1..)).with(Alignment::left())); + .modify(Rows::first(), Alignment::center()) + .modify(Rows::new(1..), Alignment::left()); println!("{table}"); println!("Segment row: (1..=2) column: (1..)"); - let table = table.with(Extract::segment(1..=2, 1..)); - println!("{table}"); - - println!("Refinished segment"); - - let highlight = Format::content(|s| { - if s == "Outstanding" { - format!("+{s}+") - } else { - s.to_string() - } - }); - - let table = table - .with(Style::modern()) - .with(Modify::new(Columns::new(1..)).with(highlight)); + table.with(Extract::segment(1..=2, 1..)); println!("{table}"); } diff --git a/tabled/examples/format.rs b/tabled/examples/format.rs index 5eed98db..54641689 100644 --- a/tabled/examples/format.rs +++ b/tabled/examples/format.rs @@ -40,17 +40,12 @@ fn main() { }, ]; - let table = Table::new(data) - .with(Style::psql()) - .modify( - Rows::first(), - Format::positioned(|_, (_, column)| column.to_string()), - ) - .modify( - Columns::first().not(Rows::first()), - Format::content(|s| format!("{s}...")), - ) - .to_string(); + let mut table = Table::new(data); + table.with(Style::psql()); + table.modify( + Columns::first().not(Rows::first()), + Format::content(|s| s.chars().take(5).collect()), + ); println!("{table}"); } diff --git a/tabled/examples/formatting_settings.rs b/tabled/examples/formatting_settings.rs index 19c8a480..c0f86d25 100644 --- a/tabled/examples/formatting_settings.rs +++ b/tabled/examples/formatting_settings.rs @@ -7,8 +7,7 @@ use tabled::{ settings::{ formatting::{AlignmentStrategy, TrimStrategy}, - object::Segment, - Alignment, Modify, Style, + Alignment, Style, }, Table, }; @@ -27,21 +26,17 @@ fn main() { ]"#; let mut table = Table::new([some_json]); - table - .with(Style::rounded()) - .with(Modify::new(Segment::all()).with(Alignment::center())); + table.with(Style::rounded()).with(Alignment::center()); println!("A default Alignment settings\n{table}"); - table.with(Modify::new(Segment::all()).with(AlignmentStrategy::PerLine)); + table.with(AlignmentStrategy::PerLine); println!("Per line Alignment strategy\n{table}"); - table.with( - Modify::new(Segment::all()) - .with(AlignmentStrategy::PerCell) - .with(TrimStrategy::Both), - ); + table + .with(AlignmentStrategy::PerCell) + .with(TrimStrategy::Both); println!("A default Alignment; allowing vertical and horizontal trim\n{table}"); } diff --git a/tabled/examples/grid_colors.rs b/tabled/examples/grid_colors.rs index f48b39f4..096a2d0a 100644 --- a/tabled/examples/grid_colors.rs +++ b/tabled/examples/grid_colors.rs @@ -5,21 +5,21 @@ //! reusable themes for backgrounds. use tabled::{ - settings::{Color, Modify, Style}, + settings::{Color, Style}, Table, Tabled, }; #[derive(Tabled)] struct Bsd { - distribution: &'static str, + distribution: String, year_of_first_release: usize, is_active: bool, } impl Bsd { - fn new(distribution: &'static str, year_of_first_release: usize, is_active: bool) -> Self { + fn new(distribution: &str, year_of_first_release: usize, is_active: bool) -> Self { Self { - distribution, + distribution: distribution.to_string(), year_of_first_release, is_active, } @@ -38,9 +38,9 @@ fn main() { let mut table = Table::new(data); table .with(Style::psql()) - .with(Modify::new((0, 0)).with(Color::BG_BLUE)) - .with(Modify::new((1, 1)).with(Color::BG_GREEN)) - .with(Modify::new((2, 2)).with(Color::BG_RED)); + .modify((0, 0), Color::BG_BLUE) + .modify((1, 1), Color::BG_GREEN) + .modify((2, 2), Color::BG_RED); println!("{table}"); } diff --git a/tabled/examples/highlight.rs b/tabled/examples/highlight.rs index c99b7ff9..3ad4fbab 100644 --- a/tabled/examples/highlight.rs +++ b/tabled/examples/highlight.rs @@ -16,13 +16,14 @@ use tabled::{ fn main() { let data = vec![["A", "B", "C"], ["D", "E", "F"], ["G", "H", "I"]]; - let table = Table::new(data) - .with(Style::modern()) - .with(Highlight::outline( - Rows::first().and(Columns::single(1)), - '*', - )) - .to_string(); + let target = Columns::first() + .not(Rows::last()) + .and(Rows::last() - 1) + .and(Rows::last().intersect(Columns::last())); + + let mut table = Table::new(data); + table.with(Style::modern()); + table.with(Highlight::outline(target, '*')); println!("{table}"); } diff --git a/tabled/examples/highlight_color.rs b/tabled/examples/highlight_color.rs index 8cdd1536..af21e24f 100644 --- a/tabled/examples/highlight_color.rs +++ b/tabled/examples/highlight_color.rs @@ -15,13 +15,12 @@ use tabled::{ fn main() { let data = vec![["A", "B", "C"], ["D", "E", "F"], ["G", "H", "I"]]; - let table = Table::new(data) - .with(Style::modern()) - .with(Highlight::color( - Rows::first().and(Columns::single(1)), - BorderColor::filled(Color::BG_BRIGHT_BLACK), - )) - .to_string(); + let target = Rows::first().and(Columns::single(1)); + let color = Color::BG_BRIGHT_BLACK; + + let mut table = Table::new(data); + table.with(Style::modern()); + table.with(Highlight::color(target, BorderColor::filled(color))); println!("{table}"); } diff --git a/tabled/examples/iter_table.rs b/tabled/examples/iter_table.rs index 0a77f743..1194a5df 100644 --- a/tabled/examples/iter_table.rs +++ b/tabled/examples/iter_table.rs @@ -11,21 +11,26 @@ //! * Column cutoff //! * Column width -use std::io::BufRead; +use std::{ + fs::File, + io::{stdout, BufRead, BufReader}, +}; use tabled::{settings::Style, tables::IterTable}; fn main() { let path = file!(); - let file = std::fs::File::open(path).unwrap(); - let reader = std::io::BufReader::new(file); + let file = File::open(path).unwrap(); + let reader = BufReader::new(file); + let iterator = reader.lines().enumerate().map(|(i, line)| match line { - Ok(line) => [i.to_string(), String::from("ok"), line], - Err(err) => [i.to_string(), String::from("error"), err.to_string()], + Ok(line) => [i.to_string(), "ok".into(), line], + Err(err) => [i.to_string(), "error".into(), err.to_string()], }); let table = IterTable::new(iterator).with(Style::ascii_rounded()); - table.build(std::io::stdout()).unwrap(); + table.build(stdout()).unwrap(); + println!() } diff --git a/tabled/examples/merge_duplicates_2.rs b/tabled/examples/merge_duplicates_horizontal.rs similarity index 84% rename from tabled/examples/merge_duplicates_2.rs rename to tabled/examples/merge_duplicates_horizontal.rs index 8afeeee3..e7ee161d 100644 --- a/tabled/examples/merge_duplicates_2.rs +++ b/tabled/examples/merge_duplicates_horizontal.rs @@ -36,24 +36,19 @@ fn main() { #[derive(Tabled)] struct Database { #[tabled(rename = "db")] - db_name: &'static str, - origin_db: &'static str, + db_name: String, + origin_db: String, #[tabled(rename = "table")] - table_name: &'static str, + table_name: String, total: usize, } impl Database { - fn new( - db_name: &'static str, - origin_db: &'static str, - table_name: &'static str, - total: usize, - ) -> Self { + fn new(db_name: &str, origin_db: &str, table_name: &str, total: usize) -> Self { Self { - db_name, - origin_db, - table_name, + db_name: db_name.to_string(), + origin_db: origin_db.to_string(), + table_name: table_name.to_string(), total, } } diff --git a/tabled/examples/merge_duplicates.rs b/tabled/examples/merge_duplicates_vertical.rs similarity index 87% rename from tabled/examples/merge_duplicates.rs rename to tabled/examples/merge_duplicates_vertical.rs index 20ec9a3e..d6facec9 100644 --- a/tabled/examples/merge_duplicates.rs +++ b/tabled/examples/merge_duplicates_vertical.rs @@ -17,25 +17,6 @@ use tabled::{ Table, Tabled, }; -#[derive(Tabled)] -struct DatabaseTable { - #[tabled(rename = "db")] - db_name: &'static str, - #[tabled(rename = "table")] - table_name: &'static str, - total: usize, -} - -impl DatabaseTable { - fn new(db_name: &'static str, table_name: &'static str, total: usize) -> Self { - Self { - db_name, - table_name, - total, - } - } -} - fn main() { let data = [ DatabaseTable::new("database_1", "table_1", 10712), @@ -56,3 +37,22 @@ fn main() { println!("{table}"); } + +#[derive(Tabled)] +struct DatabaseTable { + #[tabled(rename = "db")] + db_name: String, + #[tabled(rename = "table")] + table_name: String, + total: usize, +} + +impl DatabaseTable { + fn new(db_name: &str, table_name: &str, total: usize) -> Self { + Self { + db_name: db_name.to_string(), + table_name: table_name.to_string(), + total, + } + } +} diff --git a/tabled/examples/nested_table_2.rs b/tabled/examples/nested_table_2.rs index 40b0cd0a..6b929c80 100644 --- a/tabled/examples/nested_table_2.rs +++ b/tabled/examples/nested_table_2.rs @@ -8,83 +8,55 @@ use tabled::{settings::Style, Table, Tabled}; +fn main() { + #[rustfmt::skip] + let data = [ + Vendor::new("Azure", Dist::new("Windows", None), Dist::new("Manjaro", Some("Arch"))), + Vendor::new("AWS", Dist::new("Debian", None), Dist::new("Arch", None)), + Vendor::new("GCP", Dist::new("Debian", None), Dist::new("Arch", None)), + ]; + + let mut table = Table::new(data); + table.with(Style::modern()); + + println!("{table}"); +} + #[derive(Tabled)] struct Vendor { - name: &'static str, + name: String, #[tabled(display_with = "display_distribution")] - main_os: Distribution, + main_os: Dist, #[tabled(display_with = "display_distribution")] - switch_os: Distribution, + switch_os: Dist, } impl Vendor { - fn new(name: &'static str, main_os: Distribution, switch_os: Distribution) -> Self { + fn new(name: &str, main_os: Dist, switch_os: Dist) -> Self { Self { - name, + name: name.to_string(), main_os, switch_os, } } } -fn display_distribution(d: &Distribution) -> String { +fn display_distribution(d: &Dist) -> String { Table::new([d]).with(Style::extended()).to_string() } #[derive(Tabled)] -struct Distribution { - name: &'static str, - #[tabled(display_with = "Self::display_based_on")] - based_on: Option<&'static str>, - is_active: bool, - is_cool: bool, -} - -impl Distribution { - fn display_based_on(o: &Option<&'static str>) -> String { - match o { - &Some(s) => s.into(), - None => "Independent".into(), - } - } +struct Dist { + name: String, + #[tabled(format("{}", self.based_on.as_deref().unwrap_or_else(|| "Independent")))] + based_on: Option, } -impl Distribution { - fn new( - name: &'static str, - based_on: Option<&'static str>, - is_active: bool, - is_cool: bool, - ) -> Self { +impl Dist { + fn new(name: &str, based_on: Option<&str>) -> Self { Self { - name, - based_on, - is_active, - is_cool, + name: name.to_string(), + based_on: based_on.map(|s| s.to_string()), } } } - -fn main() { - let data = [ - Vendor::new( - "Azure", - Distribution::new("Windows", None, true, true), - Distribution::new("Manjaro", Some("Arch"), true, true), - ), - Vendor::new( - "AWS", - Distribution::new("Debian", None, true, true), - Distribution::new("Arch", None, true, true), - ), - Vendor::new( - "GCP", - Distribution::new("Debian", None, true, true), - Distribution::new("Arch", None, true, true), - ), - ]; - - let table = Table::new(data).with(Style::modern()).to_string(); - - println!("{table}"); -} diff --git a/tabled/examples/nested_table_3.rs b/tabled/examples/nested_table_3.rs index b1ea7c51..00eec47d 100644 --- a/tabled/examples/nested_table_3.rs +++ b/tabled/examples/nested_table_3.rs @@ -5,9 +5,9 @@ use tabled::{ settings::{ - object::{Cell, Segment}, - style::Style, - Alignment, Border, Extract, Highlight, Modify, Panel, + object::Rows, + style::{BorderSpanCorrection, Style}, + Alignment, Border, Extract, Highlight, Padding, Panel, }, Table, Tabled, }; @@ -37,21 +37,24 @@ fn main() { let committers_table = Table::new(committers) .with(Panel::header("Contributors")) - .with(Modify::new(Segment::all()).with(Alignment::center())) + .with(Alignment::center()) + .with(BorderSpanCorrection) .to_string(); let issues_table = Table::new(issuers) .with(Panel::header("Issuers")) - .with(Modify::new(Segment::all()).with(Alignment::center())) + .with(Alignment::center()) + .with(BorderSpanCorrection) .to_string(); - let mut a_welcome_table = - Table::new([String::from("Thank You"), committers_table, issues_table]); - a_welcome_table + let mut welcome_table = Table::new([(committers_table, issues_table)]); + welcome_table .with(Extract::rows(1..)) + .with(Panel::header("Thank You")) .with(Style::ascii().remove_horizontal()) + .modify(Rows::new(1..), Padding::new(1, 1, 1, 0)) .with(Alignment::center()) - .with(Highlight::border(Cell::new(0, 0), Border::filled('*'))); + .with(Highlight::border(Rows::first(), Border::filled('*'))); - println!("{a_welcome_table}"); + println!("{welcome_table}"); } diff --git a/tabled/examples/panel.rs b/tabled/examples/panel.rs index 343abcd6..485e9ec6 100644 --- a/tabled/examples/panel.rs +++ b/tabled/examples/panel.rs @@ -25,17 +25,12 @@ struct Release { } impl Release { - const fn new( - version: &'static str, - published_date: &'static str, - is_active: bool, - major_feature: &'static str, - ) -> Self { + const fn new(v: &'static str, p: &'static str, active: bool, feature: &'static str) -> Self { Self { - version, - published_date, - is_active, - major_feature, + version: v, + published_date: p, + is_active: active, + major_feature: feature, } } } diff --git a/tabled/examples/table.rs b/tabled/examples/table.rs index 518f8fee..2e685d98 100644 --- a/tabled/examples/table.rs +++ b/tabled/examples/table.rs @@ -19,7 +19,7 @@ //! * [`Padding`] use tabled::{ - settings::{object::Rows, Alignment, Modify, Style}, + settings::{object::Rows, Alignment, Style}, Table, Tabled, }; @@ -50,7 +50,7 @@ fn main() { let mut table = Table::new(data); table .with(Style::markdown()) - .with(Modify::new(Rows::first()).with(Alignment::center())); + .modify(Rows::first(), Alignment::center()); println!("{table}"); } diff --git a/tabled/examples/table_width_2.rs b/tabled/examples/table_width_2.rs index d4ed9be3..ed970642 100644 --- a/tabled/examples/table_width_2.rs +++ b/tabled/examples/table_width_2.rs @@ -4,7 +4,7 @@ //! greatly reducing the legibility of the display. use tabled::{ - settings::{object::Segment, Alignment, Modify, Style, Width}, + settings::{object::Segment, Style, Width}, Table, }; @@ -13,11 +13,8 @@ fn main() { let lines = readme_text.lines().filter(|s| !s.is_empty()).enumerate(); let mut table = Table::new(lines); - table.with(Style::ascii_rounded()).with( - Modify::new(Segment::all()) - .with(Width::wrap(30).keep_words(true)) - .with(Alignment::left()), - ); + table.with(Style::ascii_rounded()); + table.modify(Segment::all(), Width::wrap(30).keep_words(true)); println!("{table}"); } diff --git a/tabled/src/settings/highlight/mod.rs b/tabled/src/settings/highlight/mod.rs index ca4c8616..f3bc529d 100644 --- a/tabled/src/settings/highlight/mod.rs +++ b/tabled/src/settings/highlight/mod.rs @@ -127,7 +127,7 @@ impl Highlight { /// /// BE AWARE: if target exceeds boundaries it may panic. // #[cfg(feature = "ansi")] - pub fn color(target: O, border: BorderColor) -> Self { + pub fn color(target: O, border: BorderColor) -> Self { let color = border.into_inner(); let color = color.convert(); @@ -158,7 +158,7 @@ impl Highlight { pub fn colored_border( target: O, border: Border, - color: BorderColor, + color: BorderColor, ) -> Self { let border = border.into_inner(); let color = color.into_inner().convert(); diff --git a/tabled/src/settings/style/border_color.rs b/tabled/src/settings/style/border_color.rs index bf3b3d49..6a587034 100644 --- a/tabled/src/settings/style/border_color.rs +++ b/tabled/src/settings/style/border_color.rs @@ -1,13 +1,11 @@ //! This module contains a configuration of a Border to set its color via [`BorderColor`]. -use core::marker::PhantomData; - use crate::{ grid::{ config::{Border as GridBorder, ColoredConfig, Entity}, records::{ExactRecords, Records}, }, - settings::{style::On, CellOption, Color, TableOption}, + settings::{CellOption, Color, TableOption}, }; /// Border represents a border color of a Cell. @@ -36,34 +34,20 @@ use crate::{ /// .modify(Rows::single(0), BorderColor::new().set_top(Color::FG_RED)); /// ``` #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct BorderColor { +pub struct BorderColor { inner: GridBorder, - _top: PhantomData, - _bottom: PhantomData, - _left: PhantomData, - _right: PhantomData, } -impl BorderColor { - pub(crate) const fn from_border(inner: GridBorder) -> BorderColor { - BorderColor { - inner, - _top: PhantomData, - _bottom: PhantomData, - _left: PhantomData, - _right: PhantomData, - } +impl BorderColor { + pub(crate) const fn from_border(inner: GridBorder) -> Self { + BorderColor { inner } } -} -impl BorderColor<(), (), (), ()> { /// Creates an empty border. pub const fn new() -> Self { Self::from_border(GridBorder::empty()) } -} -impl BorderColor { /// This function constructs a cell borders with all sides set. #[allow(clippy::too_many_arguments)] pub const fn full( @@ -102,29 +86,27 @@ impl BorderColor { c, ) } -} -impl BorderColor { /// Set a top border color. - pub fn set_top(mut self, c: Color) -> BorderColor { + pub fn top(mut self, c: Color) -> Self { self.inner.top = Some(c); BorderColor::from_border(self.inner) } /// Set a bottom border color. - pub fn set_bottom(mut self, c: Color) -> BorderColor { + pub fn bottom(mut self, c: Color) -> Self { self.inner.bottom = Some(c); BorderColor::from_border(self.inner) } /// Set a left border color. - pub fn set_left(mut self, c: Color) -> BorderColor { + pub fn left(mut self, c: Color) -> Self { self.inner.left = Some(c); BorderColor::from_border(self.inner) } /// Set a right border color. - pub fn set_right(mut self, c: Color) -> BorderColor { + pub fn right(mut self, c: Color) -> Self { self.inner.right = Some(c); BorderColor::from_border(self.inner) } @@ -133,95 +115,39 @@ impl BorderColor { pub fn into_inner(self) -> GridBorder { self.inner } -} - -impl BorderColor { - /// Get a right color. - pub fn get_right(&self) -> Color { - get_color(self.inner.right.clone()) - } -} - -impl BorderColor { - /// Get a left color. - pub fn get_left(&self) -> Color { - get_color(self.inner.left.clone()) - } -} - -impl BorderColor { - /// Get a top color. - pub fn get_top(&self) -> Color { - get_color(self.inner.top.clone()) - } -} - -impl BorderColor { - /// Get a bottom color. - pub fn get_bottom(&self) -> Color { - get_color(self.inner.bottom.clone()) - } -} -impl BorderColor { /// Set a top left intersection color. - pub fn set_corner_top_left(mut self, c: Color) -> Self { + pub fn corner_top_left(mut self, c: Color) -> Self { self.inner.left_top_corner = Some(c); self } - /// Get a top left intersection color. - pub fn get_corner_top_left(&self) -> Color { - get_color(self.inner.left_top_corner.clone()) - } -} - -impl BorderColor { /// Set a top right intersection color. - pub fn set_corner_top_right(mut self, c: Color) -> Self { + pub fn corner_top_right(mut self, c: Color) -> Self { self.inner.right_top_corner = Some(c); self } - /// Get a top right intersection color. - pub fn get_corner_top_right(&self) -> Color { - get_color(self.inner.right_top_corner.clone()) - } -} - -impl BorderColor { /// Set a bottom left intersection color. - pub fn set_corner_bottom_left(mut self, c: Color) -> Self { + pub fn corner_bottom_left(mut self, c: Color) -> Self { self.inner.left_bottom_corner = Some(c); self } - /// Get a bottom left intersection color. - pub fn get_corner_bottom_left(&self) -> Color { - get_color(self.inner.left_bottom_corner.clone()) - } -} - -impl BorderColor { /// Set a bottom right intersection color. - pub fn set_corner_bottom_right(mut self, c: Color) -> Self { + pub fn corner_bottom_right(mut self, c: Color) -> Self { self.inner.right_bottom_corner = Some(c); self } - - /// Get a bottom left intersection color. - pub fn get_corner_bottom_right(&self) -> Color { - get_color(self.inner.right_bottom_corner.clone()) - } } -impl From> for GridBorder { - fn from(value: BorderColor) -> Self { +impl From for GridBorder { + fn from(value: BorderColor) -> Self { value.inner } } -impl CellOption for BorderColor +impl CellOption for BorderColor where Data: Records + ExactRecords, { @@ -237,7 +163,7 @@ where } } -impl TableOption for BorderColor +impl TableOption for BorderColor where Data: Records + ExactRecords, { @@ -254,10 +180,3 @@ where } } } - -fn get_color(c: Option) -> Color { - match c { - Some(c) => c, - None => unreachable!(), - } -} diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs index cf1b9941..6119a4e8 100644 --- a/tabled/src/settings/themes/theme.rs +++ b/tabled/src/settings/themes/theme.rs @@ -118,11 +118,19 @@ impl Theme { /// Remove horizontal lines. pub fn remove_horizontal_lines(&mut self) { self.set_horizontal_lines(HashMap::new()); + self.chars.horizontal = None; + self.chars.left_intersection = None; + self.chars.right_intersection = None; + self.chars.intersection = None; } /// Remove vertical lines. pub fn remove_vertical_lines(&mut self) { self.set_vertical_lines(HashMap::new()); + self.chars.vertical = None; + self.chars.top_intersection = None; + self.chars.bottom_intersection = None; + self.chars.intersection = None; } /// Set an outer border. diff --git a/tabled/tests/settings/style_test.rs b/tabled/tests/settings/style_test.rs index 9f262139..2e5281ea 100644 --- a/tabled/tests/settings/style_test.rs +++ b/tabled/tests/settings/style_test.rs @@ -337,7 +337,7 @@ test_table!( test_table!( border_color_global, - Matrix::table(2, 2).with(BorderColor::new().set_bottom(Color::FG_RED)), + Matrix::table(2, 2).with(BorderColor::new().bottom(Color::FG_RED)), "+---+----------+----------+" "| N | column 0 | column 1 |" "+\u{1b}[31m---\u{1b}[39m+\u{1b}[31m----------\u{1b}[39m+\u{1b}[31m----------\u{1b}[39m+" From 76d11d8a74bc17832251ecc76e5855950a502557 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Mon, 22 Jul 2024 00:44:58 +0300 Subject: [PATCH 18/20] fix --- tabled/src/settings/style/border_color.rs | 2 +- tabled/tests/settings/style_test.rs | 32 +++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tabled/src/settings/style/border_color.rs b/tabled/src/settings/style/border_color.rs index 6a587034..3d72a44c 100644 --- a/tabled/src/settings/style/border_color.rs +++ b/tabled/src/settings/style/border_color.rs @@ -31,7 +31,7 @@ use crate::{ /// # let data: Vec<&'static str> = Vec::new(); /// let table = Table::new(&data) /// .with(Style::ascii()) -/// .modify(Rows::single(0), BorderColor::new().set_top(Color::FG_RED)); +/// .modify(Rows::single(0), BorderColor::new().top(Color::FG_RED)); /// ``` #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct BorderColor { diff --git a/tabled/tests/settings/style_test.rs b/tabled/tests/settings/style_test.rs index 2e5281ea..8e6544db 100644 --- a/tabled/tests/settings/style_test.rs +++ b/tabled/tests/settings/style_test.rs @@ -353,8 +353,8 @@ test_table!( Matrix::table(2, 2) .with(LineText::new("-Table", Rows::single(1))) .with(LineText::new("-Table213123", Rows::single(2))) - .with(Modify::new(Rows::single(1)).with(BorderColor::new().set_bottom(Color::FG_RED))) - .with(Modify::new(Rows::single(2)).with(BorderColor::new().set_bottom(Color::try_from(" ".blue().on_green().to_string()).unwrap()))), + .with(Modify::new(Rows::single(1)).with(BorderColor::new().bottom(Color::FG_RED))) + .with(Modify::new(Rows::single(2)).with(BorderColor::new().bottom(Color::try_from(" ".blue().on_green().to_string()).unwrap()))), "+---+----------+----------+" "| N | column 0 | column 1 |" "-Table---------+----------+" @@ -2076,7 +2076,7 @@ fn border_colored_test() { Modify::new(Rows::single(1)) .with( BorderColor::filled(Color::try_from('*'.blue().to_string()).unwrap()) - .set_top(Color::try_from('#'.truecolor(12, 220, 100).to_string()).unwrap()), + .top(Color::try_from('#'.truecolor(12, 220, 100).to_string()).unwrap()), ) .with(Border::filled('*').set_top('#')), ) @@ -2114,7 +2114,7 @@ fn border_colored_test() { Modify::new(Rows::single(1)) .with( BorderColor::filled(Color::try_from('*'.blue().to_string()).unwrap()) - .set_top(Color::try_from('#'.truecolor(12, 220, 100).to_string()).unwrap()), + .top(Color::try_from('#'.truecolor(12, 220, 100).to_string()).unwrap()), ) .with(Border::filled('*').set_top('#')), ) @@ -2141,18 +2141,18 @@ fn border_colored_test() { #[test] fn style_with_color_test() { let mut style = Theme::from_style(Style::ascii()); - style.set_border_left('['); - style.set_border_right(']'); - style.set_border_top('-'); - style.set_border_bottom('-'); - style.set_border_vertical('|'); - style.set_border_intersection('+'); - style.set_border_color_left(Color::FG_RED); - style.set_border_color_right(Color::FG_RED); - style.set_border_color_top(Color::FG_BLUE); - style.set_border_color_bottom(Color::FG_BLUE); - style.set_border_color_vertical(Color::FG_YELLOW); - style.set_border_color_intersection(Color::try_from(' '.purple().to_string()).unwrap()); + style.set_borders_left('['); + style.set_borders_right(']'); + style.set_borders_top('-'); + style.set_borders_bottom('-'); + style.set_borders_vertical('|'); + style.set_borders_intersection('+'); + style.set_colors_left(Color::FG_RED); + style.set_colors_right(Color::FG_RED); + style.set_colors_top(Color::FG_BLUE); + style.set_colors_bottom(Color::FG_BLUE); + style.set_colors_vertical(Color::FG_YELLOW); + style.set_colors_intersection(Color::try_from(' '.purple().to_string()).unwrap()); let table = Matrix::new(3, 3).with(style).to_string(); From f277597330a2617ff854cb08a41913637542d894 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Mon, 22 Jul 2024 02:41:01 +0300 Subject: [PATCH 19/20] fix --- tabled/examples/compact_table.rs | 2 +- tabled/examples/compact_table_2.rs | 2 +- tabled/examples/compact_table_3.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tabled/examples/compact_table.rs b/tabled/examples/compact_table.rs index 6dc2ff03..86e870c5 100644 --- a/tabled/examples/compact_table.rs +++ b/tabled/examples/compact_table.rs @@ -4,7 +4,7 @@ //! * [`CompactTable`] is a [`Table`] alternative that trades off reduced //! flexibility for improved performance. -#![allow(dead_code)] +#![allow(unused_variables)] use tabled::{settings::style::Style, tables::CompactTable}; diff --git a/tabled/examples/compact_table_2.rs b/tabled/examples/compact_table_2.rs index ef543da2..61bd9d34 100644 --- a/tabled/examples/compact_table_2.rs +++ b/tabled/examples/compact_table_2.rs @@ -4,7 +4,7 @@ //! * Note how [`CompactTable::from()`] inherits the lengths of the nested arrays //! as typed definitions through [const generics](https://practice.rs/generics-traits/const-generics.html). -#![allow(dead_code)] +#![allow(unused_variables)] use tabled::{settings::style::Style, tables::CompactTable}; diff --git a/tabled/examples/compact_table_3.rs b/tabled/examples/compact_table_3.rs index 252eafd1..93b0ceca 100644 --- a/tabled/examples/compact_table_3.rs +++ b/tabled/examples/compact_table_3.rs @@ -3,7 +3,7 @@ //! //! * Note how the multiline data is accepted, but then truncated in the display. -#![allow(dead_code)] +#![allow(unused_variables)] use tabled::{settings::style::Style, tables::CompactTable}; From 84b5d980ef61d42fa960bd530fea38fd9ac7563f Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Mon, 22 Jul 2024 03:02:41 +0300 Subject: [PATCH 20/20] Fix SpanBorderCorrection issue --- .../settings/style/span_border_correction.rs | 5 ++++ tabled/tests/settings/span_test.rs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/tabled/src/settings/style/span_border_correction.rs b/tabled/src/settings/style/span_border_correction.rs index e3e6571a..b6a07c45 100644 --- a/tabled/src/settings/style/span_border_correction.rs +++ b/tabled/src/settings/style/span_border_correction.rs @@ -171,10 +171,15 @@ fn correct_span_styles(cfg: &mut SpannedConfig, shape: (usize, usize)) { let has_right = col + 1 < shape.1 && has_top(cfg, (row, col + 1), shape); let has_up = has_left(cfg, (row - 1, col), shape); + if has_up && !has_right { border.right_top_corner = borders.right_intersection; } + if !has_up && has_right { + border.right_top_corner = borders.left_intersection; + } + let has_down = row + 1 < shape.0 && has_left(cfg, (row + 1, col), shape); if has_down { border.left_bottom_corner = borders.top_intersection; diff --git a/tabled/tests/settings/span_test.rs b/tabled/tests/settings/span_test.rs index da60435e..4436139e 100644 --- a/tabled/tests/settings/span_test.rs +++ b/tabled/tests/settings/span_test.rs @@ -1229,6 +1229,32 @@ test_table!( "+------+-----++++++++++++++++++++++++++++------------+------------+------------+------------+------------+-----------+-----------+------------+------------+-----------+" ); +test_table!( + test_span_issue_0, + Table::new([["just 1 column"; 5]; 5]) + .modify((3, 1), "span 2 columns\nspan\n2\ncolumns") + .modify((3, 1), Span::row(2)) + .modify((3, 1), Span::column(2)) + .with(Style::modern()) + .with(BorderSpanCorrection) + .with(Alignment::center_vertical()) + .to_string(), + "┌───────────────┬───────────────┬───────────────┬───────────────┬───────────────┐" + "│ 0 │ 1 │ 2 │ 3 │ 4 │" + "├───────────────┼───────────────┼───────────────┼───────────────┼───────────────┤" + "│ just 1 column │ just 1 column │ just 1 column │ just 1 column │ just 1 column │" + "├───────────────┼───────────────┼───────────────┼───────────────┼───────────────┤" + "│ just 1 column │ just 1 column │ just 1 column │ just 1 column │ just 1 column │" + "├───────────────┼───────────────┴───────────────┼───────────────┼───────────────┤" + "│ just 1 column │ span 2 columns │ just 1 column │ just 1 column │" + "│ │ span │ │ │" + "├───────────────┤ 2 ├───────────────┼───────────────┤" + "│ just 1 column │ columns │ just 1 column │ just 1 column │" + "├───────────────┼───────────────┬───────────────┼───────────────┼───────────────┤" + "│ just 1 column │ just 1 column │ just 1 column │ just 1 column │ just 1 column │" + "└───────────────┴───────────────┴───────────────┴───────────────┴───────────────┘" +); + fn create_span_list(count_rows: usize, count_cols: usize) -> impl Iterator { (0..count_rows).flat_map(move |r| (0..count_cols).map(move |c| (r, c))) }