github.com/puellanivis/breton@v0.2.16/lib/display/tables/display.go (about)

     1  package tables
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  )
     9  
    10  func (d *Divider) writeDivider(wr io.Writer, widths []int) (n int64, err error) {
    11  	line := new(bytes.Buffer)
    12  
    13  	if d.Left != "" {
    14  		line.WriteString(d.Left)
    15  	}
    16  
    17  	switch {
    18  	case d.Bar == "":
    19  		var cols []string
    20  
    21  		for _, width := range widths {
    22  			if width < 0 {
    23  				width = -width
    24  			}
    25  
    26  			cols = append(cols, strings.Repeat(d.Space, width))
    27  		}
    28  
    29  		line.WriteString(strings.Join(cols, d.Space))
    30  
    31  	case d.Space != "":
    32  		var cols []string
    33  
    34  		for _, width := range widths {
    35  			if width < 0 {
    36  				width = -width
    37  			}
    38  
    39  			cols = append(cols, strings.Repeat(d.Space, width+2))
    40  		}
    41  
    42  		line.WriteString(strings.Join(cols, d.Bar))
    43  	}
    44  
    45  	if d.Right != "" {
    46  		line.WriteString(d.Right)
    47  	}
    48  
    49  	if line.Len() == 0 {
    50  		return 0, nil
    51  	}
    52  
    53  	line.WriteByte('\n')
    54  	return io.Copy(wr, line)
    55  }
    56  
    57  func (d *Divider) scale(width int, text string, fn func(string) int) string {
    58  	if width == 0 || d.Space == "" {
    59  		return text
    60  	}
    61  
    62  	l := len(text)
    63  
    64  	if fn != nil {
    65  		l = fn(text)
    66  	}
    67  
    68  	if width < 0 {
    69  		padding := strings.Repeat(d.Space, -width-l)
    70  		return fmt.Sprint(padding, text)
    71  	}
    72  
    73  	padding := strings.Repeat(d.Space, width-l)
    74  	return fmt.Sprint(text, padding)
    75  }
    76  
    77  // writeRow buffers the whole line together, then makes a single wr.Write of the rendered row.
    78  func (f *Format) writeRow(wr io.Writer, cols []string) (n int64, err error) {
    79  	line := new(bytes.Buffer)
    80  
    81  	if f.Inner == nil {
    82  		// if there is no defined Inner format, just dump it raw.
    83  		for _, col := range cols {
    84  			line.WriteString(col)
    85  		}
    86  
    87  		line.WriteByte('\n')
    88  		return io.Copy(wr, line)
    89  	}
    90  
    91  	if f.Inner.Left != "" {
    92  		line.WriteString(f.Inner.Left)
    93  		line.WriteString(f.Inner.Space)
    94  	}
    95  
    96  	var sep = f.Inner.Space
    97  	if f.Inner.Bar != "" {
    98  		sep = fmt.Sprint(f.Inner.Space, f.Inner.Bar, f.Inner.Space)
    99  	}
   100  	line.WriteString(strings.Join(cols, sep))
   101  
   102  	if f.Inner.Right != "" {
   103  		line.WriteString(f.Inner.Space)
   104  		line.WriteString(f.Inner.Right)
   105  	}
   106  
   107  	if line.Len() == 0 {
   108  		// if line is empty, don’t perform any Write at all.
   109  		// Otherwise we would put a newline in.
   110  		return 0, nil
   111  	}
   112  
   113  	line.WriteByte('\n')
   114  	return io.Copy(wr, line)
   115  }
   116  
   117  func (f *Format) writeRowScale(wr io.Writer, row []string, widths []int) (n int64, err error) {
   118  	var cols []string
   119  
   120  	if f.Inner.Right == "" {
   121  		w := make([]int, len(row)-1)
   122  		copy(w, widths)
   123  		widths = w
   124  		widths = append(widths, 0)
   125  	}
   126  
   127  	for i, width := range widths {
   128  		cols = append(cols, f.Inner.scale(width, row[i], f.WidthFunc))
   129  	}
   130  
   131  	return f.writeRow(wr, cols)
   132  }
   133  
   134  // WriteSimple takes only a 2D slice to fill in the table. It uses the Default format.
   135  func WriteSimple(wr io.Writer, table Table) error {
   136  	return Default.WriteSimple(wr, table)
   137  }
   138  
   139  // WriteSimple takes only a 2D slice to fill in the table.
   140  func (f *Format) WriteSimple(wr io.Writer, table Table) error {
   141  	widths := table.widths(f.Inner.Space != "", f.WidthFunc)
   142  
   143  	if f.Upper != nil {
   144  		if _, err := f.Upper.writeDivider(wr, widths); err != nil {
   145  			return err
   146  		}
   147  	}
   148  
   149  	for _, row := range table {
   150  		if len(row) < 1 {
   151  			if f.Middle != nil {
   152  				if _, err := f.Middle.writeDivider(wr, widths); err != nil {
   153  					return err
   154  				}
   155  			}
   156  
   157  			continue
   158  		}
   159  
   160  		if f.Inner.Space == "" {
   161  			if _, err := f.writeRow(wr, row); err != nil {
   162  				return err
   163  			}
   164  
   165  			continue
   166  		}
   167  
   168  		if f.Inner.Right != "" && len(row) < len(widths) {
   169  			// in this case, we need to pad the available rows to match the rest of the table.
   170  			l := len(widths) - len(row)
   171  			row = append(row, make([]string, l)...)
   172  		}
   173  
   174  		if _, err := f.writeRowScale(wr, row, widths); err != nil {
   175  			return err
   176  		}
   177  	}
   178  
   179  	if f.Lower != nil {
   180  		if _, err := f.Lower.writeDivider(wr, widths); err != nil {
   181  			return err
   182  		}
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  // WriteMulti writes the data given out it uses the Default format
   189  func WriteMulti(wr io.Writer, table [][][]string) error {
   190  	return Default.WriteMulti(wr, table)
   191  }
   192  
   193  func rowHeight(row [][]string) int {
   194  	var height int
   195  
   196  	for _, col := range row {
   197  		if height < len(col) {
   198  			height = len(col)
   199  		}
   200  	}
   201  
   202  	return height
   203  }
   204  
   205  // WriteMulti writes the table given out according to the Format. Each row is checked for height > 1, and if true, it inserts additional lines in a normal 2D Table, populated with available data, and with empty cells for columns where its height is less than the height of the row. It also inserts a new empty row after any row that is height > 1 if the next row is height > 1.
   206  func (f *Format) WriteMulti(wr io.Writer, table [][][]string) error {
   207  	var tbl Table
   208  	var last int
   209  
   210  	for _, row := range table {
   211  		height := rowHeight(row)
   212  
   213  		if height > 1 || last > 1 {
   214  			tbl = append(tbl, []string{})
   215  		}
   216  
   217  		for i := 0; i < height; i++ {
   218  			var r []string
   219  
   220  			for _, col := range row {
   221  				var c string
   222  
   223  				if i < len(col) {
   224  					c = col[i]
   225  				}
   226  
   227  				r = append(r, c)
   228  			}
   229  
   230  			tbl = append(tbl, r)
   231  		}
   232  
   233  		last = height
   234  	}
   235  
   236  	return f.WriteSimple(wr, tbl)
   237  }