...

Source file src/golang.conradwood.net/go-easyops/utils/table_formatter.go

Documentation: golang.conradwood.net/go-easyops/utils

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"unicode/utf8"
     7  )
     8  
     9  type TextFormatter struct {
    10  	table    *Table
    11  	colSizes []int
    12  }
    13  
    14  func (t *TextFormatter) tableWidth() int {
    15  	res := 0
    16  	for _, cs := range t.colSizes {
    17  		res = res + cs
    18  	}
    19  	return res
    20  }
    21  func (t *Table) ToPrettyString() string {
    22  	tf := &TextFormatter{table: t}
    23  	return tf.ToPrettyString()
    24  }
    25  func (tf *TextFormatter) adjustColsToMatchTerminal() {
    26  	di, err := TerminalSize()
    27  	if err != nil {
    28  		fmt.Printf("[go-easyops] unable to determine terminal size (%s)\n", err)
    29  		return
    30  	}
    31  	if di.Columns() < len(tf.colSizes) {
    32  		fmt.Printf("[go-easyops] terminal has %d columns, but table has %d columns\n", di.Columns(), len(tf.colSizes))
    33  		return
    34  	}
    35  
    36  	extraSize := len(tf.colSizes)*3 + 2 // borders and seperators
    37  	if di.Columns() < extraSize {
    38  		return
    39  	}
    40  	// make sure table fits into terminal
    41  	shrank := false
    42  	for tf.tableWidth() > di.Columns()-extraSize {
    43  
    44  		// find column to shrink
    45  		col_shrink := -1
    46  		for col, size := range tf.colSizes {
    47  			if col_shrink == -1 || tf.colSizes[col_shrink] < size {
    48  				col_shrink = col
    49  			}
    50  		}
    51  		if col_shrink == -1 {
    52  			// no columns to shrink at all??
    53  			return
    54  		}
    55  		tf.colSizes[col_shrink]--
    56  		shrank = true
    57  	}
    58  	for col, size := range tf.colSizes {
    59  		tf.table.SetMaxLen(col, size)
    60  	}
    61  	if shrank {
    62  		/*
    63  			fmt.Printf("Shrank to %d\n", di.Columns())
    64  			for i, size := range tf.colSizes {
    65  				fmt.Printf("Colsizes %d. %d\n", i, size)
    66  			}
    67  		*/
    68  	}
    69  
    70  }
    71  func (tf *TextFormatter) ToPrettyString() string {
    72  	r := tf.table.GetPrintingRows()
    73  	if tf.table.headerRow != nil {
    74  		r = append(r, tf.table.headerRow)
    75  	}
    76  	tf.colSizes = getCharWidth(r)
    77  	tf.adjustColsToMatchTerminal()
    78  	var sb strings.Builder
    79  	if tf.table.headerRow != nil {
    80  		sb.WriteString(tf.renderRow(tf.table.headerRow, 2))
    81  		sb.WriteString(tf.seperatorRow())
    82  	}
    83  	for _, row := range tf.table.GetPrintingRows() {
    84  		sb.WriteString(tf.renderRow(row, 0))
    85  	}
    86  	sb.WriteString(tf.seperatorRow())
    87  	return sb.String()
    88  }
    89  func (tf *TextFormatter) seperatorRow() string {
    90  	s := ""
    91  	for _, cs := range tf.colSizes {
    92  		xs := "|"
    93  		for len(xs) < (cs + 3) {
    94  			xs = xs + "="
    95  		}
    96  		s = s + xs
    97  	}
    98  	return s + "|\n"
    99  
   100  }
   101  
   102  // pos: 0 left, 1 right, 2 center
   103  func (tf *TextFormatter) renderRow(row *Row, pos int) string {
   104  	res := "| "
   105  	l := false
   106  	for i, c := range row.Cells() {
   107  		s := c.String()
   108  		for len(s) < tf.colSizes[i] {
   109  			if pos == 2 {
   110  				if l {
   111  					l = false
   112  					s = " " + s
   113  				} else {
   114  					l = true
   115  					s = s + " "
   116  				}
   117  			} else if pos == 0 {
   118  				s = s + " "
   119  			} else {
   120  				s = " " + s
   121  			}
   122  		}
   123  		res = res + s + " | "
   124  	}
   125  	res = res + "\n"
   126  	return res
   127  
   128  }
   129  
   130  // calculate max width of columns
   131  func getCharWidth(rows []*Row) []int {
   132  	maxCols := 0
   133  	for _, r := range rows {
   134  		if r.Cols() > maxCols {
   135  			maxCols = r.Cols()
   136  		}
   137  	}
   138  	sz := make(map[int]int) // colidx -> size
   139  	for _, r := range rows {
   140  		for i := 0; i < maxCols; i++ {
   141  			c := r.GetCell(i)
   142  			if c == nil {
   143  				continue
   144  			}
   145  			w := utf8.RuneCountInString(c.String())
   146  			if w > sz[i] {
   147  				sz[i] = w
   148  			}
   149  		}
   150  	}
   151  
   152  	// turn map into array
   153  	var res []int
   154  	for i := 0; i < len(sz); i++ {
   155  		res = append(res, sz[i])
   156  	}
   157  	return res
   158  }
   159  

View as plain text