Repository: zhiburt/tabled
Pull request #237 (2022-10-17 10:45:28)

Add sharp border
Hi @zhiburt, thanks for maintaining this awesome project. Recently I used it in a new cli project. However I found a very common style is missing from tabled：

<img width="411" alt="image" src="https://user-images.githubusercontent.com/6105425/196156024-49a2ad59-bc82-4cae-bf33-1846cda140f2.png">

So I created this patch to:

- Add a common `sharp` style.
- Fix `rounded` style show case in readme.

BTW that would be nice to put a `.rustfmt.toml` in project root so that other contributors don't have trouble when editor feature like `auto format on save` is enabled.

zhiburt: Hi @wfxr agree in both cases.

Could you create a small test (take a look at `tests/style_test.rs`)?

_________________________

I had an opinion that if you make things customazible enough these small changes will be easier to do on callers end.
But apparently we still fail to do so :disappointed_relieved: (we certainly do) 

For your style for example you could do

```rust
Style::modern()
    .off_horizontal()
    .horizontals(vec![HorizontalLine::new(1, Style::modern().get_horizontal())])
```

PS: This idea of pre-defined themes is something which yet not totally achieved (#126).
wfxr: > Could you create a small test (take a look at `tests/style_test.rs`)? (Let me know if you'll have no chance to)

Done. These tests look very neat, cool!

> This idea of pre-defined themes is something which yet not totally achieved; Where for example modern style could have a list of "flavors" like "sharp", "rounded" etc.

I also like this idea. How about this apporach:
```rust
enum Corner {
    Sharp,     // ┌
    Rounded,   // ╭
    BoldSharp, // ┏
}

enum Grid {
    All,
    Header,
    Body,
}

fn modern(corner: Corner::Sharp, grid: Grid::Header) -> ... {
   ...
}
```
zhiburt: 
> I also like this idea. How about this apporach:

It's OK,
But I guess these settings can be better wrapped to some "builder"?

Overall I thing that the level of abstraction of this thing must be higher than `Style`.
Cause not all styles have this `Corner/Grid` settings. (For example `psql` which is strict in its nature).

Also look at `markdown` for example. It doesn't have this also but it has something different.

```
| name | designed_by    | invented_year |
|------|----------------|---------------|
| C    | Dennis Ritchie | 1972          |
| Rust | Graydon Hoare  | 2010          |
| Go   | Rob Pike       | 2009          |
```

This uses no alignment.
But we could have 

1. left 

```
|:------|:----------------|:---------------|
```

2. right 

```
|------:|----------------:|---------------:|
```

3. center 

```
|:------:|:----------------:|:---------------:|
```

______________________

It's correct that we could have a separate builder for each style.
And `style::modern()` would return `ModernBuilder` which would have settings like `grid`, `corner` etc.

_______________

To conclude I just don't yet haven't came up with a good interface to all of this.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 25eab77..e3742eb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "tabled"
-version = "0.9.0-fix.docs.rs.4"
+version = "0.9.1"
 authors = ["Maxim Zhiburt <zhiburt@gmail.com>"]
 edition = "2018"
 description = "An easy to use library for pretty print tables of Rust `struct`s and `enum`s."
@@ -120,6 +120,11 @@ name = "rotate"
 path = "examples/rotate.rs"
 required-features = ["derive"]
 
+[[example]]
+name = "shadow"
+path = "examples/shadow.rs"
+required-features = ["macros"]
+
 [[example]]
 name = "nested_table_2"
 path = "examples/nested_table_2.rs"
diff --git a/README.md b/README.md
index abfa94c..3faee7f 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ An easy to use library for pretty printing tables of Rust `struct`s and `enum`s.
     - [Themes](#themes)
       - [ascii](#ascii)
       - [modern](#modern)
+      - [sharp](#sharp)
       - [rounded](#rounded)
       - [extended](#extended)
       - [psql](#psql)
@@ -203,6 +204,18 @@ please open an issue.
 └──────┴────────────────┴───────────────┘
 ```
 
+##### sharp
+
+```text
+┌──────┬────────────────┬───────────────┐
+│ name │ designed_by    │ invented_year │
+├──────┼────────────────┼───────────────┤
+│ C    │ Dennis Ritchie │ 1972          │
+│ Rust │ Graydon Hoare  │ 2010          │
+│ Go   │ Rob Pike       │ 2009          │
+└──────┴────────────────┴───────────────┘
+```
+
 ##### rounded
 
 ```text
@@ -210,9 +223,7 @@ please open an issue.
 │ name │ designed_by    │ invented_year │
 ├──────┼────────────────┼───────────────┤
 │ C    │ Dennis Ritchie │ 1972          │
-├──────┼────────────────┼───────────────┤
 │ Rust │ Graydon Hoare  │ 2010          │
-├──────┼────────────────┼───────────────┤
 │ Go   │ Rob Pike       │ 2009          │
 ╰──────┴────────────────┴───────────────╯
 ```
diff --git a/examples/README.md b/examples/README.md
index fbd36fb..9c60d73 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -463,6 +463,24 @@ vvvvvvvvvvvvvvvvvv
 +--------------+------------------------+---------------------------+--------------------------+
 ```
 
+## shadow
+
+```
+┌──┬┐ ╔══╦╗ ╓──┬╖ ╒═╤╕
+│  ││ ║  ║║ ║  │║ │ ││
+├──┼┤ ╠══╬╣ ╟──┼╢ ╞═╪╡
+└──┴┘ ╚══╩╝ ╙──┴╜ ╘═╧╛
+┌──────────────────┐  
+│  ╔═══╗ Some text │▒▒
+│  ╚═╦═╝ In the box│▒▒
+╞═╤══╩══╤══════════╡▒▒
+│ ├──┬──┤          │▒▒
+│ └──┴──┘          │▒▒
+└──────────────────┘▒▒
+ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
+ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
+```
+
 ## span
 
 ```
diff --git a/examples/shadow.rs b/examples/shadow.rs
index eb510c8..ba9c091 100644
--- a/examples/shadow.rs
+++ b/examples/shadow.rs
@@ -1,41 +1,150 @@
-//! The example can be run by this command
-//! `cargo run --example basic`
+//! The example relayes on STDIN to read the message which will be outputed.
+//!
+//! The table is inspired by <https://en.wikipedia.org/wiki/Box-drawing_character>
+//!
+//! ## Example
+//!
+//! `echo -e -n 'Some text\nIn the box' | cargo run --package tabled --example shadow`
 
-use std::iter::FromIterator;
+use std::{io::Read, iter::FromIterator};
 
-use tabled::{object::Rows, shadow::Shadow, Alignment, ModifyObject, Style, Table, Tabled};
+use tabled::{
+    builder::Builder,
+    object::Cell,
+    row,
+    shadow::Shadow,
+    style::{BorderChar, Offset, RawStyle},
+    Height, Modify, Padding, Style, Table, Width,
+};
 
-#[derive(Tabled)]
-struct Distribution {
-    name: String,
-    based_on: String,
-    is_active: bool,
-    is_cool: bool,
+fn main() {
+    let message = read_message();
+
+    let main_table = create_main_table(&message);
+    let main_table_width = main_table.total_width();
+    let small_table_row = create_small_table_list(main_table_width);
+    println!("{}", small_table_row);
+    println!("{}", main_table);
+}
+
+fn read_message() -> String {
+    let mut buf = String::new();
+    std::io::stdin().read_to_string(&mut buf).unwrap();
+
+    buf
 }
 
-impl Distribution {
-    fn new(name: &str, based_on: &str, is_active: bool, is_cool: bool) -> Self {
-        Self {
-            name: name.to_string(),
-            based_on: based_on.to_string(),
-            is_active,
-            is_cool,
+fn create_small_table_list(width_available: usize) -> String {
+    let mut tables = [
+        create_small_table(Style::modern().into()),
+        create_small_table(Style::extended().into()),
+        create_small_table(
+            Style::modern()
+                .left('║')
+                .right('║')
+                .left_intersection('╟')
+                .right_intersection('╢')
+                .top_right_corner('╖')
+                .top_left_corner('╓')
+                .bottom_right_corner('╜')
+                .bottom_left_corner('╙')
+                .into(),
+        ),
+        create_small_table(
+            Style::modern()
+                .top('═')
+                .bottom('═')
+                .top_right_corner('╕')
+                .top_left_corner('╒')
+                .bottom_right_corner('╛')
+                .bottom_left_corner('╘')
+                .horizontal('═')
+                .left_intersection('╞')
+                .right_intersection('╡')
+                .inner_intersection('╪')
+                .top_intersection('╤')
+                .bottom_intersection('╧')
+                .into(),
+        ),
+    ];
+    const TOTAL_TABLE_WIDTH: usize = 19;
+
+    if width_available > TOTAL_TABLE_WIDTH {
+        let mut rest = width_available - TOTAL_TABLE_WIDTH;
+        while rest > 0 {
+            for table in &mut tables {
+                let current_width = table.total_width();
+                table.with(Width::increase(current_width + 1));
+                rest -= 1;
+
+                if rest == 0 {
+                    break;
+                }
+            }
         }
     }
+
+    let small_table_row = row![tables[0], tables[1], tables[2], tables[3]]
+        .with(Style::blank())
+        .with(Padding::zero())
+        .to_string();
+    small_table_row
 }
 
-fn main() {
-    let data = [
-        Distribution::new("Manjaro", "Arch", true, true),
-        Distribution::new("Arch", "", true, true),
-        Distribution::new("Debian", "", true, true),
-    ];
+fn create_small_table(style: RawStyle) -> Table {
+    let mut table = Builder::from_iter(vec![vec![" ", ""], vec![" ", ""]]).build();
+    table
+        .with(style)
+        .with(Padding::zero())
+        .with(Height::list([1, 0]));
 
-    let mut table = Table::from_iter(&data);
     table
-        .with(Style::ascii())
-        .with(Rows::first().modify().with(Alignment::center()))
+}
+
+// ┌───────────────────┐
+// │  ╔═══╗ Some Text  │▒
+// │  ╚═╦═╝ in the box │▒
+// ╞═╤══╩══╤═══════════╡▒
+// │ ├──┬──┤           │▒
+// │ └──┴──┘           │▒
+// └───────────────────┘▒
+// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
+
+fn create_main_table(message: &str) -> Table {
+    let count_lines = papergrid::util::count_lines(message);
+    let message_width = papergrid::util::string_width_multiline_tab(message, 4);
+    let count_additional_separators = if count_lines > 2 { count_lines - 2 } else { 0 };
+
+    let left_table = format!(
+        "  ╔═══╗ \n  ╚═╦═╝ \n{}═╤══╩══╤\n ├──┬──┤\n └──┴──┘",
+        (0..count_additional_separators)
+            .map(|_| "    ║   \n")
+            .collect::<String>()
+    );
+
+    let message = if count_lines < 2 {
+        let mut i = count_lines;
+        let mut buf = message.to_string();
+        while i < 2 {
+            buf.push('\n');
+            i += 1;
+        }
+
+        buf
+    } else {
+        message.to_owned()
+    };
+    let count_lines = count_lines.max(2);
+
+    let message = format!("{}\n{}", message, "═".repeat(message_width));
+
+    let mut table = row![left_table, message];
+    table
+        .with(Padding::zero())
+        .with(Style::modern().off_vertical())
+        .with(Modify::new(Cell(0, 0)).with(BorderChar::vertical('╞', Offset::Begin(count_lines))))
+        .with(Modify::new(Cell(0, 2)).with(BorderChar::vertical('╡', Offset::Begin(count_lines))))
         .with(Shadow::new(2));
 
-    println!("{}", table);
+    table
 }
diff --git a/src/features/height/height_list.rs b/src/features/height/height_list.rs
new file mode 100644
index 0000000..879a246
--- /dev/null
+++ b/src/features/height/height_list.rs
@@ -0,0 +1,47 @@
+use std::iter::FromIterator;
+
+use papergrid::records::Records;
+
+use crate::{Table, TableOption};
+
+/// A structure used to set [`Table`] height via a list of rows heights.
+#[derive(Debug)]
+pub struct HeightList {
+    list: Vec<usize>,
+}
+
+impl HeightList {
+    /// Creates a new object.
+    pub fn new(list: Vec<usize>) -> Self {
+        Self { list }
+    }
+}
+
+impl From<Vec<usize>> for HeightList {
+    fn from(list: Vec<usize>) -> Self {
+        Self::new(list)
+    }
+}
+
+impl FromIterator<usize> for HeightList {
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = usize>,
+    {
+        Self::new(iter.into_iter().collect())
+    }
+}
+
+impl<R> TableOption<R> for HeightList
+where
+    R: Records,
+{
+    fn change(&mut self, table: &mut Table<R>) {
+        if self.list.len() < table.count_rows() {
+            return;
+        }
+
+        table.cache_height(self.list.clone());
+        table.destroy_width_cache();
+    }
+}
diff --git a/src/features/height/mod.rs b/src/features/height/mod.rs
index e2fdfc9..fa601f0 100644
--- a/src/features/height/mod.rs
+++ b/src/features/height/mod.rs
@@ -6,11 +6,13 @@ use crate::measurment::Measurment;
 
 mod cell_height_increase;
 mod cell_height_limit;
+mod height_list;
 mod table_height_increase;
 mod table_height_limit;
 
 pub use cell_height_increase::CellHeightIncrease;
 pub use cell_height_limit::CellHeightLimit;
+pub use height_list::HeightList;
 pub use table_height_increase::TableHeightIncrease;
 pub use table_height_limit::TableHeightLimit;
 
@@ -198,6 +200,42 @@ impl Height {
     {
         CellHeightLimit::new(width)
     }
+
+    /// Create [`HeightList`] to set a table height to a constant list of row heights.
+    ///
+    /// Notice if you provide a list with `.len()` less than `Table::count_rows` then it will have no affect.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use tabled::{Table, Height, Modify, object::Columns};
+    ///
+    /// let data = vec![
+    ///     ("Some\ndata", "here", "and here"),
+    ///     ("Some\ndata on a next", "line", "right here"),
+    /// ];
+    ///
+    /// let table = Table::new(data)
+    ///     .with(Height::list([1, 0, 2]))
+    ///     .to_string();
+    ///
+    /// assert_eq!(
+    ///     table,
+    ///     "+----------------+------+------------+\n\
+    ///      | &str           | &str | &str       |\n\
+    ///      +----------------+------+------------+\n\
+    ///      +----------------+------+------------+\n\
+    ///      | Some           | line | right here |\n\
+    ///      | data on a next |      |            |\n\
+    ///      +----------------+------+------------+",
+    /// )
+    /// ```
+    pub fn list<I>(rows: I) -> HeightList
+    where
+        I: IntoIterator<Item = usize>,
+    {
+        HeightList::new(rows.into_iter().collect())
+    }
 }
 
 pub(crate) fn get_table_total_height<R, E>(records: &R, cfg: &GridConfig, ctrl: &E) -> usize
diff --git a/src/features/style/style.rs b/src/features/style/style.rs
index 73af992..3b70fa9 100644
--- a/src/features/style/style.rs
+++ b/src/features/style/style.rs
@@ -318,7 +318,35 @@ impl Style<(), (), (), (), (), (), (), ()> {
         )
     }
 
-    /// This style looks like a [`Style::modern`] but with rounded corners and no horozizontal lines except a header.
+    /// This style looks like a [`Style::modern`] but without horozizontal lines except a header.
+    ///
+    /// Beware: It uses UTF-8 characters.
+    ///
+    /// ```text
+    ///     ┌────┬──────────────┬───────────────────────────┐
+    ///     │ id │ destribution │           link            │
+    ///     ├────┼──────────────┼───────────────────────────┤
+    ///     │ 0  │    Fedora    │  https://getfedora.org/   │
+    ///     │ 2  │   OpenSUSE   │ https://www.opensuse.org/ │
+    ///     │ 3  │ Endeavouros  │ https://endeavouros.com/  │
+    ///     └────┴──────────────┴───────────────────────────┘
+    /// ```
+    pub const fn sharp() -> Style<On, On, On, On, (), On, HLineArray<1>> {
+        Style::new(
+            create_borders(
+                Line::full('─', '┬', '┌', '┐'),
+                Line::full('─', '┴', '└', '┘'),
+                Line::empty(),
+                Some('│'),
+                Some('│'),
+                Some('│'),
+            ),
+            [HorizontalLine::new(1, Line::full('─', '┼', '├', '┤'))],
+            [],
+        )
+    }
+
+    /// This style looks like a [`Style::sharp`] but with rounded corners.
     ///
     /// Beware: It uses UTF-8 characters.
     ///
diff --git a/src/features/width/mod.rs b/src/features/width/mod.rs
index e66fa6d..53d9198 100644
--- a/src/features/width/mod.rs
+++ b/src/features/width/mod.rs
@@ -35,6 +35,7 @@
 mod justify;
 mod min_width;
 mod truncate;
+mod width_list;
 mod wrap;
 
 use crate::measurment::Measurment;
@@ -43,6 +44,7 @@ pub use self::{
     justify::Justify,
     min_width::MinWidth,
     truncate::{SuffixLimit, Truncate},
+    width_list::WidthList,
     wrap::Wrap,
 };
 
@@ -136,6 +138,46 @@ impl Width {
     {
         Justify::new(width)
     }
+
+    /// Create [`WidthList`] to set a table width to a constant list of column widths.
+    ///
+    /// Notice if you provide a list with `.len()` smaller than `Table::count_columns` then it will have no affect.
+    ///
+    /// Also notice that you must provide values bigger than or equal to a real content width, otherwise it may panic.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use tabled::{Table, Width};
+    ///
+    /// let data = vec![
+    ///     ("Some\ndata", "here", "and here"),
+    ///     ("Some\ndata on a next", "line", "right here"),
+    /// ];
+    ///
+    /// let table = Table::new(data)
+    ///     .with(Width::list([20, 10, 12]))
+    ///     .to_string();
+    ///
+    /// assert_eq!(
+    ///     table,
+    ///     "+--------------------+----------+------------+\n\
+    ///      | &str               | &str     | &str       |\n\
+    ///      +--------------------+----------+------------+\n\
+    ///      | Some               | here     | and here   |\n\
+    ///      | data               |          |            |\n\
+    ///      +--------------------+----------+------------+\n\
+    ///      | Some               | line     | right here |\n\
+    ///      | data on a next     |          |            |\n\
+    ///      +--------------------+----------+------------+"
+    /// )
+    /// ```
+    pub fn list<I>(rows: I) -> WidthList
+    where
+        I: IntoIterator<Item = usize>,
+    {
+        WidthList::new(rows.into_iter().collect())
+    }
 }
 
 pub(crate) fn get_table_widths<R>(records: R, cfg: &GridConfig) -> Vec<usize>
diff --git a/src/features/width/width_list.rs b/src/features/width/width_list.rs
new file mode 100644
index 0000000..1c5c3e7
--- /dev/null
+++ b/src/features/width/width_list.rs
@@ -0,0 +1,47 @@
+use std::iter::FromIterator;
+
+use papergrid::records::Records;
+
+use crate::{Table, TableOption};
+
+/// A structure used to set [`Table`] width via a list of columns widths.
+#[derive(Debug)]
+pub struct WidthList {
+    list: Vec<usize>,
+}
+
+impl WidthList {
+    /// Creates a new object.
+    pub fn new(list: Vec<usize>) -> Self {
+        Self { list }
+    }
+}
+
+impl From<Vec<usize>> for WidthList {
+    fn from(list: Vec<usize>) -> Self {
+        Self::new(list)
+    }
+}
+
+impl FromIterator<usize> for WidthList {
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = usize>,
+    {
+        Self::new(iter.into_iter().collect())
+    }
+}
+
+impl<R> TableOption<R> for WidthList
+where
+    R: Records,
+{
+    fn change(&mut self, table: &mut Table<R>) {
+        if self.list.len() < table.count_columns() {
+            return;
+        }
+
+        table.cache_width(self.list.clone());
+        table.destroy_height_cache();
+    }
+}


Test patch:
diff --git a/papergrid/tests/render.rs b/papergrid/tests/render.rs
index c579904..3e1753d 100644
--- a/papergrid/tests/render.rs
+++ b/papergrid/tests/render.rs
@@ -10,7 +10,9 @@
 // The above copyright notice and this permission notice shall be included in all
 // copies or substantial portions of the Software.
 
-use papergrid::{AlignmentHorizontal, AlignmentVertical, Entity};
+use std::vec;
+
+use papergrid::{width::CfgWidthFunction, AlignmentHorizontal, AlignmentVertical, Entity};
 
 use crate::util::{grid, test_table};
 
@@ -26,6 +28,58 @@ test_table!(
     "+--------+"
 );
 
+test_table!(
+    render_1x1_empty,
+    grid(1, 1).change_cell((0, 0), "").build(),
+    "++"
+    "||"
+    "++"
+);
+
+test_table!(
+    render_1x1_empty_with_height_0,
+    {
+        let ctrl = CfgWidthFunction::default();
+        let data = vec![vec![papergrid::records::cell_info::CellInfo::new("", &ctrl)]];
+        let records = papergrid::records::vec_records::VecRecords::new(data, (1, 1), &ctrl);
+        let width = util::EstimationList::from(vec![0]);
+        let height = util::EstimationList::from(vec![0]);
+        let mut cfg = papergrid::GridConfig::default();
+        cfg.set_borders(util::DEFAULT_BORDERS);
+
+        let grid = papergrid::Grid::new(records, &cfg, &width, &height);
+        grid.to_string()
+    },
+    "++"
+    "++"
+);
+
+test_table!(
+    render_1x1_empty_with_height_with_width,
+    {
+        let ctrl = CfgWidthFunction::default();
+        let data = vec![vec![papergrid::records::cell_info::CellInfo::new("", &ctrl)]];
+        let records = papergrid::records::vec_records::VecRecords::new(data, (1, 1), &ctrl);
+        let width = util::EstimationList::from(vec![10]);
+        let height = util::EstimationList::from(vec![0]);
+        let mut cfg = papergrid::GridConfig::default();
+        cfg.set_borders(papergrid::Borders {
+            top_left: Some('┌'),
+            top_right: Some('┐'),
+            bottom_left: Some('└'),
+            bottom_right: Some('┘'),
+            top: Some('─'),
+            bottom: Some('─'),
+            ..Default::default()
+        });
+
+        let grid = papergrid::Grid::new(records, &cfg, &width, &height);
+        grid.to_string()
+    },
+    "┌──────────┐"
+    "└──────────┘"
+);
+
 test_table!(
     render_2x2,
     grid(2, 2).build(),
diff --git a/papergrid/tests/util.rs b/papergrid/tests/util.rs
index 126c48f..eaece20 100644
--- a/papergrid/tests/util.rs
+++ b/papergrid/tests/util.rs
@@ -4,7 +4,7 @@ use std::collections::HashMap;
 
 use papergrid::{
     height::HeightEstimator,
-    records::{cell_info::CellInfo, vec_records::VecRecords},
+    records::{cell_info::CellInfo, vec_records::VecRecords, Records},
     width::{CfgWidthFunction, WidthEstimator},
     Borders, Estimate, Grid, GridConfig, Position,
 };
@@ -146,3 +146,32 @@ pub const DEFAULT_BORDERS: Borders = Borders {
 
     intersection: Some('+'),
 };
+
+/// A [`Estimate`]or of a width for a [`Grid`].
+///
+/// [`Grid`]: crate::Grid
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
+pub struct EstimationList {
+    list: Vec<usize>,
+}
+
+impl From<Vec<usize>> for EstimationList {
+    fn from(list: Vec<usize>) -> Self {
+        Self { list }
+    }
+}
+
+impl<R> Estimate<R> for EstimationList
+where
+    R: Records,
+{
+    fn estimate(&mut self, _: R, _: &GridConfig) {}
+
+    fn get(&self, column: usize) -> Option<usize> {
+        self.list.get(column).cloned()
+    }
+
+    fn total(&self) -> usize {
+        self.list.iter().sum()
+    }
+}
diff --git a/tests/style_test.rs b/tests/style_test.rs
index d9b14a3..bd22486 100644
--- a/tests/style_test.rs
+++ b/tests/style_test.rs
@@ -72,6 +72,18 @@ test_table!(
     "╰───┴──────────┴──────────┴──────────╯"
 );
 
+test_table!(
+    sharp_style,
+    create_table::<3, 3>().with(Style::sharp()),
+    "┌───┬──────────┬──────────┬──────────┐"
+    "│ 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    │"
+    "└───┴──────────┴──────────┴──────────┘"
+);
+
 test_table!(
     modern_clean_style,
     create_table::<3, 3>().with(Style::modern().off_horizontal().horizontals(vec![HorizontalLine::new(1, Style::modern().get_horizontal())])),
diff --git a/tests/table_test.rs b/tests/table_test.rs
index 34e5de9..2f51c0e 100644
--- a/tests/table_test.rs
+++ b/tests/table_test.rs
@@ -1,4 +1,6 @@
-use tabled::{Style, Table, Width};
+use std::iter::FromIterator;
+
+use tabled::{builder::Builder, Height, Padding, Style, Table, Width};
 
 use crate::util::{create_table, test_table};
 
@@ -761,3 +763,60 @@ fn multiline_table_test2() {
         ),
     );
 }
+
+test_table!(
+    table_1x1_empty,
+    {
+        Builder::from_iter(vec![vec![""]]).build()
+            .with(tabled::Style::modern())
+            .with(Height::limit(0))
+            .with(Width::increase(10))
+    },
+    "┌────────┐"
+    "└────────┘"
+);
+
+test_table!(
+    table_2x2_empty,
+    {
+        Builder::from_iter(vec![vec![" ", ""], vec![" ", ""]]).build()
+            .with(tabled::Style::modern())
+            .with(Padding::zero())
+            .with(Height::list([1, 0]))
+    },
+    "┌─┬┐"
+    "│ ││"
+    "├─┼┤"
+    "└─┴┘"
+);
+
+test_table!(
+    table_2x2_empty_height_list_together_with_width_list_dont_work_0,
+    {
+        Builder::from_iter(vec![vec!["", ""], vec!["", ""]]).build()
+            .with(tabled::Style::modern())
+            .with(Padding::zero())
+            .with(Height::list([1, 0]))
+            .with(Width::list([1, 0]))
+    },
+    "┌─┬┐"
+    "│ ││"
+    "├─┼┤"
+    "│ ││"
+    "└─┴┘"
+);
+
+test_table!(
+    table_2x2_empty_height_list_together_with_width_list_dont_work_1,
+    {
+        Builder::from_iter(vec![vec!["", ""], vec!["", ""]]).build()
+            .with(tabled::Style::modern())
+            .with(Padding::zero())
+            .with(Width::list([1, 0]))
+            .with(Height::list([1, 0]))
+    },
+    "┌┬┐"
+    "│││"
+    "├┼┤"
+    "└┴┘"
+);