clitable

package module
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2026 License: MPL-2.0 Imports: 14 Imported by: 0

README

= CLITable

Pretty print Data as tables on the command line.

== CLI tool

The csvtable cli tool allows printing CSV data as a table:

  go install github.com/DavidGamba/dgtools/clitable/cmd/csvtable@latest

To parse TSV data use the `--tsv` flag.

To normalize CSV data use the `--normalize` flag.

== Library

image:https://pkg.go.dev/badge/github.com/DavidGamba/dgtools/clitable.svg[Go Reference, link="https://pkg.go.dev/github.com/DavidGamba/dgtools/clitable"]

[source, go]
----
import "github.com/DavidGamba/dgtools/clitable"
----

=== String Slices

For simple tables of type `[][]string`:

[source, go]
----
simpleData := [][]string{{"Hello", "1"}, {"World", "2"}}
clitable.NewTablePrinter().Print(clitable.SimpleTable{Data: simpleData})
----

----
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘
----

=== CSV

For CSV from an `io.Reader`:

[source, go]
----
r := strings.NewReader("Hello,1\nWorld,2\n")
clitable.NewTablePrinter().FprintCSVReader(os.Stdout, r)
----

----
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘
----

=== TSV

For TSV from an `io.Reader`:

[source, go]
----
r := strings.NewReader("Hello	1\nWorld	2\n")
clitable.NewTablePrinter().Separator('\t').FprintCSVReader(os.Stdout, r)
----

----
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘
----

=== Map Slices

[source, go]
----
clitable.NewTablePrinter().Print(clitable.MapTable{MapList: []map[string]any{
	{"a": "c", "b": "d"},
	{"a": "e", "b": "f"},
}})
----

----
┌───┬───┐
│ a │ b │
╞═══╪═══╡
│ c │ d │
├───┼───┤
│ e │ f │
└───┴───┘
----

Nested data gets json Marshalled:

[source, go]
----
mapData = []map[string]any{
	{"a": map[string]any{"c": "g", "h": "i"}, "b": "d"},
	{"a": "e", "b": map[string]any{"f": 123, "j": 456}},
}
clitable.NewTablePrinter().Print(clitable.MapTable{MapList: mapData})
----

----
┌─────────────┬─────────────┐
│ a           │ b           │
╞═════════════╪═════════════╡
│ {           │ d           │
│   "c": "g", │             │
│   "h": "i"  │             │
│ }           │             │
├─────────────┼─────────────┤
│ e           │ {           │
│             │   "f": 123, │
│             │   "j": 456  │
│             │ }           │
└─────────────┴─────────────┘
----

=== Custom Structs

For iterating over structs you need to implement the table interface by adding a `RowIterator` function:

[source, go]
----
type Data struct {
	Info []struct {
		Name string
		ID   int
	}
}

func (d *Data) RowIterator() <-chan clitable.Row {
	c := make(chan clitable.Row)
	go func() {
		c <- clitable.Row{Fields: []string{"", "Name", "ID"}}
		for i, row := range d.Info {
			c <- clitable.Row{Fields: []string{strconv.Itoa(i + 1), row.Name, strconv.Itoa(row.ID)}}
		}
		close(c)
	}()
	return c
}
----

Then print:

[source, go]
----
data := &Data{[]struct {
  Name string
  ID   int
}{{"Hello", 1}, {"World", 2}}}

clitable.NewTablePrinter().Fprint(os.Stdout, data)
----

----
┌───┬───────┬────┐
│   │ Name  │ ID │
╞═══╪═══════╪════╡
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘
----

=== Controlling Style

[source, go]
----
clitable.NewTablePrinter().SetStyle(clitable.Full).Print(data)

┌───┬───────┬────┐
│   │ Name  │ ID │
╞═══╪═══════╪════╡
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘

clitable.NewTablePrinter().SetStyle(clitable.Full).HasHeader(false).Print(data)

┌───┬───────┬────┐
│   │ Name  │ ID │
├───┼───────┼────┤
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘

clitable.NewTablePrinter().SetStyle(clitable.Compact).Print(data)

───┬───────┬────
   │ Name  │ ID 
═══╪═══════╪════
 1 │ Hello │ 1  
 2 │ World │ 2  
───┴───────┴────

clitable.NewTablePrinter().SetStyle(clitable.Ascii).Print(data)

+---+-------+----+
|   | Name  | ID |
+===+=======+====+
| 1 | Hello | 1  |
+---+-------+----+
| 2 | World | 2  |
+---+-------+----+

clitable.NewTablePrinter().SetStyle(clitable.Space).Print(data)

     Name    ID 
 1   Hello   1  
 2   World   2  

clitable.NewTablePrinter().SetStyle(clitable.CSV).Print(data)

,Name,ID
1,Hello,1
2,World,2
----

Documentation

Overview

Package clitable provides a tool to view data as a table on the cmdline.

┌──┬──┐
│  │  │
├──┼──┤
└──┴──┘

Index

Examples

Constants

This section is empty.

Variables

View Source
var Logger = log.New(io.Discard, "clitable DEBUG ", log.LstdFlags)

Logger - Default *log.Logger variable. Set output to os.Stderr or override.

Functions

func CSVRowIterator

func CSVRowIterator(reader io.Reader, separator rune) <-chan Row

CSVRowIterator -

func SimpleRowIterator

func SimpleRowIterator(data [][]string) <-chan Row

SimpleRowIterator -

func StringWidth

func StringWidth(s string) (width int, doubleWidthCount int)

Types

type CSVTable

type CSVTable struct {
	Reader    io.Reader
	Separator rune
}

CSVTable - Implements the table interface from an io.Reader to CSV data.

Example
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("CSV")
	r := strings.NewReader("Hello,1\nWorld,2\n")
	clitable.NewTablePrinter().FprintCSVReader(os.Stdout, r)

}
Output:
CSV
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘
Example (Tsv)
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("TSV")
	r := strings.NewReader("Hello	1\nWorld	2\n")
	clitable.NewTablePrinter().Separator('\t').FprintCSVReader(os.Stdout, r)

}
Output:
TSV
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘

func (CSVTable) RowIterator

func (t CSVTable) RowIterator() <-chan Row

RowIterator - Implements the Table interface.

type MapTable added in v0.5.0

type MapTable struct {
	MapList []map[string]any // list of maps to traverse

	Keys         []string // User Key order override, doesn't not have to be exhaustive
	IgnoreHeader bool     // Don't include table header
	// contains filtered or unexported fields
}

MapTable - Implements the table interface on a map Nested map entries will be json marshalled.

Example
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("Map Slices Simple")
	mapData := []map[string]any{
		{"a": "c", "b": "d"},
		{"a": "e", "b": "f"},
	}
	clitable.NewTablePrinter().Print(clitable.MapTable{MapList: mapData})
	fmt.Println("Map Slices Nested")
	mapData = []map[string]any{
		{"a": map[string]any{"c": "g", "h": "i"}, "b": "d"},
		{"a": "e", "b": map[string]any{"f": 123, "j": 456}},
	}
	clitable.NewTablePrinter().Print(clitable.MapTable{MapList: mapData})

}
Output:
Map Slices Simple
┌───┬───┐
│ a │ b │
╞═══╪═══╡
│ c │ d │
├───┼───┤
│ e │ f │
└───┴───┘
Map Slices Nested
┌─────────────┬─────────────┐
│ a           │ b           │
╞═════════════╪═════════════╡
│ {           │ d           │
│   "c": "g", │             │
│   "h": "i"  │             │
│ }           │             │
├─────────────┼─────────────┤
│ e           │ {           │
│             │   "f": 123, │
│             │   "j": 456  │
│             │ }           │
└─────────────┴─────────────┘

func (MapTable) RowIterator added in v0.5.0

func (t MapTable) RowIterator() <-chan Row

type Row

type Row struct {
	Fields []string
	Error  error
}

Row - Data and Error struct

type SimpleTable

type SimpleTable struct {
	Data [][]string
}

SimpleTable - A basic structure that implements the Table interface.

Example
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("String Slices")
	simpleData := [][]string{{"Hello", "1"}, {"World", "2"}}
	clitable.NewTablePrinter().Print(clitable.SimpleTable{Data: simpleData})

}
Output:
String Slices
┌───────┬───┐
│ Hello │ 1 │
╞═══════╪═══╡
│ World │ 2 │
└───────┴───┘

func (SimpleTable) RowIterator

func (t SimpleTable) RowIterator() <-chan Row

RowIterator - Implements the Table interface.

type Style

type Style int
const (
	Full Style = iota
	Ascii
	Compact
	Space
	CSV
)

type Table

type Table interface {
	RowIterator() <-chan Row
}

Table - interface used to walk through a table one row at a time

Example
package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/DavidGamba/dgtools/clitable"
)

type Data struct {
	Info []struct {
		Name string
		ID   int
	}
}

func (d *Data) RowIterator() <-chan clitable.Row {
	c := make(chan clitable.Row)
	go func() {
		c <- clitable.Row{Fields: []string{"", "Name", "ID"}}
		for i, row := range d.Info {
			c <- clitable.Row{Fields: []string{strconv.Itoa(i + 1), row.Name, strconv.Itoa(row.ID)}}
		}
		close(c)
	}()
	return c
}

func main() {
	fmt.Println("Custom Structs")
	data := &Data{[]struct {
		Name string
		ID   int
	}{{"Hello", 1}, {"World", 2}}}
	clitable.NewTablePrinter().Fprint(os.Stdout, data)

}
Output:
Custom Structs
┌───┬───────┬────┐
│   │ Name  │ ID │
╞═══╪═══════╪════╡
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘

type TableInfo

type TableInfo struct {
	Columns            int
	Rows               int
	PerRowColumnWidths [][]int
	PerRowRows         [][]int // Number of Lines in a Row due to multiline entries.
	ColumnWidths       []int
	RowHeights         []int
}

TableInfo - Table information

func GetTableInfo

func GetTableInfo(t Table) (*TableInfo, error)

GetTableInfo - Iterates over all the elements of the table to get number of Colums, Colum widths, etc.

func (*TableInfo) String

func (i *TableInfo) String() string

type TablePrinter

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

func NewTablePrinter

func NewTablePrinter() *TablePrinter

func (*TablePrinter) Fprint

func (tp *TablePrinter) Fprint(w io.Writer, t Table) error

func (*TablePrinter) FprintCSVReader

func (tp *TablePrinter) FprintCSVReader(w io.Writer, r io.Reader) error

func (*TablePrinter) HasHeader

func (tp *TablePrinter) HasHeader(b bool) *TablePrinter
Example
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("No Header")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.Full).HasHeader(false).Print(clitable.SimpleTable{Data: simpleData})

}
Output:
No Header
┌───┬───────┬────┐
│   │ Name  │ ID │
├───┼───────┼────┤
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘

func (*TablePrinter) Print

func (tp *TablePrinter) Print(t Table) error

func (*TablePrinter) Separator added in v0.3.0

func (tp *TablePrinter) Separator(c rune) *TablePrinter

func (*TablePrinter) SetStyle

func (tp *TablePrinter) SetStyle(s Style) *TablePrinter
Example (Ascii)
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("ASCII")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.Ascii).Print(clitable.SimpleTable{Data: simpleData})

}
Output:
ASCII
+---+-------+----+
|   | Name  | ID |
+===+=======+====+
| 1 | Hello | 1  |
+---+-------+----+
| 2 | World | 2  |
+---+-------+----+
Example (Compact)
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("Compact")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.Compact).Print(clitable.SimpleTable{Data: simpleData})
}
Example (Csv)
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("CSV")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.CSV).Print(clitable.SimpleTable{Data: simpleData})

}
Output:
CSV
,Name,ID
1,Hello,1
2,World,2
Example (Full)
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("Full")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.Full).Print(clitable.SimpleTable{Data: simpleData})

}
Output:
Full
┌───┬───────┬────┐
│   │ Name  │ ID │
╞═══╪═══════╪════╡
│ 1 │ Hello │ 1  │
├───┼───────┼────┤
│ 2 │ World │ 2  │
└───┴───────┴────┘
Example (Space)
package main

import (
	"fmt"

	"github.com/DavidGamba/dgtools/clitable"
)

func main() {
	fmt.Println("Space")
	simpleData := [][]string{{"", "Name", "ID"}, {"1", "Hello", "1"}, {"2", "World", "2"}}
	clitable.NewTablePrinter().SetStyle(clitable.Space).Print(clitable.SimpleTable{Data: simpleData})
}

Directories

Path Synopsis
cmd
csvtable command
Package csvtable provides a tool to view csv files on the cmdline.
Package csvtable provides a tool to view csv files on the cmdline.

Jump to

Keyboard shortcuts

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