Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

aquasecurity/table

Repository files navigation

table: Tables for terminals

This is a Go module for rendering tables in the terminal.

A fruity demonstration table

Features

  • ↕️ Headers/footers
  • ↩️ Text wrapping
  • 🔀 Auto-merging of cells
  • !?️ Customisable line/border characters
  • 🌈 Customisable line/border colours
  • ⏯️ Individually enable/disable borders, row lines
  • ↔️ Set alignments on a per-column basis, with separate settings for headers/footers
  • 📐 Intelligently wrap/pad/measure ANSI coloured input
  • 👯 Support for double-width unicode characters
  • 📊 Load data from CSV files

Check out the documentation for full features/usage.

Examples

Example: Basic

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘

Example: No Row Lines

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetRowLines(false)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
│ 2 │ Banana │ 88,041 │
│ 3 │ Cherry │ 342 │
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘

Example: No Borders

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetBorders(false)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

 ID │ Fruit │ Stock 
────┼─────────────┼────────
 1 │ Apple │ 14 
────┼─────────────┼────────
 2 │ Banana │ 88,041 
────┼─────────────┼────────
 3 │ Cherry │ 342 
────┼─────────────┼────────
 4 │ Dragonfruit │ 1 

Example: No Borders Or Row Lines

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetRowLines(false)
	t.SetBorders(false)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

 ID │ Fruit │ Stock 
────┼─────────────┼────────
 1 │ Apple │ 14 
 2 │ Banana │ 88,041 
 3 │ Cherry │ 342 
 4 │ Dragonfruit │ 1 

Example: Specific Borders

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetRowLines(false)
	t.SetBorderLeft(true)
	t.SetBorderRight(false)
	t.SetBorderTop(true)
	t.SetBorderBottom(false)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────┬─────────────┬────────
│ ID │ Fruit │ Stock 
├────┼─────────────┼────────
│ 1 │ Apple │ 14 
│ 2 │ Banana │ 88,041 
│ 3 │ Cherry │ 342 
│ 4 │ Dragonfruit │ 1 

Example: Footers

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.SetRowLines(false)
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.SetFooters("", "Count", "4")
	t.Render()
}

Output

┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
│ 2 │ Banana │ 88,041 │
│ 3 │ Cherry │ 342 │
│ 4 │ Dragonfruit │ 1 │
├────┼─────────────┼────────┤
│ │ Count │ 4 │
└────┴─────────────┴────────┘

Example: Padding

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetPadding(5)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────────────┬─────────────────────┬────────────────┐
│ ID │ Fruit │ Stock │
├────────────┼─────────────────────┼────────────────┤
│ 1 │ Apple │ 14 │
├────────────┼─────────────────────┼────────────────┤
│ 2 │ Banana │ 88,041 │
├────────────┼─────────────────────┼────────────────┤
│ 3 │ Cherry │ 342 │
├────────────┼─────────────────────┼────────────────┤
│ 4 │ Dragonfruit │ 1 │
└────────────┴─────────────────────┴────────────────┘

Example: Alignment

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetAlignment(table.AlignLeft, table.AlignCenter, table.AlignRight)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘

Example: Rounded Corners

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetDividers(table.UnicodeRoundedDividers)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

╭────┬─────────────┬────────╮
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
╰────┴─────────────┴────────╯

Example: Custom Dividers

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetDividers(table.Dividers{
		ALL: "@",
		NES: "@",
		NSW: "@",
		NEW: "@",
		ESW: "@",
		NE: "@",
		NW: "@",
		SW: "@",
		ES: "@",
		EW: "~",
		NS: "!",
	})
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! ID ! Fruit ! Stock !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 1 ! Apple ! 14 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 2 ! Banana ! 88,041 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 3 ! Cherry ! 342 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 4 ! Dragonfruit ! 1 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@

Example: Auto Merge Cells

package main
import (
	"os"
	"time"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetAutoMerge(true)
	t.SetHeaders("System", "Status", "Last Check")
	t.AddRow("Life Support", "OK", time.Now().Format(time.Stamp))
	t.AddRow("Nuclear Generator", "OK", time.Now().Add(-time.Minute).Format(time.Stamp))
	t.AddRow("Weapons Systems", "FAIL", time.Now().Format(time.Stamp))
	t.AddRow("Shields", "OK", time.Now().Format(time.Stamp))
	t.Render()
}

Output

┌───────────────────┬────────┬────────────────┐
│ System │ Status │ Last Check │
├───────────────────┼────────┼────────────────┤
│ Life Support │ OK │ May 2 09:28:05 │
├───────────────────┤ ├────────────────┤
│ Nuclear Generator │ │ May 2 09:27:05 │
├───────────────────┼────────┼────────────────┤
│ Weapons Systems │ FAIL │ May 2 09:28:05 │
├───────────────────┼────────┤ │
│ Shields │ OK │ │
└───────────────────┴────────┴────────────────┘

Example: Load Data From Csv

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	f, err := os.Open("./_examples/12-load-data-from-csv/data.csv")
	if err != nil {
		panic(err)
	}
	t := table.New(os.Stdout)
	if err := t.LoadCSV(f, true); err != nil {
		panic(err)
	}
	t.Render()
}

Output

┌────┬────────────┬────────────────────────────────────────────┐
│ Id │ Date │ Message │
├────┼────────────┼────────────────────────────────────────────┤
│ 1 │ 2022年05月12日 │ Hello world! │
├────┼────────────┼────────────────────────────────────────────┤
│ 2 │ 2022年05月12日 │ These messages are loaded from a CSV file. │
├────┼────────────┼────────────────────────────────────────────┤
│ 3 │ 2022年05月13日 │ Incredible! │
└────┴────────────┴────────────────────────────────────────────┘

Example: Markdown Format

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetDividers(table.MarkdownDividers)
	t.SetBorderTop(false)
	t.SetBorderBottom(false)
	t.SetRowLines(false)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "Apple", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

| ID | Fruit | Stock |
|----|-------------|--------|
| 1 | Apple | 14 |
| 2 | Banana | 88,041 |
| 3 | Cherry | 342 |
| 4 | Dragonfruit | 1 |

Example: Header Colspans

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("Namespace", "Resource", "Vulnerabilities", "Misconfigurations")
	t.AddHeaders("Namespace", "Resource", "Critical", "High", "Medium", "Low", "Unknown", "Critical", "High", "Medium", "Low", "Unknown")
	t.SetHeaderColSpans(0, 1, 1, 5, 5)
	t.SetAutoMergeHeaders(true)
	t.AddRow("default", "Deployment/app", "2", "5", "7", "8", "0", "0", "3", "5", "19", "0")
	t.AddRow("default", "Ingress/test", "-", "-", "-", "-", "-", "1", "0", "2", "17", "0")
	t.AddRow("default", "Service/test", "0", "0", "0", "1", "0", "3", "0", "4", "9", "0")
	t.Render()
}

Output

┌───────────┬────────────────┬──────────────────────────────────────────┬──────────────────────────────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │
│ │ ├──────────┬──────┬────────┬─────┬─────────┼──────────┬──────┬────────┬─────┬─────────┤
│ │ │ Critical │ High │ Medium │ Low │ Unknown │ Critical │ High │ Medium │ Low │ Unknown │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Deployment/app │ 2 │ 5 │ 7 │ 8 │ 0 │ 0 │ 3 │ 5 │ 19 │ 0 │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Ingress/test │ - │ - │ - │ - │ - │ 1 │ 0 │ 2 │ 17 │ 0 │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Service/test │ 0 │ 0 │ 0 │ 1 │ 0 │ 3 │ 0 │ 4 │ 9 │ 0 │
└───────────┴────────────────┴──────────┴──────┴────────┴─────┴─────────┴──────────┴──────┴────────┴─────┴─────────┘

Example: Only Wrap When Needed

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("ID", "Fruit", "Stock")
	t.AddRow("1", "01234567890123456789012345678901234567890123456789012345678901234567890123456789", "14")
	t.AddRow("2", "Banana", "88,041")
	t.AddRow("3", "Cherry", "342")
	t.AddRow("4", "Dragonfruit", "1")
	t.Render()
}

Output

┌────┬──────────────────────────────────────────────────────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 1 │ 01234567890123456789012345678901234567890123456789012345678- │ 14 │
│ │ 901234567890123456789 │ │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴──────────────────────────────────────────────────────────────┴────────┘

Example: Double-width Unicode

package main
import (
	"os"
	"github.com/aquasecurity/table"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("A", "B", "C")
	t.AddRow("🔥 unicode 🔥 characters 🔥", "2", "3")
	t.AddRow("4", "5", "6")
	t.Render()
}

Output

a table with double-width runes

Example: ANSI Colours

package main
import (
	"os"
	"github.com/aquasecurity/table"
	"github.com/liamg/tml"
)
func main() {
	t := table.New(os.Stdout)
	t.SetHeaders("ID", "Fruit", "Stock", "Description")
	t.SetHeaderStyle(table.StyleBold)
	t.SetLineStyle(table.StyleBlue)
	t.SetDividers(table.UnicodeRoundedDividers)
	t.AddRow("1", tml.Sprintf("<green>Apple</green>"), "14", tml.Sprintf("An apple is an edible fruit produced by an apple tree (<italic>Malus domestica</italic>). "))
	t.AddRow("2", tml.Sprintf("<yellow>Banana</yellow>"), "88,041", "A banana is an elongated, edible fruit - botanically a berry.")
	t.AddRow("3", tml.Sprintf("<red>Cherry</red>"), "342", "A cherry is the fruit of many plants of the genus Prunus, and is a fleshy drupe (stone fruit). ")
	t.AddRow("4", tml.Sprintf("<magenta>Dragonfruit</magenta>"), "1", "A dragonfruit is the fruit of several different cactus species indigenous to the Americas.")
	t.Render()
}

Output

a colourful table

About

🧮 Tables for terminals, in Go.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors 3

AltStyle によって変換されたページ (->オリジナル) /