tablewriter

package module
v0.0.0-...-6d6105d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2022 License: Apache-2.0 Imports: 12 Imported by: 0

README

ASCII Table Writer

ci Total views Godoc

A fork from github.com/olekukonko/tablewriter. Credits to Oleku Konko , Mitsuo Heijo and mattn for this great original contribution.

A go library to generate ASCII tables.

    go get github.com/fredbi/tablewriter
Features
  • Automatic Padding
  • Support Multiple Lines
  • Supports Alignment
  • Support Custom Separators
  • Automatic Alignment of numbers & percentage
  • Write directly to http , file etc via io.Writer
  • Read directly from CSV file
  • Optional row line via SetRowLine
  • Normalise table header
  • Make CSV Headers optional
  • Enable or disable table border
  • Set custom footer support
  • Optional identical cells merging
  • Set custom caption
  • Optional reflowing of paragraphs in multi-line cells.
Example 1 - Basic
data := [][]string{
    []string{"A", "The Good", "500"},
    []string{"B", "The Very very Bad Man", "288"},
    []string{"C", "The Ugly", "120"},
    []string{"D", "The Gopher", "800"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Name", "Sign", "Rating"})

for _, v := range data {
    table.Append(v)
}
table.Render() // Send output
Output 1
+------+-----------------------+--------+
| NAME |         SIGN          | RATING |
+------+-----------------------+--------+
|  A   |       The Good        |    500 |
|  B   | The Very very Bad Man |    288 |
|  C   |       The Ugly        |    120 |
|  D   |      The Gopher       |    800 |
+------+-----------------------+--------+
data := [][]string{
    []string{"1/1/2014", "Domain name", "2233", "$10.98"},
    []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
    []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
    []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
table.SetBorder(false)                                // Set Border to false
table.AppendBulk(data)                                // Add Bulk Data
table.Render()
Output 2

    DATE   |       DESCRIPTION        |  CV2  | AMOUNT
-----------+--------------------------+-------+----------
  1/1/2014 | Domain name              |  2233 | $10.98
  1/1/2014 | January Hosting          |  2233 | $54.95
  1/4/2014 | February Hosting         |  2233 | $51.00
  1/4/2014 | February Extra Bandwidth |  2233 | $30.00
-----------+--------------------------+-------+----------
                                        TOTAL | $146 93
                                      --------+----------

Example 3 - CSV
table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test_info.csv", true)
table.SetAlignment(tablewriter.ALIGN_LEFT)   // Set Alignment
table.Render()
Output 3
+----------+--------------+------+-----+---------+----------------+
|  FIELD   |     TYPE     | NULL | KEY | DEFAULT |     EXTRA      |
+----------+--------------+------+-----+---------+----------------+
| user_id  | smallint(5)  | NO   | PRI | NULL    | auto_increment |
| username | varchar(10)  | NO   |     | NULL    |                |
| password | varchar(100) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
Example 4 - Custom Separator
table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test.csv", true)
table.SetRowLine(true)         // Enable row line

// Change table lines
table.SetCenterSeparator("*")
table.SetColumnSeparator("╪")
table.SetRowSeparator("-")

table.SetAlignment(tablewriter.ALIGN_LEFT)
table.Render()
Output 4
*------------*-----------*---------*
╪ FIRST NAME ╪ LAST NAME ╪   SSN   ╪
*------------*-----------*---------*
╪ John       ╪ Barry     ╪ 123456  ╪
*------------*-----------*---------*
╪ Kathy      ╪ Smith     ╪ 687987  ╪
*------------*-----------*---------*
╪ Bob        ╪ McCornick ╪ 3979870 ╪
*------------*-----------*---------*
Example 5 - Markdown Format
data := [][]string{
	[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
	[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
	[]string{"1/4/2014", "February Hosting", "2233", "$51.00"},
	[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
table.AppendBulk(data) // Add Bulk Data
table.Render()
Output 5
|   DATE   |       DESCRIPTION        | CV2  | AMOUNT |
|----------|--------------------------|------|--------|
| 1/1/2014 | Domain name              | 2233 | $10.98 |
| 1/1/2014 | January Hosting          | 2233 | $54.95 |
| 1/4/2014 | February Hosting         | 2233 | $51.00 |
| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
Example 6 - Identical cells merging
data := [][]string{
  []string{"1/1/2014", "Domain name", "1234", "$10.98"},
  []string{"1/1/2014", "January Hosting", "2345", "$54.95"},
  []string{"1/4/2014", "February Hosting", "3456", "$51.00"},
  []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetFooter([]string{"", "", "Total", "$146.93"})
table.SetAutoMergeCells(true)
table.SetRowLine(true)
table.AppendBulk(data)
table.Render()
Output 6
+----------+--------------------------+-------+---------+
|   DATE   |       DESCRIPTION        |  CV2  | AMOUNT  |
+----------+--------------------------+-------+---------+
| 1/1/2014 | Domain name              |  1234 | $10.98  |
+          +--------------------------+-------+---------+
|          | January Hosting          |  2345 | $54.95  |
+----------+--------------------------+-------+---------+
| 1/4/2014 | February Hosting         |  3456 | $51.00  |
+          +--------------------------+-------+---------+
|          | February Extra Bandwidth |  4567 | $30.00  |
+----------+--------------------------+-------+---------+
|                                       TOTAL | $146 93 |
+----------+--------------------------+-------+---------+
Example 7 - Identical cells merging (specify the column index to merge)
data := [][]string{
  []string{"1/1/2014", "Domain name", "1234", "$10.98"},
  []string{"1/1/2014", "January Hosting", "1234", "$10.98"},
  []string{"1/4/2014", "February Hosting", "3456", "$51.00"},
  []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetFooter([]string{"", "", "Total", "$146.93"})
table.SetAutoMergeCellsByColumnIndex([]int{2, 3})
table.SetRowLine(true)
table.AppendBulk(data)
table.Render()
Output 7
+----------+--------------------------+-------+---------+
|   DATE   |       DESCRIPTION        |  CV2  | AMOUNT  |
+----------+--------------------------+-------+---------+
| 1/1/2014 | Domain name              |  1234 | $10.98  |
+----------+--------------------------+       +         +
| 1/1/2014 | January Hosting          |       |         |
+----------+--------------------------+-------+---------+
| 1/4/2014 | February Hosting         |  3456 | $51.00  |
+----------+--------------------------+-------+---------+
| 1/4/2014 | February Extra Bandwidth |  4567 | $30.00  |
+----------+--------------------------+-------+---------+
|                                       TOTAL | $146.93 |
+----------+--------------------------+-------+---------+
Table with color
data := [][]string{
	[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
	[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
	[]string{"1/4/2014", "February Hosting", "2233", "$51.00"},
	[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
table.SetBorder(false)                                // Set Border to false

table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},
	tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor},
	tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor},
	tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor})

table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor})

table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{},
	tablewriter.Colors{tablewriter.Bold},
	tablewriter.Colors{tablewriter.FgHiRedColor})

table.AppendBulk(data)
table.Render()
Table with color Output

Table with Color

Example - 8 Table Cells with Color

Individual Cell Colors from func Rich take precedence over Column Colors

data := [][]string{
	[]string{"Test1Merge", "HelloCol2 - 1", "HelloCol3 - 1", "HelloCol4 - 1"},
	[]string{"Test1Merge", "HelloCol2 - 2", "HelloCol3 - 2", "HelloCol4 - 2"},
	[]string{"Test1Merge", "HelloCol2 - 3", "HelloCol3 - 3", "HelloCol4 - 3"},
	[]string{"Test2Merge", "HelloCol2 - 4", "HelloCol3 - 4", "HelloCol4 - 4"},
	[]string{"Test2Merge", "HelloCol2 - 5", "HelloCol3 - 5", "HelloCol4 - 5"},
	[]string{"Test2Merge", "HelloCol2 - 6", "HelloCol3 - 6", "HelloCol4 - 6"},
	[]string{"Test2Merge", "HelloCol2 - 7", "HelloCol3 - 7", "HelloCol4 - 7"},
	[]string{"Test3Merge", "HelloCol2 - 8", "HelloCol3 - 8", "HelloCol4 - 8"},
	[]string{"Test3Merge", "HelloCol2 - 9", "HelloCol3 - 9", "HelloCol4 - 9"},
	[]string{"Test3Merge", "HelloCol2 - 10", "HelloCol3 -10", "HelloCol4 - 10"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Col1", "Col2", "Col3", "Col4"})
table.SetFooter([]string{"", "", "Footer3", "Footer4"})
table.SetBorder(false)

table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},
	tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor},
	tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor},
	tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor})

table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
	tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor})

table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{},
	tablewriter.Colors{tablewriter.Bold},
	tablewriter.Colors{tablewriter.FgHiRedColor})

colorData1 := []string{"TestCOLOR1Merge", "HelloCol2 - COLOR1", "HelloCol3 - COLOR1", "HelloCol4 - COLOR1"}
colorData2 := []string{"TestCOLOR2Merge", "HelloCol2 - COLOR2", "HelloCol3 - COLOR2", "HelloCol4 - COLOR2"}

for i, row := range data {
	if i == 4 {
		table.Rich(colorData1, []tablewriter.Colors{tablewriter.Colors{}, tablewriter.Colors{tablewriter.Normal, tablewriter.FgCyanColor}, tablewriter.Colors{tablewriter.Bold, tablewriter.FgWhiteColor}, tablewriter.Colors{}})
		table.Rich(colorData2, []tablewriter.Colors{tablewriter.Colors{tablewriter.Normal, tablewriter.FgMagentaColor}, tablewriter.Colors{}, tablewriter.Colors{tablewriter.Bold, tablewriter.BgRedColor}, tablewriter.Colors{tablewriter.FgHiGreenColor, tablewriter.Italic, tablewriter.BgHiCyanColor}})
	}
	table.Append(row)
}

table.SetAutoMergeCells(true)
table.Render()

Table cells with color Output

Table cells with Color

Example 9 - Set table caption
data := [][]string{
    []string{"A", "The Good", "500"},
    []string{"B", "The Very very Bad Man", "288"},
    []string{"C", "The Ugly", "120"},
    []string{"D", "The Gopher", "800"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Name", "Sign", "Rating"})
table.SetCaption(true, "Movie ratings.")

for _, v := range data {
    table.Append(v)
}
table.Render() // Send output

Note: Caption text will wrap with total width of rendered table.

Output 9
+------+-----------------------+--------+
| NAME |         SIGN          | RATING |
+------+-----------------------+--------+
|  A   |       The Good        |    500 |
|  B   | The Very very Bad Man |    288 |
|  C   |       The Ugly        |    120 |
|  D   |      The Gopher       |    800 |
+------+-----------------------+--------+
Movie ratings.
Example 10 - Set NoWhiteSpace and TablePadding option
data := [][]string{
    {"node1.example.com", "Ready", "compute", "1.11"},
    {"node2.example.com", "Ready", "compute", "1.11"},
    {"node3.example.com", "Ready", "compute", "1.11"},
    {"node4.example.com", "NotReady", "compute", "1.11"},
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Name", "Status", "Role", "Version"})
table.SetAutoWrapText(false)
table.SetAutoFormatHeaders(true)
table.SetHeaderAlignment(ALIGN_LEFT)
table.SetAlignment(ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetTablePadding("\t") // pad with tabs
table.SetNoWhiteSpace(true)
table.AppendBulk(data) // Add Bulk Data
table.Render()
Output 10
NAME             	STATUS  	ROLE   	VERSION 
node1.example.com	Ready   	compute	1.11   	
node2.example.com	Ready   	compute	1.11   	
node3.example.com	Ready   	compute	1.11   	
node4.example.com	NotReady	compute	1.11   	
Render table into a string

Instead of rendering the table to io.Stdout you can also render it into a string. Go 1.10 introduced the strings.Builder type which implements the io.Writer interface and can therefore be used for this task. Example:

package main

import (
    "strings"
    "fmt"

    "github.com/olekukonko/tablewriter"
)

func main() {
    tableString := &strings.Builder{}
    table := tablewriter.NewWriter(tableString)

    /*
     * Code to fill the table
     */

    table.Render()

    fmt.Println(tableString.String())
}
TODO
  • Import Directly from CSV - done
  • Support for SetFooter - done
  • Support for SetBorder - done
  • Support table with uneven rows - done
  • Support custom alignment
  • refact: more refactoring of the padding logic
  • debug: noWhiteSpace is buggy
  • feat: more general wrapper

Documentation

Overview

Package tablewriter exposes a utility to render tabular data as text.

Index

Examples

Constants

View Source
const (
	CENTER    = "+"
	ROW       = "-"
	COLUMN    = "|"
	SPACE     = " "
	NEWLINE   = "\n"
	NOPADDING = ""
)

Default separator characters.

View Source
const (
	// MaxColWidth is the default maximum width of a column.
	MaxColWidth = 30
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Border

type Border struct {
	Left   bool
	Right  bool
	Top    bool
	Bottom bool
}

Border represent a borders specification for a table.

type CellWrapper

type CellWrapper interface {
	WrapCell(row, col int) []string
}

CellWrapper knows how to wrap the content of a table cell into multiple lines.

The wrapper knows about the display constraints.

A few useful wrappers are provided by the package tablewrappers.

type CellWrapperFactory

type CellWrapperFactory func(*Table) CellWrapper

CellWrapperFactory produces a cell wrapper with the knowledge of the table to be rendered.

type Formatter

type Formatter = func(interface{}) aurora.Value

Formatter is a formatting function from the github.com/logrusorgru/aurora/v4 package, to be used for nice terminal formatting such as colors, bold face, etc.

It wraps some argument with an appropriate ANSI terminal escape sequence.

Example
data := sampleData()
table := tablewriter.New(
	tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
	tablewriter.WithRows(data),
	tablewriter.WithHeaderFormatters(map[int]tablewriter.Formatter{
		0: aurora.Red,
		1: aurora.Blue,
		2: aurora.Bold,
	}),
)

table.Render()
Output:

+------+-----------------------+--------+
| �[31mNAME�[0m | �[34m        SIGN         �[0m | �[1mRATING�[0m |
+------+-----------------------+--------+
| A    | The Good              |    500 |
| B    | The Very very Bad Man |    288 |
| C    | The Ugly              |    120 |
| D    | The Gopher            |    800 |
+------+-----------------------+--------+

type HAlignment

type HAlignment uint8

HAlignment describes how to horizontally align an element in a cell.

const (
	AlignDefault HAlignment = iota
	AlignCenter
	AlignRight
	AlignLeft
)

Horizontal alignment

type Option

type Option func(*options)

Option to render a table

Example
package main

import (
	"os"

	"github.com/fredbi/tablewriter"
)

func main() {
	data := [][]string{
		{"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data    ", "Another Data "},
		{"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"},
	}

	table := tablewriter.New(
		tablewriter.WithWriter(os.Stdout), // default is os.Stdout
		tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
		tablewriter.WithCenterSeparator("*"), // default is '+'
		tablewriter.WithRowSeparator("="),    // default is '-'
	)

	for _, v := range data {
		table.Append(v) // an alternative to WithRows(data)
	}

	table.Render()

}
Output:

*=============================*===============================*===============================*==========*
|            NAME             |             SIGN              |            RATING             |          |
*=============================*===============================*===============================*==========*
| Learn East has computers    | Some Data                     | Another Data                  |          |
| with adapted keyboards with |                               |                               |          |
| enlarged print etc          |                               |                               |          |
| Instead of lining up the    | the way across, he splits the | Like most ergonomic keyboards | See Data |
| letters all                 | keyboard in two               |                               |          |
*=============================*===============================*===============================*==========*

func WithAllBorders

func WithAllBorders(enabled bool) Option

WithAllBorders enables (resp. disables) all table borders.

Borders are enabled by default.

func WithBorders

func WithBorders(border Border) Option

WithBorders allows for a detailed specification of which borders are rendered.

func WithCaption

func WithCaption(caption string) Option

WithCaption displays a caption under the table.

func WithCaptionFormatter

func WithCaptionFormatter(formatter Formatter) Option

WithCaptionFormatter allows to specify ANSI terminal control sequences to format the table caption.

func WithCellAlignment

func WithCellAlignment(align HAlignment) Option

WithCellAlignment defines the default alignment for row cells.

The default is CENTER for strings, RIGHT for numbers (and %).

func WithCellWrapper

func WithCellWrapper(factory func(*Table) CellWrapper) Option

WithCellWrapper allows to inject a customized cell content CellWrapper.

Specifying a cell wrapper overrides any StringWrapper setting.

func WithCenterSeparator

func WithCenterSeparator(sep string) Option

WithCenterSeparator defines the string used to represent intersections of the table grid.

The default is '+'.

func WithColAlignment

func WithColAlignment(align map[int]HAlignment) Option

WithColAlignment defines the aligment for a set of columns.

func WithColFormatters

func WithColFormatters(formatters map[int]Formatter) Option

WithColFormatters allows to specify ANSI terminal control sequences to format cells by columns.

func WithColMaxWidth

func WithColMaxWidth(column int, width int) Option

WithColMaxWidth defines the maximum width for a specific column.

This overrides the setting defined by WithColWidth.

func WithColMaxWidths

func WithColMaxWidths(maxWidths map[int]int) Option

WithColMaxWidths defines the maximum width for a set of columns.

func WithColMinWidth

func WithColMinWidth(column int, width int) Option

WithColMinWidth specifies the minimum width of columns.

func WithColWidth

func WithColWidth(width int) Option

WithColWidth defines the maximum width for all columns (in characters).

The default is 30.

func WithColumnSeparator

func WithColumnSeparator(sep string) Option

WithColumnSeparator defines the character to separate columns.

The default is '|'.

func WithFooter

func WithFooter(footer []string) Option

WithFooter specifies the footer fields for this table.

func WithFooterAlignment

func WithFooterAlignment(footerAlign HAlignment) Option

WithFooterAlignment defines the alignment for all footer fields.

The default is CENTER.

func WithFooterFormatters

func WithFooterFormatters(formatters map[int]Formatter) Option

WithFooterFormatters allows to specify ANSI terminal control sequences to format the footer.

In particular this may be used to colorize the footer.

func WithFooterLine

func WithFooterLine(enabled bool) Option

WithFooterLine prints a separation line under the footer.

This is enabled by default.

func WithHeader

func WithHeader(header []string) Option

WithHeader specifies the header fields for this table.

func WithHeaderAlignment

func WithHeaderAlignment(align HAlignment) Option

WithHeaderAlignment defines the alignment for all headings.

The default is CENTER.

func WithHeaderFormatters

func WithHeaderFormatters(formatters map[int]Formatter) Option

WithHeaderFormatters allows to specify ANSI terminal control sequences to format the header.

In particular this may be used to colorize the header.

func WithHeaderLine

func WithHeaderLine(enabled bool) Option

WithHeaderLine prints a separation line under the header.

This is enabled by default.

func WithMarkdown

func WithMarkdown(enabled bool) Option

WithMarkdown reproduces classifical markdown tables.

This option is a shortcut to:

WithCenterSeparator("|")
WithBorders(Border{Left: true, Top: false, Right: true, Bottom: false})

func WithMaxTableWidth

func WithMaxTableWidth(width int, opts ...wrap.Option) Option

WithMaxTableWidth defines a maximum display width for the table.

This options injects a CellWrapper that automatically determine width constraints on columns. This option overrides max widths per column that could have been specified otherwise.

Options determine how aggressive the wrapper can be: e.g. if individual words may be split.

Example
package main

import (
	"github.com/fredbi/tablewriter"
)

func sampleData() [][]string {
	return [][]string{
		{"A", "The Good", "500"},
		{"B", "The Very very Bad Man", "288"},
		{"C", "The Ugly", "120"},
		{"D", "The Gopher", "800"},
	}
}

func main() {
	data := sampleData()

	// adapt the width of the table to the maximum display size
	table := tablewriter.New(
		tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
		tablewriter.WithRows(data),
		tablewriter.WithMaxTableWidth(30),
	)
	table.Render()

}
Output:

	+------+------------+--------+
| NAME |    SIGN    | RATING |
+------+------------+--------+
| A    | The Good   |    500 |
| B    | The Very   |    288 |
|      | very Bad   |        |
|      | Man        |        |
| C    | The Ugly   |    120 |
| D    | The Gopher |    800 |
+------+------------+--------+

func WithMergeCells

func WithMergeCells(enabled bool) Option

WithMergeCells enables the merging of adjacent cells with the same value.

func WithNewLine

func WithNewLine(nl string) Option

WithNewLine defines the end of line character.

The default is '\n'.

func WithNoWhiteSpace

func WithNoWhiteSpace(enabled bool) Option

WithNoWhiteSpace packs the table by removing some padding.

This is disabled by default.

Example
package main

import (
	"fmt"
	"os"

	"github.com/fredbi/tablewriter"
)

func main() {
	data := [][]string{
		{"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data    ", "Another Data "},
		{"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"},
	}

	options := []tablewriter.Option{
		tablewriter.WithWriter(os.Stdout), // default is os.Stdout
		tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
		tablewriter.WithCenterSeparator("*"), // default is '+'
		tablewriter.WithRowSeparator("="),    // default is '-'
		tablewriter.WithRows(data),
	}

	// packed without extraneous blank space
	table := tablewriter.New(append(options,
		tablewriter.WithNoWhiteSpace(true),
	)...)
	table.Render()
	fmt.Println()

	// default layout
	table = tablewriter.New(append(options,
		tablewriter.WithNoWhiteSpace(false),
	)...)
	table.Render()
}
Output:

func WithPadding

func WithPadding(padding string) Option

WithPadding defines the padding character inside the table.

The default is a blank space.

func WithRowLine

func WithRowLine(enabled bool) Option

WithRowLine indicates that each row is followed by a separation line.

By default, rows are packed without line separator.

func WithRowSeparator

func WithRowSeparator(sep string) Option

WithRowSeparator defines the string used to separate rows.

The default is '-'.

Example
data := sampleData()
red := func(in string) string {
	return aurora.Sprintf(aurora.Red(in))
}

// prints a colorized grid
table := tablewriter.New(
	tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
	tablewriter.WithRows(data),
	tablewriter.WithRowSeparator(red(tablewriter.ROW)),
	tablewriter.WithColumnSeparator(red(tablewriter.COLUMN)),
	tablewriter.WithCenterSeparator(red(tablewriter.CENTER)),
)

table.Render()
Output:

�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m
�[31m|�[0m NAME �[31m|�[0m         SIGN          �[31m|�[0m RATING �[31m|�[0m
�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m
�[31m|�[0m A    �[31m|�[0m The Good              �[31m|�[0m    500 �[31m|�[0m
�[31m|�[0m B    �[31m|�[0m The Very very Bad Man �[31m|�[0m    288 �[31m|�[0m
�[31m|�[0m C    �[31m|�[0m The Ugly              �[31m|�[0m    120 �[31m|�[0m
�[31m|�[0m D    �[31m|�[0m The Gopher            �[31m|�[0m    800 �[31m|�[0m
�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m-�[0m�[31m+�[0m

func WithRows

func WithRows(rows [][]string) Option

WithRows specifies the rows of the table, each being a record of columns.

The input is not required to contain the same number of columns for each row.

func WithTitledHeader

func WithTitledHeader(enabled bool) Option

WithTitledHeader autoformats headers and footer as titles. This is enabled by default.

Whenever enabled, the default titler is being used. The title string is trimmed, uppercased. Underscores are replaced by blank spaces.

func WithTitler

func WithTitler(titler Titler) Option

WithTitler injects a Titler to apply to header and footer values.

This overrides the WithTitledHeader() option.

func WithWrap

func WithWrap(enabled bool) Option

WithWrap enables content wrapping inside columns to abide by column width constraints.

Wrapping is enabled by default (the default maximum column width is 30 characters).

Whenever enabled, the default wrapper is used. The default wrapper wraps cells into multiline content, based on their maximum column width, wrapping only on word boundaries.

Example
package main

import (
	"fmt"
	"os"

	"github.com/fredbi/tablewriter"
)

func main() {
	const multiline = `A multiline
string with some lines being really long.`

	type testMode uint8
	const (
		// test mode
		testRow testMode = iota
		testHeader
		testFooter
		testFooter2
	)

	for mode := testRow; mode <= testFooter2; mode++ {
		for _, titled := range []bool{false, true} {
			if mode == testRow && titled {
				// Nothing special to test, skip
				continue
			}

			for _, wrapped := range []bool{false, true} {
				fmt.Println("mode:", mode, "titled:", titled, "wrapped:", wrapped)

				options := []tablewriter.Option{
					tablewriter.WithWriter(os.Stdout),
					tablewriter.WithTitledHeader(titled),
					tablewriter.WithWrap(wrapped),
				}

				switch mode {
				case testHeader:
					options = append(options, tablewriter.WithHeader([]string{"woo", multiline}))
					options = append(options, tablewriter.WithFooter([]string{"woo", "waa"}))
					options = append(options, tablewriter.WithRows([][]string{{"woo", "waa"}}))
				case testRow:
					options = append(options, tablewriter.WithHeader([]string{"woo", "waa"}))
					options = append(options, tablewriter.WithFooter([]string{"woo", "waa"}))
					options = append(options, tablewriter.WithRows([][]string{{"woo", multiline}}))
				case testFooter:
					options = append(options, tablewriter.WithHeader([]string{"woo", "waa"}))
					options = append(options, tablewriter.WithFooter([]string{"woo", multiline}))
					options = append(options, tablewriter.WithRows([][]string{{"woo", "waa"}}))
				case testFooter2:
					options = append(options, tablewriter.WithHeader([]string{"woo", "waa"}))
					options = append(options, tablewriter.WithFooter([]string{"", multiline}))
					options = append(options, tablewriter.WithRows([][]string{{"woo", "waa"}}))
				}

				t := tablewriter.New(options...)
				t.Render()
				fmt.Println()
			}
		}
	}

}
Output:

mode: 0 titled: false wrapped: false
+-----+-------------------------------------------+
| woo |                    waa                    |
+-----+-------------------------------------------+
| woo | A multiline                               |
|     | string with some lines being really long. |
+-----+-------------------------------------------+
| woo |                    waa                    |
+-----+-------------------------------------------+

mode: 0 titled: false wrapped: true
+-----+------------------------------+
| woo |             waa              |
+-----+------------------------------+
| woo | A multiline string with some |
|     | lines being really long.     |
+-----+------------------------------+
| woo |             waa              |
+-----+------------------------------+

mode: 1 titled: false wrapped: false
+-----+-------------------------------------------+
| woo |                A multiline                |
|     | string with some lines being really long. |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
| woo |                    waa                    |
+-----+-------------------------------------------+

mode: 1 titled: false wrapped: true
+-----+------------------------------+
| woo | A multiline string with some |
|     |   lines being really long.   |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
| woo |             waa              |
+-----+------------------------------+

mode: 1 titled: true wrapped: false
+-----+-------------------------------------------+
| WOO |                A MULTILINE                |
|     | STRING WITH SOME LINES BEING REALLY LONG  |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
| WOO |                    WAA                    |
+-----+-------------------------------------------+

mode: 1 titled: true wrapped: true
+-----+------------------------------+
| WOO | A MULTILINE STRING WITH SOME |
|     |   LINES BEING REALLY LONG    |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
| WOO |             WAA              |
+-----+------------------------------+

mode: 2 titled: false wrapped: false
+-----+-------------------------------------------+
| woo |                    waa                    |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
| woo |                A multiline                |
|     | string with some lines being really long. |
+-----+-------------------------------------------+

mode: 2 titled: false wrapped: true
+-----+------------------------------+
| woo |             waa              |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
| woo | A multiline string with some |
|     |   lines being really long.   |
+-----+------------------------------+

mode: 2 titled: true wrapped: false
+-----+-------------------------------------------+
| WOO |                    WAA                    |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
| WOO |                A MULTILINE                |
|     | STRING WITH SOME LINES BEING REALLY LONG  |
+-----+-------------------------------------------+

mode: 2 titled: true wrapped: true
+-----+------------------------------+
| WOO |             WAA              |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
| WOO | A MULTILINE STRING WITH SOME |
|     |   LINES BEING REALLY LONG    |
+-----+------------------------------+

mode: 3 titled: false wrapped: false
+-----+-------------------------------------------+
| woo |                    waa                    |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
|                      A multiline                |
|       string with some lines being really long. |
+-----+-------------------------------------------+

mode: 3 titled: false wrapped: true
+-----+------------------------------+
| woo |             waa              |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
|       A multiline string with some |
|         lines being really long.   |
+-----+------------------------------+

mode: 3 titled: true wrapped: false
+-----+-------------------------------------------+
| WOO |                    WAA                    |
+-----+-------------------------------------------+
| woo | waa                                       |
+-----+-------------------------------------------+
|                      A MULTILINE                |
|       STRING WITH SOME LINES BEING REALLY LONG  |
+-----+-------------------------------------------+

mode: 3 titled: true wrapped: true
+-----+------------------------------+
| WOO |             WAA              |
+-----+------------------------------+
| woo | waa                          |
+-----+------------------------------+
|       A MULTILINE STRING WITH SOME |
|         LINES BEING REALLY LONG    |
+-----+------------------------------+

func WithWriter

func WithWriter(writer io.Writer) Option

WithWriter specifies the output writer to render this table.

The default is os.Stdout.

type Table

type Table struct {
	// contains filtered or unexported fields
}

Table renders a text table.

Example
package main

import (
	"github.com/fredbi/tablewriter"
)

func sampleData() [][]string {
	return [][]string{
		{"A", "The Good", "500"},
		{"B", "The Very very Bad Man", "288"},
		{"C", "The Ugly", "120"},
		{"D", "The Gopher", "800"},
	}
}

func main() {
	data := sampleData()
	table := tablewriter.New(
		tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
		tablewriter.WithRows(data),
	)

	table.Render()

}
Output:

+------+-----------------------+--------+
| NAME |         SIGN          | RATING |
+------+-----------------------+--------+
| A    | The Good              |    500 |
| B    | The Very very Bad Man |    288 |
| C    | The Ugly              |    120 |
| D    | The Gopher            |    800 |
+------+-----------------------+--------+

func New

func New(opts ...Option) *Table

New builds a new empty table writer.

func NewBuffered

func NewBuffered(opts ...Option) (*Table, *bytes.Buffer)

NewBuffered builds a new empty table writer that writes in a new bytes.Buffer.

Example
package main

import (
	"fmt"

	"github.com/fredbi/tablewriter"
)

func main() {
	data := [][]string{
		{"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data    ", "Another Data "},
		{"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"},
	}

	table, buf := tablewriter.NewBuffered(
		tablewriter.WithHeader([]string{"Name", "Sign", "Rating"}),
		tablewriter.WithCenterSeparator("*"), // default is '+'
		tablewriter.WithRowSeparator("="),    // default is '-'
	)

	for _, v := range data {
		table.Append(v)
	}

	table.Render() // writes to buffer

	fmt.Println(buf)

}
Output:

*=============================*===============================*===============================*==========*
|            NAME             |             SIGN              |            RATING             |          |
*=============================*===============================*===============================*==========*
| Learn East has computers    | Some Data                     | Another Data                  |          |
| with adapted keyboards with |                               |                               |          |
| enlarged print etc          |                               |                               |          |
| Instead of lining up the    | the way across, he splits the | Like most ergonomic keyboards | See Data |
| letters all                 | keyboard in two               |                               |          |
*=============================*===============================*===============================*==========*

func NewCSV

func NewCSV(csvReader *csv.Reader, hasHeader bool, opts ...Option) (*Table, error)

NewCSV builds a Table writer that reads its rows from a csv.Reader.

Example
package main

import (
	"encoding/csv"
	"log"
	"os"

	"github.com/fredbi/tablewriter"
)

func main() {
	file, err := os.Open("testdata/test.csv")
	if err != nil {
		log.Fatal(err)
	}

	reader := csv.NewReader(file)

	table, err := tablewriter.NewCSV(reader, true,
		tablewriter.WithCenterSeparator("*"),
		tablewriter.WithRowSeparator("="),
	)
	if err != nil {
		log.Fatal(err)
	}

	table.Render()

}
Output:

*============*===========*=========*
| FIRST NAME | LAST NAME |   SSN   |
*============*===========*=========*
| John       | Barry     |  123456 |
| Kathy      | Smith     |  687987 |
| Bob        | McCornick | 3979870 |
*============*===========*=========*

func (*Table) Append

func (t *Table) Append(row []string)

Append a row to the table.

func (Table) ColLimits

func (o Table) ColLimits() map[int]int

func (*Table) Footer

func (t *Table) Footer() []string

Footer of this table.

func (*Table) Header

func (t *Table) Header() []string

Header of this table.

func (Table) Overhead

func (t Table) Overhead() int

Overhead yields the amount extra padding and separators needed to display the table.

func (*Table) Render

func (t *Table) Render()

Render the table

func (*Table) Rows

func (t *Table) Rows() [][]string

Rows of this table.

func (*Table) SetStructs

func (t *Table) SetStructs(v interface{}) error

SetStructs sets header and rows from slice of struct.

If something that is not a slice is passed, an error will be returned.

The tag specified by "tablewriter" for the struct becomes the header. If not specified or empty, the field name will be used.

The field of the first element of the slice is used as the header. If the element implements fmt.Stringer, the result will be used. And the slice contains nil, it will be skipped without rendering.

type Titler

type Titler interface {
	Title(string) string
}

Titler knows how to format an input string, suitable to display headings.

Notes

Bugs

  • this doesn't work well with noWhiteSpace

Directories

Path Synopsis
Package tablewrappers exposes different ways to wrap text under display width constraint.
Package tablewrappers exposes different ways to wrap text under display width constraint.
Package titlers expose utilities to "title-ize" headings.
Package titlers expose utilities to "title-ize" headings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL