tabled
An easy to use library for pretty printing tables of Rust structs and enums.
Table of Contents
Usage
To print a list of structs or enums as a table your types should implement the the Tabled trait or derive with a #[derive(Tabled)] macro.
use ;
let languages = vec!;
let table = new.to_string;
let expected = "+------+----------------+---------------+\n\
| name | designed_by | invented_year |\n\
+------+----------------+---------------+\n\
| C | Dennis Ritchie | 1972 |\n\
+------+----------------+---------------+\n\
| Rust | Graydon Hoare | 2010 |\n\
+------+----------------+---------------+\n\
| Go | Rob Pike | 2009 |\n\
+------+----------------+---------------+\n";
assert_eq!;
Most of the default types implement the trait out of the box.
use TableIteratorExt;
let some_numbers = ;
let table = some_numbers.table;
Settings
In this section is listened a set of settings you can apply for your table.
Style
Themes
There are a list of ready to use styles. Each style can be castomized.
A custom style also can be created from scratch.
A style can be used by passing it to .with method of Table.
use ;
let table = new.with;
Bellow rendered a list of pre configured styles.
If you think that there's some valuable style to be added, Please open an issue.
ASCII
+------+----------------+---------------+
| name | designed_by | invented_year |
+------+----------------+---------------+
| C | Dennis Ritchie | 1972 |
+------+----------------+---------------+
| Rust | Graydon Hoare | 2010 |
+------+----------------+---------------+
| Go | Rob Pike | 2009 |
+------+----------------+---------------+
Psql
name | designed_by | invented_year
------+----------------+---------------
C | Dennis Ritchie | 1972
Rust | Graydon Hoare | 2010
Go | Rob Pike | 2009
Github Markdown
| name | designed_by | invented_year |
|------+----------------+---------------|
| C | Dennis Ritchie | 1972 |
| Rust | Graydon Hoare | 2010 |
| Go | Rob Pike | 2009 |
Modern
┌──────┬────────────────┬───────────────┐
│ name │ designed_by │ invented_year │
├──────┼────────────────┼───────────────┤
│ C │ Dennis Ritchie │ 1972 │
├──────┼────────────────┼───────────────┤
│ Rust │ Graydon Hoare │ 2010 │
├──────┼────────────────┼───────────────┤
│ Go │ Rob Pike │ 2009 │
└──────┴────────────────┴───────────────┘
ReStructuredText
====== ================ ===============
name designed_by invented_year
====== ================ ===============
C Dennis Ritchie 1972
Rust Graydon Hoare 2010
Go Rob Pike 2009
====== ================ ===============
Extended
╔══════╦════════════════╦═══════════════╗
║ name ║ designed_by ║ invented_year ║
╠══════╬════════════════╬═══════════════╣
║ C ║ Dennis Ritchie ║ 1972 ║
╠══════╬════════════════╬═══════════════╣
║ Rust ║ Graydon Hoare ║ 2010 ║
╠══════╬════════════════╬═══════════════╣
║ Go ║ Rob Pike ║ 2009 ║
╚══════╩════════════════╩═══════════════╝
Dots
.........................................
: name : designed_by : invented_year :
:......:................:...............:
: C : Dennis Ritchie : 1972 :
: Rust : Graydon Hoare : 2010 :
: Go : Rob Pike : 2009 :
:......:................:...............:
Blank
name designed_by invented_year
C Dennis Ritchie 1972
Rust Graydon Hoare 2010
Go Rob Pike 2009
Custom
You can modify existing styles to fit your needs.
let style = modern.header_off.horizontal_off;
The style will look like the following.
┌──────┬────────────────┬───────────────┐
│ name │ designed_by │ invented_year │
│ C │ Dennis Ritchie │ 1972 │
│ Rust │ Graydon Hoare │ 2010 │
│ Go │ Rob Pike │ 2009 │
└──────┴────────────────┴───────────────┘
You can find more methods which are available in the documentation
Cell Border
Sometimes tabled::Style settings are not enough.
Sometimes it's nesessary to change a border of a particular cell.
For this porpouse you can use Border.
use ;
let data = ;
let table = data.table
.with
.with;
let expected = "+xxxxx+xxxxx+\n\
| 0 | 1 |\n\
+-----+-----+\n\
| 123 | 456 |\n\
+-----+-----+\n\
| 789 | 000 |\n\
+-----+-----+\n";
assert_eq!;
Text in a top border
You can write a custom text at the top border if it's present in a style.
use ;
let table = new
.with;
assert_eq!;
Alignment
You can set a horizontal and vertical alignment for a Header, Column, Row or Full set of cells.
use ;
data.table
.with;
Format
The Format function provides an interface for a modification of cells.
use ;
new
.with;
.with
It's also possible to use functions with signature Fn(&str) -> String as a formatter.
use ;
new
.with
.with;
IMPORTANT: you may need to specify type in your lambda otherwise compiler may be disagreed to work :)
Padding
The Padding structure provides an interface for a left, right, top and bottom padding of cells.
use ;
new
.with;
// It's possible to set a fill char for padding.
new
.with;
Margin
Margin sets an outside of the grid ident (top, bottom, left, right).
use ;
new
.with;
An output would depend on the data. But it could look like the following.
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
>>>┌───────────┬───────────┐<<<<
>>>│ feature │ released │<<<<
>>>│ margin │ 0.6.0 │<<<<
>>>└───────────┴───────────┘<<<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Max width
MaxWidth sets a maximum width of an object.
While tinkering content we don't forget about its color.
use ;
// Truncating content to 10 chars in all rows except a header.
data.table
.with;
// Wrapping content by new lines after 10 chars in a last row.
data.table
.with;
MaxWidth also can be used to set a maximum width of a whole table.
use ;
data.table.with;
It can be used in combination with MinWidth.
Min width
MinWidth sets a minimal width of an object.
While tinkering content we don't forget about its color.
use ;
data.table
.with;
MinWidth also can be used to set a minimum width of a whole table.
use ;
data.table.with;
It can be used in combination with MaxWidth.
Rotate
You can rotate table using tabled::Rotate.
Imagine you have a table already. And the output may look like this.
┌────┬──────────────┬───────────────────────────┐
│ id │ destribution │ link │
├────┼──────────────┼───────────────────────────┤
│ 0 │ Fedora │ https://getfedora.org/ │
├────┼──────────────┼───────────────────────────┤
│ 2 │ OpenSUSE │ https://www.opensuse.org/ │
├────┼──────────────┼───────────────────────────┤
│ 3 │ Endeavouros │ https://endeavouros.com/ │
└────┴──────────────┴───────────────────────────┘
Now we will add the following modificator and the output will be;
table.with
┌──────────────┬────────────────────────┬───────────────────────────┬──────────────────────────┐
│ link │ https://getfedora.org/ │ https://www.opensuse.org/ │ https://endeavouros.com/ │
├──────────────┼────────────────────────┼───────────────────────────┼──────────────────────────┤
│ destribution │ Fedora │ OpenSUSE │ Endeavouros │
├──────────────┼────────────────────────┼───────────────────────────┼──────────────────────────┤
│ id │ 0 │ 2 │ 3 │
└──────────────┴────────────────────────┴───────────────────────────┴──────────────────────────┘
Disable
You can remove certain rows or columns from the table.
use ;
data.table
.with
.with;
Extract
You can Extract segments of a table to focus on a reduced number of rows and columns.
use ;
let rows = 1..3;
let columns = 1..;
new
.with;
+-------+-------------+-----------+
| i32 | &str | bool |
+-------+-------------+-----------+ +-------------+-----------+
| : 0 : | : Grodno : | : true : | | : Grodno : | : true : |
+-------+-------------+-----------+ = +-------------+-----------+
| : 1 : | : Minsk : | : true : | | : Minsk : | : true : |
+-------+-------------+-----------+ +-------------+-----------+
| : 2 : | : Hamburg : | : false : |
+-------+-------------+-----------+
| : 3 : | : Brest : | : true : |
+-------+-------------+-----------+
Refinishing
For styles with unique corner and edge textures it is possible to reapply a table style once a Table extract has been created.
use ;
let rows = 1..3;
let columns = 1..;
new
.with
.with;
Raw extract
┼───────────────────────────┼──────────────────┼──────────────┤
│ The Dark Side of the Moon │ 01 March 1973 │ Unparalleled │
┼───────────────────────────┼──────────────────┼──────────────┤
│ Rumours │ 04 February 1977 │ Outstanding │
┼───────────────────────────┼──────────────────┼──────────────┤
Refinished extract
┌───────────────────────────┬──────────────────┬───────────────┐
│ The Dark Side of the Moon │ 01 March 1973 │ Unparalleled │
├───────────────────────────┼──────────────────┼───────────────┤
│ Rumours │ 04 February 1977 │ Outstanding │
└───────────────────────────┴──────────────────┴───────────────┘
Header and Footer
You can add a Header and Footer to display some information.
use ;
new
.with
.with
A look will differ from a style you choose. But it's how it may look like.
┌────────────────────────────────────────────────────────────┐
│ Tabled Name │
├────────────────────────────────────────────────────────────┤
...
├───────┼──────────────┼─────────┼───────────────────────────┤
│ 3 elements │
└────────────────────────────────────────────────────────────┘
You can also add a full row on any line using tabled::Panel.
Concat
You can concatanate 2 tables using Concat.
It will stick 2 tables together either vertically or horizontally.
let t1: Table = ...;
let t2: Table = ...;
let t3: Table = t1.with;
Highlight
Highlight can be used to change a borders of target sector.
Here's an example.
use ;
let data = vec!;
let table = data.table
.with
.with;
The printed table would be like the following.
*************
* 0 │ 1 │ 2 *
*****───┼───*
│ A * B │ C *
├───*****───*
│ D │ E * F *
└───┴───*****
Column span
It's possible to have a horizontal (column) span of a cell.
The code example and the resulting table.
use ;
+---+---+---+
| 0 |
+---+---+---+
| A | C |
+---+---+---+
| D | E | F |
+---+---+---+
Derive
To be able to use a Tabled macros each field must implement std::fmt::Display
otherwise it will not work.
The following example will cause a error.
use Tabled;
;
Column name override
You can use a #[tabled(rename = "")] attribute to override a column name.
use Tabled;
Hide a column
You can mark filds as hidden in which case they fill be ignored and not be present on a sheet.
A similar affect could be achived by the means of a Disable setting.
use Tabled;
Custom field formatting
#[derive(Tabled)] is possible only when all fields implement a Display trait.
However, this may be often not the case for example when a field uses the Option type.
There's 2 common ways how to solve this:
- Implement
Tabledtrait manually for a type. - Wrap
Optionto something likeDisplayedOption<T>(Option<T>)and implement a Display trait for it.
Or to use an attribute #[tabled(display_with = "func")] for the field. To use it you must provide a function name in a display_with parameter.
use Tabled;
Inline
It's possible to inline internal data if it implements Tabled trait.
Use #[tabled(inline)] for it.
Also you can set a prefix which will be used for all inlined elements use #[tabled(inline("prefix>>"))] for it.
use Tabled;
And it works for enums as well.
use Tabled;
Features
Color
The library doesn't bind you in usage of any color library but to be able to work corectly with color input you should provide a --features color.
use ;
new
.with
.with
.with
.with;

Tuple combination
You also can combine objets which implements Tabled by means of tuples, you will get a combined columns of them.
use ;
] &'static str);
let data = vec!;
let table = new.with.to_string;
assert_eq!;
Object
You can peak your target for settings using and and not methods for an object.
use ;
Full.not // peak all cells except header
first.and.not // peak a header and first column except a (0, 0) cell
Views
Tabled supports not only Table view!
Expanded display
You can use ExpanedDisplay if your data structure has a lot of fields.
Here's an example.
use ;
You'll see the following.
-[ RECORD 0 ]------
name | Manjaro
is_active | true
is_cool | true
-[ RECORD 1 ]------
name | Debian
is_active | true
is_cool | true
-[ RECORD 2 ]------
name | Debian
is_active | true
is_cool | true
Notes
ANSI escape codes
By default tabled doesn't handle ANSI escape codes.
By default such things as hyperlinks, blinking and others things which can be achived via ANSI codes might not work correctly.
tabled support it by setting a color feature.
= { = "*", = ["color"] }
Dynamic table
It might be hard to build a table using Tabled trait, if you have a data set which structure is determined at runtime.
In such situation you can use a Builder.
use ;
Emoji
The library support emojies out of the box but be aware that some of the terminals and editors may not render them as you would expect.
Let's add emojies to an example from a Usage section.
let languages = vec!;
The resultant table will look like the following.
As you can see Github triks a bit a return table, but GNOME terminal and Alacritty terminal handles it correctly.
+---------+----------------+---------------+
| name | designed_by | invented_year |
+---------+----------------+---------------+
| C 💕 | Dennis Ritchie | 1972 |
+---------+----------------+---------------+
| Rust 👍 | Graydon Hoare | 2010 |
+---------+----------------+---------------+
| Go 🧋 | Rob Pike | 2009 |
+---------+----------------+---------------+