comfy-table

repository·main·Indexed 23 days ago

https://github.com/nukesor/comfy-table

A Rust library for building customizable terminal tables with automatic content wrapping and dynamic arrangement. It supports ANSI styling, presets like UTF8_FULL, and various alignment options. The library provides a sophisticated algorithm for optimal layouts across different terminal widths and includes feature flags for TTY support, custom styling, and crossterm re-exports.

Tokens
8.3K
Snippets
17
Records
36
Agent score
80%

What's inside comfy-table

  1. Compare comfy-table with other Rust table libraries

    main

    When choosing a table library for Rust, consider the following trade-offs:

    • comfy-table: Focuses on being a minimalistic, rock-solid library with high test coverage and no unsafe code in its own logic (only in the tty dependency, which can be disabled). Its core strength is a sophisticated algorithm for dynamic-length content arrangement to find optimal layouts for any terminal width.
    • cli-table: Prioritizes low compile times and small crate size by limiting dependencies (primarily termcolor and unicode-width).
    • term-table: A basic feature set that allows users to bring their own color tools. It uniquely supports rows with a different number of columns than the rest of the table.
    • prettytables-rs: Provides formatting and alignment but is currently abandoned and has security advisories associated with it.
  2. How to avoid unsafe code in comfy-table

    main

    While comfy-table itself contains no unsafe code, enabling the tty feature flag introduces an unsafe call in its dependencies (specifically crossterm) to detect terminal size via ioctl.

    To circumvent this and ensure no unsafe code is used in your dependency tree, you can explicitly call Table::force_no_tty().

  3. Configure advanced table layouts and alignment

    main

    You can enhance tables by applying presets (like UTF8_FULL), modifiers (like UTF8_ROUND_CORNERS), and setting content arrangement to ContentArrangement::Dynamic for automatic wrapping.

    To control alignment:

    • Use Cell::new("...").set_alignment(CellAlignment::...) for individual cells.
    • Use table.column_mut(index).set_cell_alignment(CellAlignment::...) to set a default alignment for an entire column.
    use comfy_table::modifiers::UTF8_ROUND_CORNERS;
    use comfy_table::presets::UTF8_FULL;
    use comfy_table::*;
    
    fn main() {
        let mut table = Table::new();
        table
            .load_preset(UTF8_FULL)
            .apply_modifier(UTF8_ROUND_CORNERS)
            .set_content_arrangement(ContentArrangement::Dynamic)
            .set_width(40)
            .set_header(vec!["Header1", "Header2", "Header3"])
            .add_row(vec![
                Cell::new("Center aligned").set_alignment(CellAlignment::Center),
                Cell::new("This is another text"),
                Cell::new("This is the third text"),
            ])
            .add_row(vec![
                "This is another text",
                "Now\nadd some\nmulti line stuff",
                "This is awesome",
            ]);
    
        // Set the default alignment for the third column to right
        let column = table.column_mut(2).expect("Our table has three columns");
        column.set_cell_alignment(CellAlignment::Right);
    
        println!("{table}");
    }
  4. Create a basic table with comfy-table

    main

    To create a simple table, instantiate a Table using Table::new(), set a header with set_header(), and add rows using add_row(). By default, the table will expand to fit its content width.

    use comfy_table::Table;
    
    fn main() {
        let mut table = Table::new();
        table
            .set_header(vec!["Header1", "Header2", "Header3"])
            .add_row(vec![
                "This is a text",
                "This is another text",
                "This is the third text",
            ])
            .add_row(vec![
                "This is another text",
                "Now\nadd some\nmulti line stuff",
                "This is awesome",
            ]);
    
        println!("{table}");
    }
  5. Apply ANSI styling and colors to cells

    main

    Cells can be styled using colors (fg for foreground, bg for background) and attributes (add_attribute or add_attributes).

    Common styling methods:

    • .fg(Color::...): Set foreground color.
    • .bg(Color::...): Set background color.
    • .add_attribute(Attribute::...): Add a single attribute like Attribute::Bold or Attribute::SlowBlink.
    • .add_attributes(vec![...]): Add multiple attributes at once.
    use comfy_table::presets::UTF8_FULL;
    use comfy_table::*;
    
    fn main() {
        let mut table = Table::new();
        table.load_preset(UTF8_FULL)
            .set_content_arrangement(ContentArrangement::Dynamic)
            .set_width(80)
            .set_header(vec![
                Cell::new("Header1").add_attribute(Attribute::Bold),
                Cell::new("Header2").fg(Color::Green),
                Cell::new("Header3"),
            ])
            .add_row(vec![
                 Cell::new("This is a bold text").add_attribute(Attribute::Bold),
                 Cell::new("This is a green text").fg(Color::Green),
                 Cell::new("This one has black background").bg(Color::Black),
            ])
            .add_row(vec![
                Cell::new("Blinky boi").add_attribute(Attribute::SlowBlink),
                Cell::new("This table's content is dynamically arranged. The table is exactly 80 characters wide.\nHere comes a reallylongwordthatshoulddynamicallywrap"),
                Cell::new("COMBINE ALL THE THINGS")
                    .fg(Color::Green)
                    .bg(Color::Black)
                    .add_attributes(vec![
                        Attribute::Bold,
                        Attribute::SlowBlink,
                    ])
            ]);
    
        println!("{table}");
    }
  6. Troubleshoot broken styling in comfy-table

    main

    If styling is not appearing as expected, ensure you are using the internal styling methods provided by the comfy_table::Cell struct (such as .fg()).

    comfy-table does not support styling via external libraries, including crossterm. Because the library cannot detect or interpret ANSI escape sequences that it did not create itself, any styling injected from outside the Cell API will likely be ignored or cause layout breakage.

  7. Reference feature flags for comfy-table

    main

    Comfy-table uses feature flags to control functionality and performance:

    • tty (enabled by default): Enables terminal support, including automatic terminal width detection (if no width is set) and ANSI escape code styling.
    • custom_styling (disabled by default): Enables advanced text styling like rainbow text. Note: This makes the library 30-50% slower.
    • reexport_crossterm (disabled by default): Re-exposes crossterm::style::Attribute and crossterm::style::Color directly. Enabling this allows you to use crossterm types interchangeably with comfy-table, but makes you opt-in to breaking changes on minor/patch versions if crossterm updates.
  8. Create and style a table with comfy-table

    main

    To create a table, instantiate Table::new() and use a builder pattern to configure its appearance and content.

    Key capabilities demonstrated in this pattern include:

    • Presets: Apply predefined styles like UTF8_FULL using .load_preset().
    • Layout: Control how content is wrapped and arranged using .set_content_arrangement(ContentArrangement::Dynamic) and set a fixed width with .set_width(n).
    • Headers: Define a header row using .set_header(vec![...]).
    • Rows: Add data rows using .add_row(vec![...]).
    • Cell Styling: Individual cells are created with Cell::new("text"). You can apply styles directly to cells using:
      • .add_attribute(Attribute::...) for text effects (e.g., Attribute::Bold, Attribute::SlowBlink).
      • .fg(Color::...) to set foreground color.
      • .bg(Color::...) to set background color.
      • .add_attributes(vec![...]) to apply multiple attributes at once.

    Finally, the table can be printed using the Display implementation via println!("{table}").

    use comfy_table::{presets::UTF8_FULL, *};
    
    fn main() {
        let mut table = Table::new();
        table.load_preset(UTF8_FULL)
            .set_content_arrangement(ContentArrangement::Dynamic)
            .set_width(80)
            .set_header(vec![
                Cell::new("Header1").add_attribute(Attribute::Bold),
                Cell::new("Header2").fg(Color::Green),
                Cell::new("Header3"),
            ])
            .add_row(vec![
                Cell::new("This is a bold text").add_attribute(Attribute::Bold),
                Cell::new("This is a green text").fg(Color::Green),
                Cell::new("This one has black background").bg(Color::Black),
            ])
            .add_row(vec![
                Cell::new("Blinky boi").add_attribute(Attribute::SlowBlink),
                Cell::new("This table's content is dynamically arranged. The table is exactly 80 characters wide.\nHere comes a reallylongwordthatshoulddynamicallywrap"),
                Cell::new("COMBINE ALL THE THINGS")
                .fg(Color::Green)
                .bg(Color::Black)
                .add_attributes(vec![
                    Attribute::Bold,
                    Attribute::SlowBlink,
                ])
            ]);
    
    println!("{table}");
    }
  9. Create a basic table with dynamic content arrangement

    main

    You can create a Table and configure its layout using set_content_arrangement, set_width, and load_preset. Using ContentArrangement::Dynamic allows the table to wrap text and adjust cell content to fit within the specified width. This example demonstrates a table that functions even when the tty feature is disabled, meaning it will not attempt to use terminal-specific styling like colors or bold text.

    To run this specific example without default features, use:

    cargo run --example no_tty -- --no-default-features
    use comfy_table::{presets::UTF8_FULL, *};
    
    fn main() {
        let mut table = Table::new();
        table.load_preset(UTF8_FULL)
            .set_content_arrangement(ContentArrangement::Dynamic)
            .set_width(80)
            .set_header(vec![
                Cell::new("Header1"),
                Cell::new("Header2"),
                Cell::new("Header3"),
            ])
            .add_row(vec![
                Cell::new("No bold text without tty"),
                Cell::new("No colored text without tty"),
                Cell::new("No custom background without tty"),
            ])
            .add_row(vec![
                Cell::new("Blinky boi"),
                Cell::new("This table's content is dynamically arranged. The table is exactly 80 characters wide.\nHere comes a reallylongwordthatshoulddynamicallywrap"),
                Cell::new("Done"),
            ]);
    
    println!("{table}");
    }
  10. Create and build a Table

    main

    The Table struct is the primary interface for building and rendering tables. A table consists of Rows, which contain Cells. Columns are automatically generated as you add rows or a header.

    By default, Table::new() uses the ASCII_FULL preset. You can render the table using the Display trait (e.g., println!("{}", table)) or by iterating over its lines with .lines().

    use comfy_table::{Row, Table};
    
    let mut table = Table::new();
    table.set_header(Row::from(vec!["Header One", "Header Two"]));
    table.add_row(vec!["One", "Two"]);
    
    println!("{}", table);
  11. Create a new Cell

    main

    You can create a Cell using Cell::new(content) with any type that implements ToString, or by using the From trait for conversions. When creating a cell, the content is automatically split by newlines to handle multi-line content easily.

    use comfy_table::Cell;
    
    // Using new()
    let cell = Cell::new("Some content");
    
    // Using From trait
    let cell: Cell = "content".into();
    let cell: Cell = 5u32.into();
    use comfy_table::Cell;
    
    let cell = Cell::new("Some content");
    
    let cell: Cell = "content".into();
    let cell: Cell = 5u32.into();
  12. Use the Color enum for table styling

    main

    The Color enum is used to specify foreground (Cell::fg) and background (Cell::bg) colors for table cells. It provides a simplified interface for terminal colors, supporting standard base colors, RGB values, and ANSI color codes.

    Supported Colors

    LightDark
    DarkGreyBlack
    RedDarkRed
    GreenDarkGreen
    YellowDarkYellow
    BlueDarkBlue
    MagentaDarkMagenta
    CyanDarkCyan
    WhiteGrey

    Advanced Color Options

    • Rgb { r, g, b }: Specifies a color using the RGB model. Supported by most UNIX terminals and Windows 10 consoles.
    • AnsiValue(u8): Specifies an ANSI color code. Supported by most UNIX terminals and Windows 10 consoles.
    • Reset: Resets the terminal color.