brimtext

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 22, 2020 License: BSD-3-Clause Imports: 8 Imported by: 19

README

BrimText

Text Tools for Go

Package brimtext contains tools for working with text. Probably the most complex of these tools is Align, which allows for formatting "pretty tables".

API Documentation

Copyright See AUTHORS. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.

Example Code

package main

import (
    "fmt"

    "github.com/gholt/brimtext"
)

func main() {
    example := 1
    fmt.Printf("This is the %d%s example:\n\n",
        example, brimtext.OrdinalSuffix(example))
    fmt.Println(brimtext.Align([][]string{
        []string{"", "Bob", "Sue", "John"},
        []string{"Hometown", "San Antonio", "Austin", "New York"},
        []string{"Mother", "Bessie", "Mary", "Sarah"},
        []string{"Father", "Rick", "Dan", "Mike"},
    }, brimtext.NewDefaultAlignOptions()))

    example++
    fmt.Printf("This is the %d%s example:\n\n",
        example, brimtext.OrdinalSuffix(example))
    fmt.Println(brimtext.Align([][]string{
        []string{"", "Bob", "Sue", "John"},
        nil,
        []string{"Hometown", "San Antonio", "Austin", "New York"},
        []string{"Mother", "Bessie", "Mary", "Sarah"},
        []string{"Father", "Rick", "Dan", "Mike"},
    }, brimtext.NewSimpleAlignOptions()))

    example++
    fmt.Printf("This is the %d%s example:\n\n",
        example, brimtext.OrdinalSuffix(example))
    data := [][]int{
        {8, 20, 11},
        {5, 11, 10},
        {3, 9, 1},
        {1200000, 2400000, 1700000},
    }
    table := [][]string{[]string{"", "Bob", "Sue", "John"}}
    for rowNum, values := range data {
        row := []string{""}
        prefix := ""
        switch rowNum {
        case 0:
            row[0] = "Shot Attempts"
        case 1:
            row[0] = "Shots Made"
        case 2:
            row[0] = "Shots Missed"
        case 3:
            row[0] = "Salary"
            prefix = "$"
        }
        for _, v := range values {
            row = append(row, prefix+brimtext.ThousandsSep(int64(v), ","))
        }
        table = append(table, row)
    }
    opts := brimtext.NewUnicodeBoxedAlignOptions()
    opts.Alignments = []brimtext.Alignment{
        brimtext.Right,
        brimtext.Right,
        brimtext.Right,
        brimtext.Right,
    }
    fmt.Println(brimtext.Align(table, opts))
}

Example Output

This is the 1st example:

         Bob         Sue    John
Hometown San Antonio Austin New York
Mother   Bessie      Mary   Sarah
Father   Rick        Dan    Mike

This is the 2nd example:

+----------+-------------+--------+----------+
|          | Bob         | Sue    | John     |
+----------+-------------+--------+----------+
| Hometown | San Antonio | Austin | New York |
| Mother   | Bessie      | Mary   | Sarah    |
| Father   | Rick        | Dan    | Mike     |
+----------+-------------+--------+----------+

This is the 3rd example:

╔═══════════════╦════════════╤════════════╤════════════╗
║               ║        Bob │        Sue │       John ║
╠═══════════════╬════════════╪════════════╪════════════╣
║ Shot Attempts ║          8 │         20 │         11 ║
╟───────────────╫────────────┼────────────┼────────────╢
║    Shots Made ║          5 │         11 │         10 ║
╟───────────────╫────────────┼────────────┼────────────╢
║  Shots Missed ║          3 │          9 │          1 ║
╟───────────────╫────────────┼────────────┼────────────╢
║        Salary ║ $1,200,000 │ $2,400,000 │ $1,700,000 ║
╚═══════════════╩════════════╧════════════╧════════════╝

Documentation

Overview

Package brimtext contains tools for working with text. Probably the most complex of these tools is Align, which allows for formatting "pretty tables".

Index

Examples

Constants

This section is empty.

Variables

View Source
var ANSIEscape = ANSIEscapeCodes{
	Reset:    []byte{27, '[', '0', 'm'},
	Bold:     []byte{27, '[', '1', 'm'},
	BBlack:   []byte{27, '[', '4', '0', 'm'},
	BRed:     []byte{27, '[', '4', '1', 'm'},
	BGreen:   []byte{27, '[', '4', '2', 'm'},
	BYellow:  []byte{27, '[', '4', '3', 'm'},
	BBlue:    []byte{27, '[', '4', '4', 'm'},
	BMagenta: []byte{27, '[', '4', '5', 'm'},
	BCyan:    []byte{27, '[', '4', '6', 'm'},
	BWhite:   []byte{27, '[', '4', '7', 'm'},
	FBlack:   []byte{27, '[', '3', '0', 'm'},
	FRed:     []byte{27, '[', '3', '1', 'm'},
	FGreen:   []byte{27, '[', '3', '2', 'm'},
	FYellow:  []byte{27, '[', '3', '3', 'm'},
	FBlue:    []byte{27, '[', '3', '4', 'm'},
	FMagenta: []byte{27, '[', '3', '5', 'm'},
	FCyan:    []byte{27, '[', '3', '6', 'm'},
	FWhite:   []byte{27, '[', '3', '7', 'm'},
}

ANSIEscape provides ease of access to common ANSI Escape Codes.

Functions

func Align

func Align(data [][]string, opts *AlignOptions) string

Align will format a table according to options. If opts is nil, NewDefaultAlignOptions is used.

Example (Default)
package main

import (
	"fmt"

	"github.com/gholt/brimtext"
)

func main() {
	fmt.Println(brimtext.Align([][]string{
		{"", "Bob", "Sue", "John"},
		{"Hometown", "San Antonio", "Austin", "New York"},
		{"Mother", "Bessie", "Mary", "Sarah"},
		{"Father", "Rick", "Dan", "Mike"},
	}, nil))
}
Output:

         Bob         Sue    John
Hometown San Antonio Austin New York
Mother   Bessie      Mary   Sarah
Father   Rick        Dan    Mike
Example (Simple)
package main

import (
	"fmt"

	"github.com/gholt/brimtext"
)

func main() {
	fmt.Println(brimtext.Align([][]string{
		{"", "Bob", "Sue", "John"},
		nil,
		{"Hometown", "San Antonio", "Austin", "New York"},
		{"Mother", "Bessie", "Mary", "Sarah"},
		{"Father", "Rick", "Dan", "Mike"},
	}, brimtext.NewSimpleAlignOptions()))
}
Output:

+----------+-------------+--------+----------+
|          | Bob         | Sue    | John     |
+----------+-------------+--------+----------+
| Hometown | San Antonio | Austin | New York |
| Mother   | Bessie      | Mary   | Sarah    |
| Father   | Rick        | Dan    | Mike     |
+----------+-------------+--------+----------+
Example (UnicodeBoxed)
package main

import (
	"fmt"

	"github.com/gholt/brimtext"
)

func main() {
	data := [][]int{
		{8, 20, 11},
		{5, 11, 10},
		{3, 9, 1},
		{1200000, 2400000, 1700000},
	}
	table := [][]string{{"", "Bob", "Sue", "John"}}
	for rowNum, values := range data {
		row := []string{""}
		prefix := ""
		switch rowNum {
		case 0:
			row[0] = "Shot Attempts"
		case 1:
			row[0] = "Shots Made"
		case 2:
			row[0] = "Shots Missed"
		case 3:
			row[0] = "Salary"
			prefix = "$"
		}
		for _, v := range values {
			row = append(row, prefix+brimtext.ThousandsSep(int64(v), ","))
		}
		table = append(table, row)
	}
	opts := brimtext.NewUnicodeBoxedAlignOptions()
	opts.Alignments = []brimtext.Alignment{
		brimtext.Right,
		brimtext.Right,
		brimtext.Right,
		brimtext.Right,
	}
	fmt.Println(brimtext.Align(table, opts))
}
Output:

╔═══════════════╦════════════╤════════════╤════════════╗
║               ║        Bob │        Sue │       John ║
╠═══════════════╬════════════╪════════════╪════════════╣
║ Shot Attempts ║          8 │         20 │         11 ║
╟───────────────╫────────────┼────────────┼────────────╢
║    Shots Made ║          5 │         11 │         10 ║
╟───────────────╫────────────┼────────────┼────────────╢
║  Shots Missed ║          3 │          9 │          1 ║
╟───────────────╫────────────┼────────────┼────────────╢
║        Salary ║ $1,200,000 │ $2,400,000 │ $1,700,000 ║
╚═══════════════╩════════════╧════════════╧════════════╝
Example (UnicodeCustom)
package main

import (
	"fmt"

	"github.com/gholt/brimtext"
)

func main() {
	opts := brimtext.NewUnicodeBoxedAlignOptions()
	opts.FirstFirstDLR = opts.FirstDLR
	opts.RowSecondUD = opts.RowUD
	opts.NilFirstUDLR = opts.NilUDLR
	opts.FirstNilFirstUDR = opts.NilFirstUDR
	opts.FirstNilLR = opts.NilLR
	opts.FirstNilFirstUDLR = opts.NilFirstUDLR
	opts.FirstNilUDLR = opts.NilUDLR
	opts.FirstNilLastUDL = opts.NilLastUDL
	opts.LastFirstULR = opts.LastULR
	opts.NilBetweenEveryRow = false
	opts.Alignments = []brimtext.Alignment{
		brimtext.Left,
		brimtext.Right,
		brimtext.Right,
	}
	fmt.Println(brimtext.Align([][]string{
		{"Name", "Points", "Assists"},
		nil,
		{"Bob", "10", "1"},
		{"Sue", "7", "5"},
		{"John", "2", "1"},
		nil,
		{"Shooting Stars", "19", "7"},
	}, opts))
}
Output:

╔════════════════╤════════╤═════════╗
║ Name           │ Points │ Assists ║
╟────────────────┼────────┼─────────╢
║ Bob            │     10 │       1 ║
║ Sue            │      7 │       5 ║
║ John           │      2 │       1 ║
╟────────────────┼────────┼─────────╢
║ Shooting Stars │     19 │       7 ║
╚════════════════╧════════╧═════════╝

func AllEqual

func AllEqual(values ...string) bool

AllEqual returns true if all the values are equal strings; no strings, AllEqual() or AllEqual([]string{}...), are considered AllEqual.

func ClosestANSIForeground

func ClosestANSIForeground(red int, green int, blue int) []byte

ClosestANSIForeground translates the RGB values to the closest ANSIEscape sequence for that foreground color.

func ClosestANSIForegroundString

func ClosestANSIForegroundString(value string) []byte

ClosestANSIForegroundString translates the CSS-style color (e.g. "#ac8" "#ffee66") string to the closest ANSIEscape sequence for that foreground color.

func FalseString

func FalseString(value string) bool

FalseString returns true if the string contains a recognized false value, such as "false", "False", "FALSE", "no", "off", etc. Yes, there is already strconv.ParseBool, but this function is often easier to work with since it just returns true or false instead of (bool, error) like ParseBool does. If you need to differentiate between true, false, and unknown, ParseBool should be your choice. Although I suppose you could use TrueString(s), FalseString(s), and !TrueString(s) && !FalseString(s).

func GetTTYWidth

func GetTTYWidth() int

GetTTYWidth returns the width of the controlling TTY if it can or 80.

func HumanSize

func HumanSize(v float64, u float64, s []string) string

HumanSize returns a more readable size format. Quick, "standard" implementations are HumanSize1000 and HumanSize1024, but this more generic function is provided so you can tweak the output a bit more.

Here are the implementations of the two standard functions, to get an idea of how you might wish to use HumanSize directly.

// HumanSize1000 returns a more readable size format, such as
// HumanSize1000(1234567) giving "1.23m".
// These are 1,000 unit based: 1k = 1000, 1m = 1000000, etc.
func HumanSize1000(v float64) string {
	return HumanSize(v, 1000, []string{"", "k", "m", "g", "t", "p", "e", "z", "y"})
}

// HumanSize1024 returns a more readable size format, such as
// HumanSize1024(1234567) giving "1.18M".
// These are 1,024 unit based: 1K = 1024, 1M = 1048576, etc.
func HumanSize1024(v float64) string {
	return HumanSize(v, 1024, []string{"", "K", "M", "G", "T", "P", "E", "Z", "Y"})
}

func HumanSize1000

func HumanSize1000(v float64) string

HumanSize1000 returns a more readable size format, such as HumanSize1000(1234567) giving "1.23m". These are 1,000 unit based: 1k = 1000, 1m = 1000000, etc.

func HumanSize1024

func HumanSize1024(v float64) string

HumanSize1024 returns a more readable size format, such as HumanSize1024(1234567) giving "1.18M". These are 1,024 unit based: 1K = 1024, 1M = 1048576, etc.

func OrdinalSuffix

func OrdinalSuffix(number int) string

OrdinalSuffix returns "st", "nd", "rd", etc. for the number given (1st, 2nd, 3rd, etc.).

func RuneLenStripANSIEscapes

func RuneLenStripANSIEscapes(v string) int

func Sentence

func Sentence(value string) string

Sentence converts the value into a sentence, uppercasing the first character and ensuring the string ends with a period. Useful to output better looking error.Error() messages, which are all lower case with no trailing period by convention.

func StripANSIEscapes

func StripANSIEscapes(v string) string

func ThousandsSep

func ThousandsSep(v int64, sep string) string

ThousandsSep returns the number formatted using the separator at each thousands position, such as ThousandsSep(1234567, ",") giving 1,234,567.

func ThousandsSepU

func ThousandsSepU(v uint64, sep string) string

ThousandsSepU returns the number formatted using the separator at each thousands position, such as ThousandsSepU(1234567, ",") giving 1,234,567.

func TrueString

func TrueString(value string) bool

TrueString returns true if the string contains a recognized true value, such as "true", "True", "TRUE", "yes", "on", etc. Yes, there is already strconv.ParseBool, but this function is often easier to work with since it just returns true or false instead of (bool, error) like ParseBool does. If you need to differentiate between true, false, and unknown, ParseBool should be your choice. Although I suppose you could use TrueString(s), FalseString(s), and !TrueString(s) && !FalseString(s).

func Wrap

func Wrap(text string, width int, indent1 string, indent2 string) string

Wrap wraps text for more readable output.

The width can be a positive int for a specific width, 0 for the default width (attempted to get from terminal, 79 otherwise), or a negative number for a width relative to the default.

The indent1 is the prefix for the first line.

The indent2 is the prefix for any second or subsequent lines.

Types

type ANSIEscapeCodes

type ANSIEscapeCodes struct {
	Reset                                                         []byte
	Bold                                                          []byte
	BBlack, BRed, BGreen, BYellow, BBlue, BMagenta, BCyan, BWhite []byte
	FBlack, FRed, FGreen, FYellow, FBlue, FMagenta, FCyan, FWhite []byte
}

ANSIEscapeCodes is the defining structure for the more commonly used ANSIEscape global variable.

type AlignOptions

type AlignOptions struct {
	// Widths indicate the desired widths of each column. If nil or if a value
	// is 0, no rewrapping will be done.
	Widths     []int
	Alignments []Alignment
	// FirstDR etc. control what is output for situations with a prepended
	// display row, First row output with Down and Right connections, etc.
	FirstDR       string
	FirstLR       string
	FirstFirstDLR string
	FirstDLR      string
	FirstDL       string
	// RowFirstUD etc. control situations for each data row output.
	RowFirstUD  string
	RowSecondUD string
	RowUD       string
	RowLastUD   string
	// LeaveTrailingWhitespace should be set true if the last cell of data row
	// needs spaces to fill to the end (usually needed when setting RowLastUD).
	LeaveTrailingWhitespace bool
	// FirstNilFirstUDR etc. control situations when the first nil data row is
	// encountered. Can be used to separate the header from the rest of the
	// rows.
	FirstNilFirstUDR  string
	FirstNilLR        string
	FirstNilFirstUDLR string
	FirstNilUDLR      string
	FirstNilLastUDL   string
	// NilFirstUDR etc. control situations when the second and subsequent nil
	// data rows are encountered. Can be used to separate rows from each other.
	NilFirstUDR  string
	NilLR        string
	NilFirstUDLR string
	NilUDLR      string
	NilLastUDL   string
	// LastUR etc. control what is output for situations with an appended
	// display row.
	LastUR       string
	LastLR       string
	LastFirstULR string
	LastULR      string
	LastUL       string
	// NilBetweenEveryRow will add a nil data row between all rows; use to emit
	// FirstNil* and Nil* row separators.
	NilBetweenEveryRow bool
}

func NewBoxedAlignOptions

func NewBoxedAlignOptions() *AlignOptions

NewBoxedAlignOptions gives:

&AlignOptions{
    FirstDR:                 "+=",
    FirstLR:                 "=",
    FirstFirstDLR:           "=+=",
    FirstDLR:                "=+=",
    FirstDL:                 "=+",
    RowFirstUD:              "| ",
    RowSecondUD:             " | ",
    RowUD:                   " | ",
    RowLastUD:               " |",
    LeaveTrailingWhitespace: true,
    FirstNilFirstUDR:        "+=",
    FirstNilLR:              "=",
    FirstNilFirstUDLR:       "=+=",
    FirstNilUDLR:            "=+=",
    FirstNilLastUDL:         "=+",
    NilFirstUDR:             "+-",
    NilLR:                   "-",
    NilFirstUDLR:            "-+-",
    NilUDLR:                 "-+-",
    NilLastUDL:              "-+",
    LastUR:                  "+=",
    LastLR:                  "=",
    LastFirstULR:            "=+=",
    LastULR:                 "=+=",
    LastUL:                  "=+",
    NilBetweenEveryRow:      true,
}

Which will format tables like:

+==========+=============+========+==========+
|          | Bob         | Sue    | John     |
+==========+=============+========+==========+
| Hometown | San Antonio | Austin | New York |
+----------+-------------+--------+----------+
| Mother   | Bessie      | Mary   | Sarah    |
+----------+-------------+--------+----------+
| Father   | Rick        | Dan    | Mike     |
+==========+=============+========+==========+

func NewDefaultAlignOptions

func NewDefaultAlignOptions() *AlignOptions

NewDefaultAlignOptions gives:

&AlignOptions{RowSecondUD: " ", RowUD: " "}

Which will format tables like:

         Bob         Sue    John
Hometown San Antonio Austin New York
Mother   Bessie      Mary   Sarah
Father   Rick        Dan    Mike

func NewSimpleAlignOptions

func NewSimpleAlignOptions() *AlignOptions

NewSimpleAlignOptions gives:

return &AlignOptions{
    FirstDR:                 "+-",
    FirstLR:                 "-",
    FirstFirstDLR:           "-+-",
    FirstDLR:                "-+-",
    FirstDL:                 "-+",
    RowFirstUD:              "| ",
    RowSecondUD:             " | ",
    RowUD:                   " | ",
    RowLastUD:               " |",
    LeaveTrailingWhitespace: true,
    FirstNilFirstUDR:        "+-",
    FirstNilLR:              "-",
    FirstNilFirstUDLR:       "-+-",
    FirstNilUDLR:            "-+-",
    FirstNilLastUDL:         "-+",
    LastUR:                  "+-",
    LastLR:                  "-",
    LastFirstULR:            "-+-",
    LastULR:                 "-+-",
    LastUL:                  "-+",
}

Which will format tables like:

+----------+-------------+--------+----------+
|          | Bob         | Sue    | John     |
+----------+-------------+--------+----------+
| Hometown | San Antonio | Austin | New York |
| Mother   | Bessie      | Mary   | Sarah    |
| Father   | Rick        | Dan    | Mike     |
+----------+-------------+--------+----------+

func NewUnicodeBoxedAlignOptions

func NewUnicodeBoxedAlignOptions() *AlignOptions

NewUnicodeBoxedAlignOptions gives:

&AlignOptions{
    FirstDR:                 "\u2554\u2550",
    FirstLR:                 "\u2550",
    FirstFirstDLR:           "\u2550\u2566\u2550",
    FirstDLR:                "\u2550\u2564\u2550",
    FirstDL:                 "\u2550\u2557",
    RowFirstUD:              "\u2551 ",
    RowSecondUD:             " \u2551 ",
    RowUD:                   " \u2502 ",
    RowLastUD:               " \u2551",
    LeaveTrailingWhitespace: true,
    FirstNilFirstUDR:        "\u2560\u2550",
    FirstNilLR:              "\u2550",
    FirstNilFirstUDLR:       "\u2550\u256c\u2550",
    FirstNilUDLR:            "\u2550\u256a\u2550",
    FirstNilLastUDL:         "\u2550\u2563",
    NilFirstUDR:             "\u255f\u2500",
    NilLR:                   "\u2500",
    NilFirstUDLR:            "\u2500\u256b\u2500",
    NilUDLR:                 "\u2500\u253c\u2500",
    NilLastUDL:              "\u2500\u2562",
    LastUR:                  "\u255a\u2550",
    LastLR:                  "\u2550",
    LastFirstULR:            "\u2550\u2569\u2550",
    LastULR:                 "\u2550\u2567\u2550",
    LastUL:                  "\u2550\u255d",
    NilBetweenEveryRow:      true,
}

Which will format tables like:

╔══════════╦═════════════╤════════╤══════════╗
║          ║ Bob         │ Sue    │ John     ║
╠══════════╬═════════════╪════════╪══════════╣
║ Hometown ║ San Antonio │ Austin │ New York ║
╟──────────╫─────────────┼────────┼──────────╢
║ Mother   ║ Bessie      │ Mary   │ Sarah    ║
╟──────────╫─────────────┼────────┼──────────╢
║ Father   ║ Rick        │ Dan    │ Mike     ║
╚══════════╩═════════════╧════════╧══════════╝

type Alignment

type Alignment int
const (
	Left Alignment = iota
	Right
	Center
)

type StringSliceToLowerSort

type StringSliceToLowerSort []string

StringSliceToLowerSort provides a sort.Interface that will sort a []string by their strings.ToLower values. This isn't exactly a case insensitive sort due to Unicode situations, but is usually good enough.

func (StringSliceToLowerSort) Len

func (s StringSliceToLowerSort) Len() int

func (StringSliceToLowerSort) Less

func (s StringSliceToLowerSort) Less(x int, y int) bool

func (StringSliceToLowerSort) Swap

func (s StringSliceToLowerSort) Swap(x int, y int)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL