istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/writer/table/writer.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package table 16 17 import ( 18 "fmt" 19 "io" 20 "strings" 21 "unicode/utf8" 22 23 "github.com/fatih/color" 24 ) 25 26 type ColoredTableWriter struct { 27 writer io.Writer 28 header Row 29 rows []Row 30 addRowFunc func(obj interface{}) Row 31 } 32 33 func NewStyleWriter(writer io.Writer) *ColoredTableWriter { 34 return &ColoredTableWriter{ 35 writer: writer, 36 rows: make([]Row, 0), 37 header: Row{}, 38 } 39 } 40 41 type BuildRowFunc func(obj interface{}) Row 42 43 type Cell struct { 44 Value string 45 Attributes []color.Attribute 46 } 47 48 type Row struct { 49 Cells []Cell 50 } 51 52 func NewCell(value string, attributes ...color.Attribute) Cell { 53 attrs := append([]color.Attribute{}, attributes...) 54 return Cell{value, attrs} 55 } 56 57 func (cell Cell) String() string { 58 if len(cell.Attributes) == 0 { 59 return cell.Value 60 } 61 s := color.New(cell.Attributes...) 62 s.EnableColor() 63 return s.Sprintf("%s", cell.Value) 64 } 65 66 func (c *ColoredTableWriter) getTableOutput(allRows []Row) [][]Cell { 67 output := [][]Cell{} 68 if len(c.header.Cells) != 0 { 69 output = append(output, c.header.Cells) 70 } 71 for _, row := range allRows { 72 output = append(output, row.Cells) 73 } 74 return output 75 } 76 77 func (c *ColoredTableWriter) SetAddRowFunc(f func(obj interface{}) Row) { 78 c.addRowFunc = f 79 } 80 81 func (c *ColoredTableWriter) AddHeader(names ...string) { 82 cells := make([]Cell, 0) 83 for _, name := range names { 84 cells = append(cells, NewCell(name)) 85 } 86 c.header = Row{Cells: cells} 87 } 88 89 func (c *ColoredTableWriter) AddRow(obj interface{}) { 90 c.rows = append(c.rows, c.addRowFunc(obj)) 91 } 92 93 func (c *ColoredTableWriter) Flush() { 94 output := c.getTableOutput(c.rows) 95 if len(output) == 0 { 96 return 97 } 98 sep := getMaxWidths(output) 99 for _, row := range output { 100 for i, col := range row { 101 _, _ = fmt.Fprint(c.writer, col.String()) 102 if i == len(row)-1 { 103 _, _ = fmt.Fprint(c.writer, "\n") 104 } else { 105 padAmount := sep[i] - utf8.RuneCount([]byte(col.Value)) + 2 106 _, _ = fmt.Fprint(c.writer, strings.Repeat(" ", padAmount)) 107 } 108 } 109 } 110 } 111 112 func max(x, y int) int { 113 if x < y { 114 return y 115 } 116 return x 117 } 118 119 func getMaxWidths(output [][]Cell) []int { 120 widths := make([]int, len(output[0])) 121 for _, row := range output { 122 for i, col := range row { 123 widths[i] = max(widths[i], len(col.String())) 124 } 125 } 126 return widths 127 }