Repository: zhiburt/tabled
Pull request #473 (2025-01-01 22:21:28)

Improvements in papergrid


Patch:
diff --git a/papergrid/src/colors.rs b/papergrid/src/colors.rs
index aabcb8b..e34b848 100644
--- a/papergrid/src/colors.rs
+++ b/papergrid/src/colors.rs
@@ -64,17 +64,16 @@ where
 #[cfg(feature = "std")]
 impl<C> Colors for crate::config::spanned::EntityMap<Option<C>>
 where
-    C: ANSIFmt,
+    C: ANSIFmt + PartialEq,
 {
     type Color = C;
 
     fn get_color(&self, pos: Position) -> Option<&Self::Color> {
-        self.get(pos.into()).as_ref()
+        self.get(pos).as_ref()
     }
 
     fn is_empty(&self) -> bool {
-        crate::config::spanned::EntityMap::is_empty(self)
-            && self.get(crate::config::Entity::Global).is_none()
+        self.is_empty() && self.as_ref().is_none()
     }
 }
 
diff --git a/papergrid/src/config/sides.rs b/papergrid/src/config/sides.rs
index 25b5bcc..3185985 100644
--- a/papergrid/src/config/sides.rs
+++ b/papergrid/src/config/sides.rs
@@ -56,3 +56,10 @@ impl<T> Sides<T> {
         )
     }
 }
+
+impl<T> Sides<Option<T>> {
+    /// Checkes whether any option was set
+    pub const fn is_empty(&self) -> bool {
+        self.left.is_none() && self.right.is_none() && self.top.is_none() && self.bottom.is_none()
+    }
+}
diff --git a/papergrid/src/config/spanned/entity_map.rs b/papergrid/src/config/spanned/entity_map.rs
index 2a6d56b..79f072c 100644
--- a/papergrid/src/config/spanned/entity_map.rs
+++ b/papergrid/src/config/spanned/entity_map.rs
@@ -32,40 +32,29 @@ impl<T> EntityMap<T> {
     }
 
     /// Get a value for an [`Entity`].
-    pub fn get(&self, entity: Entity) -> &T {
-        if self.rows.is_empty() && self.columns.is_empty() && self.cells.is_empty() {
-            return &self.global;
-        }
-
-        match entity {
-            Entity::Column(col) => self.columns.get(&col).unwrap_or(&self.global),
-            Entity::Row(row) => self.rows.get(&row).unwrap_or(&self.global),
-            Entity::Cell(row, col) => {
-                // todo: optimize;
-                //
-                // Cause we can change rows/columns/cells separately we need to check them separately.
-                // But we often doing this checks in `Grid::fmt` and I believe if we could optimize it it could be beneficial.
-                //
-                // Haven't found a solution for that yet.
-                //
-                // I was wondering if there is a hash function like.
-                // Apparently it doesn't make sense cause we will reset columns/rows on cell insert which is not what we want.
-                //
-                // ```
-                // hash(column, row) == hash(column) == hash(row)
-                // ```
-                //
-                // ref: https://opendsa-server.cs.vt.edu/ODSA/Books/Everything/html/Sparse.html
-                // ref: https://users.rust-lang.org/t/make-hash-return-same-value-whather-the-order-of-element-of-a-tuple/69932/13
-
-                self.cells
-                    .get(&(row, col))
-                    .or_else(|| self.columns.get(&col))
-                    .or_else(|| self.rows.get(&row))
-                    .unwrap_or(&self.global)
-            }
-            Entity::Global => &self.global,
-        }
+    pub fn get(&self, (row, col): Position) -> &T {
+        // todo: optimize;
+        //
+        // Cause we can change rows/columns/cells separately we need to check them separately.
+        // But we often doing this checks in `Grid::fmt` and I believe if we could optimize it it could be beneficial.
+        //
+        // Haven't found a solution for that yet.
+        //
+        // I was wondering if there is a hash function like.
+        // Apparently it doesn't make sense cause we will reset columns/rows on cell insert which is not what we want.
+        //
+        // ```
+        // hash(column, row) == hash(column) == hash(row)
+        // ```
+        //
+        // ref: https://opendsa-server.cs.vt.edu/ODSA/Books/Everything/html/Sparse.html
+        // ref: https://users.rust-lang.org/t/make-hash-return-same-value-whather-the-order-of-element-of-a-tuple/69932/13
+
+        self.cells
+            .get(&(row, col))
+            .or_else(|| self.columns.get(&col))
+            .or_else(|| self.rows.get(&row))
+            .unwrap_or(&self.global)
     }
 
     /// Removes a value for an [`Entity`].
@@ -134,3 +123,9 @@ impl<T> From<EntityMap<T>> for HashMap<Entity, T> {
         m
     }
 }
+
+impl<T> AsRef<T> for EntityMap<T> {
+    fn as_ref(&self) -> &T {
+        &self.global
+    }
+}
diff --git a/papergrid/src/config/spanned/mod.rs b/papergrid/src/config/spanned/mod.rs
index 5da0207..a41046b 100644
--- a/papergrid/src/config/spanned/mod.rs
+++ b/papergrid/src/config/spanned/mod.rs
@@ -10,7 +10,6 @@ use std::collections::HashMap;
 
 use crate::ansi::{ANSIBuf, ANSIStr};
 use crate::config::compact::CompactConfig;
-use crate::config::Formatting;
 use crate::config::{
     AlignmentHorizontal, AlignmentVertical, Border, Borders, Entity, Indent, Position, Sides,
 };
@@ -18,6 +17,8 @@ use borders_config::BordersConfig;
 
 pub use self::{entity_map::EntityMap, offset::Offset};
 
+use super::Formatting;
+
 /// HorizontalLine represents a horizontal border line.
 type HorizontalLine = super::HorizontalLine<char>;
 
@@ -29,11 +30,14 @@ type VerticalLine = super::VerticalLine<char>;
 /// grid: crate::Grid.
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub struct SpannedConfig {
-    margin: Sides<ColoredMarginIndent>,
-    padding: EntityMap<Sides<ColoredIndent>>,
+    margin: Sides<MarginIndent>,
+    padding: EntityMap<Sides<Indent>>,
+    padding_color: EntityMap<Sides<Option<ANSIBuf>>>,
     alignment_h: EntityMap<AlignmentHorizontal>,
     alignment_v: EntityMap<AlignmentVertical>,
-    formatting: EntityMap<Formatting>,
+    formatting_trim_h: EntityMap<bool>,
+    formatting_trim_v: EntityMap<bool>,
+    formatting_line_alignment: EntityMap<bool>,
     span_columns: HashMap<Position, usize>,
     span_rows: HashMap<Position, usize>,
     borders: BordersConfig<char>,
@@ -52,7 +56,10 @@ impl Default for SpannedConfig {
         Self {
             margin: Sides::default(),
             padding: EntityMap::default(),
-            formatting: EntityMap::default(),
+            padding_color: EntityMap::default(),
+            formatting_trim_h: EntityMap::default(),
+            formatting_trim_v: EntityMap::default(),
+            formatting_line_alignment: EntityMap::default(),
             alignment_h: EntityMap::new(AlignmentHorizontal::Left),
             alignment_v: EntityMap::new(AlignmentVertical::Top),
             span_columns: HashMap::default(),
@@ -413,56 +420,61 @@ impl SpannedConfig {
 
     /// Set a padding to a given cells.
     pub fn set_padding(&mut self, entity: Entity, padding: Sides<Indent>) {
-        let mut pad = self.padding.get(entity).clone();
-        pad.left.indent = padding.left;
-        pad.right.indent = padding.right;
-        pad.top.indent = padding.top;
-        pad.bottom.indent = padding.bottom;
-
-        self.padding.insert(entity, pad);
+        self.padding.insert(entity, padding);
     }
 
     /// Set a padding to a given cells.
     pub fn set_padding_color(&mut self, entity: Entity, padding: Sides<Option<ANSIBuf>>) {
-        let mut pad = self.padding.get(entity).clone();
-        pad.left.color = padding.left;
-        pad.right.color = padding.right;
-        pad.top.color = padding.top;
-        pad.bottom.color = padding.bottom;
+        self.padding_color.insert(entity, padding);
+    }
 
-        self.padding.insert(entity, pad);
+    /// Get a padding for a given cell by [Position].
+    pub fn get_padding(&self, pos: Position) -> Sides<Indent> {
+        *self.padding.get(pos)
     }
 
-    /// Get a padding for a given [Entity].
-    pub fn get_padding(&self, entity: Entity) -> Sides<Indent> {
-        let pad = self.padding.get(entity);
-        Sides::new(
-            pad.left.indent,
-            pad.right.indent,
-            pad.top.indent,
-            pad.bottom.indent,
-        )
+    /// Get a padding color for a given cell by [Position].
+    pub fn get_padding_color(&self, pos: Position) -> Sides<Option<ANSIBuf>> {
+        self.padding_color.get(pos).clone()
     }
 
-    /// Get a padding color for a given [Entity].
-    pub fn get_padding_color(&self, entity: Entity) -> Sides<Option<ANSIBuf>> {
-        let pad = self.padding.get(entity);
-        Sides::new(
-            pad.left.color.clone(),
-            pad.right.color.clone(),
-            pad.top.color.clone(),
-            pad.bottom.color.clone(),
-        )
+    /// Set a formatting to a given cells.
+    pub fn set_trim_horizontal(&mut self, entity: Entity, on: bool) {
+        self.formatting_trim_h.insert(entity, on);
+    }
+
+    /// Get a formatting settings for a given cell by [Position].
+    pub fn get_trim_horizonal(&self, pos: Position) -> bool {
+        *self.formatting_trim_h.get(pos)
+    }
+
+    /// Set a formatting to a given cells.
+    pub fn set_trim_vertical(&mut self, entity: Entity, on: bool) {
+        self.formatting_trim_v.insert(entity, on);
+    }
+
+    /// Get a formatting settings for a given cell by [Position].
+    pub fn get_trim_vertical(&self, pos: Position) -> bool {
+        *self.formatting_trim_v.get(pos)
     }
 
     /// Set a formatting to a given cells.
-    pub fn set_formatting(&mut self, entity: Entity, formatting: Formatting) {
-        self.formatting.insert(entity, formatting);
+    pub fn set_line_alignment(&mut self, entity: Entity, on: bool) {
+        self.formatting_line_alignment.insert(entity, on);
     }
 
-    /// Get a formatting settings for a given [Entity].
-    pub fn get_formatting(&self, entity: Entity) -> &Formatting {
-        self.formatting.get(entity)
+    /// Get a formatting settings for a given cell by [Position].
+    pub fn get_line_alignment(&self, pos: Position) -> bool {
+        *self.formatting_line_alignment.get(pos)
+    }
+
+    /// Get a formatting settings for a given cell by [Position].
+    pub fn get_formatting(&self, pos: Position) -> Formatting {
+        Formatting::new(
+            *self.formatting_trim_h.get(pos),
+            *self.formatting_trim_v.get(pos),
+            *self.formatting_line_alignment.get(pos),
+        )
     }
 
     /// Set a vertical alignment to a given cells.
@@ -470,9 +482,9 @@ impl SpannedConfig {
         self.alignment_v.insert(entity, alignment);
     }
 
-    /// Get a vertical alignment for a given [Entity].
-    pub fn get_alignment_vertical(&self, entity: Entity) -> &AlignmentVertical {
-        self.alignment_v.get(entity)
+    /// Get a vertical alignment for a given cell by [Position].
+    pub fn get_alignment_vertical(&self, pos: Position) -> &AlignmentVertical {
+        self.alignment_v.get(pos)
     }
 
     /// Set a horizontal alignment to a given cells.
@@ -480,9 +492,9 @@ impl SpannedConfig {
         self.alignment_h.insert(entity, alignment);
     }
 
-    /// Get a horizontal alignment for a given [Entity].
-    pub fn get_alignment_horizontal(&self, entity: Entity) -> &AlignmentHorizontal {
-        self.alignment_h.get(entity)
+    /// Get a horizontal alignment for a given cell by [Position].
+    pub fn get_alignment_horizontal(&self, pos: Position) -> &AlignmentHorizontal {
+        self.alignment_h.get(pos)
     }
 
     /// Set border set a border value to all cells in [`Entity`].
@@ -555,15 +567,15 @@ impl SpannedConfig {
     }
 
     /// Get a justification which will be used while expanding cells width/height.
-    pub fn get_justification(&self, entity: Entity) -> char {
-        *self.justification.get(entity)
+    pub fn get_justification(&self, pos: Position) -> char {
+        *self.justification.get(pos)
     }
 
     /// Get a justification color which will be used while expanding cells width/height.
     ///
     /// `None` means no color.
-    pub fn get_justification_color(&self, entity: Entity) -> Option<&ANSIBuf> {
-        self.justification_color.get(entity).as_ref()
+    pub fn get_justification_color(&self, pos: Position) -> Option<&ANSIBuf> {
+        self.justification_color.get(pos).as_ref()
     }
 
     /// Set a justification which will be used while expanding cells width/height.
@@ -650,7 +662,9 @@ impl SpannedConfig {
 
     /// Verifies if there's any colors set for a borders.
     pub fn has_justification(&self) -> bool {
-        !self.justification.is_empty() || !self.justification_color.is_empty()
+        !self.justification.is_empty()
+            || !self.justification_color.is_empty()
+            || self.justification_color.as_ref().is_some()
     }
 
     /// Verifies if there's any custom padding set.
@@ -660,29 +674,27 @@ impl SpannedConfig {
 
     /// Verifies if there's any custom padding set.
     pub fn has_padding_color(&self) -> bool {
-        let map = HashMap::from(self.padding.clone());
-        let mut has_color = false;
-        for (entity, value) in map {
-            if matches!(entity, Entity::Global) {
-                continue;
-            }
-
-            has_color = value.bottom.color.is_some()
-                || value.top.color.is_some()
-                || value.left.color.is_some()
-                || value.right.color.is_some();
+        if !self.padding_color.is_empty() {
+            let map = HashMap::from(self.padding_color.clone());
+            for (entity, value) in map {
+                if matches!(entity, Entity::Global) {
+                    continue;
+                }
 
-            if has_color {
-                break;
+                if !value.is_empty() {
+                    return true;
+                }
             }
         }
 
-        has_color
+        !self.padding_color.as_ref().is_empty()
     }
 
     /// Verifies if there's any custom formatting set.
     pub fn has_formatting(&self) -> bool {
-        !self.formatting.is_empty()
+        !self.formatting_trim_h.is_empty()
+            || !self.formatting_trim_v.is_empty()
+            || !self.formatting_line_alignment.is_empty()
     }
 
     /// Verifies if there's any custom alignment vertical set.
@@ -898,15 +910,9 @@ fn is_cell_covered_by_both_spans(cfg: &SpannedConfig, pos: Position) -> bool {
     })
 }
 
-#[derive(Default, Debug, Clone, PartialEq, Eq)]
-struct ColoredIndent {
-    indent: Indent,
-    color: Option<ANSIBuf>,
-}
-
 /// A colorefull margin indent.
 #[derive(Debug, Clone, PartialEq, Eq)]
-struct ColoredMarginIndent {
+struct MarginIndent {
     /// An indent value.
     indent: Indent,
     /// An offset value.
@@ -915,7 +921,7 @@ struct ColoredMarginIndent {
     color: Option<ANSIBuf>,
 }
 
-impl Default for ColoredMarginIndent {
+impl Default for MarginIndent {
     fn default() -> Self {
         Self {
             indent: Indent::default(),
diff --git a/papergrid/src/dimension/spanned.rs b/papergrid/src/dimension/spanned.rs
index 8c5e4e5..7d52669 100644
--- a/papergrid/src/dimension/spanned.rs
+++ b/papergrid/src/dimension/spanned.rs
@@ -113,7 +113,7 @@ where
 
             let text = cell.as_ref();
             let (height, width) = get_text_dimension(text);
-            let pad = cfg.get_padding(pos.into());
+            let pad = cfg.get_padding(pos);
             let width = width + pad.left.size + pad.right.size;
             let height = height + pad.top.size + pad.bottom.size;
 
@@ -204,7 +204,7 @@ fn count_horizontal_borders(cfg: &SpannedConfig, len: usize, start: usize, end:
 
 fn get_cell_height(cell: &str, cfg: &SpannedConfig, pos: Position) -> usize {
     let count_lines = max(1, count_lines(cell));
-    let padding = cfg.get_padding(pos.into());
+    let padding = cfg.get_padding(pos);
     count_lines + padding.top.size + padding.bottom.size
 }
 
@@ -279,7 +279,7 @@ fn get_cell_width(text: &str, cfg: &SpannedConfig, pos: Position) -> usize {
 }
 
 fn get_cell_padding(cfg: &SpannedConfig, pos: Position) -> usize {
-    let padding = cfg.get_padding(pos.into());
+    let padding = cfg.get_padding(pos);
     padding.left.size + padding.right.size
 }
 
diff --git a/papergrid/src/dimension/spanned_vec_records.rs b/papergrid/src/dimension/spanned_vec_records.rs
index 75e85a8..88aefb0 100644
--- a/papergrid/src/dimension/spanned_vec_records.rs
+++ b/papergrid/src/dimension/spanned_vec_records.rs
@@ -92,7 +92,7 @@ fn build_dimensions<T: Cell + AsRef<str>>(
 
             let width = cell.width();
             let height = cell.count_lines();
-            let pad = cfg.get_padding(pos.into());
+            let pad = cfg.get_padding(pos);
             let width = width + pad.left.size + pad.right.size;
             let height = height + pad.top.size + pad.bottom.size;
 
@@ -246,12 +246,12 @@ fn adjust_column_range(
 }
 
 fn get_cell_padding_horizontal(cfg: &SpannedConfig, pos: Position) -> usize {
-    let padding = cfg.get_padding(pos.into());
+    let padding = cfg.get_padding(pos);
     padding.left.size + padding.right.size
 }
 
 fn get_cell_vertical_padding(cfg: &SpannedConfig, pos: Position) -> usize {
-    let padding = cfg.get_padding(pos.into());
+    let padding = cfg.get_padding(pos);
     padding.top.size + padding.bottom.size
 }
 
diff --git a/papergrid/src/grid/iterable.rs b/papergrid/src/grid/iterable.rs
index e97fad7..c32fd26 100644
--- a/papergrid/src/grid/iterable.rs
+++ b/papergrid/src/grid/iterable.rs
@@ -10,8 +10,10 @@ use std::{
 use crate::{
     ansi::{ANSIBuf, ANSIFmt},
     colors::Colors,
-    config::spanned::{Offset, SpannedConfig},
-    config::{AlignmentHorizontal, AlignmentVertical, Formatting, Indent, Position, Sides},
+    config::{
+        spanned::{Offset, SpannedConfig},
+        AlignmentHorizontal, AlignmentVertical, Formatting, Indent, Position, Sides,
+    },
     dimension::Dimension,
     records::{IntoRecords, Records},
     util::string::{count_lines, get_line_width, get_lines, get_text_width, Lines},
@@ -292,7 +294,6 @@ fn print_single_line_column<F: Write, C: ANSIFmt>(
     color: Option<&C>,
     pos: Position,
 ) -> fmt::Result {
-    let pos = pos.into();
     let pad = cfg.get_padding(pos);
     let pad_color = cfg.get_padding_color(pos);
     let fmt = cfg.get_formatting(pos);
@@ -782,14 +783,14 @@ where
         color: Option<C>,
         pos: Position,
     ) -> Cell<T, C> {
-        let fmt = *cfg.get_formatting(pos.into());
-        let pad = cfg.get_padding(pos.into());
-        let pad_color = cfg.get_padding_color(pos.into()).clone();
-        let alignh = *cfg.get_alignment_horizontal(pos.into());
-        let alignv = *cfg.get_alignment_vertical(pos.into());
+        let fmt = cfg.get_formatting(pos);
+        let pad = cfg.get_padding(pos);
+        let pad_color = cfg.get_padding_color(pos).clone();
+        let alignh = *cfg.get_alignment_horizontal(pos);
+        let alignv = *cfg.get_alignment_vertical(pos);
         let justification = (
-            cfg.get_justification(pos.into()),
-            cfg.get_justification_color(pos.into()).cloned(),
+            cfg.get_justification(pos),
+            cfg.get_justification_color(pos).cloned(),
         );
 
         let (count_lines, skip) = if fmt.vertical_trim {
diff --git a/papergrid/src/grid/peekable.rs b/papergrid/src/grid/peekable.rs
index 8f47841..deddac6 100644
--- a/papergrid/src/grid/peekable.rs
+++ b/papergrid/src/grid/peekable.rs
@@ -14,7 +14,7 @@ use crate::{
         spanned::{Offset, SpannedConfig},
         Formatting,
     },
-    config::{AlignmentHorizontal, AlignmentVertical, Entity, Indent, Position, Sides},
+    config::{AlignmentHorizontal, AlignmentVertical, Indent, Position, Sides},
     dimension::Dimension,
     records::{ExactRecords, PeekableRecords, Records},
     util::string::get_line_width,
@@ -103,11 +103,10 @@ where
     }
 
     let is_basic = !ctx.cfg.has_border_colors()
+        && !ctx.cfg.has_padding_color()
         && !ctx.cfg.has_justification()
-        && ctx.cfg.get_justification_color(Entity::Global).is_none()
         && !ctx.cfg.has_offset_chars()
         && !has_margin(ctx.cfg)
-        && !has_padding_color(ctx.cfg)
         && ctx.colors.is_empty();
 
     if is_basic {
@@ -122,14 +121,6 @@ fn has_margin(cfg: &SpannedConfig) -> bool {
     margin.left.size > 0 || margin.right.size > 0 || margin.top.size > 0 || margin.bottom.size > 0
 }
 
-fn has_padding_color(cfg: &SpannedConfig) -> bool {
-    let pad = cfg.get_padding_color(Entity::Global);
-    let has_pad =
-        pad.left.is_some() || pad.right.is_some() || pad.top.is_some() || pad.bottom.is_some();
-
-    has_pad || cfg.has_padding_color()
-}
-
 mod grid_basic {
     use super::*;
 
@@ -322,16 +313,14 @@ mod grid_basic {
         R: Records + PeekableRecords + ExactRecords,
         D: Dimension,
     {
-        let entity = Entity::from(pos);
-
         let width = ctx.dims.get_width(pos.1);
 
-        let pad = ctx.cfg.get_padding(entity);
-        let valignment = *ctx.cfg.get_alignment_vertical(entity);
+        let pad = ctx.cfg.get_padding(pos);
+        let valignment = *ctx.cfg.get_alignment_vertical(pos);
         let text_cfg = TextCfg {
-            alignment: *ctx.cfg.get_alignment_horizontal(entity),
-            formatting: *ctx.cfg.get_formatting(entity),
-            justification: ctx.cfg.get_justification(Entity::Global),
+            alignment: *ctx.cfg.get_alignment_horizontal(pos),
+            formatting: ctx.cfg.get_formatting(pos),
+            justification: ctx.cfg.get_justification(pos),
         };
 
         let mut cell_height = ctx.records.count_lines(pos);
@@ -833,24 +822,22 @@ mod grid_not_spanned {
         C: Colors,
         D: Dimension,
     {
-        let entity = pos.into();
-
         let width = ctx.dims.get_width(pos.1);
 
-        let formatting = ctx.cfg.get_formatting(entity);
+        let formatting = ctx.cfg.get_formatting(pos);
         let text_cfg = TextCfg {
-            alignment: *ctx.cfg.get_alignment_horizontal(entity),
+            alignment: *ctx.cfg.get_alignment_horizontal(pos),
             color: ctx.colors.get_color(pos),
             justification: Colored::new(
-                ctx.cfg.get_justification(entity),
-                ctx.cfg.get_justification_color(entity),
+                ctx.cfg.get_justification(pos),
+                ctx.cfg.get_justification_color(pos),
             ),
-            formatting: *formatting,
+            formatting,
         };
 
-        let pad = ctx.cfg.get_padding(entity);
-        let pad_color = ctx.cfg.get_padding_color(entity);
-        let valignment = *ctx.cfg.get_alignment_vertical(entity);
+        let pad = ctx.cfg.get_padding(pos);
+        let pad_color = ctx.cfg.get_padding_color(pos);
+        let valignment = *ctx.cfg.get_alignment_vertical(pos);
 
         let mut cell_height = ctx.records.count_lines(pos);
         if formatting.vertical_trim {
@@ -1699,10 +1686,8 @@ mod grid_spanned {
         R: Records + PeekableRecords + ExactRecords,
         C: Colors,
     {
-        let entity = pos.into();
-
         let mut cell_height = ctx.records.count_lines(pos);
-        let formatting = ctx.cfg.get_formatting(entity);
+        let formatting = ctx.cfg.get_formatting(pos);
         if formatting.vertical_trim {
             cell_height -= count_empty_lines_at_start(ctx.records, pos)
                 + count_empty_lines_at_end(ctx.records, pos);
@@ -1713,9 +1698,9 @@ mod grid_spanned {
             cell_height = height;
         }
 
-        let pad = ctx.cfg.get_padding(entity);
-        let pad_color = ctx.cfg.get_padding_color(entity);
-        let alignment = ctx.cfg.get_alignment_vertical(entity);
+        let pad = ctx.cfg.get_padding(pos);
+        let pad_color = ctx.cfg.get_padding_color(pos);
+        let alignment = ctx.cfg.get_alignment_vertical(pos);
         let indent = top_indent(&pad, *alignment, cell_height, height);
         if indent > line {
             return print_indent(f, pad.top.fill, width, pad_color.top.as_ref());
@@ -1742,13 +1727,13 @@ mod grid_spanned {
         let width = width - pad.left.size - pad.right.size;
 
         let line_cfg = TextCfg {
-            alignment: *ctx.cfg.get_alignment_horizontal(entity),
-            formatting: *formatting,
+            alignment: *ctx.cfg.get_alignment_horizontal(pos),
             color: ctx.colors.get_color(pos),
             justification: Colored::new(
-                ctx.cfg.get_justification(entity),
-                ctx.cfg.get_justification_color(entity),
+                ctx.cfg.get_justification(pos),
+                ctx.cfg.get_justification_color(pos),
             ),
+            formatting,
         };
 
         print_line(f, ctx.records, pos, index, width, line_cfg)?;
diff --git a/tabled/Cargo.toml b/tabled/Cargo.toml
index 02bb347..6c14109 100644
--- a/tabled/Cargo.toml
+++ b/tabled/Cargo.toml
@@ -317,7 +317,7 @@ ansi = ["papergrid/ansi", "ansi-str", "ansitok", "std"]
 macros = ["std"]
 
 [dependencies]
-papergrid = { version = "0.13", default-features = false }
+papergrid = { path = "../papergrid", default-features = false }
 tabled_derive = { version = "0.9", optional = true }
 ansi-str = { version = "0.8", optional = true }
 ansitok = { version = "0.2", optional = true }
diff --git a/tabled/benches/lib_comp/README.md b/tabled/benches/lib_comp/README.md
index 214d75a..6d5414f 100644
--- a/tabled/benches/lib_comp/README.md
+++ b/tabled/benches/lib_comp/README.md
@@ -5,6 +5,12 @@ We profile only actual table construction.
 **Be WARE** that it's being run against a specific (but general) use case.
 Some libraries **might** perform better in certain scenarios or certain use cases.
 
+```bash
+cargo bench
+```
+
+TODO: Add an option to peak a libs list at the CLI run.
+
 ## Result
 
 |                          | cli_table      | comfy_table    | prettytable_rs      | term_table     | tabled             | tabled_color     | tabled_compact     | tabled_iter    |
diff --git a/tabled/benches/lib_comp/benches/benchmark.rs b/tabled/benches/lib_comp/benches/benchmark.rs
index 5f0cc91..4e694d3 100644
--- a/tabled/benches/lib_comp/benches/benchmark.rs
+++ b/tabled/benches/lib_comp/benches/benchmark.rs
@@ -30,10 +30,12 @@ macro_rules! create_bench {
         bench_lib!(
             $name,
             $table,
-            { "tabled", lib_comp::tabled_current::build },
+            { "current", lib_comp::tabled_current::build },
+            { "current_color", lib_comp::tabled_color::build },
+            { "current_iter", lib_comp::tabled_current_iter::build },
+            { "current_compact", lib_comp::tabled_current_compact::build },
+            { "tabled", lib_comp::tabled::build },
             { "tabled_color", lib_comp::tabled_color_current::build },
-            { "tabled_iter", lib_comp::tabled_current_iter::build },
-            { "tabled_compact", lib_comp::tabled_current_compact::build },
             { "cli_table", lib_comp::cli_table::build  },
             { "comfy_table", lib_comp::comfy_table::build },
             { "term_table", lib_comp::term_table::build  },
@@ -42,43 +44,33 @@ macro_rules! create_bench {
     };
 }
 
-create_bench!(test_empty_table, |size| build_cost_table(size, "", ""));
-
-create_bench!(test_const_table, |size| build_cost_table(
-    size,
-    "Hello World",
-    "Hi!"
-));
-
-create_bench!(test_dynamic_table, build_dynamic_table);
-
-create_bench!(test_multiline_table, |size| build_cost_table(
-    size,
-    "H\ne\nl\nlo\nWo\nr\nld",
-    "Hello\n111\n111\ni\n!"
-));
+create_bench!(test_empty_table, benching_empty_table);
+create_bench!(test_small_table, benching_small_table);
+create_bench!(test_general_table, benching_general_table);
+create_bench!(test_small_multiline_table, benching_small_multiline_table);
 
 criterion_group!(
     benches,
     test_empty_table,
-    test_const_table,
-    test_dynamic_table,
-    test_multiline_table,
+    test_small_table,
+    test_general_table,
+    test_small_multiline_table,
 );
 criterion_main!(benches);
 
-fn build_cost_table<H, R>(size: usize, header: H, record: R) -> (Vec<String>, Vec<Vec<String>>)
-where
-    H: Into<String>,
-    R: Into<String>,
-{
-    (
-        vec![header.into(); size],
-        vec![vec![record.into(); size]; size],
-    )
+fn benching_empty_table(size: usize) -> (Vec<String>, Vec<Vec<String>>) {
+    build_cost_table(size, "", "")
+}
+
+fn benching_small_table(size: usize) -> (Vec<String>, Vec<Vec<String>>) {
+    build_cost_table(size, "Hello World", "Hi!")
 }
 
-fn build_dynamic_table(size: usize) -> (Vec<String>, Vec<Vec<String>>) {
+fn benching_small_multiline_table(size: usize) -> (Vec<String>, Vec<Vec<String>>) {
+    build_cost_table(size, "H\ne\nl\nlo\nWo\nr\nld", "Hello\n111\n111\ni\n!")
+}
+
+fn benching_general_table(size: usize) -> (Vec<String>, Vec<Vec<String>>) {
     let mut data = Vec::with_capacity(size);
     for i in 0..size {
         let mut row = build_row(size, |i| format!("{i}"));
@@ -105,3 +97,14 @@ fn build_row(size: usize, f: impl Fn(usize) -> String) -> Vec<String> {
 
     row
 }
+
+fn build_cost_table<H, R>(size: usize, header: H, record: R) -> (Vec<String>, Vec<Vec<String>>)
+where
+    H: Into<String>,
+    R: Into<String>,
+{
+    (
+        vec![header.into(); size],
+        vec![vec![record.into(); size]; size],
+    )
+}
diff --git a/tabled/benches/lib_comp/crates/tabled/Cargo.toml b/tabled/benches/lib_comp/crates/tabled/Cargo.toml
index 1da1f8f..7f8e8b9 100644
--- a/tabled/benches/lib_comp/crates/tabled/Cargo.toml
+++ b/tabled/benches/lib_comp/crates/tabled/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-tabled = { version = "0.10.0", default-features = false }
+tabled = { version = "0.17.0", default-features = false }
diff --git a/tabled/benches/lib_comp/crates/tabled_color/Cargo.toml b/tabled/benches/lib_comp/crates/tabled_color/Cargo.toml
index 8788577..0125a45 100644
--- a/tabled/benches/lib_comp/crates/tabled_color/Cargo.toml
+++ b/tabled/benches/lib_comp/crates/tabled_color/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-tabled = { version = "0.10.0", default-features = false, features = ["ansi"] }
+tabled = { version = "0.17.0", default-features = false, features = ["ansi"] }
diff --git a/tabled/benches/lib_comp/src/lib.rs b/tabled/benches/lib_comp/src/lib.rs
index 7a47b91..9c18a07 100644
--- a/tabled/benches/lib_comp/src/lib.rs
+++ b/tabled/benches/lib_comp/src/lib.rs
@@ -3,11 +3,14 @@ pub mod tabled {
 
     #[inline]
     pub fn build(columns: Vec<String>, data: Vec<Vec<String>>) -> String {
-        let mut b = Builder::from(data);
-        b.set_columns(columns);
-        let table = b.build();
+        let mut b = Builder::with_capacity(data.len() + 1, columns.len());
+        b.push_record(columns);
 
-        table.to_string()
+        for row in data {
+            b.push_record(row);
+        }
+
+        b.build().to_string()
     }
 }
 
@@ -16,11 +19,14 @@ pub mod tabled_color {
 
     #[inline]
     pub fn build(columns: Vec<String>, data: Vec<Vec<String>>) -> String {
-        let mut b = Builder::from(data);
-        b.set_columns(columns);
-        let table = b.build();
+        let mut b = Builder::with_capacity(data.len() + 1, columns.len());
+        b.push_record(columns);
 
-        table.to_string()
+        for row in data {
+            b.push_record(row);
+        }
+
+        b.build().to_string()
     }
 }
 
diff --git a/tabled/src/grid/config/colored_config.rs b/tabled/src/grid/config/colored_config.rs
index 09640c7..93ad790 100644
--- a/tabled/src/grid/config/colored_config.rs
+++ b/tabled/src/grid/config/colored_config.rs
@@ -106,14 +106,14 @@ impl ColorMap {
 impl crate::grid::colors::Colors for ColorMap {
     type Color = ANSIBuf;
 
-    fn get_color(&self, (row, col): (usize, usize)) -> Option<&Self::Color> {
-        self.0.as_ref().map(|map| map.get(Entity::Cell(row, col)))
+    fn get_color(&self, pos: (usize, usize)) -> Option<&Self::Color> {
+        self.0.as_ref().map(|map| map.get(pos))
     }
 
     fn is_empty(&self) -> bool {
         self.0
             .as_ref()
-            .map(|cfg| cfg.is_empty() && cfg.get(Entity::Global).is_empty())
+            .map(|cfg| cfg.is_empty() && cfg.as_ref().is_empty())
             .unwrap_or(true)
     }
 }
diff --git a/tabled/src/grid/config/compact_multiline_config.rs b/tabled/src/grid/config/compact_multiline_config.rs
index 623a50a..4211009 100644
--- a/tabled/src/grid/config/compact_multiline_config.rs
+++ b/tabled/src/grid/config/compact_multiline_config.rs
@@ -157,7 +157,9 @@ impl From<CompactMultilineConfig> for crate::grid::config::SpannedConfig {
 
         let mut cfg = SpannedConfig::from(compact.config);
         cfg.set_alignment_vertical(Global, compact.alignment_vertical);
-        cfg.set_formatting(Global, compact.formatting);
+        cfg.set_line_alignment(Global, compact.formatting.allow_lines_alignment);
+        cfg.set_trim_horizontal(Global, compact.formatting.horizontal_trim);
+        cfg.set_trim_vertical(Global, compact.formatting.vertical_trim);
 
         cfg
     }
diff --git a/tabled/src/grid/dimension/peekable_dimension.rs b/tabled/src/grid/dimension/peekable_dimension.rs
index ec63349..a60b5cf 100644
--- a/tabled/src/grid/dimension/peekable_dimension.rs
+++ b/tabled/src/grid/dimension/peekable_dimension.rs
@@ -83,7 +83,7 @@ mod estimation {
                 let height = cell.count_lines();
                 let width = cell.width();
 
-                let pad = cfg.get_padding(pos.into());
+                let pad = cfg.get_padding(pos);
                 let width = width + pad.left.size + pad.right.size;
                 let height = height + pad.top.size + pad.bottom.size;
 
diff --git a/tabled/src/settings/formatting/alignment_strategy.rs b/tabled/src/settings/formatting/alignment_strategy.rs
index 32b23d2..f75290d 100644
--- a/tabled/src/settings/formatting/alignment_strategy.rs
+++ b/tabled/src/settings/formatting/alignment_strategy.rs
@@ -143,13 +143,12 @@ pub enum AlignmentStrategy {
 
 impl<R> CellOption<R, ColoredConfig> for AlignmentStrategy {
     fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
-        let mut formatting = *cfg.get_formatting(entity);
-        match &self {
-            AlignmentStrategy::PerCell => formatting.allow_lines_alignment = false,
-            AlignmentStrategy::PerLine => formatting.allow_lines_alignment = true,
-        }
+        let on = match &self {
+            AlignmentStrategy::PerCell => false,
+            AlignmentStrategy::PerLine => true,
+        };
 
-        cfg.set_formatting(entity, formatting);
+        cfg.set_line_alignment(entity, on);
     }
 }
 
diff --git a/tabled/src/settings/formatting/trim_strategy.rs b/tabled/src/settings/formatting/trim_strategy.rs
index cd7cf4f..9ec44d3 100644
--- a/tabled/src/settings/formatting/trim_strategy.rs
+++ b/tabled/src/settings/formatting/trim_strategy.rs
@@ -87,27 +87,22 @@ pub enum TrimStrategy {
 
 impl<R> CellOption<R, ColoredConfig> for TrimStrategy {
     fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
-        let mut formatting = *cfg.get_formatting(entity);
-
-        // todo: could be changed to be a struct an enum like consts in `impl` block.
         match self {
             TrimStrategy::Vertical => {
-                formatting.vertical_trim = true;
+                cfg.set_trim_vertical(entity, true);
             }
             TrimStrategy::Horizontal => {
-                formatting.horizontal_trim = true;
+                cfg.set_trim_horizontal(entity, true);
             }
             TrimStrategy::Both => {
-                formatting.vertical_trim = true;
-                formatting.horizontal_trim = true;
+                cfg.set_trim_horizontal(entity, true);
+                cfg.set_trim_vertical(entity, true);
             }
             TrimStrategy::None => {
-                formatting.vertical_trim = false;
-                formatting.horizontal_trim = false;
+                cfg.set_trim_horizontal(entity, false);
+                cfg.set_trim_vertical(entity, false);
             }
         }
-
-        cfg.set_formatting(entity, formatting);
     }
 }
 
diff --git a/tabled/src/settings/padding_expand/mod.rs b/tabled/src/settings/padding_expand/mod.rs
index 8d1f247..7fb65e0 100644
--- a/tabled/src/settings/padding_expand/mod.rs
+++ b/tabled/src/settings/padding_expand/mod.rs
@@ -109,11 +109,10 @@ where
     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);
-
+    for pos in entity.iter(count_rows, count_cols) {
+        let col = pos.1;
         let column_width = widths[col];
-        let width = records.get_width((row, col));
+        let width = records.get_width(pos);
 
         if width < column_width {
             let alignment = *cfg.get_alignment_horizontal(pos);
@@ -125,7 +124,7 @@ where
             pad.left.size = left;
             pad.right.size = right;
 
-            cfg.set_padding(pos, pad);
+            cfg.set_padding(Entity::from(pos), pad);
         }
     }
 }
@@ -141,11 +140,10 @@ where
     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);
-
+    for pos in entity.iter(count_rows, count_cols) {
+        let row = pos.0;
         let row_height = heights[row];
-        let cell_height = records.count_lines((row, col));
+        let cell_height = records.count_lines(pos);
 
         if cell_height < row_height {
             let alignment = *cfg.get_alignment_vertical(pos);
@@ -157,7 +155,7 @@ where
             pad.top.size = top;
             pad.bottom.size = bottom;
 
-            cfg.set_padding(pos, pad);
+            cfg.set_padding(Entity::from(pos), pad);
         }
     }
 }
diff --git a/tabled/src/settings/width/truncate.rs b/tabled/src/settings/width/truncate.rs
index fc89478..61e9da4 100644
--- a/tabled/src/settings/width/truncate.rs
+++ b/tabled/src/settings/width/truncate.rs
@@ -456,7 +456,7 @@ fn get_decrease_cell_list(
                 };
 
                 if width >= width_min {
-                    let padding = cfg.get_padding((row, col).into());
+                    let padding = cfg.get_padding((row, col));
                     let width = width.saturating_sub(padding.left.size + padding.right.size);
 
                     points.push(((row, col), width));
diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs
index d83672a..36ea5ea 100644
--- a/tabled/src/settings/width/wrap.rs
+++ b/tabled/src/settings/width/wrap.rs
@@ -871,7 +871,7 @@ fn get_decrease_cell_list(
                 };
 
                 if width >= width_min {
-                    let padding = cfg.get_padding((row, col).into());
+                    let padding = cfg.get_padding((row, col));
                     let width = width.saturating_sub(padding.left.size + padding.right.size);
 
                     points.push(((row, col), width));
diff --git a/tabled/src/tables/table.rs b/tabled/src/tables/table.rs
index 79b68df..6e3a0ae 100644
--- a/tabled/src/tables/table.rs
+++ b/tabled/src/tables/table.rs
@@ -8,8 +8,8 @@ use crate::{
     grid::{
         colors::NoColors,
         config::{
-            AlignmentHorizontal, ColorMap, ColoredConfig, CompactConfig, Entity, Formatting,
-            Indent, Sides, SpannedConfig,
+            AlignmentHorizontal, ColorMap, ColoredConfig, CompactConfig, Entity, Indent, Sides,
+            SpannedConfig,
         },
         dimension::{CompleteDimensionVecRecords, Dimension, Estimate, PeekableDimension},
         records::{
@@ -536,7 +536,9 @@ fn configure_grid() -> SpannedConfig {
         ),
     );
     cfg.set_alignment_horizontal(Entity::Global, AlignmentHorizontal::Left);
-    cfg.set_formatting(Entity::Global, Formatting::new(false, false, false));
+    cfg.set_line_alignment(Entity::Global, false);
+    cfg.set_trim_horizontal(Entity::Global, false);
+    cfg.set_trim_vertical(Entity::Global, false);
     cfg.set_borders(Style::ascii().get_borders());
 
     cfg


Test patch:
diff --git a/papergrid/tests/grid/format_configuration.rs b/papergrid/tests/grid/format_configuration.rs
index c4891de..288839c 100644
--- a/papergrid/tests/grid/format_configuration.rs
+++ b/papergrid/tests/grid/format_configuration.rs
@@ -787,7 +787,9 @@ fn formatting_test() {
             .config(|cfg| {
                 cfg.set_alignment_horizontal(Entity::Global, test.0);
                 cfg.set_alignment_vertical(Entity::Global, test.1);
-                cfg.set_formatting(Entity::Global, test.2);
+                cfg.set_line_alignment(Entity::Global, test.2.allow_lines_alignment);
+                cfg.set_trim_horizontal(Entity::Global, test.2.horizontal_trim);
+                cfg.set_trim_vertical(Entity::Global, test.2.vertical_trim);
             })
             .clone()
             .build();
@@ -803,7 +805,11 @@ fn formatting_empty_test() {
         let formatting = Formatting::new(true, true, true);
         assert_eq!(
             grid(rows, cols)
-                .config(|cfg| cfg.set_formatting(Entity::Global, formatting))
+                .config(|cfg| {
+                    cfg.set_line_alignment(Entity::Global, formatting.allow_lines_alignment);
+                    cfg.set_trim_horizontal(Entity::Global, formatting.horizontal_trim);
+                    cfg.set_trim_vertical(Entity::Global, formatting.vertical_trim);
+                })
                 .build(),
             ""
         );
@@ -855,7 +861,7 @@ fn formatting_1x1_test() {
 
     assert_eq!(
         grid.clone()
-            .config(|cfg| cfg.set_formatting(Entity::Global, Formatting::new(false, false, true)))
+            .config(|cfg| cfg.set_line_alignment(Entity::Global, true))
             .build(),
         static_table!(
             r#"+--------------------------------------------------+"#
@@ -878,7 +884,8 @@ fn formatting_1x1_test() {
 
     assert_eq!(
         grid.clone()
-            .config(|cfg| cfg.set_formatting(Entity::Global, Formatting::new(true, false, true)))
+            .config(|cfg| cfg.set_line_alignment(Entity::Global, true))
+            .config(|cfg| cfg.set_trim_horizontal(Entity::Global, true))
             .build(),
         static_table!(
             r#"+--------------------------------------------------+"#
@@ -900,7 +907,9 @@ fn formatting_1x1_test() {
     );
 
     assert_eq!(
-        grid.config(|cfg| cfg.set_formatting(Entity::Global, Formatting::new(true, true, true)))
+        grid.config(|cfg| cfg.set_line_alignment(Entity::Global, true))
+            .config(|cfg| cfg.set_trim_horizontal(Entity::Global, true))
+            .config(|cfg| cfg.set_trim_vertical(Entity::Global, true))
             .build(),
         static_table!(
             r#"+--------------------------------------------------+"#