Repository: zhiburt/tabled
Pull request #443 (2024-11-13 18:24:10)

tabled/ Change Highlight interface


Patch:
diff --git a/tabled/examples/highlight_color.rs b/tabled/examples/highlight_color.rs
index af21e24..b9f45e3 100644
--- a/tabled/examples/highlight_color.rs
+++ b/tabled/examples/highlight_color.rs
@@ -6,7 +6,6 @@
 use tabled::{
     settings::{
         object::{Columns, Object, Rows},
-        style::BorderColor,
         Color, Highlight, Style,
     },
     Table,
@@ -20,7 +19,7 @@ fn main() {
 
     let mut table = Table::new(data);
     table.with(Style::modern());
-    table.with(Highlight::color(target, BorderColor::filled(color)));
+    table.with(Highlight::colored(target, color));
 
     println!("{table}");
 }
diff --git a/tabled/src/settings/highlight/mod.rs b/tabled/src/settings/highlight/mod.rs
index 89aff0c..6a61ab0 100644
--- a/tabled/src/settings/highlight/mod.rs
+++ b/tabled/src/settings/highlight/mod.rs
@@ -8,10 +8,14 @@ use std::collections::HashSet;
 use crate::{
     grid::{
         ansi::ANSIBuf,
-        config::{Border as GridBorder, ColoredConfig, Entity, Position, SpannedConfig},
+        config::{Border, ColoredConfig, Entity, Position, SpannedConfig},
         records::{ExactRecords, Records},
     },
-    settings::{object::Object, style::BorderColor, Border, Color, TableOption},
+    settings::{
+        object::Object,
+        style::{Border as ConstBorder, BorderColor},
+        Color, TableOption,
+    },
 };
 
 /// Highlight modifies a table style by changing a border of a target [`Table`] segment.
@@ -60,31 +64,16 @@ use crate::{
 #[derive(Debug)]
 pub struct Highlight<O> {
     target: O,
-    border: HighlightInner,
-}
-
-#[derive(Debug)]
-enum HighlightInner {
-    Border(GridBorder<char>),
-    // #[cfg(feature = "ansi")]
-    Color(GridBorder<ANSIBuf>),
-    // #[cfg(feature = "ansi")]
-    ColoredBorder(GridBorder<char>, GridBorder<ANSIBuf>),
+    border: Option<Border<char>>,
+    color: Option<Border<ANSIBuf>>,
 }
 
 impl<O> Highlight<O> {
-    /// Build a new instance of [`Highlight`],
-    /// highlighting by a color, while preserving existing border.
+    /// Build a new instance of [`Highlight`] with '*' char being used as changer.
     ///
     /// BE AWARE: if target exceeds boundaries it may panic.
-    pub fn color(target: O, border: BorderColor) -> Self {
-        let color = border.into_inner();
-        let color = color.convert();
-
-        Self {
-            target,
-            border: HighlightInner::Color(color),
-        }
+    pub const fn new(target: O) -> Self {
+        Self::_new(target, None, None)
     }
 
     /// Build a new instance of [`Highlight`],
@@ -92,37 +81,48 @@ impl<O> Highlight<O> {
     ///
     /// BE AWARE: if target exceeds boundaries it may panic.
     pub const fn outline(target: O, c: char) -> Self {
-        Self::new(target, Border::filled(c))
+        Self::_new(target, Some(Border::filled(c)), None)
     }
 
     /// Build a new instance of [`Highlight`],
     /// highlighting by a color and a given character for a border.
     ///
     /// BE AWARE: if target exceeds boundaries it may panic.
-    pub fn outline_colored<T, B, L, R>(target: O, c: char, color: Color) -> Self {
-        Self::colored(target, Border::filled(c), BorderColor::filled(color))
+    pub fn colored(target: O, color: Color) -> Self {
+        let color = Border::filled(&color).cloned().convert();
+        Self::_new(target, None, Some(color))
     }
 
-    /// Build a new instance of [`Highlight`]
-    ///
-    /// BE AWARE: if target exceeds boundaries it may panic.
-    pub const fn new<T, B, L, R>(target: O, border: Border<T, B, L, R>) -> Self {
+    /// Set a border for a [`Highlight`].
+    pub fn border<T, B, L, R>(self, border: ConstBorder<T, B, L, R>) -> Self {
+        let border = border.into_inner();
         Self {
-            target,
-            border: HighlightInner::Border(border.into_inner()),
+            target: self.target,
+            border: Some(border),
+            color: self.color,
         }
     }
 
-    /// Build a new instance of [`Highlight`] colored.
-    ///
-    /// BE AWARE: if target exceeds boundaries it may panic.
-    pub fn colored<T, B, L, R>(target: O, border: Border<T, B, L, R>, color: BorderColor) -> Self {
+    /// Set a border color for a [`Highlight`].
+    pub fn color(self, border: BorderColor) -> Self {
         let border = border.into_inner();
-        let color = color.into_inner().convert();
+        let border = border.convert();
 
+        Self {
+            target: self.target,
+            border: self.border,
+            color: Some(border),
+        }
+    }
+
+    /// Build a new instance of [`Highlight`]
+    ///
+    /// BE AWARE: if target exceeds boundaries it may panic.
+    const fn _new(target: O, border: Option<Border<char>>, color: Option<Border<ANSIBuf>>) -> Self {
         Self {
             target,
-            border: HighlightInner::ColoredBorder(border, color),
+            border,
+            color,
         }
     }
 }
@@ -139,19 +139,26 @@ where
         let cells = self.target.cells(records);
         let segments = split_segments(cells, count_rows, count_cols);
 
-        for sector in segments {
-            match &self.border {
-                HighlightInner::Border(border) => {
-                    set_border(cfg, &sector, *border);
+        match (self.border, self.color) {
+            (None, Some(color)) => {
+                for sector in segments {
+                    set_border_color(cfg, &sector, &color);
                 }
-                HighlightInner::Color(color) => {
-                    set_border_color(cfg, &sector, color);
+            }
+            (Some(border), None) => {
+                for sector in segments {
+                    set_border(cfg, &sector, border);
                 }
-                HighlightInner::ColoredBorder(border, color) => {
-                    set_border(cfg, &sector, *border);
-                    set_border_color(cfg, &sector, color);
+            }
+            (Some(border), Some(color)) => {
+                for sector in segments {
+                    set_border(cfg, &sector, border);
+                    set_border_color(cfg, &sector, &color);
                 }
             }
+            (None, None) => {
+                // noop
+            }
         }
     }
 
@@ -160,11 +167,7 @@ where
     }
 }
 
-fn set_border_color(
-    cfg: &mut SpannedConfig,
-    sector: &HashSet<Position>,
-    border: &GridBorder<ANSIBuf>,
-) {
+fn set_border_color(cfg: &mut SpannedConfig, sector: &HashSet<Position>, border: &Border<ANSIBuf>) {
     if sector.is_empty() {
         return;
     }
@@ -252,7 +255,7 @@ fn is_segment_connected(segment1: &HashSet<Position>, segment2: &HashSet<Positio
     false
 }
 
-fn set_border(cfg: &mut SpannedConfig, sector: &HashSet<Position>, border: GridBorder<char>) {
+fn set_border(cfg: &mut SpannedConfig, sector: &HashSet<Position>, border: Border<char>) {
     if sector.is_empty() {
         return;
     }
@@ -266,8 +269,8 @@ fn set_border(cfg: &mut SpannedConfig, sector: &HashSet<Position>, border: GridB
 fn build_cell_border<T>(
     sector: &HashSet<Position>,
     (row, col): Position,
-    border: &GridBorder<T>,
-) -> GridBorder<T>
+    border: &Border<T>,
+) -> Border<T>
 where
     T: Default + Clone,
 {
@@ -281,7 +284,7 @@ where
     let this_has_left_bottom_neighbor = is_there_left_bottom_cell(sector, row, col);
     let this_has_right_bottom_neighbor = is_there_right_bottom_cell(sector, row, col);
 
-    let mut cell_border = GridBorder::default();
+    let mut cell_border = Border::default();
     if let Some(c) = border.top.clone() {
         if !cell_has_top_neighbor {
             cell_border.top = Some(c.clone());
diff --git a/tabled/src/settings/style/mod.rs b/tabled/src/settings/style/mod.rs
index 3bdefc3..39284ea 100644
--- a/tabled/src/settings/style/mod.rs
+++ b/tabled/src/settings/style/mod.rs
@@ -105,16 +105,16 @@ mod vertical_line;
 #[cfg(feature = "std")]
 mod border_color;
 #[cfg(feature = "std")]
-mod line_text;
-#[cfg(feature = "std")]
 mod line_char;
 #[cfg(feature = "std")]
+mod line_text;
+#[cfg(feature = "std")]
 mod span_border_correction;
 
 #[cfg(feature = "std")]
 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 pub use self::{
-    border_color::BorderColor, line_text::LineText, line_char::LineChar,
+    border_color::BorderColor, line_char::LineChar, line_text::LineText,
     span_border_correction::BorderSpanCorrection,
 };
 


Test patch:
diff --git a/tabled/tests/settings/highlingt_test.rs b/tabled/tests/settings/highlingt_test.rs
index 543932b..8b6a9dc 100644
--- a/tabled/tests/settings/highlingt_test.rs
+++ b/tabled/tests/settings/highlingt_test.rs
@@ -14,7 +14,7 @@ use testing_table::{static_table, test_table};
 
 test_table!(
     highlingt_object_exceeds_boundaries,
-    Matrix::new(3, 3).with(Style::modern()).with(Highlight::new(Cell::new(1000, 0), Border::filled('+'))),
+    Matrix::new(3, 3).with(Style::modern()).with(Highlight::outline(Cell::new(1000, 0), '+')),
     "┌───┬──────────┬──────────┬──────────┐"
     "│ N │ column 0 │ column 1 │ column 2 │"
     "├───┼──────────┼──────────┼──────────┤"
@@ -30,7 +30,7 @@ test_table!(
     highlingt_empty_table,
     Builder::default()
         .build()
-        .with(Highlight::new(Segment::all(), Border::filled('+'))),
+        .with(Highlight::outline(Segment::all(), '+')),
     ""
 );
 
@@ -38,8 +38,8 @@ test_table!(
     highlingt_cell,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Cell::new(0, 0), Border::filled('+')))
-        .with(Highlight::new(Cell::new(1, 1), Border::filled('*'))),
+        .with(Highlight::outline(Cell::new(0, 0), '+'))
+        .with(Highlight::outline(Cell::new(1, 1), '*')),
     "+++++──────────┬──────────┬──────────┐"
     "+ N + column 0 │ column 1 │ column 2 │"
     "++++************──────────┼──────────┤"
@@ -55,8 +55,8 @@ test_table!(
     highlingt_row,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Rows::single(0), Border::filled('+')))
-        .with(Highlight::new(Rows::single(3), Border::filled('*'))),
+        .with(Highlight::outline(Rows::single(0), '+'))
+        .with(Highlight::outline(Rows::single(3), '*')),
     "++++++++++++++++++++++++++++++++++++++"
     "+ N │ column 0 │ column 1 │ column 2 +"
     "++++++++++++++++++++++++++++++++++++++"
@@ -72,8 +72,8 @@ test_table!(
     highlingt_column,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Columns::single(0), Border::filled('+')))
-        .with(Highlight::new(Columns::single(2), Border::filled('*'))),
+        .with(Highlight::new(Columns::single(0)).border(Border::filled('+')))
+        .with(Highlight::new(Columns::single(2)).border(Border::filled('*'))),
     "+++++──────────************──────────┐"
     "+ N + column 0 * column 1 * column 2 │"
     "+───+──────────*──────────*──────────┤"
@@ -89,7 +89,7 @@ test_table!(
     highlingt_row_range,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Rows::new(1..3), Border::filled('+'))),
+        .with(Highlight::outline(Rows::new(1..3), '+')),
     "┌───┬──────────┬──────────┬──────────┐"
     "│ N │ column 0 │ column 1 │ column 2 │"
     "++++++++++++++++++++++++++++++++++++++"
@@ -105,7 +105,7 @@ test_table!(
     highlingt_column_range,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Columns::new(..2), Border::filled('+'))),
+        .with(Highlight::outline(Columns::new(..2), '+')),
     "++++++++++++++++──────────┬──────────┐"
     "+ N │ column 0 + column 1 │ column 2 │"
     "+───┼──────────+──────────┼──────────┤"
@@ -121,8 +121,7 @@ test_table!(
     highlingt_frame,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(
-            Frame,
+        .with(Highlight::new(Frame).border(
             Border::filled('+')
                 .set_corner_top_left('*')
                 .set_corner_top_right('#')
@@ -144,8 +143,7 @@ test_table!(
     highlingt_full,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(
-            Segment::all(),
+        .with(Highlight::new(Segment::all()).border(
             Border::filled('+')
                 .set_corner_top_left('*')
                 .set_corner_top_right('#')
@@ -167,8 +165,8 @@ test_table!(
     highlingt_single_column,
     Matrix::table(3, 0)
         .with(Style::modern())
-        .with(Highlight::new(Cell::new(0, 0), Border::new().set_left('*').set_top('x')))
-        .with(Highlight::new(Rows::new(1..3), Border::new().set_left('n'))),
+        .with(Highlight::new(Cell::new(0, 0)).border(Border::new().set_left('*').set_top('x')))
+        .with(Highlight::new(Rows::new(1..3)).border(Border::new().set_left('n'))),
     "┌xxx┐"
     "* N │"
     "├───┤"
@@ -184,9 +182,9 @@ test_table!(
     highlingt_several_times,
     Matrix::new(3, 3)
         .with(Style::modern())
-        .with(Highlight::new(Frame, Border::filled('*')))
-        .with(Highlight::new(Cell::new(1, 1), Border::filled('#')))
-        .with(Highlight::new(Columns::single(3), Border::filled('x'))),
+        .with(Highlight::outline(Frame, '*'))
+        .with(Highlight::outline(Cell::new(1, 1), '#'))
+        .with(Highlight::outline(Columns::single(3), 'x')),
     "**************************xxxxxxxxxxxx"
     "* N │ column 0 │ column 1 x column 2 x"
     "*───############──────────x──────────x"
@@ -233,7 +231,7 @@ fn highlingt_complex_figures() {
 
             let table = Matrix::new(3, 3)
                 .with(Style::modern())
-                .with(Highlight::new($object, border))
+                .with(Highlight::new($object).border(border))
                 .to_string();
 
             assert_eq!(table, $expected);
diff --git a/tabled/tests/settings/rotate_test.rs b/tabled/tests/settings/rotate_test.rs
index 2d906f1..477a695 100644
--- a/tabled/tests/settings/rotate_test.rs
+++ b/tabled/tests/settings/rotate_test.rs
@@ -136,7 +136,7 @@ test_table!(
 test_table!(
     rotate_preserve_border_styles_test_0,
     Matrix::iter([(123, 456, 789), (234, 567, 891), (111, 222, 333)])
-        .with(Highlight::new(Rows::single(0), Border::new().set_top('*')))
+        .with(Highlight::new(Rows::single(0)).border(Border::new().set_top('*')))
         .with(Rotate::Left),
     "+*****************+-----+"
     "| i32 | 789 | 891 | 333 |"
@@ -154,7 +154,7 @@ test_table!(
 test_table!(
     rotate_preserve_border_styles_test_1,
     Matrix::iter([(123, 456, 789), (234, 567, 891), (111, 222, 333)])
-        .with(Highlight::new(Cell::new(0, 2), Border::new().set_bottom('*')))
+        .with(Highlight::new(Cell::new(0, 2)).border(Border::new().set_bottom('*')))
         .with(Rotate::Left),
         "+-----+-----+-----+-----+"
         "| i32 | 789 | 891 | 333 |"
diff --git a/tabled/tests/settings/style_test.rs b/tabled/tests/settings/style_test.rs
index 0370952..ae3fbb7 100644
--- a/tabled/tests/settings/style_test.rs
+++ b/tabled/tests/settings/style_test.rs
@@ -254,6 +254,18 @@ test_table!(
     "| N | column 0 | column 1 |"
     "+---+----------+----------+"
     "| 0 |   0-0    |   0-1    |"
+    "-Table---------+----------+"
+    "| 1 |   1-0    |   1-1    |"
+    "+---+----------+----------+"
+);
+
+test_table!(
+    top_border_override_last_1_test,
+    Matrix::table(2, 2).with(LineText::new("-Table", Rows::last() + 1)),
+    "+---+----------+----------+"
+    "| N | column 0 | column 1 |"
+    "+---+----------+----------+"
+    "| 0 |   0-0    |   0-1    |"
     "+---+----------+----------+"
     "| 1 |   1-0    |   1-1    |"
     "-Table---------+----------+"
@@ -537,7 +549,7 @@ test_table!(
 
 test_table!(
     style_frame_test_0,
-    Matrix::table(2, 2).with(Highlight::new(Rows::single(1), Border::inherit(Style::modern()))),
+    Matrix::table(2, 2).with(Highlight::new(Rows::single(1)).border(Border::inherit(Style::modern()))),
     "+---+----------+----------+"
     "| N | column 0 | column 1 |"
     "┌─────────────────────────┐"
@@ -551,8 +563,8 @@ test_table!(
     style_frame_test_1,
     Matrix::table(2, 2)
         .with(Style::blank())
-        .with(Highlight::new(Rows::single(0), Border::inherit(Style::extended())))
-        .with(Highlight::new(Rows::single(2), Border::inherit(Style::extended()))),
+        .with(Highlight::new(Rows::single(0)).border(Border::inherit(Style::extended())))
+        .with(Highlight::new(Rows::single(2)).border(Border::inherit(Style::extended()))),
     "╔═════════════════════════╗"
     "║ N   column 0   column 1 ║"
     "╚═════════════════════════╝"