1ASCII Table Writer 2========= 3 4[![Build Status](https://travis-ci.org/olekukonko/tablewriter.png?branch=master)](https://travis-ci.org/olekukonko/tablewriter) 5[![Total views](https://img.shields.io/sourcegraph/rrc/github.com/olekukonko/tablewriter.svg)](https://sourcegraph.com/github.com/olekukonko/tablewriter) 6[![Godoc](https://godoc.org/github.com/olekukonko/tablewriter?status.svg)](https://godoc.org/github.com/olekukonko/tablewriter) 7 8Generate ASCII table on the fly ... Installation is simple as 9 10 go get github.com/olekukonko/tablewriter 11 12 13#### Features 14- Automatic Padding 15- Support Multiple Lines 16- Supports Alignment 17- Support Custom Separators 18- Automatic Alignment of numbers & percentage 19- Write directly to http , file etc via `io.Writer` 20- Read directly from CSV file 21- Optional row line via `SetRowLine` 22- Normalise table header 23- Make CSV Headers optional 24- Enable or disable table border 25- Set custom footer support 26- Optional identical cells merging 27- Set custom caption 28- Optional reflowing of paragraphs in multi-line cells. 29 30#### Example 1 - Basic 31```go 32data := [][]string{ 33 []string{"A", "The Good", "500"}, 34 []string{"B", "The Very very Bad Man", "288"}, 35 []string{"C", "The Ugly", "120"}, 36 []string{"D", "The Gopher", "800"}, 37} 38 39table := tablewriter.NewWriter(os.Stdout) 40table.SetHeader([]string{"Name", "Sign", "Rating"}) 41 42for _, v := range data { 43 table.Append(v) 44} 45table.Render() // Send output 46``` 47 48##### Output 1 49``` 50+------+-----------------------+--------+ 51| NAME | SIGN | RATING | 52+------+-----------------------+--------+ 53| A | The Good | 500 | 54| B | The Very very Bad Man | 288 | 55| C | The Ugly | 120 | 56| D | The Gopher | 800 | 57+------+-----------------------+--------+ 58``` 59 60#### Example 2 - Without Border / Footer / Bulk Append 61```go 62data := [][]string{ 63 []string{"1/1/2014", "Domain name", "2233", "$10.98"}, 64 []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, 65 []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, 66 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, 67} 68 69table := tablewriter.NewWriter(os.Stdout) 70table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) 71table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer 72table.SetBorder(false) // Set Border to false 73table.AppendBulk(data) // Add Bulk Data 74table.Render() 75``` 76 77##### Output 2 78``` 79 80 DATE | DESCRIPTION | CV2 | AMOUNT 81-----------+--------------------------+-------+---------- 82 1/1/2014 | Domain name | 2233 | $10.98 83 1/1/2014 | January Hosting | 2233 | $54.95 84 1/4/2014 | February Hosting | 2233 | $51.00 85 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 86-----------+--------------------------+-------+---------- 87 TOTAL | $146 93 88 --------+---------- 89 90``` 91 92 93#### Example 3 - CSV 94```go 95table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test_info.csv", true) 96table.SetAlignment(tablewriter.ALIGN_LEFT) // Set Alignment 97table.Render() 98``` 99 100##### Output 3 101``` 102+----------+--------------+------+-----+---------+----------------+ 103| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA | 104+----------+--------------+------+-----+---------+----------------+ 105| user_id | smallint(5) | NO | PRI | NULL | auto_increment | 106| username | varchar(10) | NO | | NULL | | 107| password | varchar(100) | NO | | NULL | | 108+----------+--------------+------+-----+---------+----------------+ 109``` 110 111#### Example 4 - Custom Separator 112```go 113table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test.csv", true) 114table.SetRowLine(true) // Enable row line 115 116// Change table lines 117table.SetCenterSeparator("*") 118table.SetColumnSeparator("╪") 119table.SetRowSeparator("-") 120 121table.SetAlignment(tablewriter.ALIGN_LEFT) 122table.Render() 123``` 124 125##### Output 4 126``` 127*------------*-----------*---------* 128╪ FIRST NAME ╪ LAST NAME ╪ SSN ╪ 129*------------*-----------*---------* 130╪ John ╪ Barry ╪ 123456 ╪ 131*------------*-----------*---------* 132╪ Kathy ╪ Smith ╪ 687987 ╪ 133*------------*-----------*---------* 134╪ Bob ╪ McCornick ╪ 3979870 ╪ 135*------------*-----------*---------* 136``` 137 138#### Example 5 - Markdown Format 139```go 140data := [][]string{ 141 []string{"1/1/2014", "Domain name", "2233", "$10.98"}, 142 []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, 143 []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, 144 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, 145} 146 147table := tablewriter.NewWriter(os.Stdout) 148table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) 149table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) 150table.SetCenterSeparator("|") 151table.AppendBulk(data) // Add Bulk Data 152table.Render() 153``` 154 155##### Output 5 156``` 157| DATE | DESCRIPTION | CV2 | AMOUNT | 158|----------|--------------------------|------|--------| 159| 1/1/2014 | Domain name | 2233 | $10.98 | 160| 1/1/2014 | January Hosting | 2233 | $54.95 | 161| 1/4/2014 | February Hosting | 2233 | $51.00 | 162| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 | 163``` 164 165#### Example 6 - Identical cells merging 166```go 167data := [][]string{ 168 []string{"1/1/2014", "Domain name", "1234", "$10.98"}, 169 []string{"1/1/2014", "January Hosting", "2345", "$54.95"}, 170 []string{"1/4/2014", "February Hosting", "3456", "$51.00"}, 171 []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"}, 172} 173 174table := tablewriter.NewWriter(os.Stdout) 175table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) 176table.SetFooter([]string{"", "", "Total", "$146.93"}) 177table.SetAutoMergeCells(true) 178table.SetRowLine(true) 179table.AppendBulk(data) 180table.Render() 181``` 182 183##### Output 6 184``` 185+----------+--------------------------+-------+---------+ 186| DATE | DESCRIPTION | CV2 | AMOUNT | 187+----------+--------------------------+-------+---------+ 188| 1/1/2014 | Domain name | 1234 | $10.98 | 189+ +--------------------------+-------+---------+ 190| | January Hosting | 2345 | $54.95 | 191+----------+--------------------------+-------+---------+ 192| 1/4/2014 | February Hosting | 3456 | $51.00 | 193+ +--------------------------+-------+---------+ 194| | February Extra Bandwidth | 4567 | $30.00 | 195+----------+--------------------------+-------+---------+ 196| TOTAL | $146 93 | 197+----------+--------------------------+-------+---------+ 198``` 199 200#### Example 7 - Identical cells merging (specify the column index to merge) 201```go 202data := [][]string{ 203 []string{"1/1/2014", "Domain name", "1234", "$10.98"}, 204 []string{"1/1/2014", "January Hosting", "1234", "$10.98"}, 205 []string{"1/4/2014", "February Hosting", "3456", "$51.00"}, 206 []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"}, 207} 208 209table := tablewriter.NewWriter(os.Stdout) 210table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) 211table.SetFooter([]string{"", "", "Total", "$146.93"}) 212table.SetAutoMergeCellsByColumnIndex([]int{2, 3}) 213table.SetRowLine(true) 214table.AppendBulk(data) 215table.Render() 216``` 217 218##### Output 7 219``` 220+----------+--------------------------+-------+---------+ 221| DATE | DESCRIPTION | CV2 | AMOUNT | 222+----------+--------------------------+-------+---------+ 223| 1/1/2014 | Domain name | 1234 | $10.98 | 224+----------+--------------------------+ + + 225| 1/1/2014 | January Hosting | | | 226+----------+--------------------------+-------+---------+ 227| 1/4/2014 | February Hosting | 3456 | $51.00 | 228+----------+--------------------------+-------+---------+ 229| 1/4/2014 | February Extra Bandwidth | 4567 | $30.00 | 230+----------+--------------------------+-------+---------+ 231| TOTAL | $146.93 | 232+----------+--------------------------+-------+---------+ 233``` 234 235 236#### Table with color 237```go 238data := [][]string{ 239 []string{"1/1/2014", "Domain name", "2233", "$10.98"}, 240 []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, 241 []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, 242 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, 243} 244 245table := tablewriter.NewWriter(os.Stdout) 246table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) 247table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer 248table.SetBorder(false) // Set Border to false 249 250table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor}, 251 tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor}, 252 tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor}, 253 tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor}) 254 255table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, 256 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor}, 257 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, 258 tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor}) 259 260table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{}, 261 tablewriter.Colors{tablewriter.Bold}, 262 tablewriter.Colors{tablewriter.FgHiRedColor}) 263 264table.AppendBulk(data) 265table.Render() 266``` 267 268#### Table with color Output 269![Table with Color](https://cloud.githubusercontent.com/assets/6460392/21101956/bbc7b356-c0a1-11e6-9f36-dba694746efc.png) 270 271#### Example - 8 Table Cells with Color 272 273Individual Cell Colors from `func Rich` take precedence over Column Colors 274 275```go 276data := [][]string{ 277 []string{"Test1Merge", "HelloCol2 - 1", "HelloCol3 - 1", "HelloCol4 - 1"}, 278 []string{"Test1Merge", "HelloCol2 - 2", "HelloCol3 - 2", "HelloCol4 - 2"}, 279 []string{"Test1Merge", "HelloCol2 - 3", "HelloCol3 - 3", "HelloCol4 - 3"}, 280 []string{"Test2Merge", "HelloCol2 - 4", "HelloCol3 - 4", "HelloCol4 - 4"}, 281 []string{"Test2Merge", "HelloCol2 - 5", "HelloCol3 - 5", "HelloCol4 - 5"}, 282 []string{"Test2Merge", "HelloCol2 - 6", "HelloCol3 - 6", "HelloCol4 - 6"}, 283 []string{"Test2Merge", "HelloCol2 - 7", "HelloCol3 - 7", "HelloCol4 - 7"}, 284 []string{"Test3Merge", "HelloCol2 - 8", "HelloCol3 - 8", "HelloCol4 - 8"}, 285 []string{"Test3Merge", "HelloCol2 - 9", "HelloCol3 - 9", "HelloCol4 - 9"}, 286 []string{"Test3Merge", "HelloCol2 - 10", "HelloCol3 -10", "HelloCol4 - 10"}, 287} 288 289table := tablewriter.NewWriter(os.Stdout) 290table.SetHeader([]string{"Col1", "Col2", "Col3", "Col4"}) 291table.SetFooter([]string{"", "", "Footer3", "Footer4"}) 292table.SetBorder(false) 293 294table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor}, 295 tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor}, 296 tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor}, 297 tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor}) 298 299table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, 300 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor}, 301 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, 302 tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor}) 303 304table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{}, 305 tablewriter.Colors{tablewriter.Bold}, 306 tablewriter.Colors{tablewriter.FgHiRedColor}) 307 308colorData1 := []string{"TestCOLOR1Merge", "HelloCol2 - COLOR1", "HelloCol3 - COLOR1", "HelloCol4 - COLOR1"} 309colorData2 := []string{"TestCOLOR2Merge", "HelloCol2 - COLOR2", "HelloCol3 - COLOR2", "HelloCol4 - COLOR2"} 310 311for i, row := range data { 312 if i == 4 { 313 table.Rich(colorData1, []tablewriter.Colors{tablewriter.Colors{}, tablewriter.Colors{tablewriter.Normal, tablewriter.FgCyanColor}, tablewriter.Colors{tablewriter.Bold, tablewriter.FgWhiteColor}, tablewriter.Colors{}}) 314 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}}) 315 } 316 table.Append(row) 317} 318 319table.SetAutoMergeCells(true) 320table.Render() 321 322``` 323 324##### Table cells with color Output 325![Table cells with Color](https://user-images.githubusercontent.com/9064687/63969376-bcd88d80-ca6f-11e9-9466-c3d954700b25.png) 326 327#### Example 9 - Set table caption 328```go 329data := [][]string{ 330 []string{"A", "The Good", "500"}, 331 []string{"B", "The Very very Bad Man", "288"}, 332 []string{"C", "The Ugly", "120"}, 333 []string{"D", "The Gopher", "800"}, 334} 335 336table := tablewriter.NewWriter(os.Stdout) 337table.SetHeader([]string{"Name", "Sign", "Rating"}) 338table.SetCaption(true, "Movie ratings.") 339 340for _, v := range data { 341 table.Append(v) 342} 343table.Render() // Send output 344``` 345 346Note: Caption text will wrap with total width of rendered table. 347 348##### Output 9 349``` 350+------+-----------------------+--------+ 351| NAME | SIGN | RATING | 352+------+-----------------------+--------+ 353| A | The Good | 500 | 354| B | The Very very Bad Man | 288 | 355| C | The Ugly | 120 | 356| D | The Gopher | 800 | 357+------+-----------------------+--------+ 358Movie ratings. 359``` 360 361#### Example 10 - Set NoWhiteSpace and TablePadding option 362```go 363data := [][]string{ 364 {"node1.example.com", "Ready", "compute", "1.11"}, 365 {"node2.example.com", "Ready", "compute", "1.11"}, 366 {"node3.example.com", "Ready", "compute", "1.11"}, 367 {"node4.example.com", "NotReady", "compute", "1.11"}, 368} 369 370table := tablewriter.NewWriter(os.Stdout) 371table.SetHeader([]string{"Name", "Status", "Role", "Version"}) 372table.SetAutoWrapText(false) 373table.SetAutoFormatHeaders(true) 374table.SetHeaderAlignment(ALIGN_LEFT) 375table.SetAlignment(ALIGN_LEFT) 376table.SetCenterSeparator("") 377table.SetColumnSeparator("") 378table.SetRowSeparator("") 379table.SetHeaderLine(false) 380table.SetBorder(false) 381table.SetTablePadding("\t") // pad with tabs 382table.SetNoWhiteSpace(true) 383table.AppendBulk(data) // Add Bulk Data 384table.Render() 385``` 386 387##### Output 10 388``` 389NAME STATUS ROLE VERSION 390node1.example.com Ready compute 1.11 391node2.example.com Ready compute 1.11 392node3.example.com Ready compute 1.11 393node4.example.com NotReady compute 1.11 394``` 395 396#### Render table into a string 397 398Instead 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: 399 400```go 401package main 402 403import ( 404 "strings" 405 "fmt" 406 407 "github.com/olekukonko/tablewriter" 408) 409 410func main() { 411 tableString := &strings.Builder{} 412 table := tablewriter.NewWriter(tableString) 413 414 /* 415 * Code to fill the table 416 */ 417 418 table.Render() 419 420 fmt.Println(tableString.String()) 421} 422``` 423 424#### TODO 425- ~~Import Directly from CSV~~ - `done` 426- ~~Support for `SetFooter`~~ - `done` 427- ~~Support for `SetBorder`~~ - `done` 428- ~~Support table with uneven rows~~ - `done` 429- ~~Support custom alignment~~ 430- General Improvement & Optimisation 431- `NewHTML` Parse table from HTML 432