Updates ryanuber/columnize.

This commit is contained in:
James Phillips 2016-08-09 17:35:03 -07:00
parent 5ad5fe42d4
commit cc54dfa52f
No known key found for this signature in database
GPG Key ID: 77183E682AC5FC11
4 changed files with 101 additions and 73 deletions

View File

@ -1,3 +0,0 @@
language: go
go:
- tip

View File

@ -4,6 +4,7 @@ Columnize
Easy column-formatted output for golang Easy column-formatted output for golang
[![Build Status](https://travis-ci.org/ryanuber/columnize.svg)](https://travis-ci.org/ryanuber/columnize) [![Build Status](https://travis-ci.org/ryanuber/columnize.svg)](https://travis-ci.org/ryanuber/columnize)
[![GoDoc](https://godoc.org/github.com/ryanuber/columnize?status.svg)](https://godoc.org/github.com/ryanuber/columnize)
Columnize is a really small Go package that makes building CLI's a little bit Columnize is a really small Go package that makes building CLI's a little bit
easier. In some CLI designs, you want to output a number similar items in a easier. In some CLI designs, you want to output a number similar items in a
@ -65,11 +66,4 @@ config.Empty = ""
You can then pass the `Config` in using the `Format` method (signature below) to You can then pass the `Config` in using the `Format` method (signature below) to
have text formatted to your liking. have text formatted to your liking.
Usage See the [godoc](https://godoc.org/github.com/ryanuber/columnize) page for usage.
=====
```go
SimpleFormat(intput []string) string
Format(input []string, config *Config) string
```

View File

@ -1,10 +1,13 @@
package columnize package columnize
import ( import (
"bytes"
"fmt" "fmt"
"strings" "strings"
) )
// Config can be used to tune certain parameters which affect the way
// in which Columnize will format output text.
type Config struct { type Config struct {
// The string by which the lines of input will be split. // The string by which the lines of input will be split.
Delim string Delim string
@ -19,66 +22,16 @@ type Config struct {
Empty string Empty string
} }
// Returns a Config with default values. // DefaultConfig returns a *Config with default values.
func DefaultConfig() *Config { func DefaultConfig() *Config {
return &Config{ return &Config{
Delim: "|", Delim: "|",
Glue: " ", Glue: " ",
Prefix: "", Prefix: "",
Empty: "",
} }
} }
// Returns a list of elements, each representing a single item which will
// belong to a column of output.
func getElementsFromLine(config *Config, line string) []interface{} {
elements := make([]interface{}, 0)
for _, field := range strings.Split(line, config.Delim) {
value := strings.TrimSpace(field)
if value == "" && config.Empty != "" {
value = config.Empty
}
elements = append(elements, value)
}
return elements
}
// Examines a list of strings and determines how wide each column should be
// considering all of the elements that need to be printed within it.
func getWidthsFromLines(config *Config, lines []string) []int {
var widths []int
for _, line := range lines {
elems := getElementsFromLine(config, line)
for i := 0; i < len(elems); i++ {
l := len(elems[i].(string))
if len(widths) <= i {
widths = append(widths, l)
} else if widths[i] < l {
widths[i] = l
}
}
}
return widths
}
// Given a set of column widths and the number of columns in the current line,
// returns a sprintf-style format string which can be used to print output
// aligned properly with other lines using the same widths set.
func (c *Config) getStringFormat(widths []int, columns int) string {
// Start with the prefix, if any was given.
stringfmt := c.Prefix
// Create the format string from the discovered widths
for i := 0; i < columns && i < len(widths); i++ {
if i == columns-1 {
stringfmt += "%s\n"
} else {
stringfmt += fmt.Sprintf("%%-%ds%s", widths[i], c.Glue)
}
}
return stringfmt
}
// MergeConfig merges two config objects together and returns the resulting // MergeConfig merges two config objects together and returns the resulting
// configuration. Values from the right take precedence over the left side. // configuration. Values from the right take precedence over the left side.
func MergeConfig(a, b *Config) *Config { func MergeConfig(a, b *Config) *Config {
@ -105,21 +58,103 @@ func MergeConfig(a, b *Config) *Config {
return &result return &result
} }
// Format is the public-facing interface that takes either a plain string // stringFormat, given a set of column widths and the number of columns in
// or a list of strings and returns nicely aligned output. // the current line, returns a sprintf-style format string which can be used
func Format(lines []string, config *Config) string { // to print output aligned properly with other lines using the same widths set.
var result string func stringFormat(c *Config, widths []int, columns int) string {
// Create the buffer with an estimate of the length
buf := bytes.NewBuffer(make([]byte, 0, (6+len(c.Glue))*columns))
// Start with the prefix, if any was given. The buffer will not return an
// error so it does not need to be handled
buf.WriteString(c.Prefix)
// Create the format string from the discovered widths
for i := 0; i < columns && i < len(widths); i++ {
if i == columns-1 {
buf.WriteString("%s\n")
} else {
fmt.Fprintf(buf, "%%-%ds%s", widths[i], c.Glue)
}
}
return buf.String()
}
// elementsFromLine returns a list of elements, each representing a single
// item which will belong to a column of output.
func elementsFromLine(config *Config, line string) []interface{} {
seperated := strings.Split(line, config.Delim)
elements := make([]interface{}, len(seperated))
for i, field := range seperated {
value := strings.TrimSpace(field)
// Apply the empty value, if configured.
if value == "" && config.Empty != "" {
value = config.Empty
}
elements[i] = value
}
return elements
}
// widthsFromLines examines a list of strings and determines how wide each
// column should be considering all of the elements that need to be printed
// within it.
func widthsFromLines(config *Config, lines []string) []int {
widths := make([]int, 0, 8)
for _, line := range lines {
elems := elementsFromLine(config, line)
for i := 0; i < len(elems); i++ {
l := len(elems[i].(string))
if len(widths) <= i {
widths = append(widths, l)
} else if widths[i] < l {
widths[i] = l
}
}
}
return widths
}
// Format is the public-facing interface that takes a list of strings and
// returns nicely aligned column-formatted text.
func Format(lines []string, config *Config) string {
conf := MergeConfig(DefaultConfig(), config) conf := MergeConfig(DefaultConfig(), config)
widths := getWidthsFromLines(conf, lines) widths := widthsFromLines(conf, lines)
// Estimate the buffer size
glueSize := len(conf.Glue)
var size int
for _, w := range widths {
size += w + glueSize
}
size *= len(lines)
// Create the buffer
buf := bytes.NewBuffer(make([]byte, 0, size))
// Create a cache for the string formats
fmtCache := make(map[int]string, 16)
// Create the formatted output using the format string // Create the formatted output using the format string
for _, line := range lines { for _, line := range lines {
elems := getElementsFromLine(conf, line) elems := elementsFromLine(conf, line)
stringfmt := conf.getStringFormat(widths, len(elems))
result += fmt.Sprintf(stringfmt, elems...) // Get the string format using cache
numElems := len(elems)
stringfmt, ok := fmtCache[numElems]
if !ok {
stringfmt = stringFormat(conf, widths, numElems)
fmtCache[numElems] = stringfmt
}
fmt.Fprintf(buf, stringfmt, elems...)
} }
// Get the string result
result := buf.String()
// Remove trailing newline without removing leading/trailing space // Remove trailing newline without removing leading/trailing space
if n := len(result); n > 0 && result[n-1] == '\n' { if n := len(result); n > 0 && result[n-1] == '\n' {
result = result[:n-1] result = result[:n-1]
@ -128,7 +163,7 @@ func Format(lines []string, config *Config) string {
return result return result
} }
// Convenience function for using Columnize as easy as possible. // SimpleFormat is a convenience function to format text with the defaults.
func SimpleFormat(lines []string) string { func SimpleFormat(lines []string) string {
return Format(lines, nil) return Format(lines, nil)
} }

4
vendor/vendor.json vendored
View File

@ -462,9 +462,11 @@
"revisionTime": "2016-08-09T12:22:04Z" "revisionTime": "2016-08-09T12:22:04Z"
}, },
{ {
"checksumSHA1": "ExnVEVNT8APpFTm26cUb5T09yR4=",
"comment": "v2.0.1-8-g983d3a5", "comment": "v2.0.1-8-g983d3a5",
"path": "github.com/ryanuber/columnize", "path": "github.com/ryanuber/columnize",
"revision": "983d3a5fab1bf04d1b412465d2d9f8430e2e917e" "revision": "9b3edd62028f107d7cabb19353292afd29311a4e",
"revisionTime": "2016-07-12T16:32:29Z"
}, },
{ {
"checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=", "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",