Repository: zhiburt/tabled
Pull request #453 (2024-11-20 20:07:37)

tabled/ Add PriorityMax/Min left|right option


Patch:
diff --git a/README.md b/README.md
index 443aa54..15f9fdc 100644
--- a/README.md
+++ b/README.md
@@ -867,8 +867,8 @@ fn gen_table(string_size: usize, width: usize) -> String {
 
     let mut table = Table::new(data);
     table.with((
-        Width::wrap(width).priority(PriorityMax),
-        Width::increase(width).priority(PriorityMin),
+        Width::wrap(width).priority(PriorityMax::right()),
+        Width::increase(width).priority(PriorityMin::right()),
     ));
 
     table.to_string()
@@ -989,7 +989,7 @@ You can tweak `Truncate`, `Wrap`, `MinWidth` logic by setting a priority by whic
 ```rust
 use tabled::settings::{Width, peaker::PriorityMax};
 
-table.with(Width::truncate(10).priority(PriorityMax));
+table.with(Width::truncate(10).priority(PriorityMax::default()));
 ```
 
 #### Percent
@@ -2248,7 +2248,7 @@ let data = [
 ];
 
 let table_settings = Settings::default()
-    .with(Width::wrap(width).priority(PriorityMax))
+    .with(Width::wrap(width).priority(PriorityMax::default()))
     .with(Width::increase(width))
     .with(Height::limit(height))
     .with(Height::increase(height));
diff --git a/tabled/examples/height.rs b/tabled/examples/height.rs
index 655053d..f5bbc3d 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(PriorityMax))
+        .with(Height::limit(4).priority(PriorityMax::default()))
         .to_string();
 
     println!("Table decrease height to 4\n");
@@ -41,7 +41,7 @@ fn main() {
 
     let table_ = table
         .clone()
-        .with(Height::limit(0).priority(PriorityMax))
+        .with(Height::limit(0).priority(PriorityMax::default()))
         .to_string();
 
     println!("Table decrease height to 0\n");
diff --git a/tabled/examples/terminal_size2/src/main.rs b/tabled/examples/terminal_size2/src/main.rs
index d1aedca..6083bbc 100644
--- a/tabled/examples/terminal_size2/src/main.rs
+++ b/tabled/examples/terminal_size2/src/main.rs
@@ -28,7 +28,7 @@ fn main() {
     let (width, height) = get_terminal_size();
 
     let term_size_settings = Settings::default()
-        .with(Width::wrap(width).priority(PriorityMax))
+        .with(Width::wrap(width).priority(PriorityMax::default()))
         .with(Width::increase(width))
         .with(Height::limit(height))
         .with(Height::increase(height));
diff --git a/tabled/src/settings/peaker/max.rs b/tabled/src/settings/peaker/max.rs
index c488c0b..e67d60d 100644
--- a/tabled/src/settings/peaker/max.rs
+++ b/tabled/src/settings/peaker/max.rs
@@ -2,15 +2,48 @@ 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;
+pub struct PriorityMax {
+    side: bool,
+}
+
+impl PriorityMax {
+    /// Creates a [`PriorityMax`] object with a side set to right or left,
+    /// It's crusial in cases where both columns has equal widths and we need to peak a left or right.
+    ///
+    /// Passing true means a right side.
+    /// Passing false means a left side.
+    pub fn new(priorities_right: bool) -> Self {
+        Self {
+            side: priorities_right,
+        }
+    }
+
+    /// Creates a [`PriorityMax`] object with left side prioritized,
+    /// See [`PriorityMax::new`].
+    pub fn left() -> Self {
+        Self::new(false)
+    }
+
+    /// Creates a [`PriorityMax`] object with right side prioritized,
+    /// See [`PriorityMax::new`].
+    pub fn right() -> Self {
+        Self::new(true)
+    }
+}
 
 impl Peaker for PriorityMax {
-    fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option<usize> {
-        let col = (0..widths.len()).max_by_key(|&i| widths[i]).unwrap();
-        if widths[col] == 0 {
-            None
+    fn peak(&mut self, mins: &[usize], widths: &[usize]) -> Option<usize> {
+        if self.side {
+            (0..widths.len())
+                .filter(|&i| mins.is_empty() || widths[i] > mins[i])
+                .max_by_key(|&i| widths[i])
+                .filter(|&col| widths[col] != 0)
         } else {
-            Some(col)
+            (0..widths.len())
+                .rev()
+                .filter(|&i| mins.is_empty() || widths[i] > mins[i])
+                .max_by_key(|&i| widths[i])
+                .filter(|&col| widths[col] != 0)
         }
     }
 }
diff --git a/tabled/src/settings/peaker/min.rs b/tabled/src/settings/peaker/min.rs
index 4a4b04c..7831227 100644
--- a/tabled/src/settings/peaker/min.rs
+++ b/tabled/src/settings/peaker/min.rs
@@ -2,18 +2,47 @@ 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;
+pub struct PriorityMin {
+    side: bool,
+}
+
+impl PriorityMin {
+    /// Creates a [`PriorityMin`] object with a side set to right or left,
+    /// It's crusial in cases where both columns has equal widths and we need to peak a left or right.
+    ///
+    /// Passing true means a right side.
+    /// Passing false means a left side.
+    pub fn new(priorities_right: bool) -> Self {
+        Self {
+            side: priorities_right,
+        }
+    }
+
+    /// Creates a [`PriorityMin`] object with left side prioritized,
+    /// See [`PriorityMin::new`].
+    pub fn left() -> Self {
+        Self::new(false)
+    }
+
+    /// Creates a [`PriorityMin`] object with right side prioritized,
+    /// See [`PriorityMin::new`].
+    pub fn right() -> Self {
+        Self::new(true)
+    }
+}
 
 impl Peaker for PriorityMin {
-    fn peak(&mut self, min_widths: &[usize], widths: &[usize]) -> Option<usize> {
-        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)
+    fn peak(&mut self, mins: &[usize], widths: &[usize]) -> Option<usize> {
+        match self.side {
+            true => (0..widths.len())
+                .filter(|&i| mins.is_empty() || widths[i] > mins[i])
+                .min_by_key(|&i| widths[i])
+                .filter(|&col| widths[col] != 0),
+            false => (0..widths.len())
+                .rev()
+                .filter(|&i| mins.is_empty() || widths[i] > mins[i])
+                .min_by_key(|&i| widths[i])
+                .filter(|&col| widths[col] != 0),
         }
     }
 }
diff --git a/tabled/src/settings/peaker/mod.rs b/tabled/src/settings/peaker/mod.rs
index 741a6f4..8695465 100644
--- a/tabled/src/settings/peaker/mod.rs
+++ b/tabled/src/settings/peaker/mod.rs
@@ -22,3 +22,5 @@ pub use max::PriorityMax;
 pub use min::PriorityMin;
 pub use none::PriorityNone;
 pub use right::PriorityRight;
+
+// todo: Priority::max -->


Test patch:
diff --git a/tabled/tests/settings/width_test.rs b/tabled/tests/settings/width_test.rs
index f509210..19c337b 100644
--- a/tabled/tests/settings/width_test.rs
+++ b/tabled/tests/settings/width_test.rs
@@ -449,7 +449,11 @@ fn max_width_keep_words_1() {
             .remove_horizontal()
             .horizontals([(1, HorizontalLine::inherit(Style::modern()))]),
     )
-    .with(Width::wrap(21).keep_words(true).priority(PriorityMax))
+    .with(
+        Width::wrap(21)
+            .keep_words(true)
+            .priority(PriorityMax::right()),
+    )
     .with(Alignment::center())
     .to_string();
 
@@ -1822,7 +1826,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(PriorityMax))
+        .with(Width::truncate(35).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 35);
@@ -1840,7 +1844,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(PriorityMax))
+        .with(Width::truncate(20).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 20);
@@ -1858,7 +1862,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(PriorityMax))
+        .with(Width::truncate(0).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 13);
@@ -1880,7 +1884,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(PriorityMax))
+        .with(Width::truncate(15).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 15);
@@ -1901,7 +1905,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(PriorityMax))
+        .with(Width::wrap(35).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 35);
@@ -1923,7 +1927,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(PriorityMax))
+        .with(Width::wrap(20).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 20);
@@ -1958,7 +1962,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(PriorityMax))
+        .with(Width::wrap(0).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 13);
@@ -1980,7 +1984,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(PriorityMax))
+        .with(Width::wrap(15).priority(PriorityMax::right()))
         .to_string();
 
     assert_width!(table, 15);
@@ -2018,7 +2022,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(PriorityMin))
+        .with(Width::truncate(35).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 35);
@@ -2036,7 +2040,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(PriorityMin))
+        .with(Width::truncate(20).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 20);
@@ -2054,7 +2058,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(PriorityMin))
+        .with(Width::truncate(0).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 13);
@@ -2076,7 +2080,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(PriorityMin))
+        .with(Width::truncate(15).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 15);
@@ -2095,7 +2099,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(PriorityMin))
+        .with(Width::truncate(17).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 17);
@@ -2116,7 +2120,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(PriorityMin))
+        .with(Width::wrap(35).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 35);
@@ -2135,7 +2139,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(PriorityMin))
+        .with(Width::wrap(20).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 20);
@@ -2157,7 +2161,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(PriorityMin))
+        .with(Width::wrap(0).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 13);
@@ -2179,7 +2183,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(PriorityMin))
+        .with(Width::wrap(15).priority(PriorityMin::right()))
         .to_string();
 
     assert_width!(table, 15);
@@ -2208,7 +2212,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(PriorityMax))
+        .with(MinWidth::new(60).priority(PriorityMax::right()))
         .to_string();
 
     assert_eq!(get_text_width(&table), 60);
@@ -2228,7 +2232,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(PriorityMin))
+        .with(MinWidth::new(60).priority(PriorityMin::right()))
         .to_string();
 
     assert_eq!(get_text_width(&table), 60);
@@ -2481,6 +2485,62 @@ test_table!(
     "|   |          |          |          | 3 |  |  |  |  |  |  |"
 );
 
+test_table!(
+    priority_max_left,
+    Matrix::new(3, 3)
+        .insert((2, 1), "Hello World With Big Line")
+        .insert((2, 2), "Hello World With Big Line")
+        .with(Style::markdown())
+        .with(Width::truncate(37).priority(PriorityMax::left())),
+    "| N | column  | column 1 | column 2 |"
+    "|---|---------|----------|----------|"
+    "| 0 |   0-0   |   0-1    |   0-2    |"
+    "| 1 | Hello W | Hello Wo |   1-2    |"
+    "| 2 |   2-0   |   2-1    |   2-2    |"
+);
+
+test_table!(
+    priority_max_right,
+    Matrix::new(3, 3)
+        .insert((2, 1), "Hello World With Big Line")
+        .insert((2, 2), "Hello World With Big Line")
+        .with(Style::markdown())
+        .with(Width::truncate(37).priority(PriorityMax::right())),
+    "| N | column 0 | column 1 | column  |"
+    "|---|----------|----------|---------|"
+    "| 0 |   0-0    |   0-1    |   0-2   |"
+    "| 1 | Hello Wo | Hello Wo |   1-2   |"
+    "| 2 |   2-0    |   2-1    |   2-2   |"
+);
+
+test_table!(
+    priority_min_left,
+    Matrix::new(3, 3).with(Width::truncate(30).priority(PriorityMin::left())),
+    "+--+----------+----------+---+"
+    "|  | column 0 | column 1 | c |"
+    "+--+----------+----------+---+"
+    "|  |   0-0    |   0-1    | 0 |"
+    "+--+----------+----------+---+"
+    "|  |   1-0    |   1-1    | 1 |"
+    "+--+----------+----------+---+"
+    "|  |   2-0    |   2-1    | 2 |"
+    "+--+----------+----------+---+"
+);
+
+test_table!(
+    priority_min_right,
+    Matrix::new(3, 3).with(Width::truncate(30).priority(PriorityMin::right())),
+    "+--+---+----------+----------+"
+    "|  | c | column 1 | column 2 |"
+    "+--+---+----------+----------+"
+    "|  | 0 |   0-1    |   0-2    |"
+    "+--+---+----------+----------+"
+    "|  | 1 |   1-1    |   1-2    |"
+    "+--+---+----------+----------+"
+    "|  | 2 |   2-1    |   2-2    |"
+    "+--+---+----------+----------+"
+);
+
 #[cfg(feature = "derive")]
 mod derived {
     use super::*;