...

Source file src/github.com/linkerd/linkerd2/cli/table/table.go

Documentation: github.com/linkerd/linkerd2/cli/table

     1  package table
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"sort"
     7  	"strings"
     8  )
     9  
    10  type (
    11  	// Table represents a table of data to be rendered.
    12  	Table struct {
    13  		Columns       []Column
    14  		Data          []Row
    15  		Sort          []int
    16  		ColumnSpacing string
    17  	}
    18  
    19  	// Row is a single row of data in a table.
    20  	Row = []string
    21  
    22  	// Column represents metadata about a column in a table.
    23  	Column struct {
    24  		Header string
    25  		Width  int
    26  		// If false, render this column.
    27  		Hide bool
    28  		// If true, set the width to the widest value in this column.
    29  		Flexible  bool
    30  		LeftAlign bool
    31  	}
    32  )
    33  
    34  const defaultColumnSpacing = "  "
    35  
    36  // NewTable creates a new table with the given columns and rows.
    37  func NewTable(cols []Column, data []Row) Table {
    38  	return Table{
    39  		Columns:       cols,
    40  		Data:          data,
    41  		Sort:          []int{},
    42  		ColumnSpacing: defaultColumnSpacing,
    43  	}
    44  }
    45  
    46  // NewColumn creates a new flexible column with the given name.
    47  func NewColumn(header string) Column {
    48  	return Column{
    49  		Header:   header,
    50  		Flexible: true,
    51  		Width:    len(header),
    52  	}
    53  }
    54  
    55  // WithLeftAlign turns on the left align of this column and returns it.
    56  func (c Column) WithLeftAlign() Column {
    57  	c.LeftAlign = true
    58  	return c
    59  }
    60  
    61  // Render writes the full table to the given Writer.
    62  func (t *Table) Render(w io.Writer) {
    63  	columnWidths := t.columnWidths()
    64  	t.renderRow(w, t.headerRow(), columnWidths)
    65  	t.sort()
    66  	for _, row := range t.Data {
    67  		t.renderRow(w, row, columnWidths)
    68  	}
    69  }
    70  
    71  func (t *Table) columnWidths() []int {
    72  	widths := make([]int, len(t.Columns))
    73  	for c, col := range t.Columns {
    74  		width := col.Width
    75  		if col.Flexible {
    76  			for _, row := range t.Data {
    77  				if len(row[c]) > width {
    78  					width = len(row[c])
    79  				}
    80  			}
    81  		}
    82  		widths[c] = width
    83  	}
    84  	return widths
    85  }
    86  
    87  func (t *Table) sort() {
    88  	if len(t.Sort) == 0 {
    89  		return
    90  	}
    91  	sort.Slice(t.Data, func(i, j int) bool {
    92  		for _, sortCol := range t.Sort {
    93  			if t.Data[i][sortCol] < t.Data[j][sortCol] {
    94  				return true
    95  			} else if t.Data[i][sortCol] > t.Data[j][sortCol] {
    96  				return false
    97  			}
    98  		}
    99  		return false
   100  	})
   101  }
   102  
   103  func (t *Table) renderRow(w io.Writer, row Row, columnWidths []int) {
   104  	for c, col := range t.Columns {
   105  		if col.Hide {
   106  			continue
   107  		}
   108  		value := row[c]
   109  		if len(value) > columnWidths[c] {
   110  			value = value[:columnWidths[c]]
   111  		}
   112  		padding := strings.Repeat(" ", columnWidths[c]-len(value))
   113  		if col.LeftAlign {
   114  			fmt.Fprintf(w, "%s%s%s", value, padding, t.ColumnSpacing)
   115  		} else {
   116  			fmt.Fprintf(w, "%s%s%s", padding, value, t.ColumnSpacing)
   117  		}
   118  	}
   119  	fmt.Fprint(w, "\n")
   120  }
   121  
   122  func (t *Table) headerRow() Row {
   123  	row := make(Row, len(t.Columns))
   124  	for c, col := range t.Columns {
   125  		row[c] = col.Header
   126  	}
   127  	return row
   128  }
   129  

View as plain text