Coder Social home page Coder Social logo

phsym / prettytable-rs Goto Github PK

View Code? Open in Web Editor NEW
901.0 12.0 74.0 39.51 MB

A rust library to print aligned and formatted tables

Home Page: https://crates.io/crates/prettytable-rs

License: BSD 3-Clause "New" or "Revised" License

Rust 100.00%
rust crates cli formatting

prettytable-rs's Introduction

License Build Status Build status codecov Crates.io Doc.rs Doc.rs

prettytable-rs

A formatted and aligned table printer library for Rust.

Copyright © 2022 Pierre-Henri Symoneaux

THIS SOFTWARE IS DISTRIBUTED WITHOUT ANY WARRANTY
Check LICENSE.txt file for more information.

How to use

Including

Include the library as a dependency to your project by adding the following lines to your Cargo.toml file:

[dependencies]
prettytable-rs = "^0.10"

The library requires at least rust v1.56.

Any changes to the MSRV will be done with a minor version bump.

SemVer Policy

  • Pre-1.0.0 breaking changes will follow a minor version bump
  • Post-1.0.0 All default features of this library are covered by SemVer
  • MSRV is considered exempt from SemVer as noted above

Basic usage

Start using it like this:

#[macro_use] extern crate prettytable;
use prettytable::{Table, Row, Cell};

fn main() {
    // Create the table
    let mut table = Table::new();

    // Add a row per time
    table.add_row(row!["ABC", "DEFG", "HIJKLMN"]);
    table.add_row(row!["foobar", "bar", "foo"]);
    // A more complicated way to add a row:
    table.add_row(Row::new(vec![
        Cell::new("foobar2"),
        Cell::new("bar2"),
        Cell::new("foo2")]));

    // Print the table to stdout
    table.printstd();
}

The code above will output

+---------+------+---------+
| ABC     | DEFG | HIJKLMN |
+---------+------+---------+
| foobar  | bar  | foo     |
+---------+------+---------+
| foobar2 | bar2 | foo2    |
+---------+------+---------+

Using macros

For everyday usage consider table! macro. This code will produce the same output as above:

#[macro_use] extern crate prettytable;

fn main() {
    let table = table!(["ABC", "DEFG", "HIJKLMN"],
                       ["foobar", "bar", "foo"],
                       ["foobar2", "bar2", "foo2"]);

    table.printstd();
}

The ptable! macro combines creating and printing a table:

#[macro_use] extern crate prettytable;

fn main() {
    let table = ptable!(["ABC", "DEFG", "HIJKLMN"],
                        ["foobar", "bar", "foo"],
                        ["foobar2", "bar2", "foo2"]);
}

Tables also support multiline cells content. As a result, you can print a table into another table (yo dawg ;). For example:

let table1 = table!(["ABC", "DEFG", "HIJKLMN"],
                    ["foobar", "bar", "foo"],
                    ["foobar2", "bar2", "foo2"]);

let table2 = table!(["Title 1", "Title 2"],
                    ["This is\na multiline\ncell", "foo"],
                    ["Yo dawg ;) You can even\nprint tables\ninto tables", table1]);

table2.printstd();

will print

+-------------------------+------------------------------+
| Title 1                 | Title 2                      |
+-------------------------+------------------------------+
| This is                 | foo                          |
| a multiline             |                              |
| cell                    |                              |
+-------------------------+------------------------------+
| Yo dawg ;) You can even | +---------+------+---------+ |
| print tables            | | ABC     | DEFG | HIJKLMN | |
| into tables             | +---------+------+---------+ |
|                         | | foobar  | bar  | foo     | |
|                         | +---------+------+---------+ |
|                         | | foobar2 | bar2 | foo2    | |
|                         | +---------+------+---------+ |
+-------------------------+------------------------------+

Rows may have different numbers of cells. The table will automatically adapt to the largest row by printing additional empty cells in smaller rows.

Do it with style!

Tables can have a styled output with background and foreground colors, bold and italic as configurable settings, thanks to the term crate. Alignment in cells can also be set (Left, Right, Center), and a cell can span accross multiple columns.

term style attributes are reexported

  • directly:

    use prettytable::{Attr, color};
    
    /* ... */
    
    table.add_row(Row::new(vec![
        Cell::new("foobar")
            .with_style(Attr::Bold)
            .with_style(Attr::ForegroundColor(color::GREEN)),
        Cell::new("bar")
            .with_style(Attr::BackgroundColor(color::RED))
            .with_style(Attr::Italic(true))
            .with_hspan(2),
        Cell::new("foo")
        ]));
  • through style strings:

    table.add_row(Row::new(vec![
        Cell::new("foobar").style_spec("bFg"),
        Cell::new("bar").style_spec("BriH2"),
        Cell::new("foo")]));
  • using row! macro:

    table.add_row(row![bFg->"foobar", BriH2->"bar", "foo"]);
  • using table! macro (this one creates a new table, unlike previous examples):

    table!([bFg->"foobar", BriH2->"bar", "foo"]);

Here

  • bFg means bold, Foreground: green,
  • BriH2 means Background: red, italic, Horizontal span of 2.

Another example: FrBybc means Foreground: red, Background: yellow, bold, center.

All cases of styling cells in macros:

  • With row!, for each cell separately:
    row![FrByb->"ABC", FrByb->"DEFG", "HIJKLMN"];
  • With row!, for the whole row:
    row![FY => "styled", "bar", "foo"];
  • With table!, for each cell separately:
    table!([FrBybl->"A", FrBybc->"B", FrBybr->"C"], [123, 234, 345, 456]);
  • With table!, for whole rows:
    table!([Frb => "A", "B", "C"], [Frb => 1, 2, 3, 4], [1, 2, 3]);
  • With table!, mixed styling:
    table!([Frb => "A", "B", "C"], [Frb->1, Fgi->2, 3, 4], [1, 2, 3]);

List of style specifiers:

  • F : Foreground (must be followed by a color specifier)
  • B : Background (must be followed by a color specifier)
  • H : Horizontal span (must be followed by a number)
  • b : bold
  • i : italic
  • u : underline
  • c : Align center
  • l : Align left
  • r : Align right
  • d : default style

List of color specifiers:

Lowercase letters stand for usual colors:

  • r : Red
  • b : Blue
  • g : Green
  • y : Yellow
  • c : Cyan
  • m : Magenta
  • w : White
  • d : Black

Uppercase letters stand for bright counterparts of the above colors:

  • R : Bright Red
  • B : Bright Blue
  • ... and so on ...

Slicing

Tables can be sliced into immutable borrowed subtables. Slices are of type prettytable::TableSlice<'a>.

For example,

use prettytable::Slice;
/* ... */
let slice = table.slice(2..5);
table.printstd();

will print a table with only lines 2, 3 and 4 from table.

Other Range syntaxes are supported. For example:

table.slice(..); // Returns a borrowed immutable table with all rows
table.slice(2..); // Returns a table with rows starting at index 2
table.slice(..3); // Returns a table with rows until the one at index 3

Customize look and feel of a table

The look and feel of a table can be customized with prettytable::format::TableFormat.

Configurable settings include:

  • Borders (left and right)
  • Junctions
  • Column separators
  • Line separators
  • Titles (using table.set_titles())

To do this, either:

  • create a new TableFormat object, then call setters until you get the desired configuration;
  • or use the convenient FormatBuilder and Builder pattern, shown below
let mut table = Table::new();
let format = format::FormatBuilder::new()
    .column_separator('|')
    .borders('|')
    .separators(&[format::LinePosition::Top,
                  format::LinePosition::Bottom],
                format::LineSeparator::new('-', '+', '+', '+'))
    .padding(1, 1)
    .build();
table.set_format(format);

table.set_titles(row!["Title 1", "Title 2"]);
table.add_row(row!["Value 1", "Value 2"]);
table.add_row(row!["Value three", "Value four"]);

The code above will make the table look like

+-------------+------------+
| Title 1     | Title 2    |
| Value 1     | Value 2    |
| Value three | Value four |
+-------------+------------+

For convenience, several formats are predefined in prettytable::format::consts module.

Some formats and their respective outputs:

  • use prettytable::format;
    
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
    +-------------+------------+
    | Title 1     | Title 2    |
    +-------------+------------+
    | Value 1     | Value 2    |
    | Value three | Value four |
    +-------------+------------+
    
  • use prettytable::format;
    
    table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
    Title 1     | Title 2
    ------------+------------
    Value 1     | Value 2
    Value three | Value four
    

Check API documentation for the full list of available predefined formats.

CSV import/export

Tables can be imported from and exported to CSV. This is possible thanks to the default & optional feature csv.

The csv feature may become deactivated by default on future major releases.

Importing

A Table can be imported from a string:

let table = Table::from_csv_string("ABC,DEFG,HIJKLMN\n\
                                    foobar,bar,foo\n\
                                    foobar2,bar2,foo2")?;

or from CSV files:

let table = Table::from_csv_file("input_csv.txt")?;

Those 2 ways of importing CSV assumes a CSV format with no headers, and delimited with commas

Import can also be done from a CSV reader which allows more customization around the CSV format:

let reader = /* create a reader */;
/* do something with the reader */
let table = Table::from_csv(reader);

Exporting

Export to a generic Write:

let out = File::create("output_csv.txt")?;
table.to_csv(out)?;

or to a csv::Writer<W: Write>:

let writer = /* create a writer */;
/* do something with the writer */
table.to_csv_writer(writer)?;

Note on line endings

By default, the library prints tables with platform specific line ending. This means on Windows, newlines will be rendered with \r\n while on other platforms they will be rendered with \n. Since v0.6.3, platform specific line endings are activated though the default feature win_crlf, which can be deactivated. When this feature is deactivated (for instance with the --no-default-features flag in cargo), line endings will be rendered with \n on any platform.

This customization capability will probably move to Formatting API in a future release.

Additional examples are provided in the documentation and in examples directory.

Evcxr Integration

Evcxr is a Rust REPL and a Jupyter notebook kernel. This crate integrates into Evcxr and the Jupyter notebooks using the evcxr feature flag, which enables native displays of tables. This includes support for displaying colors and various formattings.

You can include prettytable as a dependency using this line:

:dep prettytable = { git = "https://github.com/phsym/prettytable-rs", package = "prettytable-rs", features = ["evcxr"] }

prettytable being used in a Jupyter notebook with Evcxr Rust kernel.

prettytable-rs's People

Contributors

5225225 avatar alex avatar alexbool avatar askobara avatar david0u0 avatar dependabot-preview[bot] avatar firstyear avatar hcpl avatar hoodie avatar jonasbb avatar matthiasbeyer avatar mohamedhayibor avatar nabijaczleweli avatar nschoellhorn avatar phsym avatar pinkforest avatar pjf avatar rivertam avatar rotty avatar silwol avatar skade avatar vn971 avatar xanonid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prettytable-rs's Issues

Make platform specific newlines optional

Right now this library prints \r\n on windows for newlines. This makes my tool a bit inconsistent, because the rest of the tool doesn't special-case for windows. In general I don't think it's a big issue for command-line tools to output unix newlines since windows isn't a natural command-line platform.

Can you add a way to turn off the platform specific newlines?

Set background for entire table

(More of a question than an issue.)

Is it possible to set the background of the entire table as apposed to setting the background of individual cells? I looked at the docs but I didn't find anything.

Setting the background of each cell gives me this:
Screenshot from 2019-03-12 16-24-23
Ideally the whole table would be white.

Implement column/table max-width

I would be neat if you could specify a max width for columns and/or tables and have prettytable automatically truncate strings (and probably add a configurable indicator like ...) that exceed that length.

Use rustup in appveyor script

It's quite borring to have to update appveyor script each time a new rust version is released.
Now that rustup s the official way of installing rust, it should be used in appveyor script.

Cell, row, column and table alignment

Hi,

I'm currently developing a tool (Process-Query) with @keeperofdakeys . I would like to be able to use your library to print text such as:

              total        used        free      shared  buff/cache   available
Mem:       12202880     3768524      663128      459220     7771228     7804748

Note that the first column is left aligned, and the rest are right aligned.

So I was thinking of various ways to implement alignment helpers beyond just per cell.

I don't think that alignment as part of the table format is correct. It would either override everything, be copied as cells are added, or have to be a "default".

Each of these three has issues.

The override on everything, doesn't work in my case. You would need code that then allows Cell alignment to override table alignment. This adds complication.

Being copied as cells are added has it's own special issues. Consider (kinda pseudo code):

let mut table = Table::new();
table.add_row(vec![...]);
let format  =FormatBuilder::new().alignment(LEFT);
table.set_format(format);

This means the format can change part way through the tables construction, which could lead to nasty surprises.

Finally, having a default, would mean that cells would need to be able to express "default" alignment. So another type in the alignment enum. But this means you need code to again, check for the default vs a real alignment, collect the default from the format. You also need to make sure the format doesn't set the default enum value itself. More edge cases.

I think the perhaps the easiest solution is a collection of map functions. map row and map column. This would allow the application of a function to each cell in the table. This could be alignment, or some other formatting, so would be rather generic.

Alternately, an iter for mut row could be added to allow "for c in row" and "for c in column": Again, similar to map.

What do you think? I'm happy to take your advice, and implement the solution.

PS: Later this may apply to padding in each cell also, as I have some specific padding / width requirements I'd like to meet.

Support box drawing characters

Unicode contains a set of characters to draw uninterrupted lines that can be used to create much cleaner, visually less noisy borders.
https://en.wikipedia.org/wiki/Box-drawing_character

Instead of

+---------+------+---------+
| ABC     | DEFG | HIJKLMN |
+---------+------+---------+
| foobar  | bar  | foo     |
+---------+------+---------+
| foobar2 | bar2 | foo2    |
+---------+------+---------+

you could create

┌─────────┬──────┬─────────┐
│ ABC     │ DEFG │ HIJKLMN │
├─────────┼──────┼─────────┤
│ foobar  │ bar  │ foo     │
├─────────┼──────┼─────────┤
│ foobar2 │ bar2 │ foo2    │
└─────────┴──────┴─────────┘

which is actually still interrupted vertically with the font my browser uses, but in my terminal and my editor those are connected.

Of course, legacy systems may not be able to deal with unicode, so you might want to keep it ASCII by default or at least add an ASCII fallback option.
I'm not currently a user of the library, I just chanced upon it when I was searching for crates to help me add this functionality to tokei. It seems to from the LineSeparator struct that the above table can't currently be created because there is only the distinction between junctions at the left and right border and the middle. Taking into account the top and bottom row, there are 5 junctions and 4 corners in total, not counting the half-bold, half-thin characters or half-single, half-double characters

TableFormat documentation is outdated

Hi,

the docs say that TableFormat gets a Option<char> as first parameter, but passing None results in:

src/ui/file.rs:165:45: 165:49 error: mismatched types:
expected `char`,
found `core::option::Option<_>`

Please fix. Besides, please continue contributing, I like your crate a lot!

Table layout breaks when cell text contains ANSI color patterns

When using Table with ordinary characters I get a nice and pretty table like this:

+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+
|      | M1    | M2    | M4     | M5    | M10   | M15    | M20   | M30    | M60    |
+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+
| VTBR | 7.55% | 0.21% | -4.37% | 1.56% | 8.49% | -1.78% | 4.95% | -5.95% | -3.80% |
+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+

When I start to paint the text inside cells with ansi_term crate, I get this:

+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+
|             | M1  | M2  | M4   | M5  | M10 | M15  | M20 | M30  | M60  |
+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+
| VTBR | 7.55% | 0.21% | -4.37% | 1.56% | 8.49% | -1.78% | 4.95% | -5.95% | -3.80% |
+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+

Seems like ANSI chars are treated as 'normal' printable symbols which is obviously not true.

CSV import / export

Add capability to import from CSV, and export into CSV.
API should support strings, streams or files.

panicked at 'Cannot print table to standard output : operation not supported by the terminal'

Inside Emacs's M-x shell, the cargo benchcmp command will always panic because of prettytable:

$ cargo benchcmp ~/scratch/before ~/scratch/after
thread 'main' panicked at 'Cannot print table to standard output : operation not supported by the terminal', /Users/fitzgen/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.6.5/src/lib.rs:173
stack backtrace:
   1:        0x103c9bafa - std::sys::backtrace::tracing::imp::write::h46f28e67d38b4637
   2:        0x103c9dabf - std::panicking::default_hook::{{closure}}::h1d3243f546573ff4
   3:        0x103c9cf85 - std::panicking::default_hook::h96c288d728df3ebf
   4:        0x103c9d536 - std::panicking::rust_panic_with_hook::hb1322e5f2588b4db
   5:        0x103c9d3d4 - std::panicking::begin_panic::hfbeda5aad583dc32
   6:        0x103c9d2f2 - std::panicking::begin_panic_fmt::h4fe9fb9d5109c4bf
   7:        0x103c05962 - prettytable::TableSlice::print_tty::h7f3d5c1f5cfe8a0a
   8:        0x103bff5fd - cargo_benchcmp::Args::run::h5c6cc5028d1347fb
   9:        0x103bfa6e9 - cargo_benchcmp::main::hb31fd77d8a66a286
  10:        0x103c9e07a - __rust_maybe_catch_panic
  11:        0x103c9cac6 - std::rt::lang_start::haaae1186de9de8cb

Ideally, prettytable would check if pretty colors or whatever are supported (which M-x shell actually will support, so maybe just removing whatever check will work?) and not use them if they aren't, rather than panicking.

(Originally filed as BurntSushi/cargo-benchcmp#15)

Macros do not work with selective import

Since Rust 1.30, macros can be individually imported with use. This does not work for ptable!, table! and row!, as they invoke other macros, which must be imported as well, exposing what can be considered implementation details. For example, the following code produces errors in both main and test_ptable:

fn main() {
    use prettytable::row;
    row!["x"];
}

fn test_ptable() {
    use prettytable::ptable;
    ptable!(["A", "B", "C"]);
}
error: cannot find macro `cell!` in this scope                                                           
[...]
error: cannot find macro `table!` in this scope                                                          

If we can bump the Rust requirement to 1.30, the fix is quite straightforward, namely prefixing macro invocations with $crate::, see the edition guide. I'll submit a PR implementing this solution; unfortunatly, the solution (also explained in the edition guide) that works on older compilers as well is quite ugly IMO; I'll leave that as an exercise for the reader ;-).

Panic when piped into head

When the output of the table is piped into head, the library panics. The issue was noticed in the measureme repo.

A minimal example would be

use prettytable::{Table, row, cell};

fn main() {
    let mut table = Table::new();
    for i in 1..=10 {
        table.add_row(row!["ROW NUMBER", i]);
    }
    table.printstd();
}

Run this with cargo run | head, and it will produce the output

$ RUST_BACKTRACE=1 cargo run | head
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/testtt`
+------------+----+
| ROW NUMBER | 1  |
+------------+----+
| ROW NUMBER | 2  |
+------------+----+
| ROW NUMBER | 3  |
+------------+----+
| ROW NUMBER | 4  |
+------------+----+
| ROW NUMBER | 5  |
thread 'main' panicked at 'Cannot print table to standard output : Broken pipe (os error 32)', /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:194:23
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
   1: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:70
   2: std::panicking::default_hook::{{closure}}
             at src/libstd/sys_common/backtrace.rs:58
             at src/libstd/panicking.rs:200
   3: std::panicking::default_hook
             at src/libstd/panicking.rs:215
   4: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:478
   5: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:385
   6: std::panicking::begin_panic_fmt
             at src/libstd/panicking.rs:340
   7: prettytable::TableSlice::print_tty
             at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:194
   8: prettytable::TableSlice::printstd
             at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:209
   9: prettytable::Table::printstd
             at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:376
  10: testtt::main
             at src/main.rs:8
  11: std::rt::lang_start::{{closure}}
             at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
  12: std::panicking::try::do_call
             at src/libstd/rt.rs:49
             at src/libstd/panicking.rs:297
  13: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:87
  14: std::rt::lang_start_internal
             at src/libstd/panicking.rs:276
             at src/libstd/panic.rs:388
             at src/libstd/rt.rs:48
  15: std::rt::lang_start
             at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
  16: main
  17: __libc_start_main
  18: _start

switch for parsable output

Many CLI programs use -H for headerless and -p for passable when it comes to printing tables. Reading the docs, I think that could be done by specifying a custom format, but it would be helpful to have a simple switch for those options.

Column macro

Hi @phsym,

I stumbled upon your crate for an application I'm writing and noticed that there isn't an easy way to create a table from columnar data. Have I missed this in the documentation, or is this yet to be implemented?

Thanks!
Mandeep

Weird indentations if externally-formatted strings are used

#[macro_use] extern crate prettytable;
extern crate ansi_term;

use prettytable::Table;
use ansi_term::Colour::Yellow;

fn main() {
    // Okay
    let mut table = Table::new();
    table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table.add_row(row![ Fybl->"Yellow Yellow Yellow" ]);
    table.printstd();

    // Messed up
    let mut table2 = Table::new();
    table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
    table2.add_row(row![ Yellow.bold().paint("Yellow Yellow Yellow") ]);
    table2.printstd();
}

In table2, the first column in the first 3 rows has extra paddings. Those paddings exist regardless of the alignment requested.

Sub-columns in title

I'm trying to generate a table like this

    foo    |    bar    |    baz    |
           |           |  a  |  b  |
===========+===========+=====+=====+
 cat       |   10      |  1  |  3  |
 dog       |   23      |  2  |  4  |

where one of the title cells has 2 rows, one row with a hspan of 2, and the other row has 2 cells, and the columns spanned by these two cells propagate to the rest of the table.

Is this possible ?

Add capability to print range of rows

Tasks

  • Implement TableSlice type
  • Create Slice trait and implement it for Table and TableSlice
    • With Range, RangeTo and RangeFrom to get a slice with only subrange of rows
    • With RangeFull to get the slice with all the rows
  • Make &Table transmutable into &TableSlice so a table can be treated as a slice
  • Implement AsRef<TableSlice<'a>>, and/or or Borrow<TableSlice>, and/or Deref<TableSlice> for Table
  • Update Doc
  • Add an example
  • Update README

Description

Create a struct TableSlice<'a> that wraps a ref to Table, which offers capability to print only a specific range of rows.
Perhaps slice syntax may be used to obtain this wrapper.
eg :

let mut table = Table::new();
/* (...) */
let slice: TableSlice<'a> = table[1..3];

Edit : Using slice syntax is not possible yet, since Index returns only references
Next idea is to create a Slice<T> trait with method slice(&self, T) -> TableSlice<'a> and implement it for Table and TableSlice with T as Range, RangeFull, RangeFrom, RangeTo

It will let us use the following syntax :

let mut table = Table::new();
/* (...) */
let slice: &'a TableSlice<'a> = table.as_ref();
let slice: TableSlice<'a> = table.slice(1..3);
let slice: TableSlice<'a> = table.slice(1..);
let slice: TableSlice<'a> = table.slice(..3);
let slice: TableSlice<'a> = table.slice(..);

Update table in-place

The tic-tac-toe example prints one table after the other. Would it be possible to have a "tic-tac-toe-inplace" example, where the table is updated in place ? How would I go about that ?

I'm looking to use this to update a table in place that can grow (e.g. get more rows, so that columns get resized).

Trailing comma results in infinite macro recursion

Looks like having a trailing comma in row!() invocation (and possibly other macros) results in infinite macro recursion.

I have something like this that triggers the error:

table.set_titles(row![
    Fg -> "Foo",
    Fg -> "Bar",
    "Baz",
    "Bad",
]);

Skip padding of final cell for FORMAT_CLEAN

FORMAT_CLEAN doesn't technically require padding of the final cell, since each row has a newline at the end. This can be desirable to avoid ridiculous output when the final cell differs in width by hundreds of characters. I'm unsure if this would be preferable in all situations though.

even prettier → encoding error

I have rewritten the original issue

Hey there,
I would love to draw line separators with these symbols:

.separators( &[format::LinePosition::Top],    format::LineSeparator::new('─', '┬', '┌', '┐'))
.separators( &[format::LinePosition::Intern], format::LineSeparator::new('─', '┼', '├', '┤'))
.separators( &[format::LinePosition::Bottom], format::LineSeparator::new('─', '┴', '└', '┘'))

however, there seems to be some sort of encoding problem, because they are not printed this way on the terminal

Expectation:

┌─────────────┬────────────┐
│ Title 1     | Title 2    │ 
├─────────────┼────────────┤
│ Value 1     | Value 2    │ 
├─────────────┼────────────┤
│ Value three | Value four │ 
└─────────────┴────────────┘

Result:

,
 Title 1      Title 2    
<$
 Value 1      Value 2    
<$
 Value three  Value four 
4▒

Do you have an idea what goes wrong here?
Thanks

Streaming

Hi,

Is there any way to generate a table/csv that doesn't required all the values to be loaded in memory ?
It looks like iterators are supported in some cases but the iterator is converted into Vec of cells/rows before it gets written.

Sorry if this is not the right place to ask question

Printing with indentation

For example, this

let table = table!([["ABC", "DEFG", "HIJKLMN"],
                    ["foobar", "bar", "foo"],
                    ["foobar2", "bar2", "foo2"]]);

// there would be `_indented` counterparts for all printing methods if API shouldn't break
table.printstd();
table.printstd_indented(8);

renders

+---------+------+---------+
| ABC     | DEFG | HIJKLMN |
+---------+------+---------+
| foobar  | bar  | foo     |
+---------+------+---------+
| foobar2 | bar2 | foo2    |
+---------+------+---------+
        +---------+------+---------+
        | ABC     | DEFG | HIJKLMN |
        +---------+------+---------+
        | foobar  | bar  | foo     |
        +---------+------+---------+
        | foobar2 | bar2 | foo2    |
        +---------+------+---------+

Would this be implemented sometime?

P.S. For convenience, a few table_print!-like macros can be defined like

macro_rules! table_printstd {
    ($table:expr) => { $table.printstd() };
    ($table:expr, indent = $indent:expr) => { $table.printstd_indented($indent) };
}
/* define for other pairs of print methods */

No Column Separator

Hi, is there a way to have NO column separator (for very tight tables), without changing the API?
Thanks

Source code with tabs, rendered in documentation, looks ugly

Each tab is rendered 8 spaces wide.

For example, with 17 levels of indentation the whole builder steps block is shifted out of the screen (its 1366 pixels wide in my case): http://phsym.github.io/prettytable-rs/v0.6.6/src/prettytable/src/format.rs.html#275-283.

Some solutions:

  • Use spaces instead of tabs
  • Change rendering options in rustdoc to render tabs 4 spaces wide

P.S. Apparently, GitHub renders with 8 spaces too (https://github.com/phsym/prettytable-rs/blob/master/src/format.rs#L275-L283), so the first solution looks more viable to me now.

Reduce visibility to private for some functions

Many functions today are public and visible to crate's users. Their usage is internal to the crate and they should be private instead.

As an example, this has already been reported in #57.

Let's warn users by deprecating them in a first time, and give them time to bring feedback if they eventually use some of those functions

This will have the advantages of simplifying the API and its documentation, and removing those internal functions from public API will make it easier to introduce bigger changes without breaking the public API.
After making them private, they can still be brought back to public later if needed.

List of deprecated function:

  • Cell::print
  • Cell::print_term
  • Cell::get_height
  • Cell::get_width
  • LineSeparator::print (Already deprecrated. Now changed to private)
  • TableFormat::print_line_separator
  • TableFormat::print_column_separator
  • TableSlice::get_column_num
  • Table::get_column_num
  • Row::column_count
  • Row::get_height
  • Row::get_column_width
  • Row::print
  • Row::print_term

If you already use some of the deprecated functions, and want them to stay public, let me know in comments

Improve / Refactor table format customization API

Table format customization API is a bit weird and not clean. Some refactoring should be done on it.
Builder Pattern may be use in a type named for example FormatBuilder.

What should be customizable :

  • Padding
    • Right
    • Left
  • Vertical separators
    • Right
    • Left
    • Intern
  • Horizontal separators
    • Top
    • Bottom
    • Intern
  • Junction characters
  • Colspan (delayed to a next release)
  • Default style (alignment, colors , ...) (delayed to a next release)
  • Implement builder pattern for API
  • Change default format constants to functions or lazy_static constants
  • Add a section about formatting in README
  • Add an example file

Cell redesign proposal

This is a proposal to remake Cell and related functionality to simplify fixing issues #45, #46 and possibly #47 (since this proposal, if accepted, will allow defining custom behaviour of cell elements in case of the outer table being shrinked).

Here are some ways how this proposal can be implemented.

1. Statically dispatched trait-based

trait CellContent { ... }
impl CellContent for Vec<String> { ... }    // represents lines
impl CellContent for Table { ... }
...
struct Cell<T: CellContent> {
    content: T,
    ...
}
  • Pros:

    • Easy for implementation: you don't have to care about the possibility of having values of different types in any given moment of time.
    • Safe: the table will behave exactly like you (author) designed it to be, since everything down to cells is verified by you.
    • Semi-easy to adapt existing public API:
      • Serious changes are likely to be required only for Cells, for other structs they're either avoidable, or have to do something with formatting and styling.
      • Thanks to this StackOverflow answer external appearance of cell! macros can remain the same.
  • Cons:

    • Unusable if you need differently typed contents, since the cell itself is locked to one type and because of the reason below. (Well, unusable if you don't want to convert everything to String. If this is the case this mode works perfectly fine)
    • Semi-difficult to adapt existing public API:
      • Since Table's and Row's backing storage is a homogeneous Vec, the <T> parameter would be needed to spread across the whole API.

2. Dynamically dispatched trait-based

For trait definition see above

struct Cell {
    content: Box<CellContent>,    // could be other box structure here
    ...
}
  • Pros:

    • Flexible: users will be able to define new types with their own behaviours in the table.

    • Easy to adapt existing public API:

      • Cell constructors: types can be backwards-compatibly generalized, whereas the amount of constructors remains the same.
      • This means cell! macro wouldn't have to be modified at all.
      • And (probably) everything else wouldn't change neither.

      As a result, public API changes would be minimal and backwards-compatible.

  • Cons:

    • Ineffective: Cell has to store CellContent boxed since we wouldn't know the exact type. This would certainly have performance implications, though their extent varies among usages.
    • Mildly unsafe: there should be some precautionary measures against bad CellContent implementations.

3. Enum-based

enum CellContentBox {
    Text(Vec<String>),    // represents lines
    Table(Table),
    ...
}

impl CellContentBox { ... }
struct Cell {
    content: CellContentBox,
    ...
}
  • Pros:

    • Effective: theoretically, everything in this case can be stored on stack.
    • Safe: same note for Statically dispatched trait-based.
  • Cons:

    • Inflexible: there is no easy way to add new types. You have to manually add a variant to CellContentBox and add implementation into all related functions and methods, which is a more cumbersome process than implementing a trait. It also makes code less clean and readable.
    • Difficult to adapt existing public API:
      • Cell constructors would probably have constructors for every enum variant.
      • Macros aren't capable of detecting types of input values, so this forces having a dedicated cell_*! for every enum variant.

UPD: More info about macros and wording.

Wrong alignment when having chinese code

+--------------+----------+----------------+
| 字段名称         | 字段描述     | 字段补充说明         |
+==============+==========+================+
| id           | 角色id值    |                |
+--------------+----------+----------------+
| name         | 角色名称     |                |
+--------------+----------+----------------+
| description  | 角色描述     |                |
+--------------+----------+----------------+
| created_time | 创建时间     | 由系统自动更新        |
+--------------+----------+----------------+
| updated_time | 更新时间     | 由系统自动更新        |
+--------------+----------+----------------+
| whatplat     | 哪个平台     |                |
+--------------+----------+----------------+
| ext_info     | 扩展信息     |                |
+--------------+----------+----------------+
+--------------+-------------------+-----------------------------+
| Field Name   | Field Description | Field Desc Complementation  |
+==============+===================+=============================+
| id           |           role id |                             |
+--------------+-------------------+-----------------------------+
| name         |         role name |                             |
+--------------+-------------------+-----------------------------+
| description  |  role description |                             |
+--------------+-------------------+-----------------------------+
| created_time |      created time | updated by db automatically |
+--------------+-------------------+-----------------------------+
| updated_time |      updated time | updated by db automatically |
+--------------+-------------------+-----------------------------+
| whatplat     |     what platform |                             |
+--------------+-------------------+-----------------------------+
| ext_info     | extend infomation |                             |
+--------------+-------------------+-----------------------------+

Automatically publish documentation from travis builds

Online crate documentation should be automatically published to github-pages from travis-ci jobs.
Documentation must be organnised into subdirectories :

  • 1 for master branch, updated for each successfully tested commits into master branch
  • 1 for each tag/release in order to archive release docs

#[derive(Hash)] for Table, Row, Cell other user facing data types

Thank you for sharing this crate, it is a great one!!

Could you please #[derive(Hash)] for the user facing data types? I want to put some tables in a HashMap and need the Hash trait.

It is always a good idea to implement the common traits listed in the API Guidelines. I think you have most of them except `Hash``.

EDIT: These are the traits I use for data types, following the API guidelines:
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]

EDIT2: an impl of std::iter::Extend for Row (to add cells) and Table (to add rows) will also be important to follow the API guidelines. I need this one even more than the HashMap

table-in-table style loss

#[macro_use] extern crate prettytable;

use prettytable::Table;

fn main() {
    let in_table = table!([
                          Frbc->"Red",
                          Fgbc->"Green",
                          Fbbc->"Blue"
    ]);

    let mut table = Table::new();
    table.add_row(row![Frbc=> "Red", "Red", "Red", "Red"]);
    table.add_row(row![in_table]);

    in_table.printstd();
    table.printstd();
}

When in_table is added as a row in table. It loses its styles.

On a related note. An option to automatically inherit the format of the outer table would be great.

Cell attributes won't show any change

I'm running a program on macOS. When using this section to put together a table:

for .. in .. {
    let mut index_cell = Cell::from(&index);
    index_cell.align(Alignment::RIGHT);

    let mut item_cell = Cell::from(&item.name);
    item_cell.style(Attr::ForegroundColor(0x00AAFF));
    table.add_row(row![index_cell, item.name, amount]);
}

the program compiles and runs but I neither see the alignment option working nor the color. Did I do something wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.