Repository: zhiburt/tabled
Pull request #325 (2023-04-10 23:04:04)

static_table/ Add static_table::pool_table


Patch:
diff --git a/json_to_table/examples/collapse.rs b/json_to_table/examples/json_collapse.rs
similarity index 100%
rename from json_to_table/examples/collapse.rs
rename to json_to_table/examples/json_collapse.rs
diff --git a/papergrid/src/config/spanned/mod.rs b/papergrid/src/config/spanned/mod.rs
index b9d3438..ceb1a90 100644
--- a/papergrid/src/config/spanned/mod.rs
+++ b/papergrid/src/config/spanned/mod.rs
@@ -85,7 +85,7 @@ impl SpannedConfig {
         self.margin.bottom.offset = margin.bottom;
     }
 
-    /// Returns a [`Margin`] value currently set.
+    /// Returns a margin value currently set.
     pub fn get_margin(&self) -> Sides<Indent> {
         Sides::new(
             self.margin.left.indent,
@@ -95,7 +95,7 @@ impl SpannedConfig {
         )
     }
 
-    /// Returns a [`Margin`] value currently set.
+    /// Returns a margin color value currently set.
     pub fn get_margin_color(&self) -> Sides<Option<AnsiColor<'static>>> {
         Sides::new(
             self.margin.left.color.clone(),
@@ -105,7 +105,7 @@ impl SpannedConfig {
         )
     }
 
-    /// Returns a [`Margin`] value currently set.
+    /// Returns a margin offset value currently set.
     pub fn get_margin_offset(&self) -> Sides<Offset> {
         Sides::new(
             self.margin.left.offset,
diff --git a/papergrid/src/dimension/compact.rs b/papergrid/src/dimension/compact.rs
index bb8b88c..e53429a 100644
--- a/papergrid/src/dimension/compact.rs
+++ b/papergrid/src/dimension/compact.rs
@@ -1,4 +1,4 @@
-//! The module contains a [`ExactDimension`] for [`CompactGrid`] height/width estimation.
+//! The module contains a [`CompactGridDimension`] for [`CompactGrid`] height/width estimation.
 //!
 //! [`CompactGrid`]: crate::grid::compact::CompactGrid
 
diff --git a/papergrid/src/dimension/spanned.rs b/papergrid/src/dimension/spanned.rs
index f760068..6597ba1 100644
--- a/papergrid/src/dimension/spanned.rs
+++ b/papergrid/src/dimension/spanned.rs
@@ -1,4 +1,4 @@
-//! The module contains a [`ExactDimension`] for [`Grid`] height/width estimation.
+//! The module contains a [`SpannedGridDimension`] for [`Grid`] height/width estimation.
 //!
 //! [`Grid`]: crate::grid::iterable::Grid
 
diff --git a/papergrid/src/grid/peekable.rs b/papergrid/src/grid/peekable.rs
index bd1ebc1..2feac39 100644
--- a/papergrid/src/grid/peekable.rs
+++ b/papergrid/src/grid/peekable.rs
@@ -1,4 +1,4 @@
-//! The module contains a [`Grid`] structure.
+//! The module contains a [`PeekableGrid`] structure.
 
 use core::borrow::Borrow;
 use std::{
diff --git a/papergrid/src/records/exact_records.rs b/papergrid/src/records/exact_records.rs
index 6564502..9a564bc 100644
--- a/papergrid/src/records/exact_records.rs
+++ b/papergrid/src/records/exact_records.rs
@@ -1,4 +1,6 @@
-/// [Records] extension which guarantees the amount of rows.
+/// [`Records`] extension which guarantees the amount of rows.
+///
+/// [`Records`]: crate::records::Records
 pub trait ExactRecords {
     /// Returns an exact amount of rows in records.
     ///
diff --git a/papergrid/src/records/peekable_records.rs b/papergrid/src/records/peekable_records.rs
index 48efb81..528ba5f 100644
--- a/papergrid/src/records/peekable_records.rs
+++ b/papergrid/src/records/peekable_records.rs
@@ -1,8 +1,6 @@
 use crate::config::Position;
 
-/// The representation of data, rows and columns of a [`Grid`].
-///
-/// [`Grid`]: crate::Grid
+/// The representation of data, rows and columns of a grid.
 pub trait PeekableRecords {
     /// Returns a text of a cell by an index.
     fn get_text(&self, pos: Position) -> &str;
diff --git a/papergrid/src/records/vec_records/cell.rs b/papergrid/src/records/vec_records/cell.rs
index ea90f20..38a36b6 100644
--- a/papergrid/src/records/vec_records/cell.rs
+++ b/papergrid/src/records/vec_records/cell.rs
@@ -1,4 +1,6 @@
 /// Cell implementation which can be used with [`VecRecords`].
+///
+/// [`VecRecords`]: crate::records::vec_records::VecRecords
 pub trait Cell {
     /// Gets a text.
     fn text(&self) -> &str;
diff --git a/papergrid/src/util/string.rs b/papergrid/src/util/string.rs
index bfa5e02..7e0bccf 100644
--- a/papergrid/src/util/string.rs
+++ b/papergrid/src/util/string.rs
@@ -4,7 +4,7 @@
 //!
 //! [`Grid`]: crate::grid::iterable::Grid
 
-/// Returns string width and count lines of a string. It's a combination of [`string_width_multiline_tab`] and [`count_lines`].
+/// Returns string width and count lines of a string. It's a combination of [`string_width_multiline`] and [`count_lines`].
 #[cfg(feature = "std")]
 pub fn string_dimension(text: &str) -> (usize, usize) {
     #[cfg(not(feature = "color"))]
diff --git a/ron_to_table/examples/collapse.rs b/ron_to_table/examples/ron_collapse.rs
similarity index 100%
rename from ron_to_table/examples/collapse.rs
rename to ron_to_table/examples/ron_collapse.rs
diff --git a/ron_to_table/examples/plain.rs b/ron_to_table/examples/ron_plain.rs
similarity index 100%
rename from ron_to_table/examples/plain.rs
rename to ron_to_table/examples/ron_plain.rs
diff --git a/static_table/Cargo.toml b/static_table/Cargo.toml
index 1f19ca1..b1c5bce 100644
--- a/static_table/Cargo.toml
+++ b/static_table/Cargo.toml
@@ -10,6 +10,9 @@ license = "MIT"
 [lib]
 proc-macro = true
 
+[features]
+color = ["tabled/color"]
+
 [dependencies]
 tabled = { path = "../tabled", features = ["std"], default-features = false }
 syn = { version = "1", features = ["parsing"] }
diff --git a/static_table/README.md b/static_table/README.md
index 33988c2..0b43d2c 100644
--- a/static_table/README.md
+++ b/static_table/README.md
@@ -6,6 +6,16 @@ To find a few features and settings which you can use with the macros please che
 
 ### Get started
 
+
+<table>
+<tr>
+<th> Example </th>
+<th> Result </th>
+</tr>
+<tr>
+<td>
+
+
 ```rust
 use static_table::static_table;
 
@@ -21,7 +31,8 @@ fn main() {
 }
 ```
 
-Output
+</td>
+<td style="vertical-align: top;">
 
 ```text
 +------+----------------+---------------+
@@ -35,6 +46,52 @@ Output
 +------+----------------+---------------+
 ```
 
+</td>
+</tr>
+</table>
+
+<table>
+<tr>
+<th> Example </th>
+<th> Result </th>
+</tr>
+<tr>
+<td>
+
+```rust
+use static_table::pool_table;
+
+static LANG_LIST: &str = pool_table!([
+    ["name", "designed by", "first release"],
+    ["C", "Dennis Ritchie", "1972"],
+    ["Go", "Rob Pike", "2009"],
+    ["Rust", "Graydon Hoare", "2010"],
+]);
+
+fn main() {
+    println!("{LANG_LIST}")
+}
+```
+
+</td>
+<td style="vertical-align: top;">
+
+```text
++------+-------------+---------------+
+| name | designed by | first release |
++------+-------------+-----+---------+
+| C    | Dennis Ritchie    | 1972    |
++------+--+---------------++---------+
+| Go      | Rob Pike      | 2009     |
++---------+---------------+-+--------+
+| Rust    | Graydon Hoare   | 2010   |
++---------+-----------------+--------+
+```
+
+</td>
+</tr>
+</table>
+
 You can even use the macros in the documentation
 
 ```rust
diff --git a/static_table/examples/static_pool_table.rs b/static_table/examples/static_pool_table.rs
new file mode 100644
index 0000000..61f3d2f
--- /dev/null
+++ b/static_table/examples/static_pool_table.rs
@@ -0,0 +1,23 @@
+//! This example demonstrates using the powerful [`static_table!`] macro to translate
+//! a sequence of arrays and several, optional settings to a static [`str`] table representation.
+//!
+//! * Note that [`static_table!`] is evaluated at compile time, resulting in highly efficient runtime performance.
+//! * [`static_table!`] supports configuration of:
+//!     * granular column and row span specification
+//!     * [`THEME`](tabled::settings::Style)
+//!     * [`ALIGNMENT`](tabled::settings::Alignment)
+//!     * [`PADDING`](`tabled::settings::Padding`)
+//!     * [`MARGIN`](tabled::settings::Margin)
+
+use static_table::pool_table;
+
+static LANG_LIST: &str = pool_table!([
+    ["name", "designed by", "first release"],
+    ["C", "Dennis Ritchie", "1972"],
+    ["Go", "Rob Pike", "2009"],
+    ["Rust", "Graydon Hoare", "2010"],
+]);
+
+fn main() {
+    println!("{LANG_LIST}")
+}
diff --git a/static_table/src/lib.rs b/static_table/src/lib.rs
index fffc158..4db5553 100644
--- a/static_table/src/lib.rs
+++ b/static_table/src/lib.rs
@@ -1,7 +1,13 @@
-//! This library provides a macro to build a table at compile time.
+//! This library provides a macros to build a table at compile time.
+//!
+//! It contains 2 macros:
+//!
+//! - [`static_table`]
+//! - [`pool_table`]
 //!
 //! # Get started
 //!
+//! ## [`static_table`]
 //! ```
 //! use static_table::static_table;
 //!
@@ -26,6 +32,32 @@
 //! );
 //! ```
 //!
+//! ## [`pool_table`]
+//!
+//! ```
+//! use static_table::pool_table;
+//!
+//! const INTRO_TABLE: &str = pool_table!([
+//!     ["name", "designed by", "first release"],
+//!     ["C", "Dennis Ritchie", "1972"],
+//!     ["Go", "Rob Pike", "2009"],
+//!     ["Rust", "Graydon Hoare", "2010"],
+//! ]);
+//!
+//! assert_eq!(
+//!     INTRO_TABLE,
+//!     "+------+-------------+---------------+\n\
+//!      | name | designed by | first release |\n\
+//!      +------+-------------+-----+---------+\n\
+//!      | C    | Dennis Ritchie    | 1972    |\n\
+//!      +------+--+---------------++---------+\n\
+//!      | Go      | Rob Pike      | 2009     |\n\
+//!      +---------+---------------+-+--------+\n\
+//!      | Rust    | Graydon Hoare   | 2010   |\n\
+//!      +---------+-----------------+--------+"
+//! );
+//! ```
+//!
 //! ## Configuration
 //!
 //! ### Span
@@ -117,6 +149,9 @@
 //!      ╚═══════╩═════════════════╩════════════════╝"
 //! )
 //! ```
+//!
+//! [`static_table`]: crate::static_table!
+//! [`pool_table`]: crate::pool_table!
 
 #![allow(clippy::uninlined_format_args)]
 #![warn(
@@ -133,27 +168,45 @@
 )]
 
 use proc_macro_error::proc_macro_error;
-use quote::{quote, ToTokens};
-use std::{
-    collections::{HashMap, HashSet},
-    iter::FromIterator,
-};
-use syn::{
-    braced, bracketed,
-    parse::{Parse, ParseStream},
-    parse_macro_input,
-    punctuated::Punctuated,
-    token::{self, Brace},
-    ExprLit, Ident, Lit, LitInt, LitStr, Result, Token,
-};
-use tabled::{
-    builder::Builder,
-    settings::{Alignment, Margin, Modify, Padding, Span, Style},
-    Table,
-};
+use quote::quote;
+use syn::parse_macro_input;
+
+mod pool_table;
+mod static_table;
 
 /// Build a table.
 ///
+/// ```
+/// use static_table::static_table;
+///
+/// let table = static_table!([
+///     [{"programming languages"; 3}],
+///     ["name", "designed by", "first release"],
+///     ["C", "Dennis Ritchie", "1972"],
+///     ["Go", "Rob Pike", "2009"],
+///     ["Rust", "Graydon Hoare", "2010"],
+///     ["Hare", "Drew DeVault", "2022"],
+/// ]);
+///
+/// assert_eq!(
+///     table,
+///     "+------+----------------+---------------+\n\
+///      | programming languages                 |\n\
+///      +------+----------------+---------------+\n\
+///      | name | designed by    | first release |\n\
+///      +------+----------------+---------------+\n\
+///      | C    | Dennis Ritchie | 1972          |\n\
+///      +------+----------------+---------------+\n\
+///      | Go   | Rob Pike       | 2009          |\n\
+///      +------+----------------+---------------+\n\
+///      | Rust | Graydon Hoare  | 2010          |\n\
+///      +------+----------------+---------------+\n\
+///      | Hare | Drew DeVault   | 2022          |\n\
+///      +------+----------------+---------------+"
+/// );
+///
+/// ```
+///
 /// # Syntax
 ///
 /// The input is expected to look like an array.
@@ -163,6 +216,13 @@ use tabled::{
 /// static_table!([["a", "b"], ["c", "d"]]);
 /// ```
 ///
+/// You can repeat an argument just like you'd do with general array of `vec!` macro.
+///
+/// ```
+/// # use static_table::static_table;
+/// static_table!([["123456789"; 2]; 5]);
+/// ```
+///
 /// Optionally you can set a column span, using the following syntax.
 ///
 /// ```
@@ -193,709 +253,87 @@ use tabled::{
 #[proc_macro]
 #[proc_macro_error]
 pub fn static_table(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    use crate::static_table::{build_table, TableStruct};
+
     let table = parse_macro_input!(input as TableStruct);
     let table = build_table(&table);
     match table {
-        Ok(table) => {
-            let out = quote! {
-                #table
-            };
-
-            proc_macro::TokenStream::from(out)
-        }
+        Ok(table) => proc_macro::TokenStream::from(quote! { #table }),
         Err(err) => proc_macro::TokenStream::from(err.into_compile_error()),
     }
 }
 
-#[allow(dead_code)]
-struct MatrixRow {
-    bracket_token: token::Bracket,
-    elems: MatrixRowElements,
-}
-
-#[allow(dead_code)]
-enum MatrixRowElements {
-    List(Punctuated<ExprVal, Token![,]>),
-    Static {
-        elem: ExprVal,
-        semi_token: Token![;],
-        len: LitInt,
-    },
-}
-
-impl Parse for MatrixRow {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let content;
-        let bracket_token = bracketed!(content in input);
-
-        if content.peek2(Token![;]) {
-            return Ok(Self {
-                bracket_token,
-                elems: MatrixRowElements::Static {
-                    elem: content.parse()?,
-                    semi_token: content.parse()?,
-                    len: content.parse()?,
-                },
-            });
-        }
-
-        let mut elems = Punctuated::new();
-        while !content.is_empty() {
-            let val = content.parse()?;
-            elems.push_value(val);
-            if content.is_empty() {
-                break;
-            }
-            let punct = content.parse()?;
-            elems.push_punct(punct);
-        }
-
-        Ok(Self {
-            bracket_token,
-            elems: MatrixRowElements::List(elems),
-        })
-    }
-}
-
-#[allow(dead_code)]
-enum ExprVal {
-    Lit(ExprLit),
-    Scope {
-        brace_token: token::Brace,
-        level: usize,
-        expr: Option<ScopeVal>,
-    },
-}
-
-#[allow(dead_code)]
-enum ScopeVal {
-    Expr(ExprLit),
-    List(Punctuated<ExprLit, Token![,]>),
-    Sized {
-        elem: ExprLit,
-        semi_token: Token![;],
-        len: LitInt,
-    },
-}
-
-impl Parse for ExprVal {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        if input.peek(Brace) {
-            let mut content;
-            let brace_token = braced!(content in input);
-
-            let mut level = 1;
-            while content.peek(Brace) {
-                let _ = braced!(content in content);
-                level += 1;
-            }
-
-            if content.is_empty() {
-                return Ok(ExprVal::Scope {
-                    brace_token,
-                    level,
-                    expr: None,
-                });
-            }
-
-            if content.peek2(Token![;]) {
-                return Ok(ExprVal::Scope {
-                    brace_token,
-                    level,
-                    expr: Some(ScopeVal::Sized {
-                        elem: content.parse()?,
-                        semi_token: content.parse()?,
-                        len: content.parse()?,
-                    }),
-                });
-            }
-
-            let elem: ExprLit = content.parse()?;
-
-            if content.is_empty() {
-                return Ok(ExprVal::Scope {
-                    brace_token,
-                    level,
-                    expr: Some(ScopeVal::Expr(elem)),
-                });
-            }
-
-            let mut elems = Punctuated::new();
-            elems.push(elem);
-
-            while !content.is_empty() {
-                let punct: Token![,] = content.parse()?;
-                elems.push_punct(punct);
-
-                if content.is_empty() {
-                    // trailing comma
-                    break;
-                }
-
-                let val: ExprLit = content.parse()?;
-                elems.push_value(val);
-            }
-
-            return Ok(ExprVal::Scope {
-                brace_token,
-                level,
-                expr: Some(ScopeVal::List(elems)),
-            });
-        }
-
-        Ok(Self::Lit(input.parse()?))
-    }
-}
-
-#[allow(dead_code)]
-struct MatrixInput {
-    bracket_token: token::Bracket,
-    data: MatrixData,
-}
-
-#[allow(dead_code)]
-enum MatrixData {
-    List(Punctuated<MatrixRow, Token![,]>),
-    Static {
-        elem: MatrixRow,
-        semi_token: Token![;],
-        len: LitInt,
-    },
-}
-
-impl Parse for MatrixInput {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let content;
-        let bracket_token = bracketed!(content in input);
-
-        if content.is_empty() {
-            return Ok(Self {
-                bracket_token,
-                data: MatrixData::List(Punctuated::new()),
-            });
-        }
-
-        let elem = content.parse()?;
-
-        if content.peek(Token![;]) {
-            return Ok(MatrixInput {
-                bracket_token,
-                data: MatrixData::Static {
-                    elem,
-                    semi_token: content.parse()?,
-                    len: content.parse()?,
-                },
-            });
-        }
-
-        let mut elems = Punctuated::new();
-        elems.push(elem);
-
-        while !content.is_empty() {
-            let punct: Token![,] = content.parse()?;
-            elems.push_punct(punct);
-
-            if content.is_empty() {
-                // trailing comma
-                break;
-            }
-
-            let val = content.parse()?;
-            elems.push_value(val);
-        }
-
-        Ok(MatrixInput {
-            bracket_token,
-            data: MatrixData::List(elems),
-        })
-    }
-}
-
-#[allow(dead_code)]
-struct KeyValue<V> {
-    key: Ident,
-    token: Token!(=),
-    value: V,
-}
-
-impl<V: Parse> Parse for KeyValue<V> {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        Ok(Self {
-            key: input.parse()?,
-            token: input.parse()?,
-            value: input.parse()?,
-        })
-    }
-}
-
-#[allow(dead_code)]
-struct TableStruct {
-    matrix: MatrixInput,
-    comma_token: Option<Token![,]>,
-    settings: Punctuated<KeyValue<LitStr>, Token!(,)>,
-}
-
-impl Parse for TableStruct {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let matrix = input.parse()?;
-        let mut comma_token = None;
-        let mut settings = Punctuated::new();
-
-        if input.peek(Token![,]) {
-            comma_token = Some(input.parse()?);
-            while !input.is_empty() {
-                let val = input.parse()?;
-                settings.push_value(val);
-                if input.is_empty() {
-                    break;
-                }
-                let punct = input.parse()?;
-                settings.push_punct(punct);
-            }
-        }
-
-        Ok(Self {
-            matrix,
-            comma_token,
-            settings,
-        })
-    }
-}
-
-#[allow(dead_code)]
-struct Pad<T> {
-    left: T,
-    comma1_tk: Token!(,),
-    right: T,
-    comma2_tk: Token!(,),
-    top: T,
-    comma3_tk: Token!(,),
-    bottom: T,
-}
-
-impl<T: Parse> Parse for Pad<T> {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        Ok(Self {
-            left: input.parse()?,
-            comma1_tk: input.parse()?,
-            right: input.parse()?,
-            comma2_tk: input.parse()?,
-            top: input.parse()?,
-            comma3_tk: input.parse()?,
-            bottom: input.parse()?,
-        })
-    }
-}
-
-fn expr_lit_to_string(expr_lit: &ExprLit) -> String {
-    match &expr_lit.lit {
-        Lit::Str(val) => val.value(),
-        Lit::ByteStr(val) => format!("{:?}", val.value()),
-        Lit::Int(val) => val.base10_digits().to_string(),
-        Lit::Float(val) => val.base10_digits().to_string(),
-        Lit::Char(val) => val.value().to_string(),
-        Lit::Byte(val) => val.value().to_string(),
-        Lit::Bool(val) => val.value().to_string(),
-        Lit::Verbatim(val) => val.to_token_stream().to_string(),
-    }
-}
-
-fn expr_val_to_list(expr_val: &ExprVal) -> Result<Vec<String>> {
-    match expr_val {
-        ExprVal::Lit(lit) => Ok(vec![expr_lit_to_string(lit)]),
-        ExprVal::Scope { expr, .. } => match expr {
-            Some(val) => match val {
-                ScopeVal::Expr(lit) => Ok(vec![expr_lit_to_string(lit)]),
-                ScopeVal::List(list) => Ok(list.into_iter().map(expr_lit_to_string).collect()),
-                ScopeVal::Sized { elem, len, .. } => {
-                    let len = len.base10_parse::<usize>()?;
-                    let mut data = vec![String::new(); len];
-                    if len > 0 {
-                        data[0] = expr_lit_to_string(elem);
-                    }
-
-                    Ok(data)
-                }
-            },
-            None => Ok(vec![String::new()]),
-        },
-    }
-}
-
-fn collect_matrix(matrix: &MatrixInput) -> Result<Vec<Vec<String>>> {
-    match &matrix.data {
-        MatrixData::List(list) => {
-            let mut data = vec![];
-            for row in list {
-                let row = collect_row(&row.elems)?;
-                data.push(row)
-            }
-
-            Ok(data)
-        }
-        MatrixData::Static { elem, len, .. } => {
-            let data = collect_row(&elem.elems)?;
-            let len = len.base10_parse::<usize>()?;
-
-            Ok(vec![data; len])
-        }
-    }
-}
-
-fn collect_row(elems: &MatrixRowElements) -> Result<Vec<String>> {
-    let mut row = vec![];
-
-    match elems {
-        MatrixRowElements::List(list) => {
-            for val in list {
-                let vals = expr_val_to_list(val)?;
-                row.extend(vals);
-            }
-        }
-        MatrixRowElements::Static { elem, len, .. } => {
-            let len = len.base10_parse::<usize>()?;
-            let elem = expr_val_to_list(elem)?;
-            let iter = std::iter::repeat(elem).take(len).flatten();
-
-            row.extend(iter);
-        }
-    }
-
-    Ok(row)
-}
-
-fn collect_vspan(matrix: &MatrixInput) -> Result<HashMap<(usize, usize), usize>> {
-    let mut spans = HashMap::new();
-
-    match &matrix.data {
-        MatrixData::List(list) => {
-            for (row, e) in list.iter().enumerate() {
-                match &e.elems {
-                    MatrixRowElements::List(list) => {
-                        let mut i = 0;
-                        for e in list {
-                            match e {
-                                ExprVal::Lit(_) => i += 1,
-                                ExprVal::Scope { expr, .. } => match expr {
-                                    Some(val) => match val {
-                                        ScopeVal::Expr(_) => i += 1,
-                                        ScopeVal::List(list) => i += list.len(),
-                                        ScopeVal::Sized { len, .. } => {
-                                            let len = len.base10_parse::<usize>()?;
-                                            if len > 0 {
-                                                spans.insert((row, i), len);
-                                                i += len;
-                                            }
-                                        }
-                                    },
-                                    None => i += 1,
-                                },
-                            }
-                        }
-                    }
-                    MatrixRowElements::Static { elem, len, .. } => {
-                        let arr_len = len.base10_parse::<usize>()?;
-                        match elem {
-                            ExprVal::Lit(_) => {}
-                            ExprVal::Scope { expr, .. } => match expr {
-                                Some(val) => match val {
-                                    ScopeVal::Expr(_) => {}
-                                    ScopeVal::List(_) => {}
-                                    ScopeVal::Sized { len, .. } => {
-                                        let len = len.base10_parse::<usize>()?;
-                                        if len > 0 {
-                                            let iter = (0..arr_len).map(|i| ((row, i * len), len));
-                                            spans.extend(iter);
-                                        }
-                                    }
-                                },
-                                None => {}
-                            },
-                        }
-                    }
-                }
-            }
-        }
-        MatrixData::Static { elem, len, .. } => {
-            let count_rows = len.base10_parse::<usize>()?;
-
-            match &elem.elems {
-                MatrixRowElements::List(list) => {
-                    let mut i = 0;
-                    for e in list {
-                        match e {
-                            ExprVal::Lit(_) => i += 1,
-                            ExprVal::Scope { expr, .. } => match expr {
-                                Some(val) => match val {
-                                    ScopeVal::Expr(_) => i += 1,
-                                    ScopeVal::List(list) => i += list.len(),
-                                    ScopeVal::Sized { len, .. } => {
-                                        let len = len.base10_parse::<usize>()?;
-                                        if len > 0 {
-                                            spans
-                                                .extend((0..count_rows).map(|row| ((row, i), len)));
-                                            i += len;
-                                        }
-                                    }
-                                },
-                                None => i += 1,
-                            },
-                        }
-                    }
-                }
-                MatrixRowElements::Static { .. } => {}
-            }
-        }
-    }
-
-    Ok(spans)
-}
-
-fn collect_hspan(matrix: &MatrixInput) -> Result<HashMap<(usize, usize), usize>> {
-    let mut filled = HashSet::new();
-    let mut empties = HashSet::new();
-    match &matrix.data {
-        MatrixData::List(list) => {
-            for (row, e) in list.iter().enumerate() {
-                match &e.elems {
-                    MatrixRowElements::List(list) => {
-                        let mut col = 0;
-                        for e in list {
-                            match e {
-                                ExprVal::Lit(_) => col += 1,
-                                ExprVal::Scope { expr, .. } => match expr {
-                                    Some(val) => match val {
-                                        ScopeVal::List(list) => col += list.len(),
-                                        ScopeVal::Expr(_) => {
-                                            filled.insert((row, col));
-                                            col += 1;
-                                        }
-                                        ScopeVal::Sized { len, .. } => {
-                                            filled.insert((row, col));
-                                            let len = len.base10_parse::<usize>()?;
-                                            col += len;
-                                        }
-                                    },
-                                    None => {
-                                        empties.insert((row, col));
-                                        col += 1;
-                                    }
-                                },
-                            }
-                        }
-                    }
-                    MatrixRowElements::Static { elem, len, .. } => {
-                        let arr_len = len.base10_parse::<usize>()?;
-
-                        match elem {
-                            ExprVal::Lit(_) => {}
-                            ExprVal::Scope { expr, .. } => match expr {
-                                Some(val) => match val {
-                                    ScopeVal::List(_) => {}
-                                    ScopeVal::Expr(_) => {
-                                        filled.extend((0..arr_len).map(|col| (row, col)));
-                                    }
-                                    ScopeVal::Sized { len, .. } => {
-                                        let len = len.base10_parse::<usize>()?;
-                                        filled.extend((0..arr_len).map(|col| (row, col * len)));
-                                    }
-                                },
-                                None => {
-                                    empties.extend((0..arr_len).map(|col| (row, col)));
-                                }
-                            },
-                        }
-                    }
-                }
-            }
-        }
-        MatrixData::Static { .. } => {}
-    }
-
-    let mut spans = HashMap::new();
-    for (row, col) in filled {
-        let mut size = 0;
-        for row in row + 1.. {
-            if empties.contains(&(row, col)) {
-                size += 1;
-            } else {
-                break;
-            }
-        }
-
-        if size > 0 {
-            spans.insert((row, col), size + 1);
-        }
-    }
-
-    Ok(spans)
-}
-
-// todo: export the constants from crate so they could be highlighted by language servers.
-// Yet this is unstable to do.
-fn is_supported_theme(name: &str) -> bool {
-    matches!(
-        name,
-        "EMPTY"
-            | "BLANK"
-            | "ASCII"
-            | "ASCII_ROUNDED"
-            | "DOTS"
-            | "MODERN"
-            | "SHARP"
-            | "ROUNDED"
-            | "EXTENDED"
-            | "RE_STRUCTURED_TEXT"
-            | "MARKDOWN"
-            | "PSQL"
-    )
-}
-
-fn apply_theme(table: &mut tabled::Table, name: &str) {
-    match name {
-        "EMPTY" => table.with(Style::empty()),
-        "BLANK" => table.with(Style::blank()),
-        "ASCII" => table.with(Style::ascii()),
-        "ASCII_ROUNDED" => table.with(Style::ascii_rounded()),
-        "DOTS" => table.with(Style::dots()),
-        "MODERN" => table.with(Style::modern()),
-        "SHARP" => table.with(Style::sharp()),
-        "ROUNDED" => table.with(Style::rounded()),
-        "EXTENDED" => table.with(Style::extended()),
-        "RE_STRUCTURED_TEXT" => table.with(Style::re_structured_text()),
-        "MARKDOWN" => table.with(Style::markdown()),
-        "PSQL" => table.with(Style::psql()),
-        _ => unreachable!(),
-    };
-}
-
-fn build_padding(pad: Pad<LitInt>) -> syn::Result<Padding> {
-    let left = pad.left.base10_parse::<usize>()?;
-    let right = pad.right.base10_parse::<usize>()?;
-    let top = pad.top.base10_parse::<usize>()?;
-    let bottom = pad.bottom.base10_parse::<usize>()?;
-
-    Ok(Padding::new(left, right, top, bottom))
-}
-
-fn build_margin(pad: Pad<LitInt>) -> syn::Result<Margin> {
-    let left = pad.left.base10_parse::<usize>()?;
-    let right = pad.right.base10_parse::<usize>()?;
-    let top = pad.top.base10_parse::<usize>()?;
-    let bottom = pad.bottom.base10_parse::<usize>()?;
-
-    Ok(Margin::new(left, right, top, bottom))
-}
-
-fn panic_not_supported_theme(ident: &LitStr) {
-    proc_macro_error::abort!(
-        ident,
-        "The given settings is not supported";
-        note="custom themes are yet not supported";
-        help = r#"Supported themes are [EMPTY, BLANK, ASCII, ASCII_ROUNDED, DOTS, MODERN, SHARP, ROUNDED, EXTENDED, RE_STRUCTURED_TEXT, MARKDOWN, PSQL]"#
-    )
-}
-
-fn panic_not_supported_alignment(ident: &LitStr) {
-    proc_macro_error::abort!(
-        ident,
-        "The given settings is not supported";
-        note="custom themes are yet not supported";
-        help = r#"Supported alignment are [LEFT, RIGHT, CENTER, CENTER_VERTICAL, TOP, BOTTOM]"#
-    )
-}
-
-fn panic_not_supported_settings(ident: &Ident) {
-    proc_macro_error::abort!(
-        ident,
-        "The given settings is not supported";
-        help = r#"Supported list is [THEME, PADDING, MARGIN]"#
-    )
-}
-
-fn build_table(table_st: &TableStruct) -> Result<String> {
-    let mut table = create_table(&table_st.matrix)?;
-
-    if table_st.comma_token.is_some() {
-        apply_settings(&mut table, &table_st.settings)?;
-    }
-
-    Ok(table.to_string())
-}
-
-fn apply_settings(
-    table: &mut Table,
-    settings: &Punctuated<KeyValue<LitStr>, Token![,]>,
-) -> Result<()> {
-    for kv in settings {
-        config_table(table, kv)?;
-    }
-
-    Ok(())
-}
-
-fn is_supported_alignment(name: &str) -> bool {
-    matches!(
-        name,
-        "LEFT" | "RIGHT" | "CENTER" | "CENTER_VERTICAL" | "TOP" | "BOTTOM"
-    )
-}
-
-fn apply_alignment(table: &mut tabled::Table, name: &str) {
-    match name {
-        "LEFT" => table.with(Alignment::left()),
-        "RIGHT" => table.with(Alignment::right()),
-        "CENTER" => table.with(Alignment::center()),
-        "CENTER_VERTICAL" => table.with(Alignment::center_vertical()),
-        "TOP" => table.with(Alignment::top()),
-        "BOTTOM" => table.with(Alignment::bottom()),
-        _ => unreachable!(),
-    };
-}
-
-fn config_table(table: &mut Table, kv: &KeyValue<LitStr>) -> Result<()> {
-    if kv.key == "THEME" {
-        let theme = kv.value.value();
-        if !is_supported_theme(&theme) {
-            panic_not_supported_theme(&kv.value);
-        }
-
-        apply_theme(table, &theme);
-    } else if kv.key == "PADDING" {
-        let padding = kv.value.parse().and_then(build_padding)?;
-        table.with(padding);
-    } else if kv.key == "MARGIN" {
-        let margin = kv.value.parse().and_then(build_margin)?;
-        table.with(margin);
-    } else if kv.key == "ALIGNMENT" {
-        let alignment = kv.value.value();
-        if !is_supported_alignment(&alignment) {
-            panic_not_supported_alignment(&kv.value);
-        }
-
-        apply_alignment(table, &alignment);
-    } else {
-        panic_not_supported_settings(&kv.key);
-    }
-
-    Ok(())
-}
-
-fn create_table(mat: &MatrixInput) -> Result<Table> {
-    let data = collect_matrix(mat)?;
-    let vspan = collect_vspan(mat)?;
-    let hspan = collect_hspan(mat)?;
-
-    let builder = Builder::from_iter(data);
-    let mut table = builder.build();
-
-    for (pos, span) in vspan {
-        table.with(Modify::new(pos).with(Span::column(span)));
-    }
+/// Build a table.
+///
+/// ```
+/// use static_table::pool_table;
+///
+/// let table = pool_table!([
+///     ["programming languages"],
+///     ["name", "designed by", "first release"],
+///     ["C", "Dennis Ritchie", "1972"],
+///     ["Go", "Rob Pike", "2009"],
+///     ["Rust", "Graydon Hoare", "2010"],
+///     ["Hare", "Drew DeVault", "2022"],
+/// ]);
+///
+/// assert_eq!(
+///     table,
+///     "+------------------------------------+\n\
+///      | programming languages              |\n\
+///      +------+-------------+---------------+\n\
+///      | name | designed by | first release |\n\
+///      +------+-------------+-----+---------+\n\
+///      | C    | Dennis Ritchie    | 1972    |\n\
+///      +------+--+---------------++---------+\n\
+///      | Go      | Rob Pike      | 2009     |\n\
+///      +---------+---------------+-+--------+\n\
+///      | Rust    | Graydon Hoare   | 2010   |\n\
+///      +---------+-----------------+--------+\n\
+///      | Hare    | Drew DeVault    | 2022   |\n\
+///      +---------+-----------------+--------+"
+/// );
+///
+/// ```
+///
+/// # Syntax
+///
+/// The input is expected to look like an array.
+///
+/// ```
+/// # use static_table::pool_table;
+/// pool_table!([["a", "b"], ["c", "d"]]);
+/// ```
+///
+/// You can repeat an argument just like you'd do with general array of `vec!` macro.
+///
+/// ```
+/// # use static_table::pool_table;
+/// pool_table!([["123456789"; 2]; 5]);
+/// ```
+///
+/// Optionally you can add settings to the table, using the following syntax.
+///
+/// ```
+/// # use static_table::pool_table;
+/// pool_table!([["a", "b"], ["c", "d"]], THEME = "ROUNDED");
+/// ```
+///
+/// Supported settings are:
+///
+/// - THEME
+/// - ALIGNMENT
+/// - PADDING
+/// - MARGIN
+#[proc_macro]
+#[proc_macro_error]
+pub fn pool_table(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    use crate::pool_table::{build_table, TableStruct};
 
-    for (pos, span) in hspan {
-        table.with(Modify::new(pos).with(Span::row(span)));
+    let table = parse_macro_input!(input as TableStruct);
+    let table = build_table(&table);
+    match table {
+        Ok(table) => proc_macro::TokenStream::from(quote! { #table }),
+        Err(err) => proc_macro::TokenStream::from(err.into_compile_error()),
     }
-
-    Ok(table)
 }
diff --git a/static_table/src/pool_table.rs b/static_table/src/pool_table.rs
new file mode 100644
index 0000000..78b6ec8
--- /dev/null
+++ b/static_table/src/pool_table.rs
@@ -0,0 +1,421 @@
+use quote::ToTokens;
+use syn::{
+    bracketed,
+    parse::{Parse, ParseStream},
+    punctuated::Punctuated,
+    token::{self},
+    ExprLit, Ident, Lit, LitInt, LitStr, Result, Token,
+};
+use tabled::{
+    settings::{Alignment, Margin, Padding, Style},
+    tables::{PoolTable, TableValue},
+};
+
+struct MatrixRow {
+    #[allow(dead_code)]
+    bracket_token: token::Bracket,
+    elems: MatrixRowElements,
+}
+
+enum MatrixRowElements {
+    List(Punctuated<ExprLit, Token![,]>),
+    Static {
+        elem: ExprLit,
+        #[allow(dead_code)]
+        semi_token: Token![;],
+        len: LitInt,
+    },
+}
+
+impl Parse for MatrixRow {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let content;
+        let bracket_token = bracketed!(content in input);
+
+        if content.peek2(Token![;]) {
+            return Ok(Self {
+                bracket_token,
+                elems: MatrixRowElements::Static {
+                    elem: content.parse()?,
+                    semi_token: content.parse()?,
+                    len: content.parse()?,
+                },
+            });
+        }
+
+        let mut elems = Punctuated::new();
+        while !content.is_empty() {
+            let val = content.parse()?;
+            elems.push_value(val);
+            if content.is_empty() {
+                break;
+            }
+            let punct = content.parse()?;
+            elems.push_punct(punct);
+        }
+
+        Ok(Self {
+            bracket_token,
+            elems: MatrixRowElements::List(elems),
+        })
+    }
+}
+
+struct MatrixInput {
+    #[allow(dead_code)]
+    bracket_token: token::Bracket,
+    data: MatrixData,
+}
+
+enum MatrixData {
+    List(Punctuated<MatrixRow, Token![,]>),
+    Static {
+        elem: MatrixRow,
+        #[allow(dead_code)]
+        semi_token: Token![;],
+        len: LitInt,
+    },
+}
+
+impl Parse for MatrixInput {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let content;
+        let bracket_token = bracketed!(content in input);
+
+        if content.is_empty() {
+            return Ok(Self {
+                bracket_token,
+                data: MatrixData::List(Punctuated::new()),
+            });
+        }
+
+        let elem = content.parse()?;
+
+        if content.peek(Token![;]) {
+            return Ok(MatrixInput {
+                bracket_token,
+                data: MatrixData::Static {
+                    elem,
+                    semi_token: content.parse()?,
+                    len: content.parse()?,
+                },
+            });
+        }
+
+        let mut elems = Punctuated::new();
+        elems.push(elem);
+
+        while !content.is_empty() {
+            let punct: Token![,] = content.parse()?;
+            elems.push_punct(punct);
+
+            if content.is_empty() {
+                // trailing comma
+                break;
+            }
+
+            let val = content.parse()?;
+            elems.push_value(val);
+        }
+
+        Ok(MatrixInput {
+            bracket_token,
+            data: MatrixData::List(elems),
+        })
+    }
+}
+
+struct KeyValue<V> {
+    key: Ident,
+    #[allow(dead_code)]
+    token: Token!(=),
+    value: V,
+}
+
+impl<V: Parse> Parse for KeyValue<V> {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        Ok(Self {
+            key: input.parse()?,
+            token: input.parse()?,
+            value: input.parse()?,
+        })
+    }
+}
+
+pub(crate) struct TableStruct {
+    matrix: MatrixInput,
+    comma_token: Option<Token![,]>,
+    settings: Punctuated<KeyValue<LitStr>, Token!(,)>,
+}
+
+impl Parse for TableStruct {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let matrix = input.parse()?;
+        let mut comma_token = None;
+        let mut settings = Punctuated::new();
+
+        if input.peek(Token![,]) {
+            comma_token = Some(input.parse()?);
+            while !input.is_empty() {
+                let val = input.parse()?;
+                settings.push_value(val);
+                if input.is_empty() {
+                    break;
+                }
+                let punct = input.parse()?;
+                settings.push_punct(punct);
+            }
+        }
+
+        Ok(Self {
+            matrix,
+            comma_token,
+            settings,
+        })
+    }
+}
+
+struct Pad<T> {
+    left: T,
+    #[allow(dead_code)]
+    comma1_tk: Token!(,),
+    right: T,
+    #[allow(dead_code)]
+    comma2_tk: Token!(,),
+    top: T,
+    #[allow(dead_code)]
+    comma3_tk: Token!(,),
+    bottom: T,
+}
+
+impl<T: Parse> Parse for Pad<T> {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        Ok(Self {
+            left: input.parse()?,
+            comma1_tk: input.parse()?,
+            right: input.parse()?,
+            comma2_tk: input.parse()?,
+            top: input.parse()?,
+            comma3_tk: input.parse()?,
+            bottom: input.parse()?,
+        })
+    }
+}
+
+fn expr_lit_to_string(expr_lit: &ExprLit) -> String {
+    match &expr_lit.lit {
+        Lit::Str(val) => val.value(),
+        Lit::ByteStr(val) => format!("{:?}", val.value()),
+        Lit::Int(val) => val.base10_digits().to_string(),
+        Lit::Float(val) => val.base10_digits().to_string(),
+        Lit::Char(val) => val.value().to_string(),
+        Lit::Byte(val) => val.value().to_string(),
+        Lit::Bool(val) => val.value().to_string(),
+        Lit::Verbatim(val) => val.to_token_stream().to_string(),
+    }
+}
+
+fn collect_matrix(matrix: &MatrixInput) -> Result<Vec<Vec<String>>> {
+    match &matrix.data {
+        MatrixData::List(list) => {
+            let mut data = vec![];
+            for row in list {
+                let row = collect_row(&row.elems)?;
+                data.push(row)
+            }
+
+            Ok(data)
+        }
+        MatrixData::Static { elem, len, .. } => {
+            let data = collect_row(&elem.elems)?;
+            let len = len.base10_parse::<usize>()?;
+
+            Ok(vec![data; len])
+        }
+    }
+}
+
+fn collect_row(elems: &MatrixRowElements) -> Result<Vec<String>> {
+    match elems {
+        MatrixRowElements::List(list) => {
+            let mut row = Vec::with_capacity(list.len());
+            for val in list {
+                let val = expr_lit_to_string(val);
+                row.push(val);
+            }
+
+            Ok(row)
+        }
+        MatrixRowElements::Static { elem, len, .. } => {
+            let len = len.base10_parse::<usize>()?;
+            let elem = expr_lit_to_string(elem);
+            let row = vec![elem; len];
+
+            Ok(row)
+        }
+    }
+}
+
+// todo: export the constants from crate so they could be highlighted by language servers.
+// Yet this is unstable to do.
+fn is_supported_theme(name: &str) -> bool {
+    matches!(
+        name,
+        "EMPTY"
+            | "BLANK"
+            | "ASCII"
+            | "ASCII_ROUNDED"
+            | "DOTS"
+            | "MODERN"
+            | "SHARP"
+            | "ROUNDED"
+            | "EXTENDED"
+            | "RE_STRUCTURED_TEXT"
+            | "MARKDOWN"
+            | "PSQL"
+    )
+}
+
+fn apply_theme(table: &mut PoolTable, name: &str) {
+    match name {
+        "EMPTY" => table.with(Style::empty()),
+        "BLANK" => table.with(Style::blank()),
+        "ASCII" => table.with(Style::ascii()),
+        "ASCII_ROUNDED" => table.with(Style::ascii_rounded()),
+        "DOTS" => table.with(Style::dots()),
+        "MODERN" => table.with(Style::modern()),
+        "SHARP" => table.with(Style::sharp()),
+        "ROUNDED" => table.with(Style::rounded()),
+        "EXTENDED" => table.with(Style::extended()),
+        "RE_STRUCTURED_TEXT" => table.with(Style::re_structured_text()),
+        "MARKDOWN" => table.with(Style::markdown()),
+        "PSQL" => table.with(Style::psql()),
+        _ => unreachable!(),
+    };
+}
+
+fn build_padding(pad: Pad<LitInt>) -> syn::Result<Padding> {
+    let left = pad.left.base10_parse::<usize>()?;
+    let right = pad.right.base10_parse::<usize>()?;
+    let top = pad.top.base10_parse::<usize>()?;
+    let bottom = pad.bottom.base10_parse::<usize>()?;
+
+    Ok(Padding::new(left, right, top, bottom))
+}
+
+fn build_margin(pad: Pad<LitInt>) -> syn::Result<Margin> {
+    let left = pad.left.base10_parse::<usize>()?;
+    let right = pad.right.base10_parse::<usize>()?;
+    let top = pad.top.base10_parse::<usize>()?;
+    let bottom = pad.bottom.base10_parse::<usize>()?;
+
+    Ok(Margin::new(left, right, top, bottom))
+}
+
+fn panic_not_supported_theme(ident: &LitStr) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        note="custom themes are yet not supported";
+        help = r#"Supported themes are [EMPTY, BLANK, ASCII, ASCII_ROUNDED, DOTS, MODERN, SHARP, ROUNDED, EXTENDED, RE_STRUCTURED_TEXT, MARKDOWN, PSQL]"#
+    )
+}
+
+fn panic_not_supported_alignment(ident: &LitStr) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        note="custom themes are yet not supported";
+        help = r#"Supported alignment are [LEFT, RIGHT, CENTER, CENTER_VERTICAL, TOP, BOTTOM]"#
+    )
+}
+
+fn panic_not_supported_settings(ident: &Ident) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        help = r#"Supported list is [THEME, PADDING, MARGIN]"#
+    )
+}
+
+pub(crate) fn build_table(table_st: &TableStruct) -> Result<String> {
+    let mut table = create_table(&table_st.matrix)?;
+
+    if table_st.comma_token.is_some() {
+        apply_settings(&mut table, &table_st.settings)?;
+    }
+
+    Ok(table.to_string())
+}
+
+fn apply_settings(
+    table: &mut PoolTable,
+    settings: &Punctuated<KeyValue<LitStr>, Token![,]>,
+) -> Result<()> {
+    for kv in settings {
+        config_table(table, kv)?;
+    }
+
+    Ok(())
+}
+
+fn is_supported_alignment(name: &str) -> bool {
+    matches!(
+        name,
+        "LEFT" | "RIGHT" | "CENTER" | "CENTER_VERTICAL" | "TOP" | "BOTTOM"
+    )
+}
+
+fn apply_alignment(table: &mut PoolTable, name: &str) {
+    match name {
+        "LEFT" => table.with(Alignment::left()),
+        "RIGHT" => table.with(Alignment::right()),
+        "CENTER" => table.with(Alignment::center()),
+        "CENTER_VERTICAL" => table.with(Alignment::center_vertical()),
+        "TOP" => table.with(Alignment::top()),
+        "BOTTOM" => table.with(Alignment::bottom()),
+        _ => unreachable!(),
+    };
+}
+
+fn config_table(table: &mut PoolTable, kv: &KeyValue<LitStr>) -> Result<()> {
+    if kv.key == "THEME" {
+        let theme = kv.value.value();
+        if !is_supported_theme(&theme) {
+            panic_not_supported_theme(&kv.value);
+        }
+
+        apply_theme(table, &theme);
+    } else if kv.key == "PADDING" {
+        let padding = kv.value.parse().and_then(build_padding)?;
+        table.with(padding);
+    } else if kv.key == "MARGIN" {
+        let margin = kv.value.parse().and_then(build_margin)?;
+        table.with(margin);
+    } else if kv.key == "ALIGNMENT" {
+        let alignment = kv.value.value();
+        if !is_supported_alignment(&alignment) {
+            panic_not_supported_alignment(&kv.value);
+        }
+
+        apply_alignment(table, &alignment);
+    } else {
+        panic_not_supported_settings(&kv.key);
+    }
+
+    Ok(())
+}
+
+fn create_table(mat: &MatrixInput) -> Result<PoolTable> {
+    let data = collect_matrix(mat)?;
+    let value = matrix_to_table_value(data);
+    Ok(PoolTable::from(value))
+}
+
+fn matrix_to_table_value(m: Vec<Vec<String>>) -> TableValue {
+    TableValue::Column(
+        m.into_iter()
+            .map(|row| TableValue::Row(row.into_iter().map(TableValue::Cell).collect()))
+            .collect(),
+    )
+}
diff --git a/static_table/src/static_table.rs b/static_table/src/static_table.rs
new file mode 100644
index 0000000..fe75d84
--- /dev/null
+++ b/static_table/src/static_table.rs
@@ -0,0 +1,701 @@
+use std::{
+    collections::{HashMap, HashSet},
+    iter::FromIterator,
+};
+
+use quote::ToTokens;
+use syn::{
+    braced, bracketed,
+    parse::{Parse, ParseStream},
+    punctuated::Punctuated,
+    token::{self, Brace},
+    ExprLit, Ident, Lit, LitInt, LitStr, Result, Token,
+};
+use tabled::{
+    builder::Builder,
+    settings::{Alignment, Margin, Modify, Padding, Span, Style},
+    Table,
+};
+
+struct MatrixRow {
+    #[allow(dead_code)]
+    bracket_token: token::Bracket,
+    elems: MatrixRowElements,
+}
+
+enum MatrixRowElements {
+    List(Punctuated<ExprVal, Token![,]>),
+    Static {
+        elem: ExprVal,
+        #[allow(dead_code)]
+        semi_token: Token![;],
+        len: LitInt,
+    },
+}
+
+impl Parse for MatrixRow {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let content;
+        let bracket_token = bracketed!(content in input);
+
+        if content.peek2(Token![;]) {
+            return Ok(Self {
+                bracket_token,
+                elems: MatrixRowElements::Static {
+                    elem: content.parse()?,
+                    semi_token: content.parse()?,
+                    len: content.parse()?,
+                },
+            });
+        }
+
+        let mut elems = Punctuated::new();
+        while !content.is_empty() {
+            let val = content.parse()?;
+            elems.push_value(val);
+            if content.is_empty() {
+                break;
+            }
+            let punct = content.parse()?;
+            elems.push_punct(punct);
+        }
+
+        Ok(Self {
+            bracket_token,
+            elems: MatrixRowElements::List(elems),
+        })
+    }
+}
+
+enum ExprVal {
+    Lit(ExprLit),
+    Scope {
+        #[allow(dead_code)]
+        brace_token: token::Brace,
+        expr: Option<ScopeVal>,
+    },
+}
+
+enum ScopeVal {
+    Expr(ExprLit),
+    List(Punctuated<ExprLit, Token![,]>),
+    Sized {
+        elem: ExprLit,
+        #[allow(dead_code)]
+        semi_token: Token![;],
+        len: LitInt,
+    },
+}
+
+impl Parse for ExprVal {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        if input.peek(Brace) {
+            let content;
+            let brace_token = braced!(content in input);
+
+            if content.is_empty() {
+                return Ok(ExprVal::Scope {
+                    brace_token,
+                    expr: None,
+                });
+            }
+
+            if content.peek2(Token![;]) {
+                return Ok(ExprVal::Scope {
+                    brace_token,
+                    expr: Some(ScopeVal::Sized {
+                        elem: content.parse()?,
+                        semi_token: content.parse()?,
+                        len: content.parse()?,
+                    }),
+                });
+            }
+
+            let elem: ExprLit = content.parse()?;
+
+            if content.is_empty() {
+                return Ok(ExprVal::Scope {
+                    brace_token,
+                    expr: Some(ScopeVal::Expr(elem)),
+                });
+            }
+
+            let mut elems = Punctuated::new();
+            elems.push(elem);
+
+            while !content.is_empty() {
+                let punct: Token![,] = content.parse()?;
+                elems.push_punct(punct);
+
+                if content.is_empty() {
+                    // trailing comma
+                    break;
+                }
+
+                let val: ExprLit = content.parse()?;
+                elems.push_value(val);
+            }
+
+            return Ok(ExprVal::Scope {
+                brace_token,
+                expr: Some(ScopeVal::List(elems)),
+            });
+        }
+
+        Ok(Self::Lit(input.parse()?))
+    }
+}
+
+struct MatrixInput {
+    #[allow(dead_code)]
+    bracket_token: token::Bracket,
+    data: MatrixData,
+}
+
+enum MatrixData {
+    List(Punctuated<MatrixRow, Token![,]>),
+    Static {
+        elem: MatrixRow,
+        #[allow(dead_code)]
+        semi_token: Token![;],
+        len: LitInt,
+    },
+}
+
+impl Parse for MatrixInput {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let content;
+        let bracket_token = bracketed!(content in input);
+
+        if content.is_empty() {
+            return Ok(Self {
+                bracket_token,
+                data: MatrixData::List(Punctuated::new()),
+            });
+        }
+
+        let elem = content.parse()?;
+
+        if content.peek(Token![;]) {
+            return Ok(MatrixInput {
+                bracket_token,
+                data: MatrixData::Static {
+                    elem,
+                    semi_token: content.parse()?,
+                    len: content.parse()?,
+                },
+            });
+        }
+
+        let mut elems = Punctuated::new();
+        elems.push(elem);
+
+        while !content.is_empty() {
+            let punct: Token![,] = content.parse()?;
+            elems.push_punct(punct);
+
+            if content.is_empty() {
+                // trailing comma
+                break;
+            }
+
+            let val = content.parse()?;
+            elems.push_value(val);
+        }
+
+        Ok(MatrixInput {
+            bracket_token,
+            data: MatrixData::List(elems),
+        })
+    }
+}
+
+struct KeyValue<V> {
+    key: Ident,
+    #[allow(dead_code)]
+    token: Token!(=),
+    value: V,
+}
+
+impl<V: Parse> Parse for KeyValue<V> {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        Ok(Self {
+            key: input.parse()?,
+            token: input.parse()?,
+            value: input.parse()?,
+        })
+    }
+}
+
+pub(crate) struct TableStruct {
+    matrix: MatrixInput,
+    comma_token: Option<Token![,]>,
+    settings: Punctuated<KeyValue<LitStr>, Token!(,)>,
+}
+
+impl Parse for TableStruct {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let matrix = input.parse()?;
+        let mut comma_token = None;
+        let mut settings = Punctuated::new();
+
+        if input.peek(Token![,]) {
+            comma_token = Some(input.parse()?);
+            while !input.is_empty() {
+                let val = input.parse()?;
+                settings.push_value(val);
+                if input.is_empty() {
+                    break;
+                }
+                let punct = input.parse()?;
+                settings.push_punct(punct);
+            }
+        }
+
+        Ok(Self {
+            matrix,
+            comma_token,
+            settings,
+        })
+    }
+}
+
+struct Pad<T> {
+    left: T,
+    #[allow(dead_code)]
+    comma1_tk: Token!(,),
+    right: T,
+    #[allow(dead_code)]
+    comma2_tk: Token!(,),
+    top: T,
+    #[allow(dead_code)]
+    comma3_tk: Token!(,),
+    bottom: T,
+}
+
+impl<T: Parse> Parse for Pad<T> {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        Ok(Self {
+            left: input.parse()?,
+            comma1_tk: input.parse()?,
+            right: input.parse()?,
+            comma2_tk: input.parse()?,
+            top: input.parse()?,
+            comma3_tk: input.parse()?,
+            bottom: input.parse()?,
+        })
+    }
+}
+
+fn expr_lit_to_string(expr_lit: &ExprLit) -> String {
+    match &expr_lit.lit {
+        Lit::Str(val) => val.value(),
+        Lit::ByteStr(val) => format!("{:?}", val.value()),
+        Lit::Int(val) => val.base10_digits().to_string(),
+        Lit::Float(val) => val.base10_digits().to_string(),
+        Lit::Char(val) => val.value().to_string(),
+        Lit::Byte(val) => val.value().to_string(),
+        Lit::Bool(val) => val.value().to_string(),
+        Lit::Verbatim(val) => val.to_token_stream().to_string(),
+    }
+}
+
+fn expr_val_to_list(expr_val: &ExprVal) -> Result<Vec<String>> {
+    match expr_val {
+        ExprVal::Lit(lit) => Ok(vec![expr_lit_to_string(lit)]),
+        ExprVal::Scope { expr, .. } => match expr {
+            Some(val) => match val {
+                ScopeVal::Expr(lit) => Ok(vec![expr_lit_to_string(lit)]),
+                ScopeVal::List(list) => Ok(list.into_iter().map(expr_lit_to_string).collect()),
+                ScopeVal::Sized { elem, len, .. } => {
+                    let len = len.base10_parse::<usize>()?;
+                    let mut data = vec![String::new(); len];
+                    if len > 0 {
+                        data[0] = expr_lit_to_string(elem);
+                    }
+
+                    Ok(data)
+                }
+            },
+            None => Ok(vec![String::new()]),
+        },
+    }
+}
+
+fn collect_matrix(matrix: &MatrixInput) -> Result<Vec<Vec<String>>> {
+    match &matrix.data {
+        MatrixData::List(list) => {
+            let mut data = vec![];
+            for row in list {
+                let row = collect_row(&row.elems)?;
+                data.push(row)
+            }
+
+            Ok(data)
+        }
+        MatrixData::Static { elem, len, .. } => {
+            let data = collect_row(&elem.elems)?;
+            let len = len.base10_parse::<usize>()?;
+
+            Ok(vec![data; len])
+        }
+    }
+}
+
+fn collect_row(elems: &MatrixRowElements) -> Result<Vec<String>> {
+    let mut row = vec![];
+
+    match elems {
+        MatrixRowElements::List(list) => {
+            for val in list {
+                let vals = expr_val_to_list(val)?;
+                row.extend(vals);
+            }
+        }
+        MatrixRowElements::Static { elem, len, .. } => {
+            let len = len.base10_parse::<usize>()?;
+            let elem = expr_val_to_list(elem)?;
+            let iter = std::iter::repeat(elem).take(len).flatten();
+
+            row.extend(iter);
+        }
+    }
+
+    Ok(row)
+}
+
+fn collect_vspan(matrix: &MatrixInput) -> Result<HashMap<(usize, usize), usize>> {
+    let mut spans = HashMap::new();
+
+    match &matrix.data {
+        MatrixData::List(list) => {
+            for (row, e) in list.iter().enumerate() {
+                match &e.elems {
+                    MatrixRowElements::List(list) => {
+                        let mut i = 0;
+                        for e in list {
+                            match e {
+                                ExprVal::Lit(_) => i += 1,
+                                ExprVal::Scope { expr, .. } => match expr {
+                                    Some(val) => match val {
+                                        ScopeVal::Expr(_) => i += 1,
+                                        ScopeVal::List(list) => i += list.len(),
+                                        ScopeVal::Sized { len, .. } => {
+                                            let len = len.base10_parse::<usize>()?;
+                                            if len > 0 {
+                                                spans.insert((row, i), len);
+                                                i += len;
+                                            }
+                                        }
+                                    },
+                                    None => i += 1,
+                                },
+                            }
+                        }
+                    }
+                    MatrixRowElements::Static { elem, len, .. } => {
+                        let arr_len = len.base10_parse::<usize>()?;
+                        match elem {
+                            ExprVal::Lit(_) => {}
+                            ExprVal::Scope { expr, .. } => match expr {
+                                Some(val) => match val {
+                                    ScopeVal::Expr(_) => {}
+                                    ScopeVal::List(_) => {}
+                                    ScopeVal::Sized { len, .. } => {
+                                        let len = len.base10_parse::<usize>()?;
+                                        if len > 0 {
+                                            let iter = (0..arr_len).map(|i| ((row, i * len), len));
+                                            spans.extend(iter);
+                                        }
+                                    }
+                                },
+                                None => {}
+                            },
+                        }
+                    }
+                }
+            }
+        }
+        MatrixData::Static { elem, len, .. } => {
+            let count_rows = len.base10_parse::<usize>()?;
+
+            match &elem.elems {
+                MatrixRowElements::List(list) => {
+                    let mut i = 0;
+                    for e in list {
+                        match e {
+                            ExprVal::Lit(_) => i += 1,
+                            ExprVal::Scope { expr, .. } => match expr {
+                                Some(val) => match val {
+                                    ScopeVal::Expr(_) => i += 1,
+                                    ScopeVal::List(list) => i += list.len(),
+                                    ScopeVal::Sized { len, .. } => {
+                                        let len = len.base10_parse::<usize>()?;
+                                        if len > 0 {
+                                            spans
+                                                .extend((0..count_rows).map(|row| ((row, i), len)));
+                                            i += len;
+                                        }
+                                    }
+                                },
+                                None => i += 1,
+                            },
+                        }
+                    }
+                }
+                MatrixRowElements::Static { .. } => {}
+            }
+        }
+    }
+
+    Ok(spans)
+}
+
+fn collect_hspan(matrix: &MatrixInput) -> Result<HashMap<(usize, usize), usize>> {
+    let mut filled = HashSet::new();
+    let mut empties = HashSet::new();
+    match &matrix.data {
+        MatrixData::List(list) => {
+            for (row, e) in list.iter().enumerate() {
+                match &e.elems {
+                    MatrixRowElements::List(list) => {
+                        let mut col = 0;
+                        for e in list {
+                            match e {
+                                ExprVal::Lit(_) => col += 1,
+                                ExprVal::Scope { expr, .. } => match expr {
+                                    Some(val) => match val {
+                                        ScopeVal::List(list) => col += list.len(),
+                                        ScopeVal::Expr(_) => {
+                                            filled.insert((row, col));
+                                            col += 1;
+                                        }
+                                        ScopeVal::Sized { len, .. } => {
+                                            filled.insert((row, col));
+                                            let len = len.base10_parse::<usize>()?;
+                                            col += len;
+                                        }
+                                    },
+                                    None => {
+                                        empties.insert((row, col));
+                                        col += 1;
+                                    }
+                                },
+                            }
+                        }
+                    }
+                    MatrixRowElements::Static { elem, len, .. } => {
+                        let arr_len = len.base10_parse::<usize>()?;
+
+                        match elem {
+                            ExprVal::Lit(_) => {}
+                            ExprVal::Scope { expr, .. } => match expr {
+                                Some(val) => match val {
+                                    ScopeVal::List(_) => {}
+                                    ScopeVal::Expr(_) => {
+                                        filled.extend((0..arr_len).map(|col| (row, col)));
+                                    }
+                                    ScopeVal::Sized { len, .. } => {
+                                        let len = len.base10_parse::<usize>()?;
+                                        filled.extend((0..arr_len).map(|col| (row, col * len)));
+                                    }
+                                },
+                                None => {
+                                    empties.extend((0..arr_len).map(|col| (row, col)));
+                                }
+                            },
+                        }
+                    }
+                }
+            }
+        }
+        MatrixData::Static { .. } => {}
+    }
+
+    let mut spans = HashMap::new();
+    for (row, col) in filled {
+        let mut size = 0;
+        for row in row + 1.. {
+            if empties.contains(&(row, col)) {
+                size += 1;
+            } else {
+                break;
+            }
+        }
+
+        if size > 0 {
+            spans.insert((row, col), size + 1);
+        }
+    }
+
+    Ok(spans)
+}
+
+// todo: export the constants from crate so they could be highlighted by language servers.
+// Yet this is unstable to do.
+fn is_supported_theme(name: &str) -> bool {
+    matches!(
+        name,
+        "EMPTY"
+            | "BLANK"
+            | "ASCII"
+            | "ASCII_ROUNDED"
+            | "DOTS"
+            | "MODERN"
+            | "SHARP"
+            | "ROUNDED"
+            | "EXTENDED"
+            | "RE_STRUCTURED_TEXT"
+            | "MARKDOWN"
+            | "PSQL"
+    )
+}
+
+fn apply_theme(table: &mut Table, name: &str) {
+    match name {
+        "EMPTY" => table.with(Style::empty()),
+        "BLANK" => table.with(Style::blank()),
+        "ASCII" => table.with(Style::ascii()),
+        "ASCII_ROUNDED" => table.with(Style::ascii_rounded()),
+        "DOTS" => table.with(Style::dots()),
+        "MODERN" => table.with(Style::modern()),
+        "SHARP" => table.with(Style::sharp()),
+        "ROUNDED" => table.with(Style::rounded()),
+        "EXTENDED" => table.with(Style::extended()),
+        "RE_STRUCTURED_TEXT" => table.with(Style::re_structured_text()),
+        "MARKDOWN" => table.with(Style::markdown()),
+        "PSQL" => table.with(Style::psql()),
+        _ => unreachable!(),
+    };
+}
+
+fn build_padding(pad: Pad<LitInt>) -> syn::Result<Padding> {
+    let left = pad.left.base10_parse::<usize>()?;
+    let right = pad.right.base10_parse::<usize>()?;
+    let top = pad.top.base10_parse::<usize>()?;
+    let bottom = pad.bottom.base10_parse::<usize>()?;
+
+    Ok(Padding::new(left, right, top, bottom))
+}
+
+fn build_margin(pad: Pad<LitInt>) -> syn::Result<Margin> {
+    let left = pad.left.base10_parse::<usize>()?;
+    let right = pad.right.base10_parse::<usize>()?;
+    let top = pad.top.base10_parse::<usize>()?;
+    let bottom = pad.bottom.base10_parse::<usize>()?;
+
+    Ok(Margin::new(left, right, top, bottom))
+}
+
+fn panic_not_supported_theme(ident: &LitStr) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        note="custom themes are yet not supported";
+        help = r#"Supported themes are [EMPTY, BLANK, ASCII, ASCII_ROUNDED, DOTS, MODERN, SHARP, ROUNDED, EXTENDED, RE_STRUCTURED_TEXT, MARKDOWN, PSQL]"#
+    )
+}
+
+fn panic_not_supported_alignment(ident: &LitStr) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        note="custom themes are yet not supported";
+        help = r#"Supported alignment are [LEFT, RIGHT, CENTER, CENTER_VERTICAL, TOP, BOTTOM]"#
+    )
+}
+
+fn panic_not_supported_settings(ident: &Ident) {
+    proc_macro_error::abort!(
+        ident,
+        "The given settings is not supported";
+        help = r#"Supported list is [THEME, PADDING, MARGIN]"#
+    )
+}
+
+pub(crate) fn build_table(table_st: &TableStruct) -> Result<String> {
+    let mut table = create_table(&table_st.matrix)?;
+
+    if table_st.comma_token.is_some() {
+        apply_settings(&mut table, &table_st.settings)?;
+    }
+
+    Ok(table.to_string())
+}
+
+fn apply_settings(
+    table: &mut Table,
+    settings: &Punctuated<KeyValue<LitStr>, Token![,]>,
+) -> Result<()> {
+    for kv in settings {
+        config_table(table, kv)?;
+    }
+
+    Ok(())
+}
+
+fn is_supported_alignment(name: &str) -> bool {
+    matches!(
+        name,
+        "LEFT" | "RIGHT" | "CENTER" | "CENTER_VERTICAL" | "TOP" | "BOTTOM"
+    )
+}
+
+fn apply_alignment(table: &mut Table, name: &str) {
+    match name {
+        "LEFT" => table.with(Alignment::left()),
+        "RIGHT" => table.with(Alignment::right()),
+        "CENTER" => table.with(Alignment::center()),
+        "CENTER_VERTICAL" => table.with(Alignment::center_vertical()),
+        "TOP" => table.with(Alignment::top()),
+        "BOTTOM" => table.with(Alignment::bottom()),
+        _ => unreachable!(),
+    };
+}
+
+fn config_table(table: &mut Table, kv: &KeyValue<LitStr>) -> Result<()> {
+    if kv.key == "THEME" {
+        let theme = kv.value.value();
+        if !is_supported_theme(&theme) {
+            panic_not_supported_theme(&kv.value);
+        }
+
+        apply_theme(table, &theme);
+    } else if kv.key == "PADDING" {
+        let padding = kv.value.parse().and_then(build_padding)?;
+        table.with(padding);
+    } else if kv.key == "MARGIN" {
+        let margin = kv.value.parse().and_then(build_margin)?;
+        table.with(margin);
+    } else if kv.key == "ALIGNMENT" {
+        let alignment = kv.value.value();
+        if !is_supported_alignment(&alignment) {
+            panic_not_supported_alignment(&kv.value);
+        }
+
+        apply_alignment(table, &alignment);
+    } else {
+        panic_not_supported_settings(&kv.key);
+    }
+
+    Ok(())
+}
+
+fn create_table(mat: &MatrixInput) -> Result<Table> {
+    let data = collect_matrix(mat)?;
+    let vspan = collect_vspan(mat)?;
+    let hspan = collect_hspan(mat)?;
+
+    let builder = Builder::from_iter(data);
+    let mut table = builder.build();
+
+    for (pos, span) in vspan {
+        table.with(Modify::new(pos).with(Span::column(span)));
+    }
+
+    for (pos, span) in hspan {
+        table.with(Modify::new(pos).with(Span::row(span)));
+    }
+
+    Ok(table)
+}
diff --git a/tabled/src/grid/colored_config.rs b/tabled/src/grid/colored_config.rs
index f59a5a4..a07a5a1 100644
--- a/tabled/src/grid/colored_config.rs
+++ b/tabled/src/grid/colored_config.rs
@@ -6,7 +6,7 @@ use papergrid::{
     config::{spanned::SpannedConfig, Position},
 };
 
-/// A [`Table`] configuration.
+/// A spanned configuration plus colors for cells.
 #[derive(Debug, Default, PartialEq, Eq, Clone)]
 pub struct ColoredConfig {
     config: SpannedConfig,
@@ -23,6 +23,8 @@ impl ColoredConfig {
     ///
     /// The outcome is the same as if you'd use [`Format`] and added a color but it'd work only with `color` feature on.
     /// While this method works in all contexts.
+    ///
+    /// [`Format`]: crate::settings::Format
     pub fn set_color(&mut self, pos: Position, color: AnsiColor<'static>) -> &mut Self {
         let _ = self.colors.insert(pos, color);
         self
diff --git a/tabled/src/grid/compact_multiline_config.rs b/tabled/src/grid/compact_multiline_config.rs
index 1e8e790..4c7ff3e 100644
--- a/tabled/src/grid/compact_multiline_config.rs
+++ b/tabled/src/grid/compact_multiline_config.rs
@@ -3,7 +3,7 @@ use crate::grid::config::{
     AlignmentHorizontal, AlignmentVertical, Borders, CompactConfig, Indent, Line, Sides,
 };
 
-/// A [`Table`] configuration.
+/// A [`CompactConfig`] configuration plus vertical alignment.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CompactMultilineConfig {
     config: CompactConfig,
diff --git a/tabled/src/grid/dimension/const_dimension.rs b/tabled/src/grid/dimension/const_dimension.rs
index 1722783..450b1ab 100644
--- a/tabled/src/grid/dimension/const_dimension.rs
+++ b/tabled/src/grid/dimension/const_dimension.rs
@@ -1,6 +1,6 @@
 //! Module contains a dimension estimator for [`CompactTable`]
 //!
-//! [`CompactTable`]: crate::tables::compact::CompactTable
+//! [`CompactTable`]: crate::tables::CompactTable
 
 use crate::grid::dimension::{Dimension, Estimate};
 
diff --git a/tabled/src/grid/records/into_records/mod.rs b/tabled/src/grid/records/into_records/mod.rs
index dfc584b..0a52c41 100644
--- a/tabled/src/grid/records/into_records/mod.rs
+++ b/tabled/src/grid/records/into_records/mod.rs
@@ -1,6 +1,6 @@
 //! The module contains a list of helpers for [`IntoRecords`]
 //!
-//! [`IntoRecords`]: crate::records::IntoRecords
+//! [`IntoRecords`]: crate::grid::records::IntoRecords
 
 pub mod limit_column_records;
 pub mod limit_row_records;
diff --git a/tabled/src/grid/records/records_mut.rs b/tabled/src/grid/records/records_mut.rs
index 08ba475..38c42d2 100644
--- a/tabled/src/grid/records/records_mut.rs
+++ b/tabled/src/grid/records/records_mut.rs
@@ -3,6 +3,8 @@ use crate::grid::config::Position;
 use crate::grid::records::vec_records::{CellInfo, VecRecords};
 
 /// A [`Records`] representation which can modify cell by (row, column) index.
+///
+/// [`Records`]: crate::grid::records::Records
 pub trait RecordsMut<Text> {
     /// Sets a text to a given cell by index.
     fn set(&mut self, pos: Position, text: Text);
diff --git a/tabled/src/settings/formatting/mod.rs b/tabled/src/settings/formatting/mod.rs
index 2cf38f7..56e6c7c 100644
--- a/tabled/src/settings/formatting/mod.rs
+++ b/tabled/src/settings/formatting/mod.rs
@@ -6,7 +6,7 @@
 //!
 //! [`Charset`] responsible for special char treatment.
 //!
-//! [`Alignment`]: crate::settings::alignment::Alignment
+//! [`Alignment`]: crate::settings::Alignment
 
 mod alignment_strategy;
 mod charset;
diff --git a/tabled/src/settings/formatting/trim_strategy.rs b/tabled/src/settings/formatting/trim_strategy.rs
index 5520795..b242df0 100644
--- a/tabled/src/settings/formatting/trim_strategy.rs
+++ b/tabled/src/settings/formatting/trim_strategy.rs
@@ -68,7 +68,7 @@ use crate::{grid::config::ColoredConfig, grid::config::Entity, settings::CellOpt
 /// );
 /// ```
 ///
-/// [`Alignment`]: crate::settings::alignment::Alignment
+/// [`Alignment`]: crate::settings::Alignment
 #[derive(Debug, Clone)]
 pub enum TrimStrategy {
     /// Allow vertical trim.
diff --git a/tabled/src/settings/split/mod.rs b/tabled/src/settings/split/mod.rs
index fdaf839..31a5609 100644
--- a/tabled/src/settings/split/mod.rs
+++ b/tabled/src/settings/split/mod.rs
@@ -33,10 +33,10 @@ enum Display {
 ///
 /// The required index parameter determines how many columns/rows a table will be redistributed into.
 ///
-/// - index [`usize`]
-/// - direction [`Direction`]
-/// - behavior [`Behavior`] DEFAULT [`Behavior::Zip`]
-/// - display [`Display`] DEFAULT [`Display::Clean`]
+/// - index
+/// - direction
+/// - behavior
+/// - display
 ///
 /// # Example
 ///
@@ -195,6 +195,7 @@ impl Split {
     /// See [`retain`] for an alternative display option.
     ///
     /// [`Table`]: crate::Table
+    /// [`retain`]: crate::settings::split::Split::retain
     pub fn clean(self) -> Self {
         Self {
             display: Display::Clean,
@@ -222,6 +223,7 @@ impl Split {
     /// See [`clean`] for an alternative display option.
     ///
     /// [`Table`]: crate::Table
+    /// [`clean`]: crate::settings::split::Split::clean
     pub fn retain(self) -> Self {
         Self {
             display: Display::Retain,
diff --git a/tabled/src/tables/compact.rs b/tabled/src/tables/compact.rs
index b3e1cf0..f4aa423 100644
--- a/tabled/src/tables/compact.rs
+++ b/tabled/src/tables/compact.rs
@@ -145,7 +145,9 @@ impl<I, const ROWS: usize, const COLS: usize> CompactTable<I, ConstDimension<COL
 impl<I, D> CompactTable<I, D> {
     /// Creates a new [`CompactTable`] structure with a known dimension.
     ///
-    /// Notice that the function will call [`Estimate`].
+    /// Notice that the function wont call [`Estimate`].
+    ///
+    /// [`Estimate`]: crate::grid::dimension::Estimate
     pub fn with_dimension(iter: I, dimension: D) -> Self
     where
         I: IntoRecords,
@@ -211,7 +213,7 @@ impl<I, D> CompactTable<I, D> {
         )
     }
 
-    /// Format table into [`io::Write`]r.
+    /// Format table into a writer.
     #[cfg(feature = "std")]
     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     pub fn build<W>(self, writer: W) -> std::io::Result<()>
diff --git a/tabled/src/tables/mod.rs b/tabled/src/tables/mod.rs
index 7f4f03f..e0c4bf7 100644
--- a/tabled/src/tables/mod.rs
+++ b/tabled/src/tables/mod.rs
@@ -6,8 +6,8 @@
 //!
 //! ## [`IterTable`]
 //!
-//! Just like [`table`] but it's API is a bit different to serve better in context
-//! where there are a memory limits.
+//! Just like [`Table`] but it's API is a bit different to serve better in context
+//! where there is a memory limit.
 //!
 //! ## [`ExtendedTable`]
 //!


Test patch:
diff --git a/static_table/tests/pool_table.rs b/static_table/tests/pool_table.rs
new file mode 100644
index 0000000..4a5eaac
--- /dev/null
+++ b/static_table/tests/pool_table.rs
@@ -0,0 +1,371 @@
+use static_table::pool_table;
+
+#[test]
+fn pool_table() {
+    let table = pool_table!([[1, 2, 123], [1, 2, 123], [1, 2, 123]]);
+    let expected = "+---+---+-----+\n\
+                          | 1 | 2 | 123 |\n\
+                          +---+---+-----+\n\
+                          | 1 | 2 | 123 |\n\
+                          +---+---+-----+\n\
+                          | 1 | 2 | 123 |\n\
+                          +---+---+-----+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_empty() {
+    let table = pool_table!([]);
+    let expected = "+--+\n|  |\n+--+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_empty_row() {
+    let table = pool_table!([[]]);
+    let expected = "+--+\n|  |\n+--+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_one_row() {
+    let table = pool_table!([[1, 2, 3]]);
+    let expected = "+---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_repeat_row() {
+    let table = pool_table!([[1, 2, 3]; 5]);
+    let expected = "+---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+\n\
+                          | 1 | 2 | 3 |\n\
+                          +---+---+---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_repeat_row_zero_times() {
+    let table = pool_table!([[1, 2, 3]; 0]);
+    let expected = "+--+\n|  |\n+--+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_repeat_column() {
+    let table = pool_table!([["Hello World"; 2], ["hello", "world"]]);
+    let expected = "+-------------+-------------+\n\
+                          | Hello World | Hello World |\n\
+                          +-------------+-------------+\n\
+                          | hello       | world       |\n\
+                          +-------------+-------------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_repeat_column_zero_times() {
+    let table = pool_table!([["Hello World"; 0]]);
+    let expected = "+--+\n|  |\n+--+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_repeat_column_zero_times_with_other_row() {
+    let table = pool_table!([["Hello World"; 0], ["hello", "world"]]);
+    let expected = "+---------------+\n\
+                          |               |\n\
+                          +-------+-------+\n\
+                          | hello | world |\n\
+                          +-------+-------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_byte_string() {
+    let table = pool_table!([[b"abcd"], [b"0123"]]);
+    let expected = "+-------------------+\n\
+                          | [97, 98, 99, 100] |\n\
+                          +-------------------+\n\
+                          | [48, 49, 50, 51]  |\n\
+                          +-------------------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_byte_char() {
+    let table = pool_table!([[b'a'], [b'b']]);
+    let expected = "+----+\n\
+                          | 97 |\n\
+                          +----+\n\
+                          | 98 |\n\
+                          +----+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_char() {
+    let table = pool_table!([['a'], ['b']]);
+    let expected = "+---+\n\
+                          | a |\n\
+                          +---+\n\
+                          | b |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_bool() {
+    let table = pool_table!([[true], [false]]);
+    let expected = "+-------+\n\
+                          | true  |\n\
+                          +-------+\n\
+                          | false |\n\
+                          +-------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_u64() {
+    let table = pool_table!([[0u64], [1u64]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_u32() {
+    let table = pool_table!([[0u32], [1u32]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_u16() {
+    let table = pool_table!([[0u16], [1u16]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_u8() {
+    let table = pool_table!([[0u8], [1u8]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_i64() {
+    let table = pool_table!([[0u64], [1u64]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_i32() {
+    let table = pool_table!([[0u32], [1u32]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_i16() {
+    let table = pool_table!([[0u16], [1u16]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_i8() {
+    let table = pool_table!([[0u8], [1u8]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_isize() {
+    let table = pool_table!([[0isize], [1isize]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_isize_minus() {
+    let table = pool_table!([[-0], [-1isize]]);
+    let expected = "+----+\n\
+                          | -0 |\n\
+                          +----+\n\
+                          | -1 |\n\
+                          +----+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_usize() {
+    let table = pool_table!([[0usize], [1usize]]);
+    let expected = "+---+\n\
+                          | 0 |\n\
+                          +---+\n\
+                          | 1 |\n\
+                          +---+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_float32() {
+    let table = pool_table!([[0.0f32], [0.1f32]]);
+    let expected = "+-----+\n\
+                          | 0.0 |\n\
+                          +-----+\n\
+                          | 0.1 |\n\
+                          +-----+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_float64() {
+    let table = pool_table!([[0.0f64], [0.1f64]]);
+    let expected = "+-----+\n\
+                          | 0.0 |\n\
+                          +-----+\n\
+                          | 0.1 |\n\
+                          +-----+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_float64_minus() {
+    let table = pool_table!([[-0.0f64], [0.1f64]]);
+    let expected = "+------+\n\
+                          | -0.0 |\n\
+                          +------+\n\
+                          | 0.1  |\n\
+                          +------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_dims_differences_0() {
+    let table = pool_table!([["Hello World"; 2], ["hello"]]);
+    let expected = "+-------------+-------------+\n\
+                          | Hello World | Hello World |\n\
+                          +-------------+-------------+\n\
+                          | hello                     |\n\
+                          +---------------------------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_dims_differences_1() {
+    let table = pool_table!([["Hello World"], ["hello", "world"]]);
+    let expected = "+---------------+\n\
+                          | Hello World   |\n\
+                          +-------+-------+\n\
+                          | hello | world |\n\
+                          +-------+-------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_dims_differences_2() {
+    let table = pool_table!([
+        ["Hello World"],
+        ["hello", "world", "!!!"],
+        ["hello", "world"]
+    ]);
+    let expected = "+---------------------+\n\
+                          | Hello World         |\n\
+                          +-------+-------+-----+\n\
+                          | hello | world | !!! |\n\
+                          +-------+--+----+-----+\n\
+                          | hello    | world    |\n\
+                          +----------+----------+";
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_with_theme_padding_margin() {
+    let table = pool_table!(
+        [[1, 2, 123], [1, 2, 123], [1, 2, 123]],
+        MARGIN = "1, 1, 1, 1",
+        PADDING = "2, 2, 0, 0",
+        THEME = "ROUNDED"
+    );
+    let expected = concat!(
+        "                           \n",
+        " ╭─────  ┬─────  ┬───────╮ \n",
+        " │  1    │  2    │  123  │ \n",
+        "                           \n",
+        "                           \n",
+        "  ─────   ─────   ───────  \n",
+        " │  1    │  2    │  123  │ \n",
+        "                           \n",
+        "                           \n",
+        "  ─────   ─────   ───────  \n",
+        " │  1    │  2    │  123  │ \n",
+        " ├─────  ┴─────  ┴───────┤ \n",
+        "                           ",
+    );
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn pool_table_with_theme() {
+    let table = pool_table!(
+        [["Hello World"], [1, 2, 123], [1, 2, 3, 4, 5, 6, 7, 8, 9],],
+        THEME = "EXTENDED"
+    );
+    let expected = concat!(
+        "╔═══════════════════════════════════╗\n",
+        "║ Hello World                       ║\n",
+        "╠═══════════╦══════════╦════════════╣\n",
+        "║ 1         ║ 2        ║ 123        ║\n",
+        "╠═══╦═══╦═══╬═══╦═══╦══╩╦═══╦═══╦═══╣\n",
+        "║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ 7 ║ 8 ║ 9 ║\n",
+        "╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝",
+    );
+    assert_eq!(table, expected);
+}
diff --git a/static_table/tests/static_table.rs b/static_table/tests/static_table.rs
index 01eb8f4..4a25b97 100644
--- a/static_table/tests/static_table.rs
+++ b/static_table/tests/static_table.rs
@@ -326,11 +326,13 @@ fn static_table_dims_differences_2() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_vspan_0() {
     let table = static_table!([
-        [{"Hello World"; 2}],
+        [{
+            "Hello World";
+            2
+        }],
         ["hello", "world", "!!!"],
         ["hello", "world"]
     ]);
@@ -344,12 +346,21 @@ fn static_table_vspan_0() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_vspan_1() {
     let table = static_table!([
-        [{"Hello World"; 4}],
-        ["hello", {"world"; 2}, "!!!"],
+        [{
+            "Hello World";
+            4
+        }],
+        [
+            "hello",
+            {
+                "world";
+                2
+            },
+            "!!!"
+        ],
         ["hello", "world"]
     ]);
     let expected = "+-------+-------+--+-----+\n\
@@ -362,14 +373,32 @@ fn static_table_vspan_1() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_vspan_2() {
     let table = static_table!([
-        [{"Hello World"; 4}],
-        ["hello", {"world"; 2}, "!!!"],
-        [{"hello"; 2}, {"world"; 2}]]
-    );
+        [{
+            "Hello World";
+            4
+        }],
+        [
+            "hello",
+            {
+                "world";
+                2
+            },
+            "!!!"
+        ],
+        [
+            {
+                "hello";
+                2
+            },
+            {
+                "world";
+                2
+            }
+        ]
+    ]);
     let expected = "+-------+---+---+-----+\n\
                           | Hello World         |\n\
                           +-------+---+---+-----+\n\
@@ -380,11 +409,13 @@ fn static_table_vspan_2() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_vspan_const() {
     let table = static_table!([
-        [{"Hello World"; 4}; 2],
+        [{
+            "Hello World";
+            4
+        }; 2],
         ["hello", "world", "!!!"],
         ["hello", "world", "!!!"],
     ]);
@@ -398,31 +429,9 @@ fn static_table_vspan_const() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
-#[test]
-fn static_table_empty_layer() {
-    let table = static_table!([
-        [{}, 1, 2, {}],
-        ["hello", "world", "!!!"],
-        [{{{{}}}}, {{}}]]
-    );
-    let expected = "+-------+-------+-----+--+\n\
-                          |       | 1     | 2   |  |\n\
-                          +-------+-------+-----+--+\n\
-                          | hello | world | !!! |  |\n\
-                          +-------+-------+-----+--+\n\
-                          |       |       |     |  |\n\
-                          +-------+-------+-----+--+";
-    assert_eq!(table, expected);
-}
-
-#[rustfmt::skip]
 #[test]
 fn static_table_empty_layer_column() {
-    let table = static_table!([
-        [{}, 1, 2, {}],
-        [{}, "world", "!!!"],
-    ]);
+    let table = static_table!([[{}, 1, 2, {}], [{}, "world", "!!!"],]);
     let expected = "+--+-------+-----+--+\n\
                           |  | 1     | 2   |  |\n\
                           +--+-------+-----+--+\n\
@@ -431,11 +440,10 @@ fn static_table_empty_layer_column() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_hspan_0() {
     let table = static_table!([
-        [{"Hello"}, "World"],
+        [{ "Hello" }, "World"],
         [{}, "hello", "world", "!!!"],
         ["hello", "world"]
     ]);
@@ -449,11 +457,10 @@ fn static_table_hspan_0() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_hspan_1() {
     let table = static_table!([
-        [{"Hello"}, "World"],
+        [{ "Hello" }, "World"],
         [{}, "hello", "world", "!!!"],
         [{}, "hello", "world"]
     ]);
@@ -467,7 +474,6 @@ fn static_table_hspan_1() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_hspan_doesnot_for_for_layers() {
     let table = static_table!([
@@ -485,11 +491,16 @@ fn static_table_hspan_doesnot_for_for_layers() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_hspan_and_vspan_cell() {
     let table = static_table!([
-        [{"Hello"; 2}, "World"],
+        [
+            {
+                "Hello";
+                2
+            },
+            "World"
+        ],
         [{}, "hello", "world", "!!!"],
         [{}, "hello", "world"]
     ]);
@@ -503,14 +514,9 @@ fn static_table_hspan_and_vspan_cell() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_hspan_const() {
-    let table = static_table!([
-        [{"Hello"}, {"World"}],
-        [{}; 3],
-        [{}, "hello", "world"]
-    ]);
+    let table = static_table!([[{ "Hello" }, { "World" }], [{}; 3], [{}, "hello", "world"]]);
     let expected = "+-------+-------+-------+\n\
                           | Hello | World |       |\n\
                           +       +       +-------+\n\
@@ -521,10 +527,12 @@ fn static_table_hspan_const() {
     assert_eq!(table, expected);
 }
 
-#[rustfmt::skip]
 #[test]
 fn static_table_vspan_const_row() {
-    let table = static_table!([[{"Hello World!"; 3}],]);
+    let table = static_table!([[{
+        "Hello World!";
+        3
+    }],]);
     let expected = "+----+----+----+\n\
                           | Hello World! |\n\
                           +----+----+----+";
@@ -551,23 +559,3 @@ fn static_table_with_theme_padding_margin() {
     );
     assert_eq!(table, expected);
 }
-
-#[test]
-fn static_table_pool_0() {
-    #[rustfmt::skip]
-    let table = static_table!([
-        [{{"Hello"}}, "World"],
-        ["123", "456"],
-        [{{"7"}}, "8"],
-    ]);
-    assert_eq!(
-        table,
-        "+-------+-------+\n\
-         | Hello | World |\n\
-         +-------+-------+\n\
-         | 123   | 456   |\n\
-         +-------+-------+\n\
-         | 7     | 8     |\n\
-         +-------+-------+"
-    );
-}
diff --git a/static_table/tests/syntax.rs b/static_table/tests/syntax.rs
index 072fa4a..e67c251 100644
--- a/static_table/tests/syntax.rs
+++ b/static_table/tests/syntax.rs
@@ -63,32 +63,6 @@ fn static_table_layer_0() {
     ]);
 }
 
-#[test]
-fn static_table_layer_1() {
-    static_table!([
-        [{ "Hello World", 2, 3 }],
-        [{{ 1, 2 }}, 4],
-        [1, {{{ 2 }}}, 123]
-    ]);
-}
-
-#[test]
-fn static_table_empty_layer() {
-    static_table!([
-        [{}, "Hello World", {}],
-        [{ {} }, 4],
-        [
-            1,
-            {
-                {
-                    {}
-                }
-            },
-            123
-        ]
-    ]);
-}
-
 #[test]
 fn static_table_style() {
     static_table!([[1, 2, 123], [1, 2, 123], [1, 2, 123]], THEME = "MODERN");