summaryrefslogtreecommitdiffstats
path: root/README.md
blob: dca2c2abfa7b52ec9a3c7f4e9cdae5e5e73d1797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
![License](http://img.shields.io/badge/license-BSD-lightgrey.svg)
[![Build Status](https://travis-ci.org/phsym/prettytable-rs.svg?branch=master)](https://travis-ci.org/phsym/prettytable-rs)
[![Build status](https://ci.appveyor.com/api/projects/status/wdh9klb35fed6ik9?svg=true)](https://ci.appveyor.com/project/phsym/tabprint)
[![codecov](https://codecov.io/gh/phsym/prettytable-rs/branch/master/graph/badge.svg)](https://codecov.io/gh/phsym/prettytable-rs)
[![Crates.io](https://img.shields.io/crates/v/prettytable-rs.svg)](https://crates.io/crates/prettytable-rs)
[![Doc.rs](https://docs.rs/prettytable-rs/badge.svg)](https://docs.rs/crate/prettytable-rs/)
[![Doc.rs](https://img.shields.io/badge/docs-master-blue.svg)](http://phsym.github.io/prettytable-rs/master)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=phsym/prettytable-rs)](https://dependabot.com)
# prettytable-rs

A formatted and aligned table printer library for [Rust](https://www.rust-lang.org).

*Copyright © 2018 Pierre-Henri Symoneaux*

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

# How to use

  * [Including](#user-content-including)
  * [Basic usage](#user-content-basic-usage)
  * [Using macros](#user-content-using-macros)
  * [Do it with style](#user-content-do-it-with-style)
    * [List of style specifiers](#user-content-list-of-style-specifiers)
    * [List of color specifiers](#user-content-list-of-color-specifiers)
  * [Slicing](#user-content-slicing)
  * [Customize look and feel of a table](#customize-look-and-feel-of-a-table)
  * [CSV import/export](#user-content-csv-importexport)
    * [Importing](#user-content-importing)
    * [Exporting](#user-content-exporting)
  * [Note on line endings](#user-content-note-on-line-endings)

## Including

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

```toml
[dependencies]
prettytable-rs = "^0.8"
```

The library requires at least `rust v1.32.0`.

## Basic usage

Start using it like this:

```rust
#[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

```text
+---------+------+---------+
| 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:
```rust
#[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:
```rust
#[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:
```rust
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
```text
+-------------------------+------------------------------+
| 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:
  ```rust
  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:
  ```rust
  table.add_row(Row::new(vec![
      Cell::new("foobar").style_spec("bFg"),
      Cell::new("bar").style_spec("BriH2"),
      Cell::new("foo")]));
  ```

- using `row!` macro:
  ```rust
  table.add_row(row![bFg->"foobar", BriH2->"bar", "foo"]);
  ```

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

Here
- **bFg** means **bold**, **F**oreground: **g**reen,
- **BriH2** means **B**ackground: **r**ed, **i**talic, **H**orizontal span of **2**.

Another example: **FrBybc** means **F**oreground: **r**ed, **B**ackground: **y**ellow, **b**old, **c**enter.

All cases of styling cells in macros:

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

### List of style specifiers:

* **F** : **F**oreground (must be followed by a color specifier)
* **B** : **B**ackground (must be followed by a color specifier)
* **H** : **H**orizontal span (must be followed by a number)
* **b** : **b**old
* **i** : **i**talic
* **u** : **u**nderline
* **c** : Align **c**enter
* **l** : Align **l**eft
* **r** : Align **r**ight
* **d** : **d**efault 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,
```rust
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:
```rust
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

```rust
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:
- ```rust
  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 |
  +-------------+------------+
  ```
- ```rust
  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:
```rust
let table = Table::from_csv_string("ABC,DEFG,HIJKLMN\n\
                                    foobar,bar,foo\n\
                                    foobar2,bar2,foo2")?;
```
or from CSV files:
```rust
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:
```rust
let reader = /* create a reader */;
/* do something with the reader */
let table = Table::from_csv(reader);
```

### Exporting
Export to a generic `Write`:
```rust
let out = File::create("output_csv.txt")?;
table.to_csv(out)?;
```
or to a `csv::Writer<W: Write>`:
```rust
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](./examples/) directory.