{"id":13487011,"url":"https://github.com/zhiburt/tabled","last_synced_at":"2025-03-27T21:31:50.108Z","repository":{"id":37227820,"uuid":"242960969","full_name":"zhiburt/tabled","owner":"zhiburt","description":"An easy to use library for pretty print tables of Rust structs and enums.","archived":false,"fork":false,"pushed_at":"2024-08-11T06:26:02.000Z","size":47994,"stargazers_count":1911,"open_issues_count":80,"forks_count":77,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-08-13T11:27:16.363Z","etag":null,"topics":["cli","hacktoberfest","pretty-print","prettytable","rust","table","table-generator"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zhiburt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-25T09:31:25.000Z","updated_at":"2024-08-13T04:27:15.000Z","dependencies_parsed_at":"2024-02-17T08:25:18.545Z","dependency_job_id":"911117cd-d8f2-4c25-b2d6-0cf54c7dd8f1","html_url":"https://github.com/zhiburt/tabled","commit_stats":{"total_commits":947,"total_committers":29,"mean_commits":32.6551724137931,"dds":0.06863780359028515,"last_synced_commit":"bbf223f889f59bb632a0ec0f1721a66f43dc5c01"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhiburt%2Ftabled","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhiburt%2Ftabled/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhiburt%2Ftabled/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhiburt%2Ftabled/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zhiburt","download_url":"https://codeload.github.com/zhiburt/tabled/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245927294,"owners_count":20695206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","hacktoberfest","pretty-print","prettytable","rust","table","table-generator"],"created_at":"2024-07-31T18:00:54.315Z","updated_at":"2025-03-27T21:31:50.060Z","avatar_url":"https://github.com/zhiburt.png","language":"Rust","funding_links":[],"categories":["Rust","cli","Libraries","库 Libraries"],"sub_categories":["Command-line","命令行 Command-line"],"readme":"[\u003cimg alt=\"github\" src=\"https://img.shields.io/badge/github-zhiburt/tabled-8da0cb?style=for-the-badge\u0026labelColor=555555\u0026logo=github\" height=\"20\"\u003e](https://github.com/zhiburt/tabled/)\n[\u003cimg alt=\"crates.io\" src=\"https://img.shields.io/crates/v/tabled.svg?style=for-the-badge\u0026color=fc8d62\u0026logo=rust\" height=\"20\"\u003e](https://crates.io/crates/tabled)\n[\u003cimg alt=\"docs.rs\" src=\"https://img.shields.io/badge/docs.rs-tabled-66c2a5?style=for-the-badge\u0026labelColor=555555\u0026logo=docs.rs\" height=\"20\"\u003e](https://docs.rs/tabled)\n[\u003cimg alt=\"build status\" src=\"https://img.shields.io/github/actions/workflow/status/zhiburt/tabled/ci.yml?branch=master\u0026style=for-the-badge\" height=\"20\"\u003e](https://github.com/zhiburt/tabled/actions)\n[\u003cimg alt=\"coverage\" src=\"https://img.shields.io/coveralls/github/zhiburt/tabled/master?style=for-the-badge\" height=\"20\"\u003e](https://coveralls.io/github/zhiburt/tabled)\n[\u003cimg alt=\"dependency status\" src=\"https://deps.rs/repo/github/zhiburt/tabled/status.svg?style=for-the-badge\" height=\"20\"\u003e](https://deps.rs/repo/github/zhiburt/tabled)\n\n# \u003ca href=\"#\"\u003e \u003cimg alt=\"logo\" align=\"center\" src=\"https://raw.githubusercontent.com/zhiburt/tabled/86ac146e532ce9f7626608d7fd05072123603a2e/assets/tabled-gear.svg\" href=\"/\" width=65\u003e \u003c/a\u003e \u003cspan\u003e tabled \u003c/span\u003e\n\nAn easy to use library for pretty printing tables of Rust `struct`s and `enum`s.\n\nYou can do a lot of things with the library.\\\nIf it does not do something which you feel it should or it is not clear how to, please file an issue.\n\nThis README contains lots of information but it might still be not complete,\\\nyou can find more examples in the **[examples](/tabled/examples/)** folder.\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/zhiburt/tabled/assets/assets/preview-show.gif\"\u003e\n  \u003cimg alt=\"Preview\" src=\"https://raw.githubusercontent.com/zhiburt/tabled/assets/assets/preview-show-light.gif\"\u003e\n\u003c/picture\u003e\n\n## Table of Contents\n\n- [Usage](#usage)\n- [Settings](#settings)\n  - [Style](#style)\n    - [Styles](#styles)\n      - [ascii](#ascii)\n      - [modern](#modern)\n      - [sharp](#sharp)\n      - [rounded](#rounded)\n      - [extended](#extended)\n      - [psql](#psql)\n      - [markdown](#markdown)\n      - [re\\_structured\\_text](#re_structured_text)\n      - [dots](#dots)\n      - [ascii\\_rounded](#ascii_rounded)\n      - [blank](#blank)\n      - [empty](#empty)\n    - [Customization](#style-customization)\n    - [Cell Border](#cell-border)\n    - [Text on borders](#text-on-borders)\n    - [Colorize borders](#colorize-borders)\n    - [Theme](#theme)\n      - [Colorize content](#colorize-content)\n      - [Column names](#colorize-content)\n  - [Alignment](#alignment)\n  - [Format](#format)\n  - [Padding](#padding)\n  - [Margin](#margin)\n    - [Color](#margin-color)\n  - [Shadow](#shadow)\n  - [Width](#width)\n    - [Truncate](#truncate)\n    - [Wrapping](#wrapping)\n    - [Increase width](#increase-width)\n    - [Justify](#justify)\n    - [Priority](#priority)\n    - [Percent](#percent)\n  - [Height](#height)\n    - [Height Increase](#height-increase)\n    - [Height Limit](#height-limit)\n  - [Rotate](#rotate)\n  - [Remove](#remove)\n  - [Extract](#extract)\n  - [Header and Footer and Panel](#header-and-footer-and-panel)\n  - [Merge](#merge)\n  - [Concat](#concat)\n  - [Highlight](#highlight)\n  - [Span](#span)\n    - [Horizontal span](#horizontal-span)\n    - [Vertical span](#vertical-span)\n  - [Split](#split)\n  - [Duplicate](#duplicate)\n- [Derive](#derive)\n  - [Override a column name](#override-a-column-name)\n  - [Hide a column](#hide-a-column)\n  - [Set column order](#set-column-order)\n  - [Format fields](#format-fields)\n  - [Format headers](#format-headers)\n  - [Inline](#inline)\n- [Table types](#table-types)\n  - [`Table`](#table)\n  - [`IterTable`](#itertable)\n  - [`CompactTable`](#compacttable)\n  - [`PoolTable`](#pooltable)\n  - [`ExtendedTable`](#extendedtable)\n  - [`Table::kv`](#tablekv)\n- [Tips and Tricks](#tips-and-tricks)\n  - [`std::fmt::*` options](#std::fmt::*-options)\n  - [Tuple combination](#tuple-combination)\n  - [Tuple options](#tuple-options)\n  - [Object](#object)\n  - [Builder](#builder)\n  - [Macros](#macros)\n    - [`col` and `row`](#col-and-row)\n    - [`static_table`](#static_table)\n- [Features](#features)\n- [Formats](#formats)\n  - [`json` format](#json-format)\n  - [`ron` format](#ron-format)\n  - [`csv` format](#csv-format)\n  - [`toml` format](#toml-format)\n  - [`html` format](#html-format)\n- [Notes](#notes)\n  - [Charset](#charset)\n  - [ANSI escape codes](#ansi-escape-codes)\n  - [Emoji](#emoji)\n  - [Semver](#semver)\n  - [MSRV](#msrv)\n  - [Comparison](#comparison)\n\n## Usage\n\nTo print a list of structs or enums as a table, there are 2 ways.\n\n* Using a builder pattern to build a table step by step.\n* Implement a `Tabled` trait for your type (or annotate your type with a derive macro) and use an iterator of this type.\n\nA builder pattern gets handy when a data schema is unknown,\nwhile a typed struct is useful in cases where we know the data structure beforehand.\n\nBoth methods are demonstrated below, starting with the derive method.\n\n```rust\nuse tabled::{Tabled, Table};\n\n#[derive(Tabled)]\nstruct Language {\n    name: \u0026'static str,\n    designed_by: \u0026'static str,\n    invented_year: usize,\n}\n\nlet languages = vec![\n    Language { name: \"C\",    designed_by: \"Dennis Ritchie\",  invented_year: 1972 },\n    Language { name: \"Rust\", designed_by: \"Graydon Hoare\",   invented_year: 2010 },\n    Language { name: \"Go\",   designed_by: \"Rob Pike\",        invented_year: 2009 },\n];\n\nlet table = Table::new(languages).to_string();\n\nlet expected = \"+------+----------------+---------------+\\n\\\n                | name | designed_by    | invented_year |\\n\\\n                +------+----------------+---------------+\\n\\\n                | C    | Dennis Ritchie | 1972          |\\n\\\n                +------+----------------+---------------+\\n\\\n                | Go   | Rob Pike       | 2009          |\\n\\\n                +------+----------------+---------------+\\n\\\n                | Rust | Graydon Hoare  | 2010          |\\n\\\n                +------+----------------+---------------+\";\n\nassert_eq!(table, expected);\n```\n\nThe next example illustrates a builder pattern.\n\n```rust\nuse std::{collections::HashMap, ops::AddAssign};\nuse tabled::{builder::Builder, settings::Style};\n\nlet lyrics = r#\"\n    … So, so you think you can tell heaven from hell?\n    Blue skies from pain?\n    Can you tell a green field from a cold steel rail?\n    A smile from a veil?\n    Do you think you can tell?\n\"#;\n\nlet mut map: HashMap\u003c\u0026str, usize\u003e = HashMap::new();\nfor line in lyrics.lines() {\n    for word in line.split_whitespace() {\n        map.entry(word).or_default().add_assign(1);\n    }\n}\n\nlet mut table = Builder::from(map).build();\ntable.with(Style::modern_rounded().remove_horizontal());\n\nlet expected =  \"╭────────┬───╮\\n\\\n                 │ you    │ 5 │\\n\\\n                 │ smile  │ 1 │\\n\\\n                 │ veil?  │ 1 │\\n\\\n                 │ tell?  │ 1 │\\n\\\n                 │ …      │ 1 │\\n\\\n                 │ tell   │ 2 │\\n\\\n                 │ think  │ 2 │\\n\\\n                 ╰────────┴───╯\"\n\nassert_eq!(table.to_string(), expected);\n```\n\n## Settings\n\nThere are a lot of [*functions*](#settings) available for your tables,\nas well as helpers such as [*derive macros*](#derive) and [*proc macros*](#macros).\n\nThis section lists the settings you can apply to your table.\nAll of the settings are leveraged by `Table::with` and `Table::modify`.\n\nBut you can tweak things yourself by using `table.get_records_mut()` and `table.get_config_mut().`\\\nor by creating a new setting, which is a simple do.\n\n### Style\n\n`Style` sole purpouse is to configure table look.\n`Style` primarily usage is in `const`/`static` context.\nIf you want to peak style at runtime `Theme` might be better suited for it.\n\nAny `Style` can be customized.\nAs well as a custom `Style` can be created from scratch.\n\n```rust\nuse tabled::{Table, Style};\n\nlet mut table = Table::new(\u0026data);\ntable.with(Style::psql());\n```\n\n#### Styles\n\nThere are numerous preconfigured styles.\nBelow there is a rendered list of them.\n\nIf you think that there's some valuable style to be added,\nplease open an issue.\n\n##### ascii\n\n```text\n+------+----------------+---------------+\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```\n\n##### modern\n\n```text\n┌──────┬────────────────┬───────────────┐\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```\n\n##### sharp\n\n```text\n┌──────┬────────────────┬───────────────┐\n│ name │ designed_by    │ invented_year │\n├──────┼────────────────┼───────────────┤\n│ C    │ Dennis Ritchie │ 1972          │\n│ Rust │ Graydon Hoare  │ 2010          │\n│ Go   │ Rob Pike       │ 2009          │\n└──────┴────────────────┴───────────────┘\n```\n\n##### rounded\n\n```text\n╭──────┬────────────────┬───────────────╮\n│ name │ designed_by    │ invented_year │\n├──────┼────────────────┼───────────────┤\n│ C    │ Dennis Ritchie │ 1972          │\n│ Rust │ Graydon Hoare  │ 2010          │\n│ Go   │ Rob Pike       │ 2009          │\n╰──────┴────────────────┴───────────────╯\n```\n\n##### extended\n\n```text\n╔══════╦════════════════╦═══════════════╗\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```\n\n##### psql\n\n```text\n name | designed_by    | invented_year \n------+----------------+---------------\n C    | Dennis Ritchie | 1972          \n Rust | Graydon Hoare  | 2010          \n Go   | Rob Pike       | 2009          \n```\n\n##### markdown\n\n```text\n| name | designed_by    | invented_year |\n|------|----------------|---------------|\n| C    | Dennis Ritchie | 1972          |\n| Rust | Graydon Hoare  | 2010          |\n| Go   | Rob Pike       | 2009          |\n```\n\n##### re_structured_text\n\n```text\n====== ================ ===============\n name   designed_by     invented_year \n====== ================ ===============\n C      Dennis Ritchie   1972          \n Rust   Graydon Hoare    2010          \n Go     Rob Pike         2009          \n====== ================ ===============\n```\n\n##### dots\n\n```text\n.........................................\n: name : designed_by    : invented_year :\n:......:................:...............:\n: C    : Dennis Ritchie : 1972          :\n: Rust : Graydon Hoare  : 2010          :\n: Go   : Rob Pike       : 2009          :\n:......:................:...............:\n```\n\n##### ascii_rounded\n\n```text\n.---------------------------------------.\n| name | designed_by    | invented_year |\n| C    | Dennis Ritchie | 1972          |\n| Rust | Graydon Hoare  | 2010          |\n| Go   | Rob Pike       | 2009          |\n'---------------------------------------'\n```\n\n##### blank\n\n```text\n name   designed_by      invented_year \n C      Dennis Ritchie   1972          \n Rust   Graydon Hoare    2010          \n Go     Rob Pike         2009                 \n```\n\n##### empty\n\n```text\nname designed_by    invented_year\nC    Dennis Ritchie 1972         \nRust Graydon Hoare  2010         \nGo   Rob Pike       2009         \n```\n\n#### Style customization\n\nYou can modify existing styles to fit your needs.\nMind that all modifications are done at compile time.\n\nCheck the [documentation](https://docs.rs/tabled/latest/tabled/settings/style/struct.Style.html)\nfor more customization options.\n\nIf you can't make desicions at compile time - use `Theme`.\n\nAn example for castomization,\nwhere we remove all vertical and horizontal lines but adding single line.\n\n```rust\nuse tabled::settings::{Style, HorizontalLine, VerticalLine};\n\nlet style = Style::modern()\n    .horizontals([(1, HorizontalLine::inherit(Style::modern()).horizontal('═'))])\n    .verticals([(1, VerticalLine::inherit(Style::modern()))])\n    .remove_horizontal()\n    .remove_vertical();\n```\n\nThis style will look like the next table:\n\n```rust\n┌──────┬───────────────────────────────┐\n│ name │ designed_by     invented_year │\n├══════┼═══════════════════════════════┤\n│ C    │ Dennis Ritchie  1972          │\n│ Go   │ Rob Pike        2009          │\n│ Rust │ Graydon Hoare   2010          │\n└──────┴───────────────────────────────┘\n```\n\nAs was said doing customization at `const`ant context is not always a best choise,\nyou may need to change a style at runtime, you may use `Theme` object to do that.\n\n`Theme` is quite powerful by itself,\nyou can check it in the [documentation](https://docs.rs/tabled/latest/tabled/settings/themes/struct.Theme.html).\n\n```rust\nuse tabled::grid::config::{Border, HorizontalLine};\nuse tabled::settings::Theme;\n\nlet mut style = Theme::default();\nstyle.insert_horizontal_line(1, HorizontalLine::full('-', '-', '+', '+'));\nstyle.set_frame(Border::filled('+'));\n```\n\nThis style will look like the following:\n\n```rust\n+++++++++++++++++++++++++++++++++++++++\n+ name  designed_by     invented_year +\n+-------------------------------------+\n+ C     Dennis Ritchie  1972          +\n+ Go    Rob Pike        2009          +\n+ Rust  Graydon Hoare   2010          +\n+++++++++++++++++++++++++++++++++++++++\n```\n\n#### Cell Border\n\nSometimes `tabled::Style` settings are not enough.\nSometimes it's necessary to change a border of a particular cell.\n\nFor this purpose you can use `Border`.\n\n```rust\nuse tabled::{\n    settings::{object::Rows, Border, Style},\n    assert::assert_table,\n    Table,\n};\n\nlet data = [[\"123\", \"456\"], [\"789\", \"000\"]];\n\nlet mut table = Table::new(data);\ntable.with(Style::ascii());\ntable.modify(\n    Rows::first(),\n    Border::inherit(Style::ascii())\n        .top('=')\n        .corner_top_left('=')\n        .corner_top_right('='),\n);\n\nassert_table!(\n    table,\n    \"=============\"\n    \"| 0   | 1   |\"\n    \"+-----+-----+\"\n    \"| 123 | 456 |\"\n    \"+-----+-----+\"\n    \"| 789 | 000 |\"\n    \"+-----+-----+\"\n);\n```\n\n#### Text on borders\n\nYou can set a string to a horizontal border line.\n\n```rust\nuse tabled::{settings::style::LineText, Table};\nuse tabled::settings::object::Rows;\n\nlet mut table = Table::new([\"Hello World\"]);\ntable.with(LineText::new(\".table\", Rows::first()).offset(2));\n\nassert_eq!(\n    table.to_string(),\n    \"+-.table------+\\n\\\n     | \u0026str        |\\n\\\n     +-------------+\\n\\\n     | Hello World |\\n\\\n     +-------------+\"\n);\n```\n\nYou can as well stick the text to a particular side using `Alignment`.\n\n```rust\nuse tabled::settings::object::Rows;\nuse tabled::{\n    settings::{style::LineText, Alignment},\n    Table,\n};\n\nlet mut table = Table::new([\"Hello World\"]);\ntable.with(LineText::new(\"TABLE NAME\", Rows::first()).align(Alignment::center()));\n\nassert_eq!(\n    table.to_string(),\n    \"+-.table------+\\n\\\n     | \u0026str        |\\n\\\n     +-------------+\\n\\\n     | Hello World |\\n\\\n     +-------------+\"\n);\n```\n\nSometimes though it's not convenient to set a string.\nBut rather necessary to set a custom `char`acter.\n\nYou can use `LineChar` to achieve this.\n\n```rust\nuse tabled::{\n    settings::{object::Columns, style::{LineChar, Offset, Style}},\n    Table,\n};\n\nlet mut table = Table::new([[\"Hello\", \"World\", \"!\"]]);\ntable.with(Style::markdown());\ntable.modify(Columns::new(..), LineChar::horizontal(':', Offset::Begin(0)));\ntable.modify(Columns::new(..), LineChar::horizontal(':', Offset::End(0)));\n```\n\n```text\n| 0     | 1     | 2 |\n|:-----:|:-----:|:-:|\n| Hello | World | ! |\n```\n\n#### Colorize borders\n\nYou can set colors of borders using `Color` and `BorderColor`.\n\nIf you need to higlight a border of a set of cells check out [`Highlight`](#highlight)\n\n\n```rust\nuse tabled::settings::{style::BorderColor, Color};\nuse tabled::settings::object::Columns;\n\n// Doing it this will set a frame of the table to green color.\ntable.with(BorderColor::filled(Color::FG_GREEN));\n\n// Doing it this will set borders of all cells in 2nd column green color.\ntable.modify(Columns::single(2), BorderColor::filled(Color::FG_GREEN));\n```\n\n#### Theme\n\nIt was considered that having a few atomic settings is better rather then have one but feature full.\n\nBut `tabled::settings::themes::*` diverges a bit from this idea.\nIt contains a list of settings which do bigger changes to the table.\n\nThe first one is `Theme` itself.\nYou can change layout, set style, colorize, config borders and even reverse the table with it.\n\n```rust\nuse tabled::settings::{\n    object::{Columns, Object},\n    Alignment, Style, Theme,\n};\n\nlet mut style = Theme::from_style(Style::ascii_rounded());\nstyle.remove_border_horizontal();\nstyle.remove_border_vertical();\nstyle.set_footer(true);\n\ntable.with(style);\ntable.with(Alignment::center());\ntable.modify(Columns::first(), Alignment::left());\ntable.modify(Columns::last(), Alignment::right());\n```\n\nYou'll see the following output when run against the first example.\n\n```text\n.---------------------------------------------------------------------------.\n| name                  C             Go          Rust                 name |\n| designed_by     Dennis Ritchie   Rob Pike   Graydon Hoare     designed_by |\n| invented_year        1972          2009         2010        invented_year |\n'---------------------------------------------------------------------------'\n```\n\n##### Colorize content\n\nYou can colorize the content by the pattern or a specific cell.\n\n```rust\nuse std::iter::FromIterator;\n\nuse tabled::{\n    builder::Builder,\n    settings::{object::Rows, style::Style, themes::Colorization, Color},\n};\n\nlet data = vec![\n    vec![\"Word\", \"Translation\", \"Lang\"],\n    vec![\"World\", \"le monde\", \"FR\"],\n    vec![\"World\", \"Welt\", \"DE\"],\n];\n\nlet mut table = Builder::from_iter(data).build();\ntable\n    .with(Style::empty())\n    .with(Colorization::columns([\n        Color::BG_GREEN | Color::FG_BLACK,\n        Color::BG_MAGENTA | Color::FG_BLACK,\n        Color::BG_YELLOW | Color::FG_BLACK,\n    ]))\n    .with(Colorization::exact([Color::BG_WHITE | Color::FG_BLACK], Rows::first()))\n    .modify(Rows::first(), Color::BG_BLUE | Color::FG_BLACK);\n\nprintln!(\"{table}\");\n```\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zhiburt/tabled/assets/20165848/5dcff779-0aa5-499e-bb08-4373459c9db6\"\u003e\n  \u003cimg alt=\"Preview\" src=\"https://github.com/zhiburt/tabled/assets/20165848/d6f9a936-9d33-4d0b-acfc-9ef875d59cc3\"\u003e\n\u003c/picture\u003e\n\n##### Column names\n\nYou can move the header right to the borders.\n\n```rust\nuse tabled::{\n    builder::Builder,\n    settings::{style::Style, themes::ColumnNames},\n};\n\nlet data = vec![\n    vec![String::from(\"header 0\"), String::from(\"header 1\")],\n    vec![String::from(\"Hello\"), String::from(\"World\")],\n    vec![String::from(\"Bonjour\"), String::from(\"le monde\")],\n    vec![String::from(\"Hallo\"), String::from(\"Welt\")],\n];\n\nlet mut table = Builder::from(data).build();\ntable.with(Style::modern());\ntable.with(ColumnNames::default());\n\nprintln!(\"{table}\");\n```\n\n```text\n┌header 0─┬header 1──┐\n│ Hello   │ World    │\n├─────────┼──────────┤\n│ Bonjour │ le monde │\n├─────────┼──────────┤\n│ Hallo   │ Welt     │\n└─────────┴──────────┘\n```\n\n### Alignment\n\nYou can set a horizontal and vertical alignment for any `Object` (e.g `Columns`, `Rows`)\\ using `Alignment`.\n\n```rust\nuse tabled::settings::{object::Segment, Alignment};\nuse tabled::Table;\n\nlet data = vec![\n    (\"text\", \"Multiline\\ntext\"),\n    (\"text\", \"text\"),\n];\n\nlet mut table = Table::new(data);\ntable.modify(Segment::all(), (Alignment::right(), Alignment::bottom()));\n\nprintln!(\"{table}\");\n```\n\n```text\n+------+-----------+\n| \u0026str |      \u0026str |\n+------+-----------+\n|      | Multiline |\n| Text | text      |\n+------+-----------+\n| text |      text |\n+------+-----------+\n```\n\n### Format\n\n`Format` function provides an interface for modification of cells.\n\n```rust\nuse tabled::{\n    settings::{format::Format, object::Rows},\n    Table,\n};\n\nlet data = vec![[0; 10]; 9];\n\nlet mut table = Table::new(data);\ntable.modify(\n    Rows::new(..),\n    Format::positioned(|_, (row, col)| ((row + 1) * (col + 1)).to_string()),\n);\n\nprintln!(\"{table}\");\n```\n\n```text\n+----+----+----+----+----+----+----+----+----+-----+\n| 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 2  | 4  | 6  | 8  | 10 | 12 | 14 | 16 | 18 | 20  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 3  | 6  | 9  | 12 | 15 | 18 | 21 | 24 | 27 | 30  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 4  | 8  | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 5  | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 6  | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 7  | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 8  | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 9  | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90  |\n+----+----+----+----+----+----+----+----+----+-----+\n| 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 |\n+----+----+----+----+----+----+----+----+----+-----+\n```\n\n### Padding\n\nThe `Padding` structure provides an interface for left, right, top and bottom padding of cells.\nYou can set indent size and color of the padding.\n\n```rust\nuse tabled::settings::{\n    object::{Columns, Object, Rows},\n    Color, Padding,\n};\n\n// Set a padding for first column\ntable.modify(Columns::first(), Padding::new(0, 10, 0, 0));\n\n// Set a padding for a last column (except first row)\ntable.modify(\n    Columns::last().not(Rows::first()),\n    Padding::new(1, 1, 0, 0).fill('[', ']', ' ', ' '),\n);\n\n// Set a padding and its color for a first row\ntable.modify(Rows::first(), Padding::new(2, 2, 0, 2).fill(' ', ' ', ' ', ' '));\ntable.modify(Rows::first(), PaddingColor::filled(Color::BG_BLUE));\n```\n\nApplying the last change to the first example will result in the following.\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zhiburt/tabled/assets/20165848/2df75093-90c4-4b26-a2be-33d45391ace3\"\u003e\n  \u003cimg alt=\"Preview\" src=\"https://github.com/zhiburt/tabled/assets/20165848/7ec1f377-362b-469a-94e2-6e8599a1bd6d\"\u003e\n\u003c/picture\u003e\n\n### Margin\n\n`Margin` sets extra space around the table (top, bottom, left, right).\nAs for `Padding` you can set indent, size and color of the extra space.\n\n```rust\nuse tabled::settings::Margin;\n\ntable.with(Margin::new(3, 4, 1, 2).fill('\u003e', '\u003c', 'v', '^'));\n```\n\nIf you run it for a first example you'll get.\n\n```text\nvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n\u003e\u003e\u003e+------+----------------+---------------+\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e| name | designed_by    | invented_year |\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e+------+----------------+---------------+\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e| C    | Dennis Ritchie | 1972          |\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e+------+----------------+---------------+\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e| Go   | Rob Pike       | 2009          |\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e+------+----------------+---------------+\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e| Rust | Graydon Hoare  | 2010          |\u003c\u003c\u003c\u003c\n\u003e\u003e\u003e+------+----------------+---------------+\u003c\u003c\u003c\u003c\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n```\n\n#### Margin Color\n\nYou can set a color for the characters.\n\n```rust\nuse tabled::settings::{Margin, Color, MarginColor};\n\ntable.with(Margin::new(3, 4, 1, 2).fill('\u003e', '\u003c', 'v', '^'));\ntable.with(MarginColor::new(\n    Color::BG_BRIGHT_BLUE,\n    Color::BG_BRIGHT_CYAN,\n    Color::BG_BLUE,\n    Color::BG_RED,\n));\n```\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zhiburt/tabled/assets/20165848/324114ce-42e3-4aaa-be5c-18abf7e835b3\"\u003e\n  \u003cimg alt=\"Preview\" src=\"https://github.com/zhiburt/tabled/assets/20165848/5e280686-a8f5-4f1f-a1f6-3c97e1dd1fe3\"\u003e\n\u003c/picture\u003e\n\n### Shadow\n\n`Shadow` can be used to set a 'shadow' like margin.\n\n```rust\nuse tabled::{settings::{Style, Shadow}, Table};\n\nlet data = vec![[\"A\", \"B\", \"C\"]];\nlet table = Table::new(data)\n    .with(Style::modern())\n    .with(Shadow::new(1))\n    .to_string();\n\nprintln!(\"{}\", table);\n```\n\n```text\n┌───┬───┬───┐ \n│ 0 │ 1 │ 2 │▒\n├───┼───┼───┤▒\n│ A │ B │ C │▒\n└───┴───┴───┘▒\n ▒▒▒▒▒▒▒▒▒▒▒▒▒\n```\n\n### Width\n\nUsing the following structures you can configure the width of a table and a single cell.\n\nBEWARE that `Width` controls only content, so it can't make things smaller then a certain minimum.\nBEWARE that it DOES NOT consider `Padding` when adjusting the width.\n\nThe functions preserves `ansi` color sequences (when `ansi` feature is on).\n\nBelow is an example of setting an exact table width.\n\n```rust\nuse tabled::{\n    settings::{peaker::Priority, Width},\n    Table,\n};\n\nfn gen_table(size: usize, width: usize) -\u003e String {\n    let data = vec![(size.to_string(), \"x\".repeat(size))];\n\n    let mut table = Table::new(data);\n    table.with((\n        Width::wrap(width).priority(Priority::max(true)),\n        Width::increase(width).priority(Priority::min(true)),\n    ));\n\n    table.to_string()\n}\n\nlet table = gen_table(50, 40);\nprintln!(\"{table}\");\n\nlet table = gen_table(20, 40);\nprintln!(\"{table}\");\n```\n\nThe result must be seen as following.\n\n```text\n+--------+-----------------------------+\n| String | String                      |\n+--------+-----------------------------+\n| 50     | xxxxxxxxxxxxxxxxxxxxxxxxxxx |\n|        | xxxxxxxxxxxxxxxxxxxxxxx     |\n+--------+-----------------------------+\n+---------------+----------------------+\n| String        | String               |\n+---------------+----------------------+\n| 20            | xxxxxxxxxxxxxxxxxxxx |\n+---------------+----------------------+\n```\n\n#### Truncate\n\n`Truncate` sets a maximum width of a cell by truncating its content.\n\n```rust\nuse tabled::settings::{Width, object::Rows};\n\n// Truncating content to 10 chars in case it's bigger than that\n// in a first row.\ntable.modify(Rows::first(), Width::truncate(10));\n\n// Truncating content to 7 chars and puts a suffix '...' after it\n// in all rows except a first.\ntable.modify(Rows::new(1..), Width::truncate(10).suffix(\"...\"));\n```\n\n`Truncate` can be used to set a maximum width of a whole table.\n\n```rust\nuse tabled::settings::Width;\n\n// Tries to set table width to 22, in case it's bigger than that.\ntable.with(Width::truncate(22));\n```\n\nIt can be used in combination with `MinWidth` to set an exact table size.\n\n#### Wrapping\n\n`Wrap` sets a maximum width of a cell by wrapping its content to new lines.\n\n```rust\nuse tabled::settings::{Width, object::Rows};\n\n// Wrap content to 10 chars in case it's bigger than that\n// in a first row.\ntable.modify(Rows::first().with(Width::wrap(10)));\n\n// Use a strategy where we try not to keep words split (where possible).\ntable.modify(Rows::new(1..).with(Width::wrap(10).keep_words()));\n```\n\n`Wrap` can be used to set a maximum width of a whole table.\n\n```rust\nuse tabled::settings::Width;\n\n// Tries to set table width to 22, in case it's bigger than that.\ntable.with(Width::wrap(22));\n```\n\nIt can be used in combination with `MinWidth` to set an exact table size.\n\n#### Increase width\n\n`MinWidth` sets a minimal width of an object.\n\n```rust\nuse tabled::settings::{Width, object::Rows};\n\n// increase the space used by cells in all rows except the header to be at least 10\ntable.modify(Rows::new(1..), Width::increase(10));\n```\n\n`MinWidth` also can be used to set a minimum width of a whole table.\n\n```rust\nuse tabled::settings::Width;\n\n// increase width of a table in case it was lower than 10.\ntable.with(Width::increase(10));\n```\n\nIt can be used in combination with `Truncate` and `Wrap` to set an exact table size.\n\n#### Justify\n\nYou can set a constant width for all columns using `Justify`.\n\n```rust\nuse tabled::settings::Width;\n\ntable.with(Width::justify(10));\n```\n\n#### Priority\n\nYou can tweak `Truncate`, `Wrap`, `MinWidth` logic by setting a priority by which a trim or increase be done.\n\n```rust\nuse tabled::settings::{Width, peaker::Priority};\n\ntable.with(Width::truncate(10).priority(Priority::min()));\n```\n\n#### Percent\n\nBy default you use `usize` int to set width settings,\nbut you could do it also with `tabled::width::Percent`.\n\n```rust\nuse tabled::settings::{Width, measurement::Percent};\n\ntable.with(Width::wrap(Percent(75)));\n```\n\n### Height\n\nYou can increase and decrease a table or a specific cell height using the `Height` modifier.\n\nBeware that `Height` controls only content,\nso it can't make things smaller then a certain minimum.\n\nBelow is an example of setting an exact table height and width.\n\n```rust\nuse std::iter::FromIterator;\nuse tabled::{\n    settings::{Height, Settings, Width},\n    Table,\n};\n\nfn gen_data(width: usize, height: usize) -\u003e Vec\u003cVec\u003cString\u003e\u003e {\n    let dims = format!(\"{}x{}\", width, height);\n    let string = vec![\"x\".repeat(width); height].join(\"\\n\");\n\n    vec![\n        vec![String::from(\"N\"), String::from(\"string\")],\n        vec![dims, string],\n    ]\n}\n\nfn gen_table(data: Vec\u003cVec\u003cString\u003e\u003e, width: usize, height: usize) -\u003e String {\n    let mut table = Table::from_iter(data);\n    table.with((\n        Width::truncate(width),\n        Width::increase(width),\n        Height::increase(height),\n        Height::limit(height),\n    ));\n\n    table.to_string()\n}\n\nprintln!(\"{}\", gen_table(gen_data(40, 10), 30, 8));\nprintln!(\"{}\", gen_table(gen_data(40, 4), 80, 12));\n```\n\n```text\n+-------+--------------------+\n| N     | string             |\n|       |                    |\n|       |                    |\n+-------+--------------------+\n| 40x10 | xxxxxxxxxxxxxxxxxx |\n|       |                    |\n+-------+--------------------+\n+-----------------------------------+------------------------------------------+\n| N                                 | string                                   |\n|                                   |                                          |\n|                                   |                                          |\n+-----------------------------------+------------------------------------------+\n| 40x4                              | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |\n|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |\n|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |\n|                                   | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |\n|                                   |                                          |\n|                                   |                                          |\n+-----------------------------------+------------------------------------------+\n```\n\n#### Height increase\n\nIncreasing the height of a cell of a whole table could be done by `Height::increase`.\n\n```rust\nuse tabled::settings::{Height, object::Rows};\n\n// increase height of a table in case it was lower than 10.\ntable.with(Height::increase(10));\n\n// increase height of cells in the last row on a table in case if some of them has it lower than 10.\ntable.modify(Rows::last(), Height::increase(10));\n```\n\n#### Height limit\n\nTruncation of the height of a cell of a whole table could be done by `Height::limit`.\n\n```rust\nuse tabled::settings::{Height, object::Rows};\n\n// decrease height of a table to 10 in case it was bigger than that.\ntable.with(Height::limit(10));\n\n// decrease height of cells in the last row on a table to 10 in case if some of them has it bigger than that.\ntable.modify(Rows::last(), Height::limit(10));\n```\n\n### Rotate\n\nYou can rotate a table using `tabled::Rotate`.\n\nImagine you have a table already which output may look like this.\n\n```text\n┌────┬──────────────┬───────────────────────────┐\n│ id │ distribution │ link                      │\n├────┼──────────────┼───────────────────────────┤\n│ 0  │ Fedora       │ https://getfedora.org/    │\n├────┼──────────────┼───────────────────────────┤\n│ 2  │ OpenSUSE     │ https://www.opensuse.org/ │\n├────┼──────────────┼───────────────────────────┤\n│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n└────┴──────────────┴───────────────────────────┘\n```\n\nNow we will add the following modificator and the output will be rotated;\n\n```rust\nuse tabled::settings::Rotate;\n\ntable.with(Rotate::Left);\n```\n\n```text\n┌──────────────┬────────────────────────┬───────────────────────────┬──────────────────────────┐\n│ link         │ https://getfedora.org/ │ https://www.opensuse.org/ │ https://endeavouros.com/ │\n├──────────────┼────────────────────────┼───────────────────────────┼──────────────────────────┤\n│ distribution │ Fedora                 │ OpenSUSE                  │ Endeavouros              │\n├──────────────┼────────────────────────┼───────────────────────────┼──────────────────────────┤\n│ id           │ 0                      │ 2                         │ 3                        │\n└──────────────┴────────────────────────┴───────────────────────────┴──────────────────────────┘\n```\n\n### Remove\n\nYou can remove certain rows or columns from the table by `Remove`.\n\n```rust\nuse tabled::settings::{object::{Columns, Rows}, Remove};\n\ntable.with(Remove::row(Rows::first()));\ntable.with(Remove::column(Columns::single(2)));\n```\n\nIf the above example be applied for a first example in a file it would look like this.\n\n```text\n+------+----------------+\n| C    | Dennis Ritchie |\n+------+----------------+\n| Go   | Rob Pike       |\n+------+----------------+\n| Rust | Graydon Hoare  |\n+------+----------------+\n```\n\n### Extract\n\nYou can `Extract` data segments of a table to focus on it closely.\n\n```rust\nuse tabled::settings::Extract;\n\ntable.with(Extract::segment(1..3, 1..));\n```\n\n```text\n+-------+-------------+-----------+\n|  i32  |    \u0026str     |   bool    |\n+-------+-------------+-----------+         +-------------+-----------+\n| : 0 : | : Grodno :  | : true :  |         | : Grodno :  | : true :  |\n+-------+-------------+-----------+    =    +-------------+-----------+\n| : 1 : |  : Minsk :  | : true :  |         |  : Minsk :  | : true :  |\n+-------+-------------+-----------+         +-------------+-----------+\n| : 2 : | : Hamburg : | : false : |\n+-------+-------------+-----------+\n| : 3 : |  : Brest :  | : true :  |\n+-------+-------------+-----------+\n```\n\n### Header and Footer and Panel\n\nYou can add a `Header` and `Footer` to display some information.\n\n```rust\nuse tabled::settings::Panel;\n\nlet count_elements = table.count_rows();\n\ntable\n    .with(Panel::vertical(0, \"A vertical panel\").width(1))\n    .with(Panel::header(\"Tabled Name\"))\n    .with(Panel::footer(format!(\"{} elements\", count_elements)));\n```\n\nWhen applied to the main example of this file it will result in the following output.\n\n```text\n+---+------+----------------+---------------+\n| Tabled Name                               |\n+---+------+----------------+---------------+\n| A | name | designed_by    | invented_year |\n|   |      |                |               |\n| v |      |                |               |\n| e |      |                |               |\n+ r +------+----------------+---------------+\n| t | C    | Dennis Ritchie | 1972          |\n| i |      |                |               |\n| c |      |                |               |\n+ a +------+----------------+---------------+\n| l | Go   | Rob Pike       | 2009          |\n|   |      |                |               |\n| p |      |                |               |\n+ a +------+----------------+---------------+\n| n | Rust | Graydon Hoare  | 2010          |\n| e |      |                |               |\n| l |      |                |               |\n+---+------+----------------+---------------+\n| 4 elements                                |\n+---+------+----------------+---------------+\n```\n\n### Merge\n\nIt's possible to create `\"Panel\"`s by combining the duplicates using `Merge`.\n\n```rust\nuse tabled::{settings::merge::Merge, Table};\n\nlet data = [['A', 'B', 'B'], ['A', 'W', 'E'], ['Z', 'Z', 'Z']];\n\nlet mut table = Table::new(data);\ntable.with(Merge::horizontal()).with(Merge::vertical());\n\nprintln!(\"{}\", table);\n```\n\n```\n+---+---+---+\n| 0 | 1 | 2 |\n+---+---+---+\n| A | B     |\n+   +---+---+\n|   | W | E |\n+---+---+---+\n| Z         |\n+---+---+---+\n```\n\n### Concat\n\nYou can concatenate 2 tables using `Concat`.\nIt will stick 2 tables together either vertically or horizontally.\n\nThe example below shows the result of horizontal concat of the primary table of this file.\n\n```rust\nuse tabled::settings::Concat;\n\ntable.with(Concat::horizontal(table.clone()));\n```\n\nThe result.\n\n```text\n+------+----------------+---------------+------+----------------+---------------+\n| name | designed_by    | invented_year | name | designed_by    | invented_year |\n+------+----------------+---------------+------+----------------+---------------+\n| C    | Dennis Ritchie | 1972          | C    | Dennis Ritchie | 1972          |\n+------+----------------+---------------+------+----------------+---------------+\n| Go   | Rob Pike       | 2009          | Go   | Rob Pike       | 2009          |\n+------+----------------+---------------+------+----------------+---------------+\n| Rust | Graydon Hoare  | 2010          | Rust | Graydon Hoare  | 2010          |\n+------+----------------+---------------+------+----------------+---------------+\n```\n\nThe example below show the result of vertical concat of the primary table of this file.\n\n```rust\nuse tabled::settings::Concat;\n\ntable.with(Concat::vertical(table.clone()));\n```\n\nThe result.\n\n```text\n+------+----------------+---------------+\n| name | designed_by    | invented_year |\n+------+----------------+---------------+\n| C    | Dennis Ritchie | 1972          |\n+------+----------------+---------------+\n| Go   | Rob Pike       | 2009          |\n+------+----------------+---------------+\n| Rust | Graydon Hoare  | 2010          |\n+------+----------------+---------------+\n| name | designed_by    | invented_year |\n+------+----------------+---------------+\n| C    | Dennis Ritchie | 1972          |\n+------+----------------+---------------+\n| Go   | Rob Pike       | 2009          |\n+------+----------------+---------------+\n| Rust | Graydon Hoare  | 2010          |\n+------+----------------+---------------+\n```\n\n### Highlight\n\n`Highlight` can be used to change the borders of target region.\nHere's an example.\n\n```rust\nuse tabled::{\n    settings::{\n        object::{Columns, Object, Rows},\n        Border, Highlight, Style,\n    },\n    Table,\n};\n\nlet data = vec![[\"A\", \"B\", \"C\"], [\"D\", \"E\", \"F\"]];\n\nlet mut table = Table::new(data);\ntable.with(Style::modern());\ntable.with(Highlight::border(\n    Rows::first().and(Columns::single(2).and((1, 1))),\n    Border::filled('*'),\n));\n\nprintln!(\"{}\", table);\n```\n\nThe resulting table would be the following.\n\n```text\n*************\n* 0 │ 1 │ 2 *\n*****───┼───*\n│ A * B │ C *\n├───*****───*\n│ D │ E * F *\n└───┴───*****\n```\n\n### Span\n\nIt's possible to set a horizontal(column) span and vertical(row) span to a cell. For certain look and feel, this might cause visual artifacts on  table borders (see #399). This can be fixed by using tabled::settings::style::BorderSpanCorrection.\n\n#### Horizontal span\n\n```rust\nuse tabled::{\n    settings::{Alignment, Span},\n    Table,\n};\n\nlet data = vec![[\"A\", \"B\", \"C\"], [\"D\", \"E\", \"F\"]];\n\nlet mut table = Table::new(data);\ntable\n    .modify((0, 0), Span::column(0))\n    .modify((1, 0), Span::column(2))\n    .with(Alignment::center());\n\nprintln!(\"{}\", table);\n```\n\n```text\n+---+---+---+\n|     0     |\n+---+---+---+\n|   A   | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+\n```\n\n#### Vertical span\n\n```rust\nuse tabled::{\n    settings::{Alignment, Span},\n    Table,\n};\n\nlet data = vec![[\"A\", \"B\", \"C\"], [\"D\", \"E\", \"F\"]];\n\nlet mut table = Table::new(data);\ntable\n    .modify((0, 1), Span::row(3))\n    .with(Alignment::center())\n    .with(Alignment::center_vertical());\n\nprintln!(\"{}\", table);\n```\n\n```text\n+---+---+---+\n| 0 |   | 2 |\n+---+   +---+\n| A | 1 | C |\n+---+   +---+\n| D |   | F |\n+---+---+---+\n```\n\n### Split\n\nYou can `Split` a table on a row or column to redistribute the cells beyond that point\ninto a new shape with the provided point acting as the new, upper boundary in the direction selected.\n\nAdding this to a first example will result in the next table.\n\n```rust\nuse tabled::settings::{Style, split::Split};\n\ntable.with(Style::modern());\ntable.with(Split::column(2).concat());\n```\n\nThe result of the running example will be as follows.\n\n```text\n┌───────────────┬────────────────┐\n│ name          │ designed_by    │\n├───────────────┼────────────────┤\n│ C             │ Dennis Ritchie │\n├───────────────┼────────────────┤\n│ Go            │ Rob Pike       │\n├───────────────┼────────────────┤\n│ Rust          │ Graydon Hoare  │\n├───────────────┼────────────────┤\n│ invented_year │                │\n├───────────────┼────────────────┤\n│ 1972          │                │\n├───────────────┼────────────────┤\n│ 2009          │                │\n├───────────────┼────────────────┤\n│ 2010          │                │\n└───────────────┴────────────────┘\n```\n\n#### Duplicate\n\nIt's possible to duplicate a given set of cell to another set.\n\n```rust\nuse tabled::{Table, settings::{Dup, object::Rows}};\n\nlet mut table = Table::new(data);\n\n// copy lastfirst line to the last line (last line gets erased).\ntable.with(Dup::new(Rows::last(), Rows::first()));\n```\n\n## Derive\n\nTo be able to use a `Tabled` macros each field must implement `std::fmt::Display`\notherwise it will not work.\n\nThe following example will cause a error.\n\n```rust,compile_fail\nuse tabled::Tabled;\n#[derive(Tabled)]\nstruct SomeType {\n    field1: SomeOtherType,\n}\n\nstruct SomeOtherType;\n```\n\nThe `Tabled` macro is available when `derive` feature in turned on.\nAnd it is by default.\n\nMost of the default types implement the corresponding traits too.\n\n### Override a column name\n\nYou can use a `#[tabled(rename = \"\")]` attribute to override a column name.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\nstruct Person {\n    #[tabled(rename = \"Name\")]\n    first_name: \u0026'static str,\n    #[tabled(rename = \"Surname\")]\n    last_name: \u0026'static str,\n}\n```\n\n### Format headers\n\nUsing `#[tabled(rename_all = \"\")]` you can change a format of a column name.\nSupported values are [`camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lowercase`, `UPPERCASE`, `lower title case`, `Upper Title Case`, `verbatim`]\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\n#[tabled(rename_all = \"CamelCase\")]\nstruct Person {\n    id: u8,\n    number: \u0026'static str,\n    name: \u0026'static str,\n    #[tabled(rename_all = \"UPPERCASE\")]\n    middle_name: \u0026'static str,\n}\n```\n\n### Hide a column\n\nYou can mark filds as hidden in which case they will be ignored and not be present on a sheet.\n\nA similar effect could be achieved by the means of a [`Remove`](#remove).\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\nstruct Person {\n   id: u8,\n   #[tabled(skip)]\n   number: \u0026'static str,\n   name: \u0026'static str,\n}\n```\n\n### Set column order\n\nYou can change the order in which they will be displayed in table.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\nstruct Person {\n   id: u8,\n   #[tabled(order = 0)]\n   number: \u0026'static str,\n   #[tabled(order = 1)]\n   name: \u0026'static str,\n}\n```\n\n### Format fields\n\nAs was said already, using `#[derive(Tabled)]` is possible only when all fields implement a `Display` trait.\nHowever, 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:\n\n- Implement `Tabled` trait manually for a type.\n- Wrap `Option` to something like `DisplayedOption\u003cT\u003e(Option\u003cT\u003e)` and implement a Display trait for it.\n\nAlternatively, you can use the `#[tabled(display = \"func\")]` attribute for the field to specify a display function.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\npub struct Record {\n    pub id: i64,\n    #[tabled(display = \"display_option\")]\n    pub valid: Option\u003cbool\u003e\n}\n\nfn display_option(o: \u0026Option\u003cbool\u003e) -\u003e String {\n    match o {\n        Some(s) =\u003e format!(\"is valid thing = {}\", s),\n        None =\u003e format!(\"is not valid\"),\n    }\n}\n```\n\nYou can send an argument to a function like this (it also possible to use `\u0026self`),\nusing `#[tabled(display(\"some_function\", \"arg1\", 2, self))]`\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\npub struct Record {\n    pub id: i64,\n    #[tabled(display(\"Self::display_valid\", self, 1))]\n    pub valid: Option\u003cbool\u003e\n}\n\nimpl Record {\n    fn display_valid(\u0026self, arg: usize) -\u003e String {\n        match self.valid {\n            Some(s) =\u003e format!(\"is valid thing = {} {}\", s, arg),\n            None =\u003e format!(\"is not valid {}\", arg),\n        }\n    }\n}\n```\n\nThere's one more case for `display` usage.\nIs a situation where you have many fields with similar types.\nYou could set a `display` function agains the whole type.\nSee next example.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\n#[tabled(display(Option, \"tabled::derive::display::option\", \"undefined\"))]\npub struct Record {\n    pub id: i64,\n    pub name: Option\u003cString\u003e,\n    pub birthdate: Option\u003cusize\u003e,\n    pub valid: Option\u003cbool\u003e,\n}\n```\n\nTo reduce boilerplate code, one can also achieve this using the `format` attribute within `#[derive(Tabled)]`.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\npub struct Motorcycle {\n    weight: usize,\n    #[tabled(format = \"{} cc\")]\n    cc: usize,\n}\n```\n\nIn the above example, the cc field will be formatted using the specified format string \"{} cc\", where {} is replaced with the value of cc.\n\nJust like with `display_with` attribute, you can pass arguments for more complex formatting scenarios:\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\npub struct Motorcycle {\n    weight: usize,\n    #[tabled(format = \"{}/{} cc/kg\", self.cc, self.weight)]\n    cc: usize,\n}\n```\n\nIn this case, the cc field will be formatted using the format string \"{}/{} cc/kg\", and {} will be replaced with the values of cc and weight, respectively.\n\n### Inline\n\nIt's possible to inline internal data if it implements the `Tabled` trait using `#[tabled(inline)]`.\nYou can also set a prefix which will be used for all inlined elements by `#[tabled(inline(\"prefix\u003e\u003e\"))]`.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\nstruct Person {\n    id: u8,\n    name: \u0026'static str,\n    #[tabled(inline)]\n    ed: Education,\n}\n\n#[derive(Tabled)]\nstruct Education {\n    uni: \u0026'static str,\n    graduated: bool,\n}\n```\n\nAnd it works for enums as well.\n\n```rust\nuse tabled::Tabled;\n\n#[derive(Tabled)]\nenum Vehicle {\n    #[tabled(inline(\"Auto::\"))]\n    Auto {\n        model: \u0026'static str,\n        engine: \u0026'static str,\n    },\n    #[tabled(inline)]\n    Bikecycle(\n        \u0026'static str,\n        #[tabled(inline)] Bike,\n    ),\n}\n\n#[derive(Tabled)]\nstruct Bike {\n    brand: \u0026'static str,\n    price: f32,\n}\n```\n\n## Table types\n\n`tabled` has a few representations of tables. Some differ in view, and some differ in implementation details.\n\nThere are situations when you might better use one but not another.\nBut sometimes some can be used interchangeably.\n\nBelow you'll find a short list of existing ones. You can find descriptive information about each in the documentation.\n\n### `Table`\n\nMain table of the library.\nIt's implemenentation requires that all data be stored on heap.\n\nNo example is provided.\nCause it must be somewhat apparent how to use it by now :).\n\n### `IterTable`\n\nIt's similar to main `Table`, it's only difference is that it does not buffer data.\\\nIt only requires a buffer for 1 row at a time.\\\nIt's configuration is quite different to original table,\\\ndifference is focused on controll how many passes and memory allocation.\n\nIt might be handy when you can't fit all your data in memory.\n\nHere's an example.\n\n```rust\nuse std::borrow::Cow;\nuse tabled::{settings::Style, tables::IterTable};\n    \nstruct Language\u003c'a\u003e {\n    name: \u0026'a str,\n    designed_by: \u0026'a str,\n    year: usize,\n}\n    \nlet languages = vec![\n    Language { name: \"C\", designed_by: \"Dennis Ritchie\", year: 1972 },\n    Language { name: \"Go\", designed_by: \"Rob Pike\", year: 2009 },\n    Language { name: \"Rust\", designed_by: \"Graydon Hoare\", year: 2010 },\n];\n    \nlet iter = languages.iter().rev().map(|l| {\n    [\n        Cow::Borrowed(l.name),\n        Cow::Borrowed(l.designed_by),\n        Cow::Owned(l.year.to_string()),\n    ]\n});\n\nlet head = [\n    Cow::Borrowed(\"lang\"),\n    Cow::Borrowed(\"inventor\"),\n    Cow::Borrowed(\"published year\"),\n];\nlet iter = std::iter::once(head).chain(iter);\n\nlet table = IterTable::new(iter)\n    .sniff(2)\n    .with(Style::modern().remove_horizontal());\n    \nlet output = table.to_string();\n    \nprintln!(\"{output}\");\n```\n\nAnd the result.\n\nNotice that \"Dennis Ritchie\" name got truncated,\\\nit's because we used only 2 rows for layout estimation.\\\nNo more additinal passes will be done.\\\nBut these 2 rows will be buffered because we can't do 2nd pass over already seen rows.\n\n```text\n┌──────┬───────────────┬────────────────┐\n│ lang │ inventor      │ published year │\n│ Rust │ Graydon Hoare │ 2010           │\n│ Go   │ Rob Pike      │ 2009           │\n│ C    │ Dennis Ritchi │ 1972           │\n└──────┴───────────────┴────────────────┘\n```\n\n### `CompactTable`\n\nSimilar to `IterTable` but it does not use any buffer.\\\nSo we don't do any allocations with this type of table.\\\nBut we pay for it with a limited configuration and a nessasity to estimate column width on your own.\n\nIt might be useful in a very constrain environments.\nIt is the only table which supports `no-std`.\n\nHere's an example.\\\nIt's very simmilar to the previous one.\\\nBut notice that we set width manually.\n\n```rust\nuse std::borrow::Cow;\nuse tabled::settings::Style;\nuse tabled::tables::CompactTable;\n    \nstruct Language\u003c'a\u003e {\n    name: \u0026'a str,\n    designed_by: \u0026'a str,\n    year: usize,\n}\n    \nlet languages = vec![\n    Language { name: \"C\", designed_by: \"Dennis Ritchie\", year: 1972 },\n    Language { name: \"Go\", designed_by: \"Rob Pike\", year: 2009 },\n    Language { name: \"Rust\", designed_by: \"Graydon Hoare\", year: 2010 },\n];\n    \nlet iter = languages.iter().rev().map(|l| {\n    [\n        Cow::Borrowed(l.name),\n        Cow::Borrowed(l.designed_by),\n        Cow::Owned(l.year.to_string()),\n    ]\n});\n\nlet head = [\n    Cow::Borrowed(\"lang\"),\n    Cow::Borrowed(\"inventor\"),\n    Cow::Borrowed(\"published year\"),\n];\nlet iter = std::iter::once(head).chain(iter);\n\nlet table = CompactTable::new(iter)\n    .rows(languages.len())\n    .columns(3)\n    .width([10, 20, 20])\n    .with(Style::modern().remove_horizontal());\n\nlet output = table.to_string();\n    \nprintln!(\"{output}\");\n```\n\nAnd the result.\n\n```text\n┌──────────┬────────────────────┬────────────────────┐\n│ lang     │ inventor           │ published year     │\n│ Rust     │ Graydon Hoare      │ 2010               │\n│ Go       │ Rob Pike           │ 2009               │\n└──────────┴────────────────────┴────────────────────┘\n```\n\n### `PoolTable`\n\nUnlike `Table` it does not nessarily require columns to be aligned.\nIt provides capabilities for a completely and utterly diverse table layout.\n\nExample\n\n```rust\nuse tabled::{\n    settings::{Alignment, Style},\n    tables::PoolTable,\n};\n\nlet characters = [\n    \"Naruto Uzumaki\",\n    \"Kakashi Hatake\",\n    \"Minato Namikaze\",\n    \"Jiraiya\",\n    \"Orochimaru\",\n    \"Itachi Uchiha\",\n];\n\nlet data = characters.chunks(2);\n\nlet table = PoolTable::new(data)\n    .with(Style::dots())\n    .with(Alignment::center())\n    .to_string();\n\nprintln!(\"{table}\");\n```\n\nThe output would look like the following.\n\n```\n...................................\n: Naruto Uzumaki : Kakashi Hatake :\n:................:................:\n:  Minato Namikaze   :  Jiraiya   :\n:....................:............:\n:  Orochimaru   :  Itachi Uchiha  :\n:...............:.................:\n```\n\n### `ExtendedTable`\n\nYou can use `ExtendedTable` if your data structure has a lot of fields.\n\nHere's an example.\n\n```rust\nuse tabled::{tables::ExtendedTable, Tabled};\n\n#[derive(Tabled)]\nstruct Distribution\u003c'a\u003e {\n    name: \u0026'a str,\n    is_active: bool,\n    is_cool: bool,\n}\n\nlet data = [\n    Distribution { name: \"Manjaro\", is_cool: true, is_active: true },\n    Distribution { name: \"Debian\", is_cool: true, is_active: true },\n    Distribution { name: \"Debian\", is_cool: true, is_active: true },\n];\n\nlet table = ExtendedTable::new(\u0026data);\n\nprintln!(\"{}\", table);\n```\n\nYou'll see the following.\n\n```text\n-[ RECORD 0 ]------\nname      | Manjaro\nis_active | true\nis_cool   | true\n-[ RECORD 1 ]------\nname      | Debian\nis_active | true\nis_cool   | true\n-[ RECORD 2 ]------\nname      | Debian\nis_active | true\nis_cool   | true\n```\n\n### `Table::kv`\n\nThere's a special layout you can build for original `Table`.\nWhich represents Key-Value pairs for your type.\nNotice that in essence there's nothing special in the build process, so it can be build for other table types as well.\n\nHere's an example.\n\n```rust\nuse tabled::{Table, Tabled, settings::Style};\n    \n#[derive(Tabled)]\nstruct Language\u003c'a\u003e {\n    name: \u0026'a str,\n    designed_by: \u0026'a str,\n    year: usize,\n}\n\nlet languages = vec![\n    Language { name: \"C\", designed_by: \"Dennis Ritchie\", year: 1972 },\n    Language { name: \"Go\", designed_by: \"Rob Pike\", year: 2009 },\n    Language { name: \"Rust\", designed_by: \"Graydon Hoare\", year: 2010 },\n];\n    \nlet mut table = Table::kv(languages);\ntable.with(Style::modern().remove_horizontal());\n\nprintln!(\"{table}\");\n```\n\nAnd the result.\n\n```text\n┌─────────────┬────────────────┐\n│ name        │ C              │\n│ designed_by │ Dennis Ritchie │\n│ year        │ 1972           │\n│ name        │ Go             │\n│ designed_by │ Rob Pike       │\n│ year        │ 2009           │\n│ name        │ Rust           │\n│ designed_by │ Graydon Hoare  │\n│ year        │ 2010           │\n└─────────────┴────────────────┘\n```\n\n## Tips and Tricks\n\n### `std::fmt::*` options\n\nYou use formatting(`std::fmt::*`) options to apply certain settings.\n\n```rust\nuse tabled::Table;\n\nlet numbers = [1, 2, 3];\nlet table = Table::new(numbers);\n\nprintln!(\"{:#^10}\", table);\n```\n\nThe result will be as follows.\n\n```text\n#+-----+##\n#| i32 |##\n#+-----+##\n#|  1  |##\n#+-----+##\n#|  2  |##\n#+-----+##\n#|  3  |##\n#+-----+##\n```\n\n### ANSI\n\nThe library doesn't bind you in the usage of any color library but to be able to work correctly with colored input (with ANSI sequences), and avoid [miscalculation of string width](https://github.com/zhiburt/tabled/issues/26)\nbecause of embedded ansi sequences, you should add the `ansi` feature to your `Cargo.toml`:\n\n```toml\ntabled = { version = \"*\", features = [\"ansi\"] }\n```\n\nThen you can use colored strings as values and table will be properly rendered.\n\nTuning our favorite example will result in the following:\n\n```rust\nuse tabled::{format::Format, object::Columns, Style, Table};\n\nlet mut table = Table::new(\u0026data);\ntable\n    .with(Style::psql())\n    .modify(Columns::single(0), Color::FG_RED)\n    .modify(Columns::single(1), Color::FG_BLUE)\n    .modify(Columns::new(2..), Color::FG_GREEN);\n```\n\n![carbon-2](https://user-images.githubusercontent.com/20165848/120526301-b95efc80-c3e1-11eb-8779-0ec48894463b.png)\n\n### Tuple combination\n\nYou also can combine objects which implement `Tabled` by means of tuples, you will get a combined columns of them.\n\n```rust\nuse tabled::{\n    settings::{Alignment, Style},\n    Table, Tabled,\n};\n\n#[derive(Tabled)]\nstruct Developer(#[tabled(rename = \"name\")] \u0026'static str);\n\n#[derive(Tabled)]\nenum Domain {\n    Security,\n    Embedded,\n    Frontend,\n    Unknown,\n}\n\nlet data = vec![\n    (Developer(\"Terri Kshlerin\"), Domain::Embedded),\n    (Developer(\"Catalina Dicki\"), Domain::Security),\n    (Developer(\"Jennie Schmeler\"), Domain::Frontend),\n    (Developer(\"Maxim Zhiburt\"), Domain::Unknown),\n];\n\nlet table = Table::new(data)\n    .with(Style::psql())\n    .with(Alignment::center())\n    .to_string();\n\nassert_eq!(\n    table,\n    concat!(\n        \"      name       | Security | Embedded | Frontend | Unknown \\n\",\n        \"-----------------+----------+---------+----------+---------\\n\",\n        \" Terri Kshlerin  |          |    +    |          |         \\n\",\n        \" Catalina Dicki  |    +     |         |          |         \\n\",\n        \" Jennie Schmeler |          |         |    +     |         \\n\",\n        \"  Maxim Zhiburt  |          |         |          |    +    \",\n    )\n);\n```\n\n### Tuple options\n\nYou can concat together options, just like `Settings` does, but in a more ideomatic way.\n\n```rust\nuse tabled::{\n    settings::{Alignment, Style},\n    Table,\n};\n\nlet movies = vec![\n    (\"The Fall Guy\", 2024, 6.9),\n    (\"Barbie\", 2023, 6.8),\n    (\"The Chase for Carrera\", 2023, 7.5),\n];\n\nlet mut table = Table::new(movies);\ntable.with((Alignment::right(), Style::modern()));\n\nassert_eq!(\n    table.to_string(),\n    \"┌───────────────────────┬──────┬─────┐\\n\\\n     │                  \u0026str │  i32 │ f64 │\\n\\\n     ├───────────────────────┼──────┼─────┤\\n\\\n     │          The Fall Guy │ 2024 │ 6.9 │\\n\\\n     ├───────────────────────┼──────┼─────┤\\n\\\n     │                Barbie │ 2023 │ 6.8 │\\n\\\n     ├───────────────────────┼──────┼─────┤\\n\\\n     │ The Chase for Carrera │ 2023 │ 7.5 │\\n\\\n     └───────────────────────┴──────┴─────┘\",\n);\n```\n\n### Object\n\nYou can apply settings to a subgroup of cells using `and` and `not` methods for an object.\n\n```rust\nuse tabled::settings::object::{Object, Segment, Cell, Rows, Columns};\nSegment::all().not(Rows::first()); // select all cells except header.\nColumns::first().and(Columns::last()); // select cells from first and last columns.\nRows::first().and(Columns::single(0)).not(Cell(0, 0)); // select the header and first column except the (0, 0) cell.\n```\n\nAlso you can target a column via its name using `ByColumnName`.\n\n```rust\nuse tabled::{location::ByColumnName, Alignment, Modify};\n\ntable.with(Modify::new(ByColumnName::new(\"name\")).with(Alignment::center()));\n```\n\n### Builder\n\n`Builder` is a powerful tool you shall be aware of.\n\nFor example you can use `Builder::index` to make a particular column an index,\nwhich will stay on the left.\n\n```rust\nuse tabled::{builder::Builder, settings::Style};\n\nlet mut builder = Builder::default();\nbuilder.push_record([\"Index\", \"Language\", \"Status\"]);\nbuilder.push_record([\"1\", \"English\", \"In progress\"]);\nbuilder.push_record([\"2\", \"Deutsch\", \"Not ready\"]);\n\nlet builder = builder.index().column(1).name(None);\n\nlet mut table = builder.build();\ntable.with(Style::rounded());\n\nprintln!(\"{}\", table);\n```\n\n```text\n╭─────────┬───────┬─────────────╮\n│         │ Index │ Status      │\n├─────────┼───────┼─────────────┤\n│ English │ 1     │ In progress │\n│ Deutsch │ 2     │ Not ready   │\n╰─────────┴───────┴─────────────╯\n```\n\nFor example you can use `transpose()` method to change the layout.\n\n```rust\n// A dynamic table example\n// ...\n\nlet mut builder = builder.index().transpose();\n```\n\n```text\n.-------------------------------------------------.\n|   | 0      | 1      | 2      | 3        | 4     |\n| 0 | And    | Little | When   | I        | You   |\n| 1 | the    | boy    | you    | don't    | know  |\n| 2 | cat's  | blue   | comin' | know     | we'll |\n| 3 | in     | and    | home   | when,    | have  |\n| 4 | the    | the    | dad?   | but      | a     |\n| 5 | cradle | man    |        | we'll    | good  |\n| 6 | and    | on     |        | get      | time  |\n| 7 | the    | the    |        | together | then  |\n| 8 | silver | moon   |        | then     |       |\n| 9 | spoon  |        |        | son      |       |\n'-------------------------------------------------'\n```\n\n### Macros\n\nUtilities for dynamic `Table` displays.\n\n#### Col and Row\n\n`col!` creates a single column table, with a given set of cells.\n`row!` creates a single row table, with a given set of cells.\n\nCombine `col!` and `row!` to create flexible table visualizations.\n\n```rust\nuse tabled::{col, row, settings::Style};\n\nlet mut table = row![\n    col![\"table 0\", \"0\", \"1\", \"2\"],\n    col![\"table 1\", \"world\"],\n    col![\"table 2\"],\n];\ntable.with(Style::modern_rounded());\n\nprintln!(\"{table}\");\n```\n\nThe output you're going to see running it.\n\n```text\n╭─────────────┬─────────────┬─────────────╮\n│ +---------+ │ +---------+ │ +---------+ │\n│ | table 0 | │ | table 1 | │ | table 2 | │\n│ +---------+ │ +---------+ │ +---------+ │\n│ | 0       | │ | world   | │             │\n│ +---------+ │ +---------+ │             │\n│ | 1       | │             │             │\n│ +---------+ │             │             │\n│ | 2       | │             │             │\n│ +---------+ │             │             │\n╰─────────────┴─────────────┴─────────────╯\n```\n\n#### `static_table`\n\nIt's possible to construct a table at compile time, via [`static_table`](/static_table/README.md).\nYou'd need to include a different crate to use it.\n\n```toml\nstatic_table = \"*\"\n```\n\n```rust\nlet table = static_table::static_table!(\n    [\n        [\"x\", \"y\", \"op\", \"result\"],\n        [\"1\", '2', '*', '2'],\n        [\"2\", '2', '*', '4']\n    ],\n    THEME = \"ROUNDED\",\n);\n\nassert_eq!(\n    table,\n    \"╭───┬───┬────┬────────╮\\n\\\n     │ x │ y │ op │ result │\\n\\\n     ├───┼───┼────┼────────┤\\n\\\n     │ 1 │ 2 │ *  │ 2      │\\n\\\n     │ 2 │ 2 │ *  │ 4      │\\n\\\n     ╰───┴───┴────┴────────╯\",\n);\n```\n\nNotice that you can even use it in documentation.\n\n```rust\n/// Multiply 2 integers together.\n///\n#[doc = static_table::static_table!([\n    [\"x\", \"y\", \"result\"],\n    [\"1\", '0', '0'],\n    [\"1\", '2', '2'],\n    [\"2\", '2', '4']\n])]\npub fn mul(left: usize, right: usize) -\u003e usize {\n    left + right\n}\n```\n\nIt will look as follows.\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zhiburt/tabled/assets/20165848/704c285b-f8ab-481b-a5bf-130406aad7d5\"\u003e\n  \u003cimg alt=\"Preview\" src=\"https://github.com/zhiburt/tabled/assets/20165848/164a82db-8ce7-4366-b21d-c679bea8d9fe\"\u003e\n\u003c/picture\u003e\n\n## Features\n\nThe library has a list of features.\n\n- `std`     - Used by default. If not its considered `no_std` with a limited set of functionality.\n- `derive`  - Used by default. Adds support for `Tabled` derive macro.\n- `ansi`    - A support for ANSI sequences.\n- `macros`  - A support for `row!`, `col!` macro.\n\n## Formats\n\nYou can convert some formats to a `Table` using a utility library.\n\n### `json` format\n\nYou can convert arbitrary `json` to a `Table` using [`json_to_table`](/json_to_table/README.md) library.\nSee the **[example](/json_to_table/README.md)**.\n\n### `ron` format\n\nYou can convert arbitrary `ron` to a `Table` using [`ron_to_table`](/ron_to_table/README.md) library.\nSee the **[example](/ron_to_table/README.md)**.\n\n### `csv` format\n\nYou can convert arbitrary `csv` to a `Table` using [`csv_to_table`](/csv_to_table/README.md) library.\nSee the **[example](/csv_to_table/README.md)**.\n\n### `toml` format\n\nYou can convert arbitrary `toml` to a `Table` using [`toml_to_table`](/toml_to_table/README.md) library.\nSee the **[example](/toml_to_table/README.md)**.\n\n### `html` format\n\nYou can convert a `Table` into `HTML` `\u003ctable\u003e` using [`table_to_html`](/table_to_html/README.md) library.\nSee the **[example](/json_to_table/README.md)**.\n\n\n## Notes\n\n### Charset\n\nSince version `0.11` we no longer have special treatment for symbols which WILL break your terminal output such as\n`\\t` and `\\r`.\nSo if your content might contain them you shall either handle it yourself,\nor call `tabled::settings::formatting::Charset::clean` and `tabled::settings::formatting::Tabsize`.\n\n### ANSI escape codes\n\nBy default `tabled` doesn't handle [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).\nBy default such things as hyperlinks, blinking and others things which can be achieved via ANSI codes might not work correctly.\n\nTo enable this support, add the `ansi` feature to your `Cargo.toml`\n\n```toml\ntabled = { version = \"*\", features = [\"ansi\"] }\n```\n\n### Emoji\n\nThe library support emojies out of the box (but sometimes `ansi` feature is required).\nBe aware that some of the terminals and editors may not render them as you would expect.\n\nLet's add emojies to an example from a [Usage](#Usage) section.\n\n```rust\nlet languages = vec![\n    Language {\n        name: \"C 💕\",\n        designed_by: \"Dennis Ritchie\",\n        invented_year: 1972,\n    },\n    Language {\n        name: \"Rust 👍\",\n        designed_by: \"Graydon Hoare\",\n        invented_year: 2010,\n    },\n    Language {\n        name: \"Go 🧋\",\n        designed_by: \"Rob Pike\",\n        invented_year: 2009,\n    },\n];\n```\n\nThe resultant table will look like the following.\nAs you can see Github tricks a bit a return table, but `GNOME terminal` and `Alacritty` terminal handle it correctly.\n\n```text\n+---------+----------------+---------------+\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```\n\n### Terminal size\n\nIt's a frequent case where it's necessary to align a table to a terminal width or height.\nYou can achieve that by using `Width` and `Height`.\nYou can peak a strategy by which a column/row truncation/widening will be done by using `Priority`.\n\nThis example uses `terminal_size` crate to determine ones size, but it's possible to use anything.\n\n```rust\nuse tabled::{\n    builder::Builder,\n    settings::{peaker::Priority, Height, Settings, Width},\n    Table,\n};\nuse terminal_size::{terminal_size, Height as TerminalHeight, Width as TerminalWidth};\n\nfn get_terminal_size() -\u003e (usize, usize) {\n    let (TerminalWidth(width), TerminalHeight(height)) =\n        terminal_size().expect(\"failed to obtain a terminal size\");\n\n    (width as usize, height as usize)\n}\n\nlet (width, height) = get_terminal_size();\n\nlet data = [\n    [\"0.2.1\", \"2021-06-23\", \"true\", \"#[header(inline)] attribute\"],\n    [\"0.2.0\", \"2021-06-19\", \"false\", \"API changes\"],\n    [\"0.1.4\", \"2021-06-07\", \"false\", \"display_with attribute\"],\n];\n\nlet settings = Settings::default()\n    .with(Width::wrap(width).priority(Priority::max(true)))\n    .with(Width::increase(width))\n    .with(Height::limit(height))\n    .with(Height::increase(height));\n\nlet mut table = Table::from_iter(data);\ntable.with(settings);\n\nprintln!(\"{table}\");\n```\n\n### Semver\n\n\u003e When you need to release a breaking change — any breaking change — you do it in a major version. Period. No excuses.\n\nWe still do it.\nWe often do breaking changes on minor version bump.\nSo you probably shall not depend on minor version (like `0.7`).\nIt's likely better to depend on constant version e.g. `=0.8.0`\n\n### MSRV\n\nBreaking MSRV considered to be a breaking change; but see [semver-note](#semver)\n\n### Comparison\n\nNowadays there are a few libraries for pretty tables.\nSome may wonder why `tabled` is better or worse than others libraries?\n\nI hope `tabled` does its job well, but at the end of the day you probably need to decide for yourself.\nIf you have any ideas for an enhancement or have a question about `tabled` please file an issue.\n\nBelow you will find a list of crates which do similar things or do something which `tabled` doesn't.\n\nYou can find performance comparison benchmarks [here](https://github.com/zhiburt/tabled/tree/master/tabled/benches/lib_comp).\n\nThe description is taken from the author's quotes.\n\n* *[`cli-table`](https://github.com/devashishdxt/cli-table/) tends to keep the compile time and crate size low and support all the platforms. It has an optional `csv` support.*\n\n* *[`comfy-table`](https://github.com/Nukesor/comfy-table) focuses on providing a minimalistic, but rock-solid library for building text-based tables with focus on safety and dynamic-length content arrangement.*\n\n* *[`term-table-rs`](https://github.com/RyanBluth/term-table-rs) main focus is on a good set of tools for rendering CLI tables, while allowing users to bring their own tools for things like colors. It has an ability to have different number of columns in each row of the table.*\n\nPlease open an issue if you feel another crate is worth mentioning.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhiburt%2Ftabled","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhiburt%2Ftabled","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhiburt%2Ftabled/lists"}