Repository: zhiburt/tabled
Pull request #384 (2023-12-19 20:17:28)

Update documentation prepare for 0.15


Patch:
diff --git a/README.md b/README.md
index 707f796..7aea57a 100644
--- a/README.md
+++ b/README.md
@@ -23,8 +23,6 @@ you can find more examples in an **[examples](/tabled/examples/)** folder.
 ## Table of Contents
 
 - [Usage](#usage)
-  - [Dynamic table](#dynamic-table)
-    - [Build index](#build-index)
 - [Settings](#settings)
   - [Style](#style)
     - [Styles](#styles)
@@ -40,19 +38,18 @@ you can find more examples in an **[examples](/tabled/examples/)** folder.
       - [ascii\_rounded](#ascii_rounded)
       - [blank](#blank)
       - [empty](#empty)
-    - [Customization](#customization)
+    - [Customization](#style-customization)
     - [Cell Border](#cell-border)
     - [Text on borders](#text-on-borders)
     - [Colorize borders](#colorize-borders)
-  - [Theme](#theme)
-    - [Colorize content](#colorize-content)
-    - [Column names](#colorize-content)
+    - [Theme](#theme)
+      - [Colorize content](#colorize-content)
+      - [Column names](#colorize-content)
   - [Alignment](#alignment)
   - [Format](#format)
   - [Padding](#padding)
-    - [Padding Color](#padding-color)
   - [Margin](#margin)
-    - [Margin Color](#margin-color)
+    - [Color](#margin-color)
   - [Shadow](#shadow)
   - [Width](#width)
     - [Truncate](#truncate)
@@ -67,7 +64,6 @@ you can find more examples in an **[examples](/tabled/examples/)** folder.
   - [Rotate](#rotate)
   - [Disable](#disable)
   - [Extract](#extract)
-    - [Refinishing](#refinishing)
   - [Header and Footer and Panel](#header-and-footer-and-panel)
   - [Merge](#merge)
   - [Concat](#concat)
@@ -76,9 +72,6 @@ you can find more examples in an **[examples](/tabled/examples/)** folder.
     - [Horizontal span](#horizontal-span)
     - [Vertical span](#vertical-span)
   - [Split](#split)
-    - [Directions](#directions)
-    - [Behaviors](#behaviors)
-    - [Displays](#displays)
   - [Duplicate](#duplicate)
 - [Derive](#derive)
   - [Override a column name](#override-a-column-name)
@@ -87,19 +80,21 @@ you can find more examples in an **[examples](/tabled/examples/)** folder.
   - [Format fields](#format-fields)
   - [Format headers](#format-headers)
   - [Inline](#inline)
-- [Features](#features)
-  - [Color](#color)
-  - [Tuple combination](#tuple-combination)
-  - [Object](#object)
-  - [Macros](#macros)
-    - [`col` and `row`](#col-and-row)
-    - [`static_table`](#static_table)
 - [Table types](#table-types)
   - [`Table`](#table)
   - [`IterTable`](#itertable)
   - [`CompactTable`](#compacttable)
   - [`PoolTable`](#pooltable)
   - [`ExpandedDisplay`](#expanded-display)
+- [Tips & Tricks](#tips-&-tricks)
+  - [`std::fmt::*` options](#std::fmt::*-options)
+  - [Tuple combination](#tuple-combination)
+  - [Object](#object)
+  - [Builder](#builder)
+  - [Macros](#macros)
+    - [`col` and `row`](#col-and-row)
+    - [`static_table`](#static_table)
+- [Features](#features)
 - [Formats](#formats)
   - [`json` format](#json-format)
   - [`ron` format](#ron-format)
@@ -154,34 +149,21 @@ let expected = "+------+----------------+---------------+\n\
                 +------+----------------+---------------+\n\
                 | C    | Dennis Ritchie | 1972          |\n\
                 +------+----------------+---------------+\n\
-                | Rust | Graydon Hoare  | 2010          |\n\
-                +------+----------------+---------------+\n\
                 | Go   | Rob Pike       | 2009          |\n\
+                +------+----------------+---------------+\n\
+                | Rust | Graydon Hoare  | 2010          |\n\
                 +------+----------------+---------------+";
 
 assert_eq!(table, expected);
 ```
 
-You can also use some of the formatting(`std::fmt::*`) options.
-
-```rust
-use tabled::Table;
-
-let numbers = [1, 2, 3];
-let table = Table::new(numbers);
-    
-println!("{:#^10}", table);
-```
-
-### Dynamic table
-
 Sometimes you can't say what type of data you are going to deal with (like parsing `csv`).
 In such cases it may be handy to build table dynamically (step by step).
 
 ```rust
 use tabled::{builder::Builder, settings::Style};
 
-let song = r#"
+let lyrics = r#"
     And the cat's in the cradle and the silver spoon
     Little boy blue and the man on the moon
     When you comin' home dad?
@@ -190,12 +172,13 @@ let song = r#"
 "#;
 
 let mut builder = Builder::default();
-for line in song.lines() {
+for line in lyrics.lines() {
+    let line = line.trim();
     if line.is_empty() {
         continue;
     }
 
-    let words: Vec<_> = line.trim().split_terminator(' ').collect();
+    let words: Vec<_> = line.split_terminator(' ').collect();
     builder.push_record(words);
 }
 
@@ -205,81 +188,24 @@ builder.insert_record(0, columns);
 let mut table = builder.build();
 table.with(Style::ascii_rounded());
 
-println!("{}", table);
-```
-
-```text
-.------------------------------------------------------------------------------------.
-| 0      | 1     | 2      | 3     | 4    | 5      | 6    | 7        | 8      | 9     |
-| And    | the   | cat's  | in    | the  | cradle | and  | the      | silver | spoon |
-| Little | boy   | blue   | and   | the  | man    | on   | the      | moon   |       |
-| When   | you   | comin' | home  | dad? |        |      |          |        |       |
-| I      | don't | know   | when, | but  | we'll  | get  | together | then   | son   |
-| You    | know  | we'll  | have  | a    | good   | time | then     |        |       |
-'------------------------------------------------------------------------------------'
-```
-
-#### Build index
-
-You can change a table layout by `Builder`.
-
-```rust
-// previous example
-// ...
-
-let mut builder = builder.index();
-builder.transpose();
-```
-
-```text
-.-------------------------------------------------.
-|   | 0      | 1      | 2      | 3        | 4     |
-| 0 | And    | Little | When   | I        | You   |
-| 1 | the    | boy    | you    | don't    | know  |
-| 2 | cat's  | blue   | comin' | know     | we'll |
-| 3 | in     | and    | home   | when,    | have  |
-| 4 | the    | the    | dad?   | but      | a     |
-| 5 | cradle | man    |        | we'll    | good  |
-| 6 | and    | on     |        | get      | time  |
-| 7 | the    | the    |        | together | then  |
-| 8 | silver | moon   |        | then     |       |
-| 9 | spoon  |        |        | son      |       |
-'-------------------------------------------------'
-```
-
-You can use `Builder::index` to make a particular column an index, which will stay on the left.
-
-```rust
-use tabled::{builder::Builder, settings::Style};
-
-let mut builder = Builder::default();
-builder.push_record(["Index", "Language", "Status"]);
-builder.push_record(["1", "English", "In progress"]);
-builder.push_record(["2", "Deutsch", "Not ready"]);
-
-let builder = builder.index().column(1).name(None);
-
-let mut table = builder.build();
-table.with(Style::rounded());
-
-println!("{}", table);
-```
+let expected = concat!(
+    ".------------------------------------------------------------------------------------.\n",
+    "| 0      | 1     | 2      | 3     | 4    | 5      | 6    | 7        | 8      | 9     |\n",
+    "| And    | the   | cat's  | in    | the  | cradle | and  | the      | silver | spoon |\n",
+    "| Little | boy   | blue   | and   | the  | man    | on   | the      | moon   |       |\n",
+    "| When   | you   | comin' | home  | dad? |        |      |          |        |       |\n",
+    "| I      | don't | know   | when, | but  | we'll  | get  | together | then   | son   |\n",
+    "| You    | know  | we'll  | have  | a    | good   | time | then     |        |       |\n",
+    "'------------------------------------------------------------------------------------'",
+);
 
-```text
-╭─────────┬───────┬─────────────╮
-│         │ Index │ Status      │
-├─────────┼───────┼─────────────┤
-│ English │ 1     │ In progress │
-│ Deutsch │ 2     │ Not ready   │
-╰─────────┴───────┴─────────────╯
+assert_eq!(table, expected);
 ```
 
 ## Settings
 
 This section lists the set of settings you can apply to your table.
-Most of the settings are used by `.with` method of `Table`.
-
-You can find a list of show cases in **[examples folder](/tabled/examples/README.md)**.
+Most of the settings are laveraged by `Table::with` and `Table::modify`.
 
 ### Style
 
@@ -442,53 +368,61 @@ Rust Graydon Hoare  2010
 Go   Rob Pike       2009         
 ```
 
-#### Customization
+#### Style customization
 
 You can modify existing styles to fit your needs.
+Notice that all modifications are done at compile time.
 
-```rust
-let style = tabled::settings::Style::modern().remove_horizontal();
-```
-
-The style will look like the following.
-
-```rust
-┌──────┬────────────────┬───────────────┐
-│ name │ designed_by    │ invented_year │
-│ C    │ Dennis Ritchie │ 1972          │
-│ Rust │ Graydon Hoare  │ 2010          │
-│ Go   │ Rob Pike       │ 2009          │
-└──────┴────────────────┴───────────────┘
-```
-
-You can change the existing styles.
+Check the [documentation](https://docs.rs/tabled/latest/tabled/settings/struct.Style.html) for
+more customization options.
 
 ```rust
-use tabled::settings::style::{HorizontalLine, Style, VerticalLine};
+use tabled::settings::{Style, HorizontalLine, VerticalLine};
 
 let style = Style::modern()
-    .remove_horizontals()
-    .remove_verticals()
-    .horizontals([HorizontalLine::new(1, Style::modern().get_horizontal())
-        .main(Some('═'))
-        .intersection(None)])
-    .verticals([VerticalLine::new(1, Style::modern().get_vertical())]);
+    .horizontals([(1, HorizontalLine::inherit(Style::modern()).horizontal('═'))])
+    .verticals([(1, VerticalLine::inherit(Style::modern()))])
+    .remove_horizontal()
+    .remove_vertical();
 ```
 
-The style will look like the following.
+The style will look like the following for the first example.
 
 ```rust
 ┌──────┬───────────────────────────────┐
 │ name │ designed_by     invented_year │
 ├══════┼═══════════════════════════════┤
 │ C    │ Dennis Ritchie  1972          │
-│ Rust │ Graydon Hoare   2010          │
 │ Go   │ Rob Pike        2009          │
+│ Rust │ Graydon Hoare   2010          │
 └──────┴───────────────────────────────┘
 ```
 
-Check the [documentation](https://docs.rs/tabled/latest/tabled/style/struct.Style.html) for
-more customization options.
+Also you can build your own one from scratch, and doing so not always possible at compile time,
+so you may use `Theme` object to do that.
+
+Notice that the `Theme` is quite powerfull on itself, you can check it in the [documentation](https://docs.rs/tabled/latest/tabled/settings/struct.Theme.html).
+
+```rust
+use tabled::grid::config::{Border, HorizontalLine};
+use tabled::settings::Theme;
+
+let mut style = Theme::default();
+style.set_lines_horizontal(HashMap::from_iter([(1, HorizontalLine::full('-', '-', '+', '+'))]));
+style.set_border_frame(Border::filled('+'));
+```
+
+The style will look like the following.
+
+```rust
++++++++++++++++++++++++++++++++++++++++
++ name  designed_by     invented_year +
++-------------------------------------+
++ C     Dennis Ritchie  1972          +
++ Go    Rob Pike        2009          +
++ Rust  Graydon Hoare   2010          +
++++++++++++++++++++++++++++++++++++++++
+```
 
 #### Cell Border
 
@@ -498,24 +432,25 @@ Sometimes it's nesessary to change a border of a particular cell.
 For this purpose you can use `Border`.
 
 ```rust
-use tabled::{settings::{object::Rows, Border, Modify, Style}, Table};
+use tabled::{settings::{object::Rows, Border, Style}, Table};
 
 let data = [["123", "456"], ["789", "000"]];
-    
+        
 let table = Table::new(data)
     .with(Style::ascii())
-    .with(Modify::new(Rows::first()).with(Border::default().top('x')))
+    .modify(Rows::first(), Border::new().set_top('x'))
     .to_string();
-    
-let expected = "+xxxxx+xxxxx+\n\
-                | 0   | 1   |\n\
-                +-----+-----+\n\
-                | 123 | 456 |\n\
-                +-----+-----+\n\
-                | 789 | 000 |\n\
-                +-----+-----+";
-    
-assert_eq!(table, expected);
+
+assert_eq!(
+    table,
+    "+xxxxx+xxxxx+\n\
+     | 0   | 1   |\n\
+     +-----+-----+\n\
+     | 123 | 456 |\n\
+     +-----+-----+\n\
+     | 789 | 000 |\n\
+     +-----+-----+"
+);
 ```
 
 #### Text on borders
@@ -523,10 +458,11 @@ assert_eq!(table, expected);
 You can set a string to a horizontal border line.
 
 ```rust
-use tabled::{settings::style::BorderText, Table};
+use tabled::{settings::style::LineText, Table};
+use tabled::settings::object::Rows;
 
 let mut table = Table::new(["Hello World"]);
-table.with(BorderText::new("+-.table").horizontal(0));
+table.with(LineText::new("+-.table", Rows::first()));
 
 assert_eq!(
     table.to_string(),
@@ -541,13 +477,13 @@ assert_eq!(
 Sometimes though it's not convenient to set a string.
 But rather necessary to set a custom char.
 
-You can use `BorderChar` to achieve this.
+You can use `LineChar` to achieve this.
 
 ```rust
 use tabled::{
     settings::{
         object::Columns,
-        style::{BorderChar, Offset},
+        style::{LineChar, Offset},
         Modify, Style,
     },
     Table,
@@ -557,8 +493,8 @@ let table = Table::new([["Hello", "World", "!"]])
     .with(Style::markdown())
     .with(
         Modify::new(Columns::new(..))
-            .with(BorderChar::horizontal(':', Offset::Begin(0)))
-            .with(BorderChar::horizontal(':', Offset::End(0))),
+            .with(LineChar::horizontal(':', Offset::Begin(0)))
+            .with(LineChar::horizontal(':', Offset::End(0))),
     )
     .to_string();
 
@@ -575,57 +511,97 @@ assert_eq!(
 You can set a colors of all borders using `Color`.
 
 ```rust
-use tabled::settings::{Color, style::BorderColor};
+use tabled::settings::{style::BorderColor, Color};
 
-table.with(BorderColor::default().top(Color::FG_GREEN)))
+table.with(BorderColor::new().set_top(Color::FG_GREEN));
 ```
 
 You can also set a color border of intividial cell by using `BorderColored`.
 
 ```rust
-use tabled::settings::{Modify, style::BorderColor, Color, object::Columns};
+use tabled::settings::{object::Columns, style::BorderColor, Color};
+
+table.modify(Columns::single(2), BorderColor::new().set_top(Color::FG_GREEN));
+```
+
+#### Theme
+
+It was considered that having a few atomic settings is better rather then have one but feature full.
+
+But `tabled::settings::themes::*` are a bit diverge from this idea.
+It contains a list of settings which do bigger changes to the table.
+
+The first one is `Theme` itself.
+You can change layout, set style, colorize, config borders and even revers table with it. 
+
+```rust
+use tabled::settings::{
+    object::{Columns, Object},
+    Alignment, Style, Theme,
+};
 
-table.with(Modify::new(Columns::single(2)).with(BorderColor::default().top(Color::FG_GREEN)))
+let mut style = Theme::from_style(Style::ascii_rounded());
+style.remove_border_horizontal();
+style.remove_border_vertical();
+style.align_columns(Alignment::left());
+style.set_footer(true);
+
+table.with(style);
+table.modify(Columns::new(1..).not(Columns::last()), Alignment::center());
+table.modify(Columns::last(), Alignment::right());
 ```
 
-### Theme
+You'll must see the following output when run against the first example.
+
+```text
+.---------------------------------------------------------------------------.
+| name                  C             Go          Rust                 name |
+| designed_by     Dennis Ritchie   Rob Pike   Graydon Hoare     designed_by |
+| invented_year        1972          2009         2010        invented_year |
+'---------------------------------------------------------------------------'
+```
 
-#### Colorize content
+##### Colorize content
 
 You can colorize the content by the pattern or a specific cell.
 
 ```rust
+use std::iter::FromIterator;
+
 use tabled::{
     builder::Builder,
-    settings::{object::Rows, style::Style, themes::Colorization, Color, Modify},
+    settings::{object::Rows, style::Style, themes::Colorization, Color},
 };
 
 let data = vec![
-    vec![String::from("header 0"), String::from("header 1")],
-    vec![String::from("Hello"), String::from("World")],
-    vec![String::from("Bonjour"), String::from("le monde")],
-    vec![String::from("Hallo"), String::from("Welt")],
+    vec!["Word", "Translation", "Lang"],
+    vec!["World", "le monde", "FR"],
+    vec!["World", "Welt", "DE"],
 ];
 
-let color1 = Color::BG_WHITE | Color::FG_BLACK;
-let color2 = Color::BG_GREEN | Color::FG_BLACK;
-let color3 = Color::BG_MAGENTA | Color::FG_BLACK;
-let color4 = Color::BG_BLUE | Color::FG_BLACK;
+let color_col1 = Color::BG_GREEN | Color::FG_BLACK;
+let color_col2 = Color::BG_MAGENTA | Color::FG_BLACK;
+let color_col3 = Color::BG_YELLOW | Color::FG_BLACK;
+let color_head = Color::BG_WHITE | Color::FG_BLACK;
+let color_head_text = Color::BG_BLUE | Color::FG_BLACK;
 
-let mut table = Builder::from(data).build();
+let mut table = Builder::from_iter(data).build();
 table
     .with(Style::empty())
-    .with(Colorization::columns([color2, color3]))
-    .with(Colorization::exact([color1], Rows::first()))
-    .with(Modify::new(Rows::first()).with(color4));
+    .with(Colorization::columns([color_col1, color_col2, color_col3]))
+    .with(Colorization::exact([color_head], Rows::first()))
+    .modify(Rows::first(), color_head_text);
+
+println!("{table}");
 ```
 
 <picture>
-  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/zhiburt/tabled/assets/20165848/7e9b139c-a0fa-470d-9095-a36d1f01b55a">
-  <img alt="Preview" src="https://github.com/zhiburt/tabled/assets/20165848/2096a1a2-aaee-42f1-b00f-ca6f9317cd29">
+  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/zhiburt/tabled/assets/20165848/5dcff779-0aa5-499e-bb08-4373459c9db6">
+  <img alt="Preview" src="https://github.com/zhiburt/tabled/assets/20165848/d6f9a936-9d33-4d0b-acfc-9ef875d59cc3">
+
 </picture>
 
-#### Column names
+##### Column names
 
 You can move the header right to the borders.
 
@@ -644,6 +620,8 @@ let data = vec![
 
 let mut table = Builder::from(data).build();
 table.with(Style::modern()).with(ColumnNames::default());
+
+println!("{table}");
 ```
 
 ```text
@@ -662,13 +640,31 @@ You can set a horizontal and vertical alignment for any `Object` (e.g `Columns`,
 
 ```rust
 use tabled::{
-    settings::{Modify, Alignment, object::Segment}
+    settings::{object::Segment, Alignment, Settings},
     Table,
 };
 
+let data = [("Text", "Multiline\ntext"), ("text", "text")];
 let mut table = Table::new(data);
-table
-    .with(Modify::new(Segment::all()).with(Alignment::left()).with(Alignment::top()));
+table.modify(
+    Segment::all(),
+    Settings::new(Alignment::right(), Alignment::bottom()),
+);
+
+println!("{table}");
+```
+
+The output would be.
+
+```text
++------+-----------+
+| &str |      &str |
++------+-----------+
+|      | Multiline |
+| Text | text      |
++------+-----------+
+| text |      text |
++------+-----------+
 ```
 
 ### Format
@@ -677,95 +673,130 @@ The `Format` function provides an interface for a modification of cells.
 
 ```rust
 use tabled::{
+    settings::{format::Format, object::Rows},
     Table,
-    settings::{Modify, format::Format, object::{Rows, Columns}},
 };
 
-let mut table = Table::new(&data);
-table
-    .with(Modify::new(Rows::first()).with(Format::new(|s| format!("Head {}", s))))
-    .with(Modify::new(Columns::new(1..=2)).with(Format::new(|s| format!("<< {} >>", s))));
+let data = vec![[0; 10]; 9];
+let mut table = Table::new(data);
+table.modify(
+    Rows::new(..),
+    Format::positioned(|_, (row, col)| ((row + 1) * (col + 1)).to_string()),
+);
+
+println!("{table}");
+```
+
+The result you must get will be.
+
+```text
++----+----+----+----+----+----+----+----+----+-----+
+| 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10  |
++----+----+----+----+----+----+----+----+----+-----+
+| 2  | 4  | 6  | 8  | 10 | 12 | 14 | 16 | 18 | 20  |
++----+----+----+----+----+----+----+----+----+-----+
+| 3  | 6  | 9  | 12 | 15 | 18 | 21 | 24 | 27 | 30  |
++----+----+----+----+----+----+----+----+----+-----+
+| 4  | 8  | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40  |
++----+----+----+----+----+----+----+----+----+-----+
+| 5  | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50  |
++----+----+----+----+----+----+----+----+----+-----+
+| 6  | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60  |
++----+----+----+----+----+----+----+----+----+-----+
+| 7  | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70  |
++----+----+----+----+----+----+----+----+----+-----+
+| 8  | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80  |
++----+----+----+----+----+----+----+----+----+-----+
+| 9  | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90  |
++----+----+----+----+----+----+----+----+----+-----+
+| 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 |
++----+----+----+----+----+----+----+----+----+-----+
 ```
 
 ### Padding
 
 The `Padding` structure provides an interface for a left, right, top and bottom padding of cells.
+You can set indent size, and color of the padding.
 
 ```rust
-use tabled::{
-    Table,
-    settings::{Modify, Padding, object::Cell}
+use tabled::settings::{
+    object::{Columns, Object, Rows},
+    Color, Padding,
 };
 
-let mut table = Table::new(&data);
-table.with(Modify::new(Cell(0, 3)).with(Padding::new(1, 1, 0, 2)));
-
-// It's possible to set a fill char for padding.
-let mut table = Table::new(&data)
-table.with(Modify::new(Cell(0, 3)).with(Padding::new(1, 1, 0, 2).fill('>', '<', '^', 'V')));
-```
-
-#### Padding Color
+// Set a padding size for first column
+table.modify(Columns::first().not((0, 0)), Padding::new(0, 10, 0, 0));
 
-You can set a color for padding characters.
+// Set a padding for a last column (except first row)
+table.modify(Columns::last().not(Rows::first()), Padding::new(1, 1, 0, 0).fill('[', ']', ' ', ' '));
 
-BE AWARE: It only works with `color` feature.
-
-```rust
-use tabled::{
-    settings::{Color, Padding},
-    Table,
-};
+// Set a padding for a first row
+table.modify(
+    Rows::first(),
+    Padding::new(2, 2, 0, 2).fill(' ', ' ', ' ', ' ').colorize(
+        Color::BG_BLUE,
+        Color::BG_BLUE,
+        Color::BG_BLUE,
+        Color::BG_BLUE,
+    ),
+);
+```
 
-let mut table = Table::new(&data);
+Applying the last change to the first example will result in the following.
 
-table.with(Padding::new(1, 1, 0, 2).colorize(
-    Color::FG_BLUE,
-    Color::FG_BLUE,
-    Color::FG_BLUE,
-    Color::FG_BLUE,
-));
-```
+<picture>
+  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/zhiburt/tabled/assets/20165848/2df75093-90c4-4b26-a2be-33d45391ace3">
+  <img alt="Preview" src="https://github.com/zhiburt/tabled/assets/20165848/7ec1f377-362b-469a-94e2-6e8599a1bd6d">
+</picture>
 
 ### Margin
 
-`Margin` sets extra space around the border (top, bottom, left, right).
+`Margin` sets extra space around the table (top, bottom, left, right).
+As for `Padding` you can set indent, size and color of the extra space.
 
 ```rust
-use tabled::{Table, settings::Margin};
+use tabled::settings::Margin;
 
-let mut table = Table::new(&data);
 table.with(Margin::new(3, 4, 1, 2).fill('>', '<', 'v', '^'));
 ```
 
-An output would depend on the `data`. But it could look like the following.
+If you run it for a first example you'll get.
 
 ```text
-vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
->>>┌─────────┬──────────┐<<<<
->>>│ feature │ released │<<<<
->>>│ margin  │ 0.6.0    │<<<<
->>>└─────────┴──────────┘<<<<
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+>>>+------+----------------+---------------+<<<<
+>>>| name | designed_by    | invented_year |<<<<
+>>>+------+----------------+---------------+<<<<
+>>>| C    | Dennis Ritchie | 1972          |<<<<
+>>>+------+----------------+---------------+<<<<
+>>>| Go   | Rob Pike       | 2009          |<<<<
+>>>+------+----------------+---------------+<<<<
+>>>| Rust | Graydon Hoare  | 2010          |<<<<
+>>>+------+----------------+---------------+<<<<
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ```
 
 #### Margin Color
 
-You can set a color for padding characters.
+You can set a color for the characters.
 
 ```rust
-use tabled::{
-    settings::{Color, Margin},
-    Table,
-};
+use tabled::settings::{Margin, Color};
 
-let mut table = Table::new(data);
-table
-    .with(Margin::new(3, 4, 1, 2))
-    .with(Margin::new(1, 1, 1, 1).colorize( Color::BG_RED, Color::BG_RED, Color::BG_RED, Color::BG_RED));
+table.with(Margin::new(3, 4, 1, 2).fill('>', '<', 'v', '^').colorize(
+    Color::BG_BRIGHT_BLUE,
+    Color::BG_BRIGHT_CYAN,
+    Color::BG_BLUE,
+    Color::BG_RED,
+));
 ```
 
+<picture>
+  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/zhiburt/tabled/assets/20165848/324114ce-42e3-4aaa-be5c-18abf7e835b3">
+  <img alt="Preview" src="https://github.com/zhiburt/tabled/assets/20165848/5e280686-a8f5-4f1f-a1f6-3c97e1dd1fe3">
+</picture>
+
 ### Shadow
 
 `Shadow` can be used to set a 'shadow' like margin.
@@ -796,34 +827,79 @@ An output could look like the following.
 ### Width
 
 Using the following structures you can configure a width of a table and a single cell.
-But be aware that it doesn't often consider `Padding`.
 
-The functions preserves the text color.
+But be aware that it often DOES NOT consider `Padding` when adjusting the width.
+
+The functions preserves `ansi` color sequences (when `ansi` feature is on).
+
+Beware that we `Width` controls only content, so it can't make things smaller then a certain minimum.
+
+Bellow is an example of setting an exact table width.
+
+```rust
+use tabled::{
+    settings::{
+        peaker::{PriorityMax, PriorityMin},
+        Settings, Width,
+    },
+    Table,
+};
+
+fn generate_table(string_size: usize, width: usize) -> String {
+    let data = vec![(string_size.to_string(), "x".repeat(string_size))];
+
+    let mut table = Table::new(data);
+    table.with(Settings::new(
+        Width::wrap(width).priority::<PriorityMax>(),
+        Width::increase(width).priority::<PriorityMin>(),
+    ));
+
+    table.to_string()
+}
+
+let table = generate_table(50, 40);
+println!("{table}");
+
+let table = generate_table(20, 40);
+println!("{table}");
+```
+
+The result must be seen as following.
+
+```text
++--------+-----------------------------+
+| String | String                      |
++--------+-----------------------------+
+| 50     | xxxxxxxxxxxxxxxxxxxxxxxxxxx |
+|        | xxxxxxxxxxxxxxxxxxxxxxx     |
++--------+-----------------------------+
++---------------+----------------------+
+| String        | String               |
++---------------+----------------------+
+| 20            | xxxxxxxxxxxxxxxxxxxx |
++---------------+----------------------+
+```
 
 #### Truncate
 
 `Truncate` sets a maximum width of a cell by truncating its content.
 
 ```rust
-use tabled::{Table, settings::{Modify, Width, object::Rows}};
-
-let mut table = Table::new(data);
+use tabled::settings::{Width, object::Rows};
 
 // Truncating content to 10 chars in case it's bigger than that
 // in a first row.
-table.with(Modify::new(Rows::first()).with(Width::truncate(10)));
+table.modify(Rows::first(), Width::truncate(10));
 
 // Truncating content to 7 chars and puts a suffix '...' after it
 // in all rows except a first.
-table.with(Modify::new(Rows::new(1..)).with(Width::truncate(10).suffix("...")));
+table.modify(Rows::new(1..), Width::truncate(10).suffix("..."));
 ```
 
-`Truncate` also can be used to set a maximum width of a whole table.
+`Truncate` can be used to set a maximum width of a whole table.
 
 ```rust
-use tabled::{Table, settings::Width};
-
-let mut table = Table::new(data);
+use tabled::settings::Width;
 
 // Tries to set table width to 22, in case it's bigger than that.
 table.with(Width::truncate(22));
@@ -836,24 +912,20 @@ It can be used in combination with `MinWidth` to set an exact table size.
 `Wrap` sets a maximum width of a cell by wrapping its content to new lines.
 
 ```rust
-use tabled::{Table, settings::{Modify, Width, object::Rows}};
-
-let mut table = Table::new(data);
+use tabled::settings::{Width, object::Rows};
 
 // Wrap content to 10 chars in case it's bigger than that
 // in a first row.
-table.with(Modify::new(Rows::first()).with(Width::wrap(10)));
+table.modify(Rows::first().with(Width::wrap(10)));
 
 // Use a strategy where we try to keep words not splited (where possible).
-table.with(Modify::new(Rows::new(1..)).with(Width::wrap(10).keep_words()));
+table.modify(Rows::new(1..).with(Width::wrap(10).keep_words()));
 ```
 
-`Wrap` also can be used to set a maximum width of a whole table.
+`Wrap` can be used to set a maximum width of a whole table.
 
 ```rust
-use tabled::{Table, settings::Width};
-
-let mut table = Table::new(data);
+use tabled::settings::Width;
 
 // Tries to set table width to 22, in case it's bigger than that.
 table.with(Width::wrap(22));
@@ -866,20 +938,16 @@ It can be used in combination with `MinWidth` to set an exact table size.
 `MinWidth` sets a minimal width of an object.
 
 ```rust
-use tabled::{Table, settings::{Modify, Width, object::Rows}};
-
-let mut table = Table::new(data);
+use tabled::settings::{Width, object::Rows};
 
 // increase the space used by cells in all rows except the header to be at least 10
-table.with(Modify::new(Rows::new(1..)).with(Width::increase(10)));
+table.modify(Rows::new(1..), Width::increase(10));
 ```
 
 `MinWidth` also can be used to set a minimum width of a whole table.
 
 ```rust
-use tabled::{Table, settings::Width};
-
-let mut table = Table::new(data);
+use tabled::settings::Width;
 
 // increase width of a table in case it was lower than 10.
 table.with(Width::increase(10));
@@ -892,9 +960,8 @@ It can be used in combination with `Truncate` and `Wrap` to set an exact table s
 You can set a constant width for all columns using `Justify`.
 
 ```rust
-use tabled::{Table, settings::Width};
+use tabled::settings::Width;
 
-let mut table = Table::new(data);
 table.with(Width::justify(10));
 ```
 
@@ -903,9 +970,8 @@ table.with(Width::justify(10));
 You can tweak `Truncate`, `Wrap`, `MinWidth` logic by setting a priority by which a trim/inc be done.
 
 ```rust
-use tabled::{Table, settings::{Width, peaker::PriorityMax}};
+use tabled::settings::{Width, peaker::PriorityMax};
 
-let mut table = Table::new(data);
 table.with(Width::truncate(10).priority::<PriorityMax>());
 ```
 
@@ -915,42 +981,111 @@ By default you use `usize` int to set width settings,
 but you could do it also with `tabled::width::Percent`.
 
 ```rust
-use tabled::width::{Table, settings::{measurement::Percent, Width}};
+use tabled::settings::{Width, measurement::Percent};
 
-let mut table = Table::new(data);
 table.with(Width::wrap(Percent(75)));
 ```
 
 ### Height
 
-You can increase a table or a specific cell height using `Height` motifier.
+You can increase a table or a specific cell height using `Height` modifier.
 
-#### Height increase
+Beware that we `Height` controls only content,
+so it can't make things smaller then a certain minimum.
+
+Bellow is an example of setting an exact table height and width.
 
 ```rust
-use tabled::{Table, settings::{Height, Modify, object::Rows}};
+use std::iter::FromIterator;
 
-let mut table = Table::new(data);
+use tabled::{
+    settings::{
+        peaker::{PriorityMax, PriorityMin},
+        Height, Settings, Width,
+    },
+    Table,
+};
+
+fn generate_data(width: usize, height: usize) -> Vec<Vec<String>> {
+    let dims = format!("{}x{}", width, height);
+    let string = vec!["x".repeat(width); height].join("\n");
+
+    vec![
+        vec![String::from("N"), String::from("string")],
+        vec![dims, string],
+    ]
+}
+
+fn generate_table(data: Vec<Vec<String>>, width: usize, height: usize) -> String {
+    let mut table = Table::from_iter(data);
+
+    table.with(
+        Settings::empty()
+            .with(Width::truncate(width).priority::<PriorityMax>())
+            .with(Width::increase(width).priority::<PriorityMin>())
+            .with(Height::increase(height))
+            .with(Height::limit(height).priority::<PriorityMax>()),
+    );
+
+    table.to_string()
+}
+
+let table = generate_table(generate_data(40, 10), 30, 8);
+println!("{table}");
+
+let table = generate_table(generate_data(40, 4), 80, 12);
+println!("{table}");
+```
+
+```text
++-------+--------------------+
+| N     | string             |
+|       |                    |
+|       |                    |
++-------+--------------------+
+| 40x10 | xxxxxxxxxxxxxxxxxx |
+|       |                    |
++-------+--------------------+
++-----------------------------------+------------------------------------------+
+| N                                 | string                                   |
+|                                   |                                          |
+|                                   |                                          |
++-----------------------------------+------------------------------------------+
+| 40x4                              | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+|                                   |                                          |
+|                                   |                                          |
++-----------------------------------+------------------------------------------+
+```
+
+#### Height increase
+
+Increase a of a height of a cell of a whole table could be done by `Height::increase`.
+
+```rust
+use tabled::settings::{Height, object::Rows};
 
 // increase height of a table in case it was lower than 10.
 table.with(Height::increase(10));
 
 // increase height of cells in the last row on a table in case if some of them has it lower than 10.
-table.with(Modify::new(Rows::last()).with(Height::increase(10)));
+table.modify(Rows::last(), Height::increase(10));
 ```
 
 #### Height limit
 
-```rust
-use tabled::{Table, settings::{Height, Modify, object::Rows}};
+Truncation a of a height of a cell of a whole table could be done by `Height::limit`.
 
-let mut table = Table::new(data);
+```rust
+use tabled::settings::{Height, object::Rows};
 
 // decrease height of a table to 10 in case it was bigger than that.
 table.with(Height::limit(10));
 
 // decrease height of cells in the last row on a table to 10 in case if some of them has it bigger than that.
-table.with(Modify::new(Rows::last()).with(Height::limit(10)));
+table.modify(Rows::last(), Height::limit(10));
 ```
 
 ### Rotate
@@ -971,12 +1106,12 @@ Imagine you have a table already which output may look like this.
 └────┴──────────────┴───────────────────────────┘
 ```
 
-Now we will add the following modificator and the output will be;
+Now we will add the following modificator and the output will be rotated;
 
 ```rust
 use tabled::settings::Rotate;
 
-table.with(Rotate::Left)
+table.with(Rotate::Left);
 ```
 
 ```text
@@ -991,25 +1126,38 @@ table.with(Rotate::Left)
 
 ### Disable
 
-You can remove certain rows or columns from the table.
+You can remove certain rows or columns from the table by `Disable`.
 
 ```rust
-use tabled::{Table, settings::Disable};
+use tabled::settings::{
+    object::{Columns, Rows},
+    Disable,
+};
 
-let mut table = Table::new(data);
 table
-    .with(Disable::Row(..1))
-    .with(Disable::Column(3..4));
+    .with(Disable::row(Rows::first()))
+    .with(Disable::column(Columns::single(2)));
 ```
 
-### Extract
+If the above example be applied for a first example in a file it would look like this.
 
-You can `Extract` segments of a table to focus on a reduced number of rows and columns.
+```text
++------+----------------+
+| C    | Dennis Ritchie |
++------+----------------+
+| Go   | Rob Pike       |
++------+----------------+
+| Rust | Graydon Hoare  |
++------+----------------+
+```
+
+### Extract
+
+You can `Extract` data segments of a table to focus on it closely.
 
 ```rust
-use tabled::{Table, settings::Extract};
+use tabled::settings::Extract;
 
-let mut table = Table::new(&data);
 table.with(Extract::segment(1..3, 1..));
 ```
 
@@ -1027,70 +1175,46 @@ table.with(Extract::segment(1..3, 1..));
 +-------+-------------+-----------+
 ```
 
-#### Refinishing
-
-For styles with unique corner and edge textures it is possible to reapply a table style once a `Table` extract has been created.
-
-```rust
-use tabled::{Table, settings::{Extract, Style}};
-
-let mut table = Table::new(&data);
-table
-    .with(Extract::segment(1..3, 1..))
-    .with(Style::modern());
-```
-
-```text
-Raw extract
-┼───────────────────────────┼──────────────────┼──────────────┤
-│ The Dark Side of the Moon │ 01 March 1973    │ Unparalleled │
-┼───────────────────────────┼──────────────────┼──────────────┤
-│ Rumours                   │ 04 February 1977 │ Outstanding  │
-┼───────────────────────────┼──────────────────┼──────────────┤
-
-Refinished extract
-┌───────────────────────────┬──────────────────┬───────────────┐
-│ The Dark Side of the Moon │ 01 March 1973    │ Unparalleled  │
-├───────────────────────────┼──────────────────┼───────────────┤
-│ Rumours                   │ 04 February 1977 │  Outstanding  │
-└───────────────────────────┴──────────────────┴───────────────┘
-```
-
 ### Header and Footer and Panel
 
 You can add a `Header` and `Footer` to display some information.
 
 ```rust
-use tabled::{Table, settings::Panel};
+use tabled::settings::Panel;
+
+let count_elements = table.count_rows();
 
-let mut table = Table::new(&data);
 table
+    .with(Panel::vertical(0, "A vertical panel").width(1))
     .with(Panel::header("Tabled Name"))
-    .with(Panel::footer(format!("{} elements", data.len())))
+    .with(Panel::footer(format!("{} elements", count_elements)));
 ```
 
-The look will depend on the style you choose
-but it may look something like this:
+When applied to the main example of this file it will result in the following output.
 
 ```text
-┌────────────────────────────────────────────────────────────┐
-│                       Tabled Name                          │
-├────────────────────────────────────────────────────────────┤
-                            ...
-├───────┼──────────────┼─────────┼───────────────────────────┤
-│                        3 elements                          │
-└────────────────────────────────────────────────────────────┘
-```
-
-You can also add a full row/column using `tabled::Panel`.
-
-```rust
-use tabled::{Table, settings::Panel};
-
-let mut table = Table::new(&data);
-table
-    .with(Panel::vertical(2).text("A panel on 2nd row"))
-    .with(Panel::horizontal(0).text("A panel on 1st column"));
++---+------+----------------+---------------+
+| Tabled Name                               |
++---+------+----------------+---------------+
+| A | name | designed_by    | invented_year |
+|   |      |                |               |
+| v |      |                |               |
+| e |      |                |               |
++ r +------+----------------+---------------+
+| t | C    | Dennis Ritchie | 1972          |
+| i |      |                |               |
+| c |      |                |               |
++ a +------+----------------+---------------+
+| l | Go   | Rob Pike       | 2009          |
+|   |      |                |               |
+| p |      |                |               |
++ a +------+----------------+---------------+
+| n | Rust | Graydon Hoare  | 2010          |
+| e |      |                |               |
+| l |      |                |               |
++---+------+----------------+---------------+
+| 4 elements                                |
++---+------+----------------+---------------+
 ```
 
 ### Merge
@@ -1125,17 +1249,56 @@ println!("{}", table);
 You can concatanate 2 tables using `Concat`.
 It will stick 2 tables together either vertically or horizontally.
 
+The example below show the result of horizontal concat of primarily table of this file.
+
+```rust
+use tabled::settings::Concat;
+
+table.with(Concat::horizontal(table.clone()));
+```
+
+The result.
+
+```text
++------+----------------+---------------+------+----------------+---------------+
+| name | designed_by    | invented_year | name | designed_by    | invented_year |
++------+----------------+---------------+------+----------------+---------------+
+| C    | Dennis Ritchie | 1972          | C    | Dennis Ritchie | 1972          |
++------+----------------+---------------+------+----------------+---------------+
+| Go   | Rob Pike       | 2009          | Go   | Rob Pike       | 2009          |
++------+----------------+---------------+------+----------------+---------------+
+| Rust | Graydon Hoare  | 2010          | Rust | Graydon Hoare  | 2010          |
++------+----------------+---------------+------+----------------+---------------+
+```
+
+The example below show the result of vertical concat of primarily table of this file.
+
 ```rust
 use tabled::settings::Concat;
 
-// let t1: Table = ...;
-// let t2: Table = ...;
+table.with(Concat::vertical(table.clone()));
+```
 
-// vertical concat
-t1.with(Concat::vertical(t2));
+The result.
 
-// horizontal concat
-t1.with(Concat::horizontal(t2));
+```text
++------+----------------+---------------+
+| name | designed_by    | invented_year |
++------+----------------+---------------+
+| C    | Dennis Ritchie | 1972          |
++------+----------------+---------------+
+| Go   | Rob Pike       | 2009          |
++------+----------------+---------------+
+| Rust | Graydon Hoare  | 2010          |
++------+----------------+---------------+
+| name | designed_by    | invented_year |
++------+----------------+---------------+
+| C    | Dennis Ritchie | 1972          |
++------+----------------+---------------+
+| Go   | Rob Pike       | 2009          |
++------+----------------+---------------+
+| Rust | Graydon Hoare  | 2010          |
++------+----------------+---------------+
 ```
 
 ### Highlight
@@ -1156,7 +1319,7 @@ let data = vec![["A", "B", "C"], ["D", "E", "F"]];
 
 let mut table = Table::new(data);
 table.with(Style::modern());
-table.with(Highlight::new(
+table.with(Highlight::border(
     Rows::first().and(Columns::single(2).and((1, 1))),
     Border::filled('*'),
 ));
@@ -1184,7 +1347,7 @@ It's possible to set a horizontal(column) span and vertical(row) span to a cell.
 
 ```rust
 use tabled::{
-    settings::{Alignment, Modify, Span},
+    settings::{Alignment, Span},
     Table,
 };
 
@@ -1192,8 +1355,8 @@ let data = vec![["A", "B", "C"], ["D", "E", "F"]];
 
 let mut table = Table::new(data);
 table
-    .with(Modify::new((0, 0)).with(Span::column(3)))
-    .with(Modify::new((1, 0)).with(Span::column(2)))
+    .modify((0, 0), Span::column(3))
+    .modify((1, 0), Span::column(2))
     .with(Alignment::center());
 
 println!("{}", table);
@@ -1213,7 +1376,7 @@ println!("{}", table);
 
 ```rust
 use tabled::{
-    settings::{Alignment, Modify, Span},
+    settings::{Alignment, Span},
     Table,
 };
 
@@ -1221,7 +1384,7 @@ let data = vec![["A", "B", "C"], ["D", "E", "F"]];
 
 let mut table = Table::new(data);
 table
-    .with(Modify::new((0, 1)).with(Span::row(3)))
+    .modify((0, 1), Span::row(3))
     .with(Alignment::center())
     .with(Alignment::center_vertical());
 
@@ -1243,123 +1406,35 @@ println!("{}", table);
 You can `Split` a table on a row or column to redistribute the cells beyond that point 
 into a new shape with the provided point acting as the new, upper boundry in the direction selected.
 
-#### Directions
-
-Direction functions are the entry point for the `Split` setting.
-
-There are two directions available: `column` and `row`.
+Adding this to a first example will result in the next table.
 
 ```rust
-use std::iter::FromIterator;
-use tabled::{Table, settings::split::Split};
-
-let mut table = Table::from_iter(['a'..='z']);
-table.with(Split::column(12));
-table.with(Split::row(2));
-```
-
-```text
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
-│ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
-│ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │
-├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
-│ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │
-├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
-│ y │ z │   │   │   │   │   │   │   │   │   │   │<- y and z act as anchors to new empty cells
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘   to conform to the new shape
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
-│ a │ y │ b │ z │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │
-├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤<- Display::Clean removes empty cells that would be anchors otherwise
-│ m │   │ n │   │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
-      ^anchors^
-```
-
-
-#### Behaviors
-
-Behaviors determine how cells attempt to conform to the new tables shape.
-
-There are two behaviors available: `zip` and `concat`. 
-
-`zip` is the default behavior.
-
-```rust
-use tabled::{Table, settings::split::Split};
-
-let mut table = Table::new(&data);
+use tabled::settings::{Style, split::Split};
 
+table.with(Style::modern());
 table.with(Split::column(2).concat());
-table.with(Split::column(2).zip());
 ```
 
-```text
-                                                +---+---+
-                                                | a | b |
-                                                +---+---+
-+---+---+---+---+---+                           | f | g |
-| a | b | c | d | e | Split::column(2).concat() +---+---+
-+---+---+---+---+---+           =>              | c | d |
-| f | g | h | i | j |                           +---+---+
-+---+---+---+---+---+                           | h | i |
-                                                +---+---+
-                                                | e |   |
-                                                +---+---+
-                                                | j |   |
-                                                +---+---+
-
-                  sect 3                        +---+---+
- sect 1   sect 2 (anchors)                      | a | b |
-  /   \   /   \   /   \                         +---+---+
-+---+---+---+---+---+                           | c | d |
-| a | b | c | d | e |  Split::column(2).zip()   +---+---+
-+---+---+---+---+---+           =>              | e |   |
-| f | g | h | i | j |                           +---+---+
-+---+---+---+---+---+                           | f | g |
-                                                +---+---+
-                                                | h | i |
-                                                +---+---+
-                                                | j |   |
-                                                +---+---+
-```
-
-#### Displays
-
-Display functions give the user the choice to `retain` or `clean` empty sections in a `Split` table result.
-
-- `retain` does not filter any existing or newly added cells when conforming to a new shape.
-
-- `clean` filters out empty columns/rows from the output and prevents empty cells from acting as anchors to newly inserted cells.
-
-`clean` is the default `Display`.
-
-```rust
-use std::iter::FromIterator;
-use tabled::{
-    settings::{split::Split, style::Style},
-    Table,
-};
-let mut table = Table::from_iter(['a'..='z']);
-
-table.with(Split::column(25)).with(Style::modern());
-table.clone().with(Split::column(1).concat().retain());
-table.clone().with(Split::column(1).concat()); // .clean() is not necessary as it is the default display property 
-```
+The result of the running example will be as follows.
 
 ```text
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
-│ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │
-├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
-│ z │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │<- lots of extra cells generated
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
-│ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
-┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ ^ cells retained during concatenation
-│ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │
-└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘<- cells removed during concatenation
+┌───────────────┬────────────────┐
+│ name          │ designed_by    │
+├───────────────┼────────────────┤
+│ C             │ Dennis Ritchie │
+├───────────────┼────────────────┤
+│ Go            │ Rob Pike       │
+├───────────────┼────────────────┤
+│ Rust          │ Graydon Hoare  │
+├───────────────┼────────────────┤
+│ invented_year │                │
+├───────────────┼────────────────┤
+│ 1972          │                │
+├───────────────┼────────────────┤
+│ 2009          │                │
+├───────────────┼────────────────┤
+│ 2010          │                │
+└───────────────┴────────────────┘
 ```
 
 #### Duplicate
@@ -1371,8 +1446,8 @@ use tabled::{Table, settings::{Dup, object::Rows}};
 
 let mut table = Table::new(data);
 
-// copy last line to the first line (first line gets erased).
-table.with(Dup::new(Rows::first(), Rows::last()));
+// copy lastfirst line to the last line (last line gets erased).
+table.with(Dup::new(Rows::last(), Rows::first()));
 ```
 
 ## Derive
@@ -1392,7 +1467,7 @@ struct SomeType {
 struct SomeOtherType;
 ```
 
-The `Tabled` macros available when `derive` feature in turned on.
+The `Tabled` macro available when `derive` feature in turned on.
 And it is by default.
 
 ### Override a column name
@@ -1565,223 +1640,6 @@ struct Bike {
 }
 ```
 
-## Features
-
-### Color
-
-The library doesn't bind you in usage of any color library but to be able to work correctly with color input, and avoid [miscalculation of string width](https://github.com/zhiburt/tabled/issues/26)
-because of embedded ansi sequences, you should add the `color` feature of `tabled` to your `Cargo.toml`:
-
-```toml
-tabled = { version = "*", features = ["ansi"] } 
-```
-
-Then you can use colored strings as values and table dimension will be properly estimated.
-
-```rust
-use owo_colors::OwoColorize;
-// ...
-let mut builder = tabled::builder::Builder::default();
-builder.push_record(vec!["green".green(), "red".red()])
-let mut table = builder.build();
-```
-
-Another example:
-
-```rust
-use tabled::{format::Format, object::Columns, Modify, Style, Table};
-
-let mut table = Table::new(&data);
-table
-    .with(Style::psql())
-    .with(Modify::new(Columns::single(0)).with(Format::new(|s| s.red().to_string())))
-    .with(Modify::new(Columns::single(1)).with(Format::new(|s| s.blue().to_string())))
-    .with(Modify::new(Columns::new(2..)).with(Format::new(|s| s.green().to_string())));
-```
-
-![carbon-2](https://user-images.githubusercontent.com/20165848/120526301-b95efc80-c3e1-11eb-8779-0ec48894463b.png)
-
-### Tuple combination
-
-You also can combine objects which implements `Tabled` by means of tuples, you will get a combined columns of them.
-
-```rust
-use tabled::{
-    settings::{Alignment, Style},
-    Table, Tabled,
-};
-
-#[derive(Tabled)]
-struct Developer(#[tabled(rename = "name")] &'static str);
-
-#[derive(Tabled)]
-enum Domain {
-    Security,
-    Embedded,
-    Frontend,
-    Unknown,
-}
-
-let data = vec![
-    (Developer("Terri Kshlerin"), Domain::Embedded),
-    (Developer("Catalina Dicki"), Domain::Security),
-    (Developer("Jennie Schmeler"), Domain::Frontend),
-    (Developer("Maxim Zhiburt"), Domain::Unknown),
-];
-
-let table = Table::new(data)
-    .with(Style::psql())
-    .with(Alignment::center())
-    .to_string();
-
-assert_eq!(
-    table,
-    concat!(
-        "      name       | Security | Embedded | Frontend | Unknown \n",
-        "-----------------+----------+---------+----------+---------\n",
-        " Terri Kshlerin  |          |    +    |          |         \n",
-        " Catalina Dicki  |    +     |         |          |         \n",
-        " Jennie Schmeler |          |         |    +     |         \n",
-        "  Maxim Zhiburt  |          |         |          |    +    ",
-    )
-);
-```
-
-### Object
-
-You can apply settings to a subgroup of cells using `and` and `not` methods for an object.
-
-```rust
-use tabled::settings::object::{Object, Segment, Cell, Rows, Columns};
-Segment::all().not(Rows::first()); // select all cells except header.
-Columns::first().and(Columns::last()); // select cells from first and last columns.
-Rows::first().and(Columns::single(0)).not(Cell(0, 0)); // select the header and first column except the (0, 0) cell.
-```
-
-Also you can target a column via its name using `ByColumnName`.
-
-```rust
-use tabled::{locator::ByColumnName, Alignment, Modify};
-
-table.with(Modify::new(ByColumnName::new("name")).with(Alignment::center()));
-```
-
-### Macros
-
-Utilities for dynamic `Table` displays.
-
-#### Col and Row
-
-Combine `col!` and `row!` to create flexible table visualizations.
-
-```rust
-row![table1, table2];
-```
-
-```text
-+-------------------------------------------+---------------------------------------------+
-| .---------------------------------------. | ┌────────────────────┬─────┬──────────────┐ |
-| | name             | age | is_validated | | │ name               │ age │ is_validated │ |
-| | Jon Doe          | 255 | false        | | ├────────────────────┼─────┼──────────────┤ |
-| | Mark Nelson      | 13  | true         | | │ Jack Black         │ 51  │ false        │ |
-| | Terminal Monitor | 0   | false        | | ├────────────────────┼─────┼──────────────┤ |
-| | Adam Blend       | 17  | true         | | │ Michelle Goldstein │ 44  │ true         │ |
-| '---------------------------------------' | └────────────────────┴─────┴──────────────┘ |
-+-------------------------------------------+---------------------------------------------+
-```
-
-```rust
-col![table1, table2];
-```
-
-```text
-+---------------------------------------------+
-| .---------------------------------------.   |
-| | name             | age | is_validated |   |
-| | Jon Doe          | 255 | false        |   |
-| | Mark Nelson      | 13  | true         |   |
-| | Terminal Monitor | 0   | false        |   |
-| | Adam Blend       | 17  | true         |   |
-| '---------------------------------------'   |
-+---------------------------------------------+
-| ┌────────────────────┬─────┬──────────────┐ |
-| │ name               │ age │ is_validated │ |
-| ├────────────────────┼─────┼──────────────┤ |
-| │ Jack Black         │ 51  │ false        │ |
-| ├────────────────────┼─────┼──────────────┤ |
-| │ Michelle Goldstein │ 44  │ true         │ |
-| └────────────────────┴─────┴──────────────┘ |
-+---------------------------------------------+
-```
-
-```rust
-row![table1; 3];
-```
-
-```text
-+-------------------------------------------+-------------------------------------------+-------------------------------------------+
-| .---------------------------------------. | .---------------------------------------. | .---------------------------------------. |
-| | name             | age | is_validated | | | name             | age | is_validated | | | name             | age | is_validated | |
-| | Jon Doe          | 255 | false        | | | Jon Doe          | 255 | false        | | | Jon Doe          | 255 | false        | |
-| | Mark Nelson      | 13  | true         | | | Mark Nelson      | 13  | true         | | | Mark Nelson      | 13  | true         | |
-| | Terminal Monitor | 0   | false        | | | Terminal Monitor | 0   | false        | | | Terminal Monitor | 0   | false        | |
-| | Adam Blend       | 17  | true         | | | Adam Blend       | 17  | true         | | | Adam Blend       | 17  | true         | |
-| '---------------------------------------' | '---------------------------------------' | '---------------------------------------' |
-+-------------------------------------------+-------------------------------------------+-------------------------------------------+
-```
-
-```rust
-col![
-    row![table_a, table_b], 
-    table_c
-]
-```
-
-```text
-+----------------------------------------------------------------------------------+
-| +--------------------------------+---------------------------------------------+ |
-| | +-------+-----+--------------+ | ┌────────────────────┬─────┬──────────────┐ | |
-| | | name  | age | is_validated | | │ name               │ age │ is_validated │ | |
-| | +-------+-----+--------------+ | ├────────────────────┼─────┼──────────────┤ | |
-| | | Sam   | 31  | true         | | │ Jack Black         │ 51  │ false        │ | |
-| | +-------+-----+--------------+ | ├────────────────────┼─────┼──────────────┤ | |
-| | | Sarah | 26  | true         | | │ Michelle Goldstein │ 44  │ true         │ | |
-| | +-------+-----+--------------+ | └────────────────────┴─────┴──────────────┘ | |
-| +--------------------------------+---------------------------------------------+ |
-+----------------------------------------------------------------------------------+
-| .---------------------------------------.                                        |
-| | name             | age | is_validated |                                        |
-| | Jon Doe          | 255 | false        |                                        |
-| | Mark Nelson      | 13  | true         |                                        |
-| | Terminal Monitor | 0   | false        |                                        |
-| | Adam Blend       | 17  | true         |                                        |
-| '---------------------------------------'                                        |
-+----------------------------------------------------------------------------------+
-```
-
-#### `static_table`
-
-It's possible to construct a table at compile time, via [`static_table`](/static_table/README.md).
-You'd need to include a different crate to use it.
-
-Notice that you can even use it in documentation.
-
-```rust
-/// Multiply 2 integers together.
-/// 
-/// ```
-#[doc = static_table::static_table!([
-    ["a", "b", "result"],
-    ["1", '2', '3'],
-    ["2", '2', '4']
-])]
-/// ```
-pub fn mul(left: usize, right: usize) -> usize {
-    left + right
-}
-```
-
-
 ## Table types
 
 `tabled` has a few representations of tables some differs from it's view some from it's implememtation details.
@@ -1914,9 +1772,290 @@ is_active | true
 is_cool   | true
 ```
 
+## Tips & Tricks
+
+### `std::fmt::*` options
+
+You use formatting(`std::fmt::*`) options.
+To apply certain settings.
+
+```rust
+use tabled::Table;
+
+let numbers = [1, 2, 3];
+let table = Table::new(numbers);
+
+println!("{:#^10}", table);
+```
+
+The result will be as follows.
+
+```text
+#+-----+##
+#| i32 |##
+#+-----+##
+#|  1  |##
+#+-----+##
+#|  2  |##
+#+-----+##
+#|  3  |##
+#+-----+##
+```
+
+### ANSI
+
+The library doesn't bind you in usage of any color library but to be able to work correctly with colored input (with ANSI sequences), and avoid [miscalculation of string width](https://github.com/zhiburt/tabled/issues/26)
+because of embedded ansi sequences, you should add the `ansi` feature to your `Cargo.toml`:
+
+```toml
+tabled = { version = "*", features = ["ansi"] } 
+```
+
+Then you can use colored strings as values and table will be properly rendered.
+
+Tunning our favorite example will result in the following:
+
+```rust
+use tabled::{format::Format, object::Columns, Style, Table};
+use owo_colors::OwoColorize;
+
+let mut table = Table::new(&data);
+table
+    .with(Style::psql())
+    .modify(Columns::single(0), Format::new(|s| s.red().to_string()))
+    .modify(Columns::single(1), Format::new(|s| s.blue().to_string()))
+    .modify(Columns::new(2..), Format::new(|s| s.green().to_string()));
+```
+
+![carbon-2](https://user-images.githubusercontent.com/20165848/120526301-b95efc80-c3e1-11eb-8779-0ec48894463b.png)
+
+### Tuple combination
+
+You also can combine objects which implements `Tabled` by means of tuples, you will get a combined columns of them.
+
+```rust
+use tabled::{
+    settings::{Alignment, Style},
+    Table, Tabled,
+};
+
+#[derive(Tabled)]
+struct Developer(#[tabled(rename = "name")] &'static str);
+
+#[derive(Tabled)]
+enum Domain {
+    Security,
+    Embedded,
+    Frontend,
+    Unknown,
+}
+
+let data = vec![
+    (Developer("Terri Kshlerin"), Domain::Embedded),
+    (Developer("Catalina Dicki"), Domain::Security),
+    (Developer("Jennie Schmeler"), Domain::Frontend),
+    (Developer("Maxim Zhiburt"), Domain::Unknown),
+];
+
+let table = Table::new(data)
+    .with(Style::psql())
+    .with(Alignment::center())
+    .to_string();
+
+assert_eq!(
+    table,
+    concat!(
+        "      name       | Security | Embedded | Frontend | Unknown \n",
+        "-----------------+----------+---------+----------+---------\n",
+        " Terri Kshlerin  |          |    +    |          |         \n",
+        " Catalina Dicki  |    +     |         |          |         \n",
+        " Jennie Schmeler |          |         |    +     |         \n",
+        "  Maxim Zhiburt  |          |         |          |    +    ",
+    )
+);
+```
+
+### Object
+
+You can apply settings to a subgroup of cells using `and` and `not` methods for an object.
+
+```rust
+use tabled::settings::object::{Object, Segment, Cell, Rows, Columns};
+Segment::all().not(Rows::first()); // select all cells except header.
+Columns::first().and(Columns::last()); // select cells from first and last columns.
+Rows::first().and(Columns::single(0)).not(Cell(0, 0)); // select the header and first column except the (0, 0) cell.
+```
+
+Also you can target a column via its name using `ByColumnName`.
+
+```rust
+use tabled::{locator::ByColumnName, Alignment, Modify};
+
+table.with(Modify::new(ByColumnName::new("name")).with(Alignment::center()));
+```
+
+### Builder
+
+`Builder` is a powerfull tool you shall be aware of.
+
+For example you can use `Builder::index` to make a particular column an index,
+which will stay on the left.
+
+```rust
+use tabled::{builder::Builder, settings::Style};
+
+let mut builder = Builder::default();
+builder.push_record(["Index", "Language", "Status"]);
+builder.push_record(["1", "English", "In progress"]);
+builder.push_record(["2", "Deutsch", "Not ready"]);
+
+let builder = builder.index().column(1).name(None);
+
+let mut table = builder.build();
+table.with(Style::rounded());
+
+println!("{}", table);
+```
+
+```text
+╭─────────┬───────┬─────────────╮
+│         │ Index │ Status      │
+├─────────┼───────┼─────────────┤
+│ English │ 1     │ In progress │
+│ Deutsch │ 2     │ Not ready   │
+╰─────────┴───────┴─────────────╯
+```
+
+For example you can use `transpose()` method to change the layout.
+
+```rust
+// A dynamic table example
+// ...
+
+let mut builder = builder.index().transpose();
+```
+
+```text
+.-------------------------------------------------.
+|   | 0      | 1      | 2      | 3        | 4     |
+| 0 | And    | Little | When   | I        | You   |
+| 1 | the    | boy    | you    | don't    | know  |
+| 2 | cat's  | blue   | comin' | know     | we'll |
+| 3 | in     | and    | home   | when,    | have  |
+| 4 | the    | the    | dad?   | but      | a     |
+| 5 | cradle | man    |        | we'll    | good  |
+| 6 | and    | on     |        | get      | time  |
+| 7 | the    | the    |        | together | then  |
+| 8 | silver | moon   |        | then     |       |
+| 9 | spoon  |        |        | son      |       |
+'-------------------------------------------------'
+```
+
+### Macros
+
+Utilities for dynamic `Table` displays.
+
+#### Col and Row
+
+`col!` creates a single column table, with a given set of cells.
+`row!` creates a single row table, with a given set of cells.
+
+Combine `col!` and `row!` to create flexible table visualizations.
+
+```rust
+use tabled::{col, row, settings::Style};
+
+let mut table = row![
+    col!["table 0", "0", "1", "2"],
+    col!["table 1", "world"],
+    col!["table 2"],
+];
+table.with(Style::modern_rounded());
+
+println!("{table}");
+```
+
+The output you're goint to see running it.
+
+```text
+╭─────────────┬─────────────┬─────────────╮
+│ +---------+ │ +---------+ │ +---------+ │
+│ | table 0 | │ | table 1 | │ | table 2 | │
+│ +---------+ │ +---------+ │ +---------+ │
+│ | 0       | │ | world   | │             │
+│ +---------+ │ +---------+ │             │
+│ | 1       | │             │             │
+│ +---------+ │             │             │
+│ | 2       | │             │             │
+│ +---------+ │             │             │
+╰─────────────┴─────────────┴─────────────╯
+```
+
+#### `static_table`
+
+It's possible to construct a table at compile time, via [`static_table`](/static_table/README.md).
+You'd need to include a different crate to use it.
+
+```toml
+static_table = "*"
+```
+
+```rust
+let table = static_table::static_table!(
+    [
+        ["x", "y", "op", "result"],
+        ["1", '2', '*', '2'],
+        ["2", '2', '*', '4']
+    ],
+    THEME = "ROUNDED",
+);
+
+assert_eq!(
+    table,
+    "╭───┬───┬────┬────────╮\n\
+     │ x │ y │ op │ result │\n\
+     ├───┼───┼────┼────────┤\n\
+     │ 1 │ 2 │ *  │ 2      │\n\
+     │ 2 │ 2 │ *  │ 4      │\n\
+     ╰───┴───┴────┴────────╯",
+);
+```
+
+Notice that you can even use it in documentation.
+
+```rust
+/// Multiply 2 integers together.
+/// 
+#[doc = static_table::static_table!([
+    ["x", "y", "result"],
+    ["1", '0', '0'],
+    ["1", '2', '2'],
+    ["2", '2', '4']
+])]
+pub fn mul(left: usize, right: usize) -> usize {
+    left + right
+}
+```
+
+It will be looking as foolows.
+
+<picture>
+  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/zhiburt/tabled/assets/20165848/704c285b-f8ab-481b-a5bf-130406aad7d5">
+  <img alt="Preview" src="https://github.com/zhiburt/tabled/assets/20165848/164a82db-8ce7-4366-b21d-c679bea8d9fe">
+</picture>
+
+## Features
+
+The library has a list of features.
+
+- `std`     - Used by default. If not its considered `no_std` with a limited set of functionality. 
+- `derive`  - Used by default. A support for `Tabled` derive macro.
+- `ansi`    - A support for ANSI sequences.
+- `macros`  - A support for `row!`, `col!` macro.
+
 ## Formats
 
-You can convert some formats to a `Table`.
+You can convert some formats to a `Table` using an utility library.
 
 ### `json` format
 
@@ -1994,7 +2133,7 @@ let languages = vec![
 The resultant table will look like the following.
 As you can see Github tricks a bit a return table, but `GNOME terminal` and `Alacritty` terminal handles it correctly.
 
- ```rust
+```text
 +---------+----------------+---------------+
 | name    | designed_by    | invented_year |
 +---------+----------------+---------------+
diff --git a/papergrid/src/ansi/mod.rs b/papergrid/src/ansi/mod.rs
index 01e7843..cee7c38 100644
--- a/papergrid/src/ansi/mod.rs
+++ b/papergrid/src/ansi/mod.rs
@@ -1,5 +1,5 @@
-//! A module which contains [`Color`] trait and its implementation [`AnsiColor`].
-
+//! A module which contains [`ANSIFmt`] trait and its implementation [`ANSIStr`]
+#[cfg_attr(feature = "std", doc = "and [`ANSIBuf`].")]
 #[cfg(feature = "std")]
 mod ansi_buf;
 mod ansi_str;
diff --git a/papergrid/src/config/entity.rs b/papergrid/src/config/entity.rs
index 0a2d3ba..bcdafcf 100644
--- a/papergrid/src/config/entity.rs
+++ b/papergrid/src/config/entity.rs
@@ -118,3 +118,117 @@ impl Iterator for EntityIterator {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_entity_iter() {
+        assert_eq!(
+            Entity::Global.iter(10, 10).collect::<Vec<_>>(),
+            vec![
+                (0, 0),
+                (0, 1),
+                (0, 2),
+                (0, 3),
+                (0, 4),
+                (0, 5),
+                (0, 6),
+                (0, 7),
+                (0, 8),
+                (0, 9),
+                (1, 0),
+                (1, 1),
+                (1, 2),
+                (1, 3),
+                (1, 4),
+                (1, 5),
+                (1, 6),
+                (1, 7),
+                (1, 8),
+                (1, 9),
+                (2, 0),
+                (2, 1),
+                (2, 2),
+                (2, 3),
+                (2, 4),
+                (2, 5),
+                (2, 6),
+                (2, 7),
+                (2, 8),
+                (2, 9),
+                (3, 0),
+                (3, 1),
+                (3, 2),
+                (3, 3),
+                (3, 4),
+                (3, 5),
+                (3, 6),
+                (3, 7),
+                (3, 8),
+                (3, 9),
+                (4, 0),
+                (4, 1),
+                (4, 2),
+                (4, 3),
+                (4, 4),
+                (4, 5),
+                (4, 6),
+                (4, 7),
+                (4, 8),
+                (4, 9),
+                (5, 0),
+                (5, 1),
+                (5, 2),
+                (5, 3),
+                (5, 4),
+                (5, 5),
+                (5, 6),
+                (5, 7),
+                (5, 8),
+                (5, 9),
+                (6, 0),
+                (6, 1),
+                (6, 2),
+                (6, 3),
+                (6, 4),
+                (6, 5),
+                (6, 6),
+                (6, 7),
+                (6, 8),
+                (6, 9),
+                (7, 0),
+                (7, 1),
+                (7, 2),
+                (7, 3),
+                (7, 4),
+                (7, 5),
+                (7, 6),
+                (7, 7),
+                (7, 8),
+                (7, 9),
+                (8, 0),
+                (8, 1),
+                (8, 2),
+                (8, 3),
+                (8, 4),
+                (8, 5),
+                (8, 6),
+                (8, 7),
+                (8, 8),
+                (8, 9),
+                (9, 0),
+                (9, 1),
+                (9, 2),
+                (9, 3),
+                (9, 4),
+                (9, 5),
+                (9, 6),
+                (9, 7),
+                (9, 8),
+                (9, 9)
+            ]
+        );
+    }
+}
diff --git a/tabled/src/grid/records/into_records/buf_records.rs b/tabled/src/grid/records/into_records/buf_records.rs
index d277fd5..158647f 100644
--- a/tabled/src/grid/records/into_records/buf_records.rs
+++ b/tabled/src/grid/records/into_records/buf_records.rs
@@ -1,14 +1,9 @@
-//! A module contains [`BufRows`] and [`BufColumns`] iterators.
-//!
-//! Almoust always they both can be used interchangeably but [`BufRows`] is supposed to be lighter cause it
-//! does not reads columns.
+//! A module contains [`BufRecords`] iterator.
 
 use crate::grid::records::IntoRecords;
 
 /// BufRecords inspects [`IntoRecords`] iterator and keeps read data buffered.
 /// So it can be checking before hand.
-///
-/// In contrast to [`BufRows`] it keeps records by columns.
 #[derive(Debug)]
 pub struct BufRecords<I, T> {
     iter: I,
@@ -16,7 +11,7 @@ pub struct BufRecords<I, T> {
 }
 
 impl BufRecords<(), ()> {
-    /// Creates new [`BufColumns`] structure, filling the buffer.
+    /// Creates new [`BufRecords`] structure, filling the buffer.
     pub fn new<I>(
         records: I,
         sniff: usize,
@@ -60,7 +55,7 @@ where
     }
 }
 
-/// A row iterator for [`BufColumns`]
+/// A row iterator for [`BufRecords`]
 #[derive(Debug)]
 pub struct BufRecordsIter<I, T> {
     iter: I,
diff --git a/tabled/src/lib.rs b/tabled/src/lib.rs
index 68cfb71..0bb0f06 100644
--- a/tabled/src/lib.rs
+++ b/tabled/src/lib.rs
@@ -4,7 +4,7 @@
 //! You can use [`Tabled`] trait if the data type is known.
 //! Or you can use [`Builder`] to construct the table from scratch.
 //!
-//! ## Usage
+//! ## Derive
 //!
 //! If you want to build a table for your custom type.
 //! A starting point is to a anotate your type with `#[derive(Tabled)]`.
@@ -55,9 +55,12 @@
 //! assert_eq!(table, expected);
 //! ```
 //!
-//! Not all types can derive [`Tabled`] trait though.
+//! BEWARE not all types can derive [`Tabled`] trait.
 //! The example below can't be compiled.
 //!
+//! Because `tabled` must know what we're up to print as a field, so
+//! each field must implement [`std::fmt::Display`].
+//!
 //! ```rust,compile_fail
 //!   # use tabled::Tabled;
 //!     #[derive(Tabled)]
@@ -68,8 +71,7 @@
 //!     struct SomeOtherType;
 //! ```
 //!
-//! Because `tabled` must know what we're up to print as a field, so
-//! each (almost) field must implement [`std::fmt::Display`].
+//! You can tweak it by derive options.
 //!
 //! ### Default implementations
 //!
@@ -92,7 +94,7 @@
 //! # assert_eq!(table.to_string(), expected);
 //! ```
 //!
-//! ### Dynamic table
+//! ### Builder
 //!
 //! When you data scheme is not known at compile time.
 //! You most likely will not able to relay on [`Tabled`] trait.
@@ -171,14 +173,21 @@
 //!
 //! You can use many settings which is found in [`tabled::settings`] module.
 //!
+//! # Features
+//!
+//! - `std`     - Used by default. If not its considered `no_std` with a limited set of functionality.
+//! - `derive`  - Used by default. A support for `Tabled` derive macro.
+//! - `ansi`    - A support for ANSI sequences.
+//! - `macros`  - A support for `row!`, `col!` macro.
+//!
 //! # Advanced
 //!
-//! ## Alloc
+//! ## Table types
 //!
 //! [`Table`] keeps data buffered, which sometimes not ideal choise.
 //! For such reason there is [`IterTable`] and [`CompactTable`].
 //!
-//! ### Less allocations
+//! ### [`IterTable`]
 //!
 //! [`IterTable`] stands on a middle ground between [`Table`] and [`CompactTable`].
 //!
@@ -205,9 +214,9 @@
 //! );
 //! ```
 //!
-//! ## Alloc free (`#nostd`)
+//! ### [`CompactTable`]
 //!
-//! [`CompactTable`] can be configured ('1) to not make any allocations.
+//! Alloc free can be configured ('1) to not make any allocations.
 //! But the price is that the set of settings which can be applied to it is limited.  
 //!
 //! It also can be printed directly to [`fmt::Write`] to not have any intermidiaries.
@@ -237,6 +246,10 @@
 //! table.fmt(StubWriter);
 //! ```
 //!
+//! ## `no_std`
+//!
+//! [`CompactTable`] can be used in `no_std` context.
+//!
 //! ## More information
 //!
 //! You can find more examples of settings and attributes in
@@ -275,6 +288,8 @@
 )]
 #![allow(clippy::uninlined_format_args)]
 
+mod util;
+
 #[cfg(feature = "std")]
 mod tabled;
 
@@ -294,12 +309,12 @@ pub mod grid;
 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 pub use crate::{tabled::Tabled, tables::Table};
 
-/// A derive to implement a [`Tabled`] trait.
+/// A derive macro to implement a [`Tabled`] trait.
 ///
-/// The macros available only when `derive` feature in turned on (and it is by default).
+/// The macro available only when `derive` feature in turned on (and it is by default).
 ///
 /// To be able to use the derive each field must implement `std::fmt::Display`.
-/// The following example will cause a error because of that.
+/// The following example will cause an error because of that.
 ///
 /// ```rust,compile_fail
 /// use tabled::Tabled;
@@ -323,9 +338,9 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// #[derive(Tabled)]
 /// struct Person {
 ///     #[tabled(rename = "Name")]
-///     first_name: &'static str,
+///     first_name: String,
 ///     #[tabled(rename = "Surname")]
-///     last_name: &'static str,
+///     last_name: String,
 /// }
 /// ```
 ///
@@ -342,8 +357,8 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// struct Person {
 ///    id: u8,
 ///    #[tabled(skip)]
-///    number: &'static str,
-///    name: &'static str,
+///    number: String,
+///    name: String,
 /// }
 /// ```
 ///
@@ -358,9 +373,9 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// struct Person {
 ///    id: u8,
 ///    #[tabled(order = 0)]
-///    number: &'static str,
+///    number: String,
 ///    #[tabled(order = 1)]
-///    name: &'static str,
+///    name: String,
 /// }
 /// ```
 ///
@@ -427,10 +442,10 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// #[tabled(rename_all = "CamelCase")]
 /// struct Person {
 ///     id: u8,
-///     number: &'static str,
-///     name: &'static str,
+///     number: String,
+///     name: String,
 ///     #[tabled(rename_all = "snake_case")]
-///     middle_name: &'static str,
+///     middle_name: String,
 /// }
 /// ```
 ///
@@ -445,14 +460,14 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// #[derive(Tabled)]
 /// struct Person {
 ///     id: u8,
-///     name: &'static str,
+///     name: String,
 ///     #[tabled(inline)]
 ///     ed: Education,
 /// }
 ///
 /// #[derive(Tabled)]
 /// struct Education {
-///     uni: &'static str,
+///     uni: String,
 ///     graduated: bool,
 /// }
 /// ```
@@ -466,12 +481,12 @@ pub use crate::{tabled::Tabled, tables::Table};
 /// enum Vehicle {
 ///     #[tabled(inline("Auto::"))]
 ///     Auto {
-///         model: &'static str,
-///         engine: &'static str,
+///         model: String,
+///         engine: String,
 ///     },
 ///     #[tabled(inline)]
 ///     Bikecycle(
-///         &'static str,
+///         String,
 ///         #[tabled(inline)] Bike,
 ///     ),
 /// }
diff --git a/tabled/src/settings/color/mod.rs b/tabled/src/settings/color/mod.rs
index c793b31..5e7b8db 100644
--- a/tabled/src/settings/color/mod.rs
+++ b/tabled/src/settings/color/mod.rs
@@ -197,6 +197,11 @@ impl Color {
         Self { inner }
     }
 
+    /// Creates a new empty [`Color`]`.
+    pub fn empty() -> Self {
+        Self::new_static("", "")
+    }
+
     const fn new_static(prefix: &'static str, suffix: &'static str) -> Self {
         let color = StaticColor::new(prefix, suffix);
         let inner = ColorInner::Static(color);
diff --git a/tabled/src/settings/concat/mod.rs b/tabled/src/settings/concat/mod.rs
index 9f6fe1e..18284ba 100644
--- a/tabled/src/settings/concat/mod.rs
+++ b/tabled/src/settings/concat/mod.rs
@@ -27,6 +27,9 @@ use crate::{
 /// [`Concat`] in horizontal mode has similar behaviour to tuples `(a, b)`.
 /// But it behaves on tables rather than on an actual data.
 ///
+/// [`Concat`] DOES NOT handle style merge and other configuration of 2nd table,
+/// it just uses 1st one as a bases.
+///
 /// # Example
 ///
 ///
diff --git a/tabled/src/settings/height/mod.rs b/tabled/src/settings/height/mod.rs
index ad9caff..0c84d65 100644
--- a/tabled/src/settings/height/mod.rs
+++ b/tabled/src/settings/height/mod.rs
@@ -119,8 +119,8 @@ impl Height {
     ///      +---------------------+------+------------+",
     /// )
     /// ```
-    pub fn increase<W: Measurement<Height>>(width: W) -> CellHeightIncrease<W> {
-        CellHeightIncrease::new(width)
+    pub fn increase<W: Measurement<Height>>(height: W) -> CellHeightIncrease<W> {
+        CellHeightIncrease::new(height)
     }
 
     /// Create [`CellHeightLimit`] to set a table/cell height.
@@ -189,8 +189,8 @@ impl Height {
     ///      +--+--+--+",
     /// );
     /// ```
-    pub fn limit<W: Measurement<Height>>(width: W) -> CellHeightLimit<W> {
-        CellHeightLimit::new(width)
+    pub fn limit<W: Measurement<Height>>(height: W) -> CellHeightLimit<W> {
+        CellHeightLimit::new(height)
     }
 
     /// Create [`HeightList`] to set a table height to a constant list of row heights.
diff --git a/tabled/src/settings/panel/vertical_panel.rs b/tabled/src/settings/panel/vertical_panel.rs
index dee2405..b24459d 100644
--- a/tabled/src/settings/panel/vertical_panel.rs
+++ b/tabled/src/settings/panel/vertical_panel.rs
@@ -19,6 +19,23 @@ impl<S> VerticalPanel<S> {
     {
         Self { text, col }
     }
+
+    /// Split the set text to a certain width, so it fits within it.
+    pub fn width(self, width: usize) -> VerticalPanel<String>
+    where
+        S: AsRef<str>,
+    {
+        let mut text = String::new();
+
+        if width > 0 {
+            text = split_string_by_width(self.text.as_ref(), width);
+        }
+
+        VerticalPanel {
+            text,
+            col: self.col,
+        }
+    }
 }
 
 impl<S, R, D> TableOption<R, ColoredConfig, D> for VerticalPanel<S>
@@ -81,3 +98,55 @@ fn move_column_spans(cfg: &mut SpannedConfig, target_column: usize) {
         cfg.set_row_span((row, col + 1), span);
     }
 }
+
+fn split_string_by_width(str: &str, width: usize) -> String {
+    if width == 0 {
+        return String::new();
+    }
+
+    let (lhs, rhs) = crate::util::string::split_str(str, width);
+    if rhs.is_empty() {
+        return lhs.into_owned();
+    }
+
+    let mut buf = lhs.into_owned();
+    let mut next = rhs.into_owned();
+    while !next.is_empty() {
+        let (lhs, rhs) = crate::util::string::split_str(&next, width);
+        buf.push('\n');
+        buf.push_str(&lhs);
+        next = rhs.into_owned();
+    }
+
+    buf
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_split_string_by_width() {
+        assert_eq!(split_string_by_width("123456789", 3), "123\n456\n789");
+        assert_eq!(split_string_by_width("123456789", 2), "12\n34\n56\n78\n9");
+        assert_eq!(
+            split_string_by_width("123456789", 1),
+            "1\n2\n3\n4\n5\n6\n7\n8\n9"
+        );
+        assert_eq!(split_string_by_width("123456789", 0), "");
+
+        assert_eq!(
+            split_string_by_width("\u{1b}[31;100m😳😳🏳️\u{1b}[39m\u{1b}[49m😳🏳️", 3),
+            {
+                #[cfg(feature = "ansi")]
+                {
+                    "\u{1b}[31m\u{1b}[100m😳\u{1b}[39m\u{1b}[49m�\n\u{1b}[31m\u{1b}[100m🏳\u{fe0f}\u{1b}[39m\u{1b}[49m😳\n🏳\u{fe0f}"
+                }
+                #[cfg(not(feature = "ansi"))]
+                {
+                    "\u{1b}[31\n;10\n0m�\n😳🏳\n\u{fe0f}\u{1b}[39\nm\u{1b}[4\n9m�\n🏳\u{fe0f}"
+                }
+            }
+        );
+    }
+}
diff --git a/tabled/src/settings/split/mod.rs b/tabled/src/settings/split/mod.rs
index becb3c1..097cc96 100644
--- a/tabled/src/settings/split/mod.rs
+++ b/tabled/src/settings/split/mod.rs
@@ -39,9 +39,128 @@ enum Display {
 /// - behavior
 /// - display
 ///
+/// #### Directions
+///
+/// Direction functions are the entry point for the `Split` setting.
+///
+/// There are two directions available: `column` and `row`.
+///
+/// ```rust
+/// use std::iter::FromIterator;
+/// use tabled::{Table, settings::split::Split};
+///
+/// let mut table = Table::from_iter(['a'..='z']);
+/// table.with(Split::column(12));
+/// table.with(Split::row(2));
+/// ```
+///
+/// ```text
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
+/// │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
+/// │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │
+/// ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
+/// │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │
+/// ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
+/// │ y │ z │   │   │   │   │   │   │   │   │   │   │<- y and z act as anchors to new empty cells
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘   to conform to the new shape
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
+/// │ a │ y │ b │ z │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │
+/// ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤<- Display::Clean removes empty cells that would be anchors otherwise
+/// │ m │   │ n │   │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
+///       ^anchors^
+/// ```
+///
+///
+/// #### Behaviors
+///
+/// Behaviors determine how cells attempt to conform to the new tables shape.
+///
+/// There are two behaviors available: `zip` and `concat`.
+///
+/// `zip` is the default behavior.
+///
+/// ```rust
+/// use std::iter::FromIterator;
+/// use tabled::{Table, settings::split::Split};
+///
+/// let mut table = Table::from_iter(['a'..='z']);
+/// table.with(Split::column(2).concat());
+/// table.with(Split::column(2).zip());
+/// ```
+///
+/// ```text
+///                                                 +---+---+
+///                                                 | a | b |
+///                                                 +---+---+
+/// +---+---+---+---+---+                           | f | g |
+/// | a | b | c | d | e | Split::column(2).concat() +---+---+
+/// +---+---+---+---+---+           =>              | c | d |
+/// | f | g | h | i | j |                           +---+---+
+/// +---+---+---+---+---+                           | h | i |
+///                                                 +---+---+
+///                                                 | e |   |
+///                                                 +---+---+
+///                                                 | j |   |
+///                                                 +---+---+
+///
+///                   sect 3                        +---+---+
+///  sect 1   sect 2 (anchors)                      | a | b |
+///   /   \   /   \   /   \                         +---+---+
+/// +---+---+---+---+---+                           | c | d |
+/// | a | b | c | d | e |  Split::column(2).zip()   +---+---+
+/// +---+---+---+---+---+           =>              | e |   |
+/// | f | g | h | i | j |                           +---+---+
+/// +---+---+---+---+---+                           | f | g |
+///                                                 +---+---+
+///                                                 | h | i |
+///                                                 +---+---+
+///                                                 | j |   |
+///                                                 +---+---+
+/// ```
+///
+/// #### Displays
+///
+/// Display functions give the user the choice to `retain` or `clean` empty sections in a `Split` table result.
+///
+/// - `retain` does not filter any existing or newly added cells when conforming to a new shape.
+///
+/// - `clean` filters out empty columns/rows from the output and prevents empty cells from acting as anchors to newly inserted cells.
+///
+/// `clean` is the default `Display`.
+///
+/// ```rust
+/// use std::iter::FromIterator;
+/// use tabled::{
+///     settings::{split::Split, style::Style},
+///     Table,
+/// };
+/// let mut table = Table::from_iter(['a'..='z']);
+/// table.with(Split::column(25)).with(Style::modern());
+/// table.clone().with(Split::column(1).concat().retain());
+/// table.clone().with(Split::column(1).concat()); // .clean() is not necessary as it is the default display property
+/// ```
+///
+/// ```text
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
+/// │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │
+/// ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
+/// │ z │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │<- lots of extra cells generated
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
+/// │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+/// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ ^ cells retained during concatenation
+/// │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │ k │ l │ m │ n │ o │ p │ q │ r │ s │ t │ u │ v │ w │ x │ y │ z │
+/// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘<- cells removed during concatenation
+/// ```
+///
+///
 /// # Example
 ///
-/// ```rust,no_run
+/// ```rust
 /// use std::iter::FromIterator;
 /// use tabled::{
 ///     settings::split::Split,
diff --git a/tabled/src/settings/style/border_color.rs b/tabled/src/settings/style/border_color.rs
index 89ce216..bf3b3d4 100644
--- a/tabled/src/settings/style/border_color.rs
+++ b/tabled/src/settings/style/border_color.rs
@@ -89,7 +89,7 @@ impl BorderColor<On, On, On, On> {
     }
 
     /// This function constructs a cell borders with all sides's char set to a given color.
-    /// It behaves like [`Border::full`] with the same color set to each side.
+    /// It behaves like [`BorderColor::full`] with the same color set to each side.
     pub fn filled(c: Color) -> Self {
         Self::full(
             c.clone(),
diff --git a/tabled/src/settings/style/builder.rs b/tabled/src/settings/style/builder.rs
index eaa60c8..38b4331 100644
--- a/tabled/src/settings/style/builder.rs
+++ b/tabled/src/settings/style/builder.rs
@@ -51,7 +51,7 @@ use crate::grid::config::ColoredConfig;
 /// It tries to limit an controlling a valid state of it.
 /// For example, it won't allow to call method [`Style::corner_top_left`] unless [`Style::left`] and [`Style::top`] is set.
 ///
-/// You can turn [`Style`] into [`RawStyle`] to have more control using [`Into`] implementation.
+/// You can turn [`Style`] into [`Theme`] to have a precise control using [`Into`] implementation.
 ///
 /// # Example
 ///
@@ -69,7 +69,7 @@ use crate::grid::config::ColoredConfig;
 /// ```
 ///
 /// [`Table`]: crate::Table
-/// [`RawStyle`]: crate::settings::Style::RawStyle
+/// [`Theme`]: crate::settings::themes::Theme
 /// [`Style::corner_top_left`]: Style::corner_top_left
 /// [`Style::left`]: Style.left
 /// [`Style::top`]: Style.function.top
@@ -1424,6 +1424,20 @@ impl<T, B, L, R, H, const HN: usize, const VN: usize> Style<T, B, L, R, H, On, H
     }
 }
 
+impl<H, V, const HN: usize, const VN: usize> Style<On, On, On, On, H, V, HN, VN> {
+    /// Removes frame.
+    pub const fn remove_frame(self) -> Style<(), (), (), (), H, V, HN, VN>
+    where
+        V: Copy,
+        H: Copy,
+    {
+        self.remove_bottom()
+            .remove_top()
+            .remove_left()
+            .remove_right()
+    }
+}
+
 #[cfg(feature = "std")]
 impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
     TableOption<Data, ColoredConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
diff --git a/tabled/src/settings/style/horizontal_line.rs b/tabled/src/settings/style/horizontal_line.rs
index cebf9d3..f3b2a85 100644
--- a/tabled/src/settings/style/horizontal_line.rs
+++ b/tabled/src/settings/style/horizontal_line.rs
@@ -29,7 +29,7 @@ impl<L, R, I> HorizontalLine<L, R, I> {
 
     /// Fetches vertical line from a style.
     pub const fn inherit<T, B, const HSIZE: usize, const VSIZE: usize>(
-        style: Style<T, B, L, R, I, On, HSIZE, VSIZE>,
+        style: Style<T, B, L, R, On, I, HSIZE, VSIZE>,
     ) -> Self {
         let borders = style.get_borders();
         let line = Line::new(
diff --git a/tabled/src/settings/style/mod.rs b/tabled/src/settings/style/mod.rs
index f8fec99..233c577 100644
--- a/tabled/src/settings/style/mod.rs
+++ b/tabled/src/settings/style/mod.rs
@@ -85,16 +85,16 @@
 //! )
 //! ```
 //!
-//! ## [`RawStyle`]
+//! ## [`Theme`]
 //!
-//! A different representation of [`Style`].
+//! A different representation of [`Theme`].
 //! With no checks in place.
 //!
 //! It also contains a list of types to support colors.
 //!
 //! [`Table`]: crate::Table
 //! [`BorderText`]: crate::settings::style::BorderText
-//! [`RawStyle`]: crate::settings::style::RawStyle
+//! [`Theme`]: crate::settings::themes::Theme
 
 mod border;
 mod builder;
diff --git a/tabled/src/settings/themes/colorization.rs b/tabled/src/settings/themes/colorization.rs
index c0461a9..be7a754 100644
--- a/tabled/src/settings/themes/colorization.rs
+++ b/tabled/src/settings/themes/colorization.rs
@@ -9,7 +9,7 @@ use crate::{
 
 /// [`Colorization`] sets a color for the whole table data (so it's not include the borders).
 ///
-/// You can colorize borders in a different round using [`BorderColor`] or [`RawStyle`]
+/// You can colorize borders in a different round using [`BorderColor`] or [`Theme`]
 ///
 /// # Examples
 ///
@@ -34,7 +34,7 @@ use crate::{
 /// println!("{table}");
 /// ```
 ///
-/// [`RawStyle`]: crate::settings::style::RawStyle
+/// [`Theme`]: crate::settings::themes::Theme
 /// [`BorderColor`]: crate::settings::style::BorderColor
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Colorization {
diff --git a/tabled/src/settings/themes/theme.rs b/tabled/src/settings/themes/theme.rs
index ef60195..1457f62 100644
--- a/tabled/src/settings/themes/theme.rs
+++ b/tabled/src/settings/themes/theme.rs
@@ -96,9 +96,15 @@ impl Theme {
     }
 }
 
+impl Default for Theme {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 macro_rules! func_set_chars {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Set a border character", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Set a border character", " ", "", $desc, "", " ", ".")]
         pub fn $name(&mut self, c: char) {
             self.border.chars.$arg = Some(c);
         }
@@ -107,7 +113,7 @@ macro_rules! func_set_chars {
 
 macro_rules! func_remove_chars {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Remove a border character", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Remove a border character", " ", "", $desc, "", " ", ".")]
         pub fn $name(&mut self) {
             self.border.chars.$arg = None;
         }
@@ -116,7 +122,7 @@ macro_rules! func_remove_chars {
 
 macro_rules! func_get_chars {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Get a border character", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Get a border character", " ", "", $desc, "", " ", ".")]
         pub const fn $name(&self) -> Option<char> {
             self.border.chars.$arg
         }
@@ -125,7 +131,7 @@ macro_rules! func_get_chars {
 
 macro_rules! func_set_colors {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Set a border color", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Set a border color", " ", "", $desc, "", " ", ".")]
         pub fn $name(&mut self, color: Color) {
             self.border.colors.$arg = Some(color);
         }
@@ -134,7 +140,7 @@ macro_rules! func_set_colors {
 
 macro_rules! func_remove_colors {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Remove a border color", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Remove a border color", " ", "", $desc, "", " ", ".")]
         pub fn $name(&mut self) {
             self.border.colors.$arg = None;
         }
@@ -143,7 +149,7 @@ macro_rules! func_remove_colors {
 
 macro_rules! func_get_colors {
     ($name:ident, $arg:ident, $desc:expr) => {
-        #[doc = concat!("Set a border color", " ", "<", $desc, ">", " ", ".")]
+        #[doc = concat!("Get a border color", " ", "", $desc, "", " ", ".")]
         pub fn $name(&self) -> Option<&Color> {
             self.border.colors.$arg.as_ref()
         }
diff --git a/tabled/src/settings/width/truncate.rs b/tabled/src/settings/width/truncate.rs
index 83a05ba..516ebba 100644
--- a/tabled/src/settings/width/truncate.rs
+++ b/tabled/src/settings/width/truncate.rs
@@ -18,7 +18,8 @@ use crate::{
     },
 };
 
-use super::util::{cut_str, get_table_widths, get_table_widths_with_total};
+use super::util::{get_table_widths, get_table_widths_with_total};
+use crate::util::string::cut_str;
 
 /// Truncate cut the string to a given width if its length exceeds it.
 /// Otherwise keeps the content of a cell untouched.
diff --git a/tabled/src/settings/width/util.rs b/tabled/src/settings/width/util.rs
index 4cdf049..18394df 100644
--- a/tabled/src/settings/width/util.rs
+++ b/tabled/src/settings/width/util.rs
@@ -1,5 +1,3 @@
-use std::borrow::Cow;
-
 use crate::{
     grid::config::SpannedConfig,
     grid::dimension::SpannedGridDimension,
@@ -31,284 +29,3 @@ fn get_table_total_width(list: &[usize], cfg: &SpannedConfig) -> usize {
         + margin.left.size
         + margin.right.size
 }
-
-/// The function cuts the string to a specific width.
-///
-/// BE AWARE: width is expected to be in bytes.
-pub(crate) fn cut_str(s: &str, width: usize) -> Cow<'_, str> {
-    #[cfg(feature = "ansi")]
-    {
-        const REPLACEMENT: char = '\u{FFFD}';
-
-        let stripped = ansi_str::AnsiStr::ansi_strip(s);
-        let (length, count_unknowns, _) = split_at_pos(&stripped, width);
-
-        let mut buf = ansi_str::AnsiStr::ansi_cut(s, ..length);
-        if count_unknowns > 0 {
-            let mut b = buf.into_owned();
-            b.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
-            buf = Cow::Owned(b);
-        }
-
-        buf
-    }
-
-    #[cfg(not(feature = "ansi"))]
-    {
-        cut_str_basic(s, width)
-    }
-}
-
-/// The function cuts the string to a specific width.
-///
-/// BE AWARE: width is expected to be in bytes.
-#[cfg(not(feature = "ansi"))]
-pub(crate) fn cut_str_basic(s: &str, width: usize) -> Cow<'_, str> {
-    const REPLACEMENT: char = '\u{FFFD}';
-
-    let (length, count_unknowns, _) = split_at_pos(s, width);
-    let buf = &s[..length];
-    if count_unknowns == 0 {
-        return Cow::Borrowed(buf);
-    }
-
-    let mut buf = buf.to_owned();
-    buf.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
-
-    Cow::Owned(buf)
-}
-
-/// The function splits a string in the position and
-/// returns a exact number of bytes before the position and in case of a split in an unicode grapheme
-/// a width of a character which was tried to be splited in.
-///
-/// BE AWARE: pos is expected to be in bytes.
-pub(crate) fn split_at_pos(s: &str, pos: usize) -> (usize, usize, usize) {
-    let mut length = 0;
-    let mut i = 0;
-    for c in s.chars() {
-        if i == pos {
-            break;
-        };
-
-        let c_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or_default();
-
-        // We cut the chars which takes more then 1 symbol to display,
-        // in order to archive the necessary width.
-        if i + c_width > pos {
-            let count = pos - i;
-            return (length, count, c.len_utf8());
-        }
-
-        i += c_width;
-        length += c.len_utf8();
-    }
-
-    (length, 0, 0)
-}
-
-/// Strip OSC codes from `s`. If `s` is a single OSC8 hyperlink, with no other text, then return
-/// (s_with_all_hyperlinks_removed, Some(url)). If `s` does not meet this description, then return
-/// (s_with_all_hyperlinks_removed, None). Any ANSI color sequences in `s` will be retained. See
-/// <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>
-///
-/// The function is based on Dan Davison <https://github.com/dandavison> delta <https://github.com/dandavison/delta> ansi library.
-#[cfg(feature = "ansi")]
-pub(crate) fn strip_osc(text: &str) -> (String, Option<String>) {
-    #[derive(Debug)]
-    enum ExtractOsc8HyperlinkState {
-        ExpectOsc8Url,
-        ExpectFirstText,
-        ExpectMoreTextOrTerminator,
-        SeenOneHyperlink,
-        WillNotReturnUrl,
-    }
-
-    use ExtractOsc8HyperlinkState::*;
-
-    let mut url = None;
-    let mut state = ExpectOsc8Url;
-    let mut buf = String::with_capacity(text.len());
-
-    for el in ansitok::parse_ansi(text) {
-        match el.kind() {
-            ansitok::ElementKind::Osc => match state {
-                ExpectOsc8Url => {
-                    url = Some(&text[el.start()..el.end()]);
-                    state = ExpectFirstText;
-                }
-                ExpectMoreTextOrTerminator => state = SeenOneHyperlink,
-                _ => state = WillNotReturnUrl,
-            },
-            ansitok::ElementKind::Sgr => buf.push_str(&text[el.start()..el.end()]),
-            ansitok::ElementKind::Csi => buf.push_str(&text[el.start()..el.end()]),
-            ansitok::ElementKind::Esc => {}
-            ansitok::ElementKind::Text => {
-                buf.push_str(&text[el.start()..el.end()]);
-                match state {
-                    ExpectFirstText => state = ExpectMoreTextOrTerminator,
-                    ExpectMoreTextOrTerminator => {}
-                    _ => state = WillNotReturnUrl,
-                }
-            }
-        }
-    }
-
-    match state {
-        WillNotReturnUrl => (buf, None),
-        _ => {
-            let url = url.and_then(|s| {
-                s.strip_prefix("\x1b]8;;")
-                    .and_then(|s| s.strip_suffix('\x1b'))
-            });
-            if let Some(url) = url {
-                (buf, Some(url.to_string()))
-            } else {
-                (buf, None)
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    use crate::grid::util::string::string_width;
-
-    #[cfg(feature = "ansi")]
-    use owo_colors::{colors::Yellow, OwoColorize};
-
-    #[test]
-    fn strip_test() {
-        assert_eq!(cut_str("123456", 0), "");
-        assert_eq!(cut_str("123456", 3), "123");
-        assert_eq!(cut_str("123456", 10), "123456");
-
-        assert_eq!(cut_str("a week ago", 4), "a we");
-
-        assert_eq!(cut_str("😳😳😳😳😳", 0), "");
-        assert_eq!(cut_str("😳😳😳😳😳", 3), "😳�");
-        assert_eq!(cut_str("😳😳😳😳😳", 4), "😳😳");
-        assert_eq!(cut_str("😳😳😳😳😳", 20), "😳😳😳😳😳");
-
-        assert_eq!(cut_str("🏳️🏳️", 0), "");
-        assert_eq!(cut_str("🏳️🏳️", 1), "🏳");
-        assert_eq!(cut_str("🏳️🏳️", 2), "🏳\u{fe0f}🏳");
-        assert_eq!(string_width("🏳️🏳️"), string_width("🏳\u{fe0f}🏳"));
-
-        assert_eq!(cut_str("🎓", 1), "�");
-        assert_eq!(cut_str("🎓", 2), "🎓");
-
-        assert_eq!(cut_str("🥿", 1), "�");
-        assert_eq!(cut_str("🥿", 2), "🥿");
-
-        assert_eq!(cut_str("🩰", 1), "�");
-        assert_eq!(cut_str("🩰", 2), "🩰");
-
-        assert_eq!(cut_str("👍🏿", 1), "�");
-        assert_eq!(cut_str("👍🏿", 2), "👍");
-        assert_eq!(cut_str("👍🏿", 3), "👍�");
-        assert_eq!(cut_str("👍🏿", 4), "👍🏿");
-
-        assert_eq!(cut_str("🇻🇬", 1), "🇻");
-        assert_eq!(cut_str("🇻🇬", 2), "🇻🇬");
-        assert_eq!(cut_str("🇻🇬", 3), "🇻🇬");
-        assert_eq!(cut_str("🇻🇬", 4), "🇻🇬");
-    }
-
-    #[cfg(feature = "ansi")]
-    #[test]
-    fn strip_color_test() {
-        let numbers = "123456".red().on_bright_black().to_string();
-
-        assert_eq!(cut_str(&numbers, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
-        assert_eq!(
-            cut_str(&numbers, 3),
-            "\u{1b}[31;100m123\u{1b}[39m\u{1b}[49m"
-        );
-        assert_eq!(cut_str(&numbers, 10), "\u{1b}[31;100m123456\u{1b}[0m");
-
-        let emojies = "😳😳😳😳😳".red().on_bright_black().to_string();
-
-        assert_eq!(cut_str(&emojies, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
-        assert_eq!(
-            cut_str(&emojies, 3),
-            "\u{1b}[31;100m😳\u{1b}[39m\u{1b}[49m�"
-        );
-        assert_eq!(
-            cut_str(&emojies, 4),
-            "\u{1b}[31;100m😳😳\u{1b}[39m\u{1b}[49m"
-        );
-        assert_eq!(cut_str(&emojies, 20), "\u{1b}[31;100m😳😳😳😳😳\u{1b}[0m");
-
-        let emojies = "🏳️🏳️".red().on_bright_black().to_string();
-
-        assert_eq!(cut_str(&emojies, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
-        assert_eq!(cut_str(&emojies, 1), "\u{1b}[31;100m🏳\u{1b}[39m\u{1b}[49m");
-        assert_eq!(
-            cut_str(&emojies, 2),
-            "\u{1b}[31;100m🏳\u{fe0f}🏳\u{1b}[39m\u{1b}[49m"
-        );
-        assert_eq!(
-            string_width(&emojies),
-            string_width("\u{1b}[31;100m🏳\u{fe0f}🏳\u{1b}[39m\u{1b}[49m")
-        );
-    }
-
-    #[test]
-    #[cfg(feature = "ansi")]
-    fn test_color_strip() {
-        let s = "Collored string"
-            .fg::<Yellow>()
-            .on_truecolor(12, 200, 100)
-            .blink()
-            .to_string();
-        assert_eq!(
-            cut_str(&s, 1),
-            "\u{1b}[5m\u{1b}[48;2;12;200;100m\u{1b}[33mC\u{1b}[25m\u{1b}[39m\u{1b}[49m"
-        )
-    }
-
-    #[test]
-    #[cfg(feature = "ansi")]
-    fn test_srip_osc() {
-        assert_eq!(
-            strip_osc("just a string here"),
-            (String::from("just a string here"), None)
-        );
-        assert_eq!(
-            strip_osc("/etc/rc.conf"),
-            (String::from("/etc/rc.conf"), None)
-        );
-        assert_eq!(
-            strip_osc(
-                "https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982"
-            ),
-            (String::from("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982"), None)
-        );
-
-        assert_eq!(
-            strip_osc(&build_link_prefix_suffix("just a string here")),
-            (String::default(), Some(String::from("just a string here")))
-        );
-        assert_eq!(
-            strip_osc(&build_link_prefix_suffix("/etc/rc.conf")),
-            (String::default(), Some(String::from("/etc/rc.conf")))
-        );
-        assert_eq!(
-            strip_osc(
-                &build_link_prefix_suffix("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982")
-            ),
-            (String::default(), Some(String::from("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982")))
-        );
-
-        #[cfg(feature = "ansi")]
-        fn build_link_prefix_suffix(url: &str) -> String {
-            // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
-            let osc8 = "\x1b]8;;";
-            let st = "\x1b\\";
-            format!("{osc8}{url}{st}")
-        }
-    }
-}
diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs
index 8146edd..eb21870 100644
--- a/tabled/src/settings/width/wrap.rs
+++ b/tabled/src/settings/width/wrap.rs
@@ -21,7 +21,8 @@ use crate::{
     },
 };
 
-use super::util::{get_table_widths, get_table_widths_with_total, split_at_pos};
+use super::util::{get_table_widths, get_table_widths_with_total};
+use crate::util::string::split_at_width;
 
 /// Wrap wraps a string to a new line in case it exceeds the provided max boundary.
 /// Otherwise keeps the content of a cell untouched.
@@ -209,7 +210,7 @@ pub(crate) fn wrap_text(text: &str, width: usize, keep_words: bool) -> String {
 
 #[cfg(feature = "ansi")]
 pub(crate) fn wrap_text(text: &str, width: usize, keep_words: bool) -> String {
-    use super::util::strip_osc;
+    use crate::util::string::strip_osc;
 
     if width == 0 {
         return String::new();
@@ -783,7 +784,8 @@ mod parsing {
 }
 
 fn split_string_at(text: &str, at: usize) -> (&str, &str, (usize, usize)) {
-    let (length, count_unknowns, split_char_size) = split_at_pos(text, at);
+    let (length, width, split_char_size) = split_at_width(text, at);
+    let count_unknowns = if split_char_size > 0 { at - width } else { 0 };
     let (lhs, rhs) = text.split_at(length);
 
     (lhs, rhs, (count_unknowns, split_char_size))
diff --git a/tabled/src/tables/extended.rs b/tabled/src/tables/extended.rs
index 478505c..60af682 100644
--- a/tabled/src/tables/extended.rs
+++ b/tabled/src/tables/extended.rs
@@ -48,7 +48,6 @@
 //! assert_eq!(table, expected);
 //! ```
 
-use std::borrow::Cow;
 use std::fmt::{self, Display};
 
 use crate::grid::util::string::string_width;
@@ -289,7 +288,7 @@ fn truncate(text: &mut String, max: usize, suffix: &str) {
     if max == 0 || text.is_empty() {
         *text = String::new();
     } else {
-        *text = cut_str_basic(text, max).into_owned();
+        *text = crate::util::string::cut_str2(text, max).into_owned();
     }
 
     let cut_was_done = text.len() < original_len;
@@ -297,42 +296,3 @@ fn truncate(text: &mut String, max: usize, suffix: &str) {
         text.push_str(suffix);
     }
 }
-
-fn cut_str_basic(s: &str, width: usize) -> Cow<'_, str> {
-    const REPLACEMENT: char = '\u{FFFD}';
-
-    let (length, count_unknowns, _) = split_at_pos(s, width);
-    let buf = &s[..length];
-    if count_unknowns == 0 {
-        return Cow::Borrowed(buf);
-    }
-
-    let mut buf = buf.to_owned();
-    buf.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
-
-    Cow::Owned(buf)
-}
-
-fn split_at_pos(s: &str, pos: usize) -> (usize, usize, usize) {
-    let mut length = 0;
-    let mut i = 0;
-    for c in s.chars() {
-        if i == pos {
-            break;
-        };
-
-        let c_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
-
-        // We cut the chars which takes more then 1 symbol to display,
-        // in order to archive the necessary width.
-        if i + c_width > pos {
-            let count = pos - i;
-            return (length, count, c.len_utf8());
-        }
-
-        i += c_width;
-        length += c.len_utf8();
-    }
-
-    (length, 0, 0)
-}
diff --git a/tabled/src/util/mod.rs b/tabled/src/util/mod.rs
new file mode 100644
index 0000000..47ed4f3
--- /dev/null
+++ b/tabled/src/util/mod.rs
@@ -0,0 +1,2 @@
+#[cfg(feature = "std")]
+pub(crate) mod string;
diff --git a/tabled/src/util/string.rs b/tabled/src/util/string.rs
new file mode 100644
index 0000000..63e0ad8
--- /dev/null
+++ b/tabled/src/util/string.rs
@@ -0,0 +1,320 @@
+use std::borrow::Cow;
+
+/// The function cuts the string to a specific width.
+/// Preserving colors with `ansi` feature on.
+pub(crate) fn split_str(s: &str, width: usize) -> (Cow<'_, str>, Cow<'_, str>) {
+    #[cfg(feature = "ansi")]
+    {
+        const REPLACEMENT: char = '\u{FFFD}';
+
+        let stripped = ansi_str::AnsiStr::ansi_strip(s);
+        let (length, cutwidth, csize) = split_at_width(&stripped, width);
+        let (mut lhs, mut rhs) = ansi_str::AnsiStr::ansi_split_at(s, length);
+
+        if csize > 0 {
+            let mut buf = lhs.into_owned();
+            let count_unknowns = width - cutwidth;
+            buf.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
+            lhs = Cow::Owned(buf);
+            rhs = Cow::Owned(ansi_str::AnsiStr::ansi_cut(rhs.as_ref(), csize..).into_owned());
+        }
+
+        (lhs, rhs)
+    }
+
+    #[cfg(not(feature = "ansi"))]
+    {
+        const REPLACEMENT: char = '\u{FFFD}';
+
+        let (length, cutwidth, csize) = split_at_width(s, width);
+        let (lhs, rhs) = s.split_at(length);
+
+        if csize == 0 {
+            return (Cow::Borrowed(lhs), Cow::Borrowed(rhs));
+        }
+
+        let count_unknowns = width - cutwidth;
+        let mut buf = lhs.to_owned();
+        buf.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
+
+        (Cow::Owned(buf), Cow::Borrowed(&rhs[csize..]))
+    }
+}
+
+/// The function cuts the string to a specific width.
+/// Preserving colors with `ansi` feature on.
+pub(crate) fn cut_str(s: &str, width: usize) -> Cow<'_, str> {
+    #[cfg(feature = "ansi")]
+    {
+        const REPLACEMENT: char = '\u{FFFD}';
+
+        let stripped = ansi_str::AnsiStr::ansi_strip(s);
+        let (length, cutwidth, csize) = split_at_width(&stripped, width);
+        let mut buf = ansi_str::AnsiStr::ansi_cut(s, ..length);
+        if csize != 0 {
+            let mut b = buf.into_owned();
+            let count_unknowns = width - cutwidth;
+            b.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
+            buf = Cow::Owned(b);
+        }
+
+        buf
+    }
+
+    #[cfg(not(feature = "ansi"))]
+    {
+        cut_str2(s, width)
+    }
+}
+
+/// The function cuts the string to a specific width.
+/// While not preserving ansi sequences.
+pub(crate) fn cut_str2(text: &str, width: usize) -> Cow<'_, str> {
+    const REPLACEMENT: char = '\u{FFFD}';
+
+    let (length, cutwidth, csize) = split_at_width(text, width);
+    if csize == 0 {
+        let buf = &text[..length];
+        return Cow::Borrowed(buf);
+    }
+
+    let buf = &text[..length];
+    let mut buf = buf.to_owned();
+    let count_unknowns = width - cutwidth;
+    buf.extend(std::iter::repeat(REPLACEMENT).take(count_unknowns));
+
+    Cow::Owned(buf)
+}
+
+/// The function splits a string in the position and
+/// returns a exact number of bytes before the position and in case of a split in an unicode grapheme
+/// a width of a character which was tried to be splited in.
+pub(crate) fn split_at_width(s: &str, at_width: usize) -> (usize, usize, usize) {
+    let mut length = 0;
+    let mut width = 0;
+    for c in s.chars() {
+        if width == at_width {
+            break;
+        };
+
+        let c_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or_default();
+        let c_length = c.len_utf8();
+
+        // We cut the chars which takes more then 1 symbol to display,
+        // in order to archive the necessary width.
+        if width + c_width > at_width {
+            return (length, width, c_length);
+        }
+
+        width += c_width;
+        length += c_length;
+    }
+
+    (length, width, 0)
+}
+
+/// Strip OSC codes from `s`. If `s` is a single OSC8 hyperlink, with no other text, then return
+/// (s_with_all_hyperlinks_removed, Some(url)). If `s` does not meet this description, then return
+/// (s_with_all_hyperlinks_removed, None). Any ANSI color sequences in `s` will be retained. See
+/// <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>
+///
+/// The function is based on Dan Davison <https://github.com/dandavison> delta <https://github.com/dandavison/delta> ansi library.
+#[cfg(feature = "ansi")]
+pub(crate) fn strip_osc(text: &str) -> (String, Option<String>) {
+    #[derive(Debug)]
+    enum ExtractOsc8HyperlinkState {
+        ExpectOsc8Url,
+        ExpectFirstText,
+        ExpectMoreTextOrTerminator,
+        SeenOneHyperlink,
+        WillNotReturnUrl,
+    }
+
+    use ExtractOsc8HyperlinkState::*;
+
+    let mut url = None;
+    let mut state = ExpectOsc8Url;
+    let mut buf = String::with_capacity(text.len());
+
+    for el in ansitok::parse_ansi(text) {
+        match el.kind() {
+            ansitok::ElementKind::Osc => match state {
+                ExpectOsc8Url => {
+                    url = Some(&text[el.start()..el.end()]);
+                    state = ExpectFirstText;
+                }
+                ExpectMoreTextOrTerminator => state = SeenOneHyperlink,
+                _ => state = WillNotReturnUrl,
+            },
+            ansitok::ElementKind::Sgr => buf.push_str(&text[el.start()..el.end()]),
+            ansitok::ElementKind::Csi => buf.push_str(&text[el.start()..el.end()]),
+            ansitok::ElementKind::Esc => {}
+            ansitok::ElementKind::Text => {
+                buf.push_str(&text[el.start()..el.end()]);
+                match state {
+                    ExpectFirstText => state = ExpectMoreTextOrTerminator,
+                    ExpectMoreTextOrTerminator => {}
+                    _ => state = WillNotReturnUrl,
+                }
+            }
+        }
+    }
+
+    match state {
+        WillNotReturnUrl => (buf, None),
+        _ => {
+            let url = url.and_then(|s| {
+                s.strip_prefix("\x1b]8;;")
+                    .and_then(|s| s.strip_suffix('\x1b'))
+            });
+            if let Some(url) = url {
+                (buf, Some(url.to_string()))
+            } else {
+                (buf, None)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::grid::util::string::string_width;
+
+    #[cfg(feature = "ansi")]
+    use owo_colors::{colors::Yellow, OwoColorize};
+
+    #[test]
+    fn strip_test() {
+        assert_eq!(cut_str("123456", 0), "");
+        assert_eq!(cut_str("123456", 3), "123");
+        assert_eq!(cut_str("123456", 10), "123456");
+
+        assert_eq!(cut_str("a week ago", 4), "a we");
+
+        assert_eq!(cut_str("😳😳😳😳😳", 0), "");
+        assert_eq!(cut_str("😳😳😳😳😳", 3), "😳�");
+        assert_eq!(cut_str("😳😳😳😳😳", 4), "😳😳");
+        assert_eq!(cut_str("😳😳😳😳😳", 20), "😳😳😳😳😳");
+
+        assert_eq!(cut_str("🏳️🏳️", 0), "");
+        assert_eq!(cut_str("🏳️🏳️", 1), "🏳");
+        assert_eq!(cut_str("🏳️🏳️", 2), "🏳\u{fe0f}🏳");
+        assert_eq!(string_width("🏳️🏳️"), string_width("🏳\u{fe0f}🏳"));
+
+        assert_eq!(cut_str("🎓", 1), "�");
+        assert_eq!(cut_str("🎓", 2), "🎓");
+
+        assert_eq!(cut_str("🥿", 1), "�");
+        assert_eq!(cut_str("🥿", 2), "🥿");
+
+        assert_eq!(cut_str("🩰", 1), "�");
+        assert_eq!(cut_str("🩰", 2), "🩰");
+
+        assert_eq!(cut_str("👍🏿", 1), "�");
+        assert_eq!(cut_str("👍🏿", 2), "👍");
+        assert_eq!(cut_str("👍🏿", 3), "👍�");
+        assert_eq!(cut_str("👍🏿", 4), "👍🏿");
+
+        assert_eq!(cut_str("🇻🇬", 1), "🇻");
+        assert_eq!(cut_str("🇻🇬", 2), "🇻🇬");
+        assert_eq!(cut_str("🇻🇬", 3), "🇻🇬");
+        assert_eq!(cut_str("🇻🇬", 4), "🇻🇬");
+    }
+
+    #[cfg(feature = "ansi")]
+    #[test]
+    fn strip_color_test() {
+        let numbers = "123456".red().on_bright_black().to_string();
+
+        assert_eq!(cut_str(&numbers, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
+        assert_eq!(
+            cut_str(&numbers, 3),
+            "\u{1b}[31;100m123\u{1b}[39m\u{1b}[49m"
+        );
+        assert_eq!(cut_str(&numbers, 10), "\u{1b}[31;100m123456\u{1b}[0m");
+
+        let emojies = "😳😳😳😳😳".red().on_bright_black().to_string();
+
+        assert_eq!(cut_str(&emojies, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
+        assert_eq!(
+            cut_str(&emojies, 3),
+            "\u{1b}[31;100m😳\u{1b}[39m\u{1b}[49m�"
+        );
+        assert_eq!(
+            cut_str(&emojies, 4),
+            "\u{1b}[31;100m😳😳\u{1b}[39m\u{1b}[49m"
+        );
+        assert_eq!(cut_str(&emojies, 20), "\u{1b}[31;100m😳😳😳😳😳\u{1b}[0m");
+
+        let emojies = "🏳️🏳️".red().on_bright_black().to_string();
+
+        assert_eq!(cut_str(&emojies, 0), "\u{1b}[31;100m\u{1b}[39m\u{1b}[49m");
+        assert_eq!(cut_str(&emojies, 1), "\u{1b}[31;100m🏳\u{1b}[39m\u{1b}[49m");
+        assert_eq!(
+            cut_str(&emojies, 2),
+            "\u{1b}[31;100m🏳\u{fe0f}🏳\u{1b}[39m\u{1b}[49m"
+        );
+        assert_eq!(
+            string_width(&emojies),
+            string_width("\u{1b}[31;100m🏳\u{fe0f}🏳\u{1b}[39m\u{1b}[49m")
+        );
+    }
+
+    #[test]
+    #[cfg(feature = "ansi")]
+    fn test_color_strip() {
+        let s = "Collored string"
+            .fg::<Yellow>()
+            .on_truecolor(12, 200, 100)
+            .blink()
+            .to_string();
+        assert_eq!(
+            cut_str(&s, 1),
+            "\u{1b}[5m\u{1b}[48;2;12;200;100m\u{1b}[33mC\u{1b}[25m\u{1b}[39m\u{1b}[49m"
+        )
+    }
+
+    #[test]
+    #[cfg(feature = "ansi")]
+    fn test_srip_osc() {
+        assert_eq!(
+            strip_osc("just a string here"),
+            (String::from("just a string here"), None)
+        );
+        assert_eq!(
+            strip_osc("/etc/rc.conf"),
+            (String::from("/etc/rc.conf"), None)
+        );
+        assert_eq!(
+            strip_osc(
+                "https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982"
+            ),
+            (String::from("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982"), None)
+        );
+
+        assert_eq!(
+            strip_osc(&build_link_prefix_suffix("just a string here")),
+            (String::default(), Some(String::from("just a string here")))
+        );
+        assert_eq!(
+            strip_osc(&build_link_prefix_suffix("/etc/rc.conf")),
+            (String::default(), Some(String::from("/etc/rc.conf")))
+        );
+        assert_eq!(
+            strip_osc(
+                &build_link_prefix_suffix("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982")
+            ),
+            (String::default(), Some(String::from("https://gitlab.com/finestructure/swiftpackageindex-builder/-/pipelines/1054655982")))
+        );
+
+        #[cfg(feature = "ansi")]
+        fn build_link_prefix_suffix(url: &str) -> String {
+            // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
+            let osc8 = "\x1b]8;;";
+            let st = "\x1b\\";
+            format!("{osc8}{url}{st}")
+        }
+    }
+}


Test patch:
diff --git a/tabled/tests/settings/panel_test.rs b/tabled/tests/settings/panel_test.rs
index 67b5996..d5cc029 100644
--- a/tabled/tests/settings/panel_test.rs
+++ b/tabled/tests/settings/panel_test.rs
@@ -345,3 +345,27 @@ test_table!(
     "     | 1 |   1-0    |  1-1  |   1-2    |     "
     "     | 2 |   2-0    |  2-1  |   2-2    |     "
 );
+
+test_table!(
+    panel_vertical_split,
+    Matrix::new(3, 3).with(Style::psql()).with(Panel::vertical(0, "Linux Distributions").width(1)),
+    " L | N | column 0 | column 1 | column 2 "
+    " i |   |          |          |          "
+    " n |   |          |          |          "
+    " u |   |          |          |          "
+    " x |   |          |          |          "
+    "   |   |          |          |          "
+    " D +---+----------+----------+----------"
+    " i | 0 |   0-0    |   0-1    |   0-2    "
+    " s |   |          |          |          "
+    " t |   |          |          |          "
+    " r |   |          |          |          "
+    " i | 1 |   1-0    |   1-1    |   1-2    "
+    " b |   |          |          |          "
+    " u |   |          |          |          "
+    " t |   |          |          |          "
+    " i | 2 |   2-0    |   2-1    |   2-2    "
+    " o |   |          |          |          "
+    " n |   |          |          |          "
+    " s |   |          |          |          "
+);