Update vendor

This commit is contained in:
Ettore Di Giacinto
2020-11-23 19:14:07 +01:00
parent 7a10ff2742
commit 5b54aeb822
147 changed files with 28614 additions and 0 deletions

21
vendor/github.com/jedib0t/go-pretty/v6/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 jedib0t
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

30
vendor/github.com/jedib0t/go-pretty/v6/list/README.md generated vendored Normal file
View File

@@ -0,0 +1,30 @@
## List
[![GoDoc](https://godoc.org/github.com/jedib0t/go-pretty/list?status.svg)](https://godoc.org/github.com/jedib0t/go-pretty/list)
Pretty-print lists with multiple levels/indents into ASCII/Unicode strings.
- Append Items one-by-one or as a group
- Indent/UnIndent as you like
- Support Items with Multiple-lines
- Mirror output to an io.Writer object (like os.StdOut)
- Completely customizable styles
- Many ready-to-use styles: [style.go](style.go)
- Render as:
- (ASCII/Unicode) List
- HTML List (with custom CSS Class)
- Markdown List
```
■ Game Of Thrones
■ Winter
■ Is
■ Coming
■ This
■ Is
■ Known
■ The Dark Tower
■ The Gunslinger
```
A demonstration of all the capabilities can be found here:
[../cmd/demo-list](../cmd/demo-list)

174
vendor/github.com/jedib0t/go-pretty/v6/list/list.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
package list
import (
"fmt"
"io"
"strings"
"unicode/utf8"
)
const (
// DefaultHTMLCSSClass stores the css-class to use when none-provided via
// SetHTMLCSSClass(cssClass string).
DefaultHTMLCSSClass = "go-pretty-table"
)
// listItem represents one line in the List
type listItem struct {
Level int
Text string
}
// List helps print a 2-dimensional array in a human readable pretty-List.
type List struct {
// approxSize stores the approximate output length/size
approxSize int
// htmlCSSClass stores the HTML CSS Class to use on the <ul> node
htmlCSSClass string
// items contains the list of items to render
items []*listItem
// level stores the current indentation level
level int
// outputMirror stores an io.Writer where the "Render" functions would write
outputMirror io.Writer
// style contains all the strings used to draw the List, and more
style *Style
}
// AppendItem appends the item to the List of items to render.
func (l *List) AppendItem(item interface{}) {
l.items = append(l.items, l.analyzeAndStringify(item))
}
// AppendItems appends the items to the List of items to render.
func (l *List) AppendItems(items []interface{}) {
for _, item := range items {
l.AppendItem(item)
}
}
// Indent indents the following items to appear right-shifted.
func (l *List) Indent() {
if len(l.items) == 0 {
// should not indent when there is no item in the current level
} else if l.level > l.items[len(l.items)-1].Level {
// already indented compared to previous item; do not indent more
} else {
l.level++
}
}
// Length returns the number of items to be rendered.
func (l *List) Length() int {
return len(l.items)
}
// Reset sets the List to its initial state.
func (l *List) Reset() {
l.approxSize = 0
l.items = make([]*listItem, 0)
l.level = 0
l.style = nil
}
// SetHTMLCSSClass sets the the HTML CSS Class to use on the <ul> node
// when rendering the List in HTML format. Recursive lists would use a numbered
// index suffix. For ex., if the cssClass is set as "foo"; the <ul> for level 0
// would have the class set as "foo"; the <ul> for level 1 would have "foo-1".
func (l *List) SetHTMLCSSClass(cssClass string) {
l.htmlCSSClass = cssClass
}
// SetOutputMirror sets an io.Writer for all the Render functions to "Write" to
// in addition to returning a string.
func (l *List) SetOutputMirror(mirror io.Writer) {
l.outputMirror = mirror
}
// SetStyle overrides the DefaultStyle with the provided one.
func (l *List) SetStyle(style Style) {
l.style = &style
}
// Style returns the current style.
func (l *List) Style() *Style {
if l.style == nil {
tempStyle := StyleDefault
l.style = &tempStyle
}
return l.style
}
func (l *List) analyzeAndStringify(item interface{}) *listItem {
itemStr := fmt.Sprint(item)
if strings.Contains(itemStr, "\t") {
itemStr = strings.Replace(itemStr, "\t", " ", -1)
}
if strings.Contains(itemStr, "\r") {
itemStr = strings.Replace(itemStr, "\r", "", -1)
}
return &listItem{
Level: l.level,
Text: itemStr,
}
}
// UnIndent un-indents the following items to appear left-shifted.
func (l *List) UnIndent() {
if l.level > 0 {
l.level--
}
}
func (l *List) initForRender() {
// pick a default style
l.Style()
// calculate the approximate size needed by looking at all entries
l.approxSize = 0
for _, item := range l.items {
// account for the following when incrementing approxSize:
// 1. prefix, 2. padding, 3. bullet, 4. text, 5. newline
l.approxSize += utf8.RuneCountInString(l.style.LinePrefix)
if item.Level > 0 {
l.approxSize += utf8.RuneCountInString(l.style.CharItemVertical) * item.Level
}
l.approxSize += utf8.RuneCountInString(l.style.CharItemVertical)
l.approxSize += utf8.RuneCountInString(item.Text)
l.approxSize += utf8.RuneCountInString(l.style.CharNewline)
}
// default to a HTML CSS Class if none-defined
if l.htmlCSSClass == "" {
l.htmlCSSClass = DefaultHTMLCSSClass
}
}
func (l *List) hasMoreItemsInLevel(levelIdx int, fromItemIdx int) bool {
for idx := fromItemIdx + 1; idx >= 0 && idx < len(l.items); idx++ {
if l.items[idx].Level < levelIdx {
return false
} else if l.items[idx].Level == levelIdx {
return true
}
}
return false
}
func (l *List) render(out *strings.Builder) string {
outStr := out.String()
if l.outputMirror != nil && len(outStr) > 0 {
l.outputMirror.Write([]byte(outStr))
l.outputMirror.Write([]byte("\n"))
}
return outStr
}
// renderHint has hints for the Render*() logic
type renderHint struct {
isTopItem bool
isFirstItem bool
isOnlyItem bool
isLastItem bool
isBottomItem bool
}

110
vendor/github.com/jedib0t/go-pretty/v6/list/render.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
package list
import (
"strings"
"unicode/utf8"
)
// Render renders the List in a human-readable "pretty" format. Example:
// * Game Of Thrones
// * Winter
// * Is
// * Coming
// * This
// * Is
// * Known
// * The Dark Tower
// * The Gunslinger
func (l *List) Render() string {
l.initForRender()
var out strings.Builder
out.Grow(l.approxSize)
for idx, item := range l.items {
hint := renderHint{
isTopItem: bool(idx == 0),
isFirstItem: bool(idx == 0 || item.Level > l.items[idx-1].Level),
isLastItem: !l.hasMoreItemsInLevel(item.Level, idx),
isBottomItem: bool(idx == len(l.items)-1),
}
if hint.isFirstItem && hint.isLastItem {
hint.isOnlyItem = true
}
l.renderItem(&out, idx, item, hint)
}
return l.render(&out)
}
func (l *List) renderItem(out *strings.Builder, idx int, item *listItem, hint renderHint) {
// when working on item number 2 or more, render a newline first
if idx > 0 {
out.WriteRune('\n')
}
// format item.Text as directed in l.style
itemStr := l.style.Format.Apply(item.Text)
// convert newlines if newlines are not "\n" in l.style
if strings.Contains(itemStr, "\n") && l.style.CharNewline != "\n" {
itemStr = strings.Replace(itemStr, "\n", l.style.CharNewline, -1)
}
// render the item.Text line by line
for lineIdx, lineStr := range strings.Split(itemStr, "\n") {
if lineIdx > 0 {
out.WriteRune('\n')
}
// render the prefix or the leading text before the actual item
l.renderItemBulletPrefix(out, idx, item.Level, lineIdx, hint)
l.renderItemBullet(out, idx, item.Level, lineIdx, hint)
// render the actual item
out.WriteString(lineStr)
}
}
func (l *List) renderItemBullet(out *strings.Builder, itemIdx int, itemLevel int, lineIdx int, hint renderHint) {
if lineIdx > 0 {
// multi-line item.Text
if hint.isLastItem {
out.WriteString(strings.Repeat(" ", utf8.RuneCountInString(l.style.CharItemVertical)))
} else {
out.WriteString(l.style.CharItemVertical)
}
} else {
// single-line item.Text (or first line of a multi-line item.Text)
if hint.isOnlyItem {
if hint.isTopItem {
out.WriteString(l.style.CharItemSingle)
} else {
out.WriteString(l.style.CharItemBottom)
}
} else if hint.isTopItem {
out.WriteString(l.style.CharItemTop)
} else if hint.isFirstItem {
out.WriteString(l.style.CharItemFirst)
} else if hint.isBottomItem || hint.isLastItem {
out.WriteString(l.style.CharItemBottom)
} else {
out.WriteString(l.style.CharItemMiddle)
}
out.WriteRune(' ')
}
}
func (l *List) renderItemBulletPrefix(out *strings.Builder, itemIdx int, itemLevel int, lineIdx int, hint renderHint) {
// write a prefix if one has been set in l.style
if l.style.LinePrefix != "" {
out.WriteString(l.style.LinePrefix)
}
// render spaces and connectors until the item's position
for levelIdx := 0; levelIdx < itemLevel; levelIdx++ {
if l.hasMoreItemsInLevel(levelIdx, itemIdx) {
out.WriteString(l.style.CharItemVertical)
} else {
out.WriteString(strings.Repeat(" ", utf8.RuneCountInString(l.style.CharItemVertical)))
}
}
}

View File

@@ -0,0 +1,70 @@
package list
import (
"html"
"strconv"
"strings"
)
// RenderHTML renders the List in the HTML format. Example:
// <ul class="go-pretty-table">
// <li>Game Of Thrones</li>
// <ul class="go-pretty-table-1">
// <li>Winter</li>
// <li>Is</li>
// <li>Coming</li>
// <ul class="go-pretty-table-2">
// <li>This</li>
// <li>Is</li>
// <li>Known</li>
// </ul>
// </ul>
// <li>The Dark Tower</li>
// <ul class="go-pretty-table-1">
// <li>The Gunslinger</li>
// </ul>
// </ul>
func (l *List) RenderHTML() string {
l.initForRender()
var out strings.Builder
if len(l.items) > 0 {
l.htmlRenderRecursively(&out, 0, l.items[0])
}
return l.render(&out)
}
func (l *List) htmlRenderRecursively(out *strings.Builder, idx int, item *listItem) int {
linePrefix := strings.Repeat(" ", item.Level)
out.WriteString(linePrefix)
out.WriteString("<ul class=\"")
out.WriteString(l.htmlCSSClass)
if item.Level > 0 {
out.WriteRune('-')
out.WriteString(strconv.Itoa(item.Level))
}
out.WriteString("\">\n")
var numItemsRendered int
for itemIdx := idx; itemIdx < len(l.items); itemIdx++ {
if l.items[itemIdx].Level == item.Level {
out.WriteString(linePrefix)
out.WriteString(" <li>")
out.WriteString(strings.Replace(html.EscapeString(l.items[itemIdx].Text), "\n", "<br/>", -1))
out.WriteString("</li>\n")
numItemsRendered++
} else if l.items[itemIdx].Level > item.Level { // indent
numItemsRenderedRecursively := l.htmlRenderRecursively(out, itemIdx, l.items[itemIdx])
numItemsRendered += numItemsRenderedRecursively
itemIdx += numItemsRenderedRecursively - 1
if numItemsRendered > 0 {
out.WriteRune('\n')
}
} else { // un-indent
break
}
}
out.WriteString(linePrefix)
out.WriteString("</ul>")
return numItemsRendered
}

View File

@@ -0,0 +1,29 @@
package list
// RenderMarkdown renders the List in the Markdown format. Example:
// * Game Of Thrones
// * Winter
// * Is
// * Coming
// * This
// * Is
// * Known
// * The Dark Tower
// * The Gunslinger
func (l *List) RenderMarkdown() string {
// make a copy of the original style and ensure it is restored on exit
originalStyle := l.style
defer func() {
if originalStyle == nil {
l.style = nil
} else {
l.SetStyle(*originalStyle)
}
}()
// override whatever style was set with StyleMarkdown
l.SetStyle(StyleMarkdown)
// render like a regular list
return l.Render()
}

295
vendor/github.com/jedib0t/go-pretty/v6/list/style.go generated vendored Normal file
View File

@@ -0,0 +1,295 @@
package list
import "github.com/jedib0t/go-pretty/v6/text"
// Style declares how to render the List (items).
type Style struct {
Format text.Format // formatting for the Text
CharItemSingle string // the bullet for a single-item list
CharItemTop string // the bullet for the top-most item
CharItemFirst string // the bullet for the first item
CharItemMiddle string // the bullet for non-first/non-last item
CharItemVertical string // the vertical connector from one bullet to the next
CharItemBottom string // the bullet for the bottom-most item
CharNewline string // new-line character to use
LinePrefix string // prefix for every single line
Name string // name of the Style
}
var (
// StyleDefault renders a List like below:
// * Game Of Thrones
// * Winter
// * Is
// * Coming
// * This
// * Is
// * Known
// * The Dark Tower
// * The Gunslinger
StyleDefault = Style{
Format: text.FormatDefault,
CharItemSingle: "*",
CharItemTop: "*",
CharItemFirst: "*",
CharItemMiddle: "*",
CharItemVertical: " ",
CharItemBottom: "*",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleDefault",
}
// StyleBulletCircle renders a List like below:
// ● Game Of Thrones
// ● Winter
// ● Is
// ● Coming
// ● This
// ● Is
// ● Known
// ● The Dark Tower
// ● The Gunslinger
StyleBulletCircle = Style{
Format: text.FormatDefault,
CharItemSingle: "●",
CharItemTop: "●",
CharItemFirst: "●",
CharItemMiddle: "●",
CharItemVertical: " ",
CharItemBottom: "●",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleBulletCircle",
}
// StyleBulletFlower renders a List like below:
// ✽ Game Of Thrones
// ✽ Winter
// ✽ Is
// ✽ Coming
// ✽ This
// ✽ Is
// ✽ Known
// ✽ The Dark Tower
// ✽ The Gunslinger
StyleBulletFlower = Style{
Format: text.FormatDefault,
CharItemSingle: "✽",
CharItemTop: "✽",
CharItemFirst: "✽",
CharItemMiddle: "✽",
CharItemVertical: " ",
CharItemBottom: "✽",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleBulletFlower",
}
// StyleBulletSquare renders a List like below:
// ■ Game Of Thrones
// ■ Winter
// ■ Is
// ■ Coming
// ■ This
// ■ Is
// ■ Known
// ■ The Dark Tower
// ■ The Gunslinger
StyleBulletSquare = Style{
Format: text.FormatDefault,
CharItemSingle: "■",
CharItemTop: "■",
CharItemFirst: "■",
CharItemMiddle: "■",
CharItemVertical: " ",
CharItemBottom: "■",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleBulletSquare",
}
// StyleBulletStar renders a List like below:
// ★ Game Of Thrones
// ★ Winter
// ★ Is
// ★ Coming
// ★ This
// ★ Is
// ★ Known
// ★ The Dark Tower
// ★ The Gunslinger
StyleBulletStar = Style{
Format: text.FormatDefault,
CharItemSingle: "★",
CharItemTop: "★",
CharItemFirst: "★",
CharItemMiddle: "★",
CharItemVertical: " ",
CharItemBottom: "★",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleBulletStar",
}
// StyleBulletTriangle renders a List like below:
// ▶ Game Of Thrones
// ▶ Winter
// ▶ Is
// ▶ Coming
// ▶ This
// ▶ Is
// ▶ Known
// ▶ The Dark Tower
// ▶ The Gunslinger
StyleBulletTriangle = Style{
Format: text.FormatDefault,
CharItemSingle: "▶",
CharItemTop: "▶",
CharItemFirst: "▶",
CharItemMiddle: "▶",
CharItemVertical: " ",
CharItemBottom: "▶",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleBulletTriangle",
}
// StyleConnectedBold renders a List like below:
// ┏━ Game Of Thrones
// ┃ ┣━ Winter
// ┃ ┣━ Is
// ┃ ┗━ Coming
// ┃ ┣━ This
// ┃ ┣━ Is
// ┃ ┗━ Known
// ┗━ The Dark Tower
// ┗━ The Gunslinger
StyleConnectedBold = Style{
Format: text.FormatDefault,
CharItemSingle: "━━",
CharItemTop: "┏━",
CharItemFirst: "┣━",
CharItemMiddle: "┣━",
CharItemVertical: "┃ ",
CharItemBottom: "┗━",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleConnectedBold",
}
// StyleConnectedDouble renders a List like below:
// ╔═ Game Of Thrones
// ║ ╠═ Winter
// ║ ╠═ Is
// ║ ╚═ Coming
// ║ ╠═ This
// ║ ╠═ Is
// ║ ╚═ Known
// ╚═ The Dark Tower
// ╚═ The Gunslinger
StyleConnectedDouble = Style{
Format: text.FormatDefault,
CharItemSingle: "══",
CharItemTop: "╔═",
CharItemFirst: "╠═",
CharItemMiddle: "╠═",
CharItemVertical: "║ ",
CharItemBottom: "╚═",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleConnectedDouble",
}
// StyleConnectedLight renders a List like below:
// ┌─ Game Of Thrones
// │ ├─ Winter
// │ ├─ Is
// │ └─ Coming
// │ ├─ This
// │ ├─ Is
// │ └─ Known
// └─ The Dark Tower
// └─ The Gunslinger
StyleConnectedLight = Style{
Format: text.FormatDefault,
CharItemSingle: "──",
CharItemTop: "┌─",
CharItemFirst: "├─",
CharItemMiddle: "├─",
CharItemVertical: "│ ",
CharItemBottom: "└─",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleConnectedLight",
}
// StyleConnectedRounded renders a List like below:
// ╭─ Game Of Thrones
// │ ├─ Winter
// │ ├─ Is
// │ ╰─ Coming
// │ ├─ This
// │ ├─ Is
// │ ╰─ Known
// ╰─ The Dark Tower
// ╰─ The Gunslinger
StyleConnectedRounded = Style{
Format: text.FormatDefault,
CharItemSingle: "──",
CharItemTop: "╭─",
CharItemFirst: "├─",
CharItemMiddle: "├─",
CharItemVertical: "│ ",
CharItemBottom: "╰─",
CharNewline: "\n",
LinePrefix: "",
Name: "StyleConnectedRounded",
}
// StyleMarkdown renders a List like below:
// * Game Of Thrones
// * Winter
// * Is
// * Coming
// * This
// * Is
// * Known
// * The Dark Tower
// * The Gunslinger
StyleMarkdown = Style{
Format: text.FormatDefault,
CharItemSingle: "*",
CharItemTop: "*",
CharItemFirst: "*",
CharItemMiddle: "*",
CharItemVertical: " ",
CharItemBottom: "*",
CharNewline: "<br/>",
LinePrefix: " ",
Name: "StyleMarkdown",
}
// styleTest renders a List like below:
// t Game Of Thrones
// |f Winter
// |m Is
// |b Coming
// | f This
// | m Is
// | b Known
// b The Dark Tower
// b The Gunslinger
styleTest = Style{
Format: text.FormatDefault,
CharItemSingle: "s",
CharItemTop: "t",
CharItemFirst: "f",
CharItemMiddle: "m",
CharItemVertical: "|",
CharItemBottom: "b",
CharNewline: "\n",
LinePrefix: "",
Name: "styleTest",
}
)

25
vendor/github.com/jedib0t/go-pretty/v6/list/writer.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
package list
import "io"
// Writer declares the interfaces that can be used to setup and render a list.
type Writer interface {
AppendItem(item interface{})
AppendItems(items []interface{})
Indent()
Length() int
Render() string
RenderHTML() string
RenderMarkdown() string
Reset()
SetHTMLCSSClass(cssClass string)
SetOutputMirror(mirror io.Writer)
SetStyle(style Style)
Style() *Style
UnIndent()
}
// NewWriter initializes and returns a Writer.
func NewWriter() Writer {
return &List{}
}

137
vendor/github.com/jedib0t/go-pretty/v6/text/align.go generated vendored Normal file
View File

@@ -0,0 +1,137 @@
package text
import (
"fmt"
"strconv"
"strings"
"unicode/utf8"
)
// Align denotes how text is to be aligned horizontally.
type Align int
// Align enumerations
const (
AlignDefault Align = iota // same as AlignLeft
AlignLeft // "left "
AlignCenter // " center "
AlignJustify // "justify it"
AlignRight // " right"
)
// Apply aligns the text as directed. For ex.:
// * AlignDefault.Apply("Jon Snow", 12) returns "Jon Snow "
// * AlignLeft.Apply("Jon Snow", 12) returns "Jon Snow "
// * AlignCenter.Apply("Jon Snow", 12) returns " Jon Snow "
// * AlignJustify.Apply("Jon Snow", 12) returns "Jon Snow"
// * AlignRight.Apply("Jon Snow", 12) returns " Jon Snow"
func (a Align) Apply(text string, maxLength int) string {
text = a.trimString(text)
sLen := utf8.RuneCountInString(text)
sLenWoE := RuneCount(text)
numEscChars := sLen - sLenWoE
// now, align the text
switch a {
case AlignDefault, AlignLeft:
return fmt.Sprintf("%-"+strconv.Itoa(maxLength+numEscChars)+"s", text)
case AlignCenter:
if sLenWoE < maxLength {
// left pad with half the number of spaces needed before using %text
return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s",
text+strings.Repeat(" ", int((maxLength-sLenWoE)/2)))
}
case AlignJustify:
return a.justifyText(text, sLenWoE, maxLength)
}
return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s", text)
}
// HTMLProperty returns the equivalent HTML horizontal-align tag property.
func (a Align) HTMLProperty() string {
switch a {
case AlignLeft:
return "align=\"left\""
case AlignCenter:
return "align=\"center\""
case AlignJustify:
return "align=\"justify\""
case AlignRight:
return "align=\"right\""
default:
return ""
}
}
// MarkdownProperty returns the equivalent Markdown horizontal-align separator.
func (a Align) MarkdownProperty() string {
switch a {
case AlignLeft:
return ":--- "
case AlignCenter:
return ":---:"
case AlignRight:
return " ---:"
default:
return " --- "
}
}
func (a Align) justifyText(text string, textLength int, maxLength int) string {
// split the text into individual words
wordsUnfiltered := strings.Split(text, " ")
words := Filter(wordsUnfiltered, func(item string) bool {
return item != ""
})
// empty string implies spaces for maxLength
if len(words) == 0 {
return strings.Repeat(" ", maxLength)
}
// get the number of spaces to insert into the text
numSpacesNeeded := maxLength - textLength + strings.Count(text, " ")
numSpacesNeededBetweenWords := 0
if len(words) > 1 {
numSpacesNeededBetweenWords = numSpacesNeeded / (len(words) - 1)
}
// create the output string word by word with spaces in between
var outText strings.Builder
outText.Grow(maxLength)
for idx, word := range words {
if idx > 0 {
// insert spaces only after the first word
if idx == len(words)-1 {
// insert all the remaining space before the last word
outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
numSpacesNeeded = 0
} else {
// insert the determined number of spaces between each word
outText.WriteString(strings.Repeat(" ", numSpacesNeededBetweenWords))
// and reduce the number of spaces needed after this
numSpacesNeeded -= numSpacesNeededBetweenWords
}
}
outText.WriteString(word)
if idx == len(words)-1 && numSpacesNeeded > 0 {
outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
}
}
return outText.String()
}
func (a Align) trimString(text string) string {
switch a {
case AlignDefault, AlignLeft:
if strings.HasSuffix(text, " ") {
return strings.TrimRight(text, " ")
}
case AlignRight:
if strings.HasPrefix(text, " ") {
return strings.TrimLeft(text, " ")
}
default:
if strings.HasPrefix(text, " ") || strings.HasSuffix(text, " ") {
return strings.Trim(text, " ")
}
}
return text
}

55
vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
package text
import "strings"
// ANSICodesSupported will be true on consoles where ANSI Escape Codes/Sequences
// are supported.
var ANSICodesSupported = areANSICodesSupported()
// Escape encodes the string with the ANSI Escape Sequence.
// For ex.:
// Escape("Ghost", "") == "Ghost"
// Escape("Ghost", "\x1b[91m") == "\x1b[91mGhost\x1b[0m"
// Escape("\x1b[94mGhost\x1b[0mLady", "\x1b[91m") == "\x1b[94mGhost\x1b[0m\x1b[91mLady\x1b[0m"
// Escape("Nymeria\x1b[94mGhost\x1b[0mLady", "\x1b[91m") == "\x1b[91mNymeria\x1b[94mGhost\x1b[0m\x1b[91mLady\x1b[0m"
// Escape("Nymeria \x1b[94mGhost\x1b[0m Lady", "\x1b[91m") == "\x1b[91mNymeria \x1b[94mGhost\x1b[0m\x1b[91m Lady\x1b[0m"
func Escape(str string, escapeSeq string) string {
out := ""
if !strings.HasPrefix(str, EscapeStart) {
out += escapeSeq
}
out += strings.Replace(str, EscapeReset, EscapeReset+escapeSeq, -1)
if !strings.HasSuffix(out, EscapeReset) {
out += EscapeReset
}
if strings.Contains(out, escapeSeq+EscapeReset) {
out = strings.Replace(out, escapeSeq+EscapeReset, "", -1)
}
return out
}
// StripEscape strips all ANSI Escape Sequence from the string.
// For ex.:
// StripEscape("Ghost") == "Ghost"
// StripEscape("\x1b[91mGhost\x1b[0m") == "Ghost"
// StripEscape("\x1b[94mGhost\x1b[0m\x1b[91mLady\x1b[0m") == "GhostLady"
// StripEscape("\x1b[91mNymeria\x1b[94mGhost\x1b[0m\x1b[91mLady\x1b[0m") == "NymeriaGhostLady"
// StripEscape("\x1b[91mNymeria \x1b[94mGhost\x1b[0m\x1b[91m Lady\x1b[0m") == "Nymeria Ghost Lady"
func StripEscape(str string) string {
var out strings.Builder
out.Grow(RuneCount(str))
isEscSeq := false
for _, sChr := range str {
if sChr == EscapeStartRune {
isEscSeq = true
}
if !isEscSeq {
out.WriteRune(sChr)
}
if isEscSeq && sChr == EscapeStopRune {
isEscSeq = false
}
}
return out.String()
}

View File

@@ -0,0 +1,7 @@
// +build !windows
package text
func areANSICodesSupported() bool {
return true
}

View File

@@ -0,0 +1,31 @@
// +build windows
package text
import (
"os"
"sync"
"golang.org/x/sys/windows"
)
var (
enableVTPMutex = sync.Mutex{}
)
func areANSICodesSupported() bool {
enableVTPMutex.Lock()
defer enableVTPMutex.Unlock()
outHandle := windows.Handle(os.Stdout.Fd())
var outMode uint32
if err := windows.GetConsoleMode(outHandle, &outMode); err == nil {
if outMode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
return true
}
if err := windows.SetConsoleMode(outHandle, outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
return true
}
}
return false
}

183
vendor/github.com/jedib0t/go-pretty/v6/text/color.go generated vendored Normal file
View File

@@ -0,0 +1,183 @@
package text
import (
"fmt"
"sort"
"strconv"
"strings"
"sync"
)
var (
colorsEnabled = areANSICodesSupported()
)
// DisableColors (forcefully) disables color coding globally.
func DisableColors() {
colorsEnabled = false
}
// EnableColors (forcefully) enables color coding globally.
func EnableColors() {
colorsEnabled = true
}
// The logic here is inspired from github.com/fatih/color; the following is
// the the bare minimum logic required to print Colored to the console.
// The differences:
// * This one caches the escape sequences for cases with multiple colors
// * This one handles cases where the incoming already has colors in the
// form of escape sequences; in which case, text that does not have any
// escape sequences are colored/escaped
// Color represents a single color to render with.
type Color int
// Base colors -- attributes in reality
const (
Reset Color = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)
// Foreground colors
const (
FgBlack Color = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)
// Foreground Hi-Intensity colors
const (
FgHiBlack Color = iota + 90
FgHiRed
FgHiGreen
FgHiYellow
FgHiBlue
FgHiMagenta
FgHiCyan
FgHiWhite
)
// Background colors
const (
BgBlack Color = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)
// Background Hi-Intensity colors
const (
BgHiBlack Color = iota + 100
BgHiRed
BgHiGreen
BgHiYellow
BgHiBlue
BgHiMagenta
BgHiCyan
BgHiWhite
)
// EscapeSeq returns the ANSI escape sequence for the color.
func (c Color) EscapeSeq() string {
return EscapeStart + strconv.Itoa(int(c)) + EscapeStop
}
// HTMLProperty returns the "class" attribute for the color.
func (c Color) HTMLProperty() string {
out := ""
if class, ok := colorCSSClassMap[c]; ok {
out = fmt.Sprintf("class=\"%s\"", class)
}
return out
}
// Sprint colorizes and prints the given string(s).
func (c Color) Sprint(a ...interface{}) string {
return colorize(fmt.Sprint(a...), c.EscapeSeq())
}
// Sprintf formats and colorizes and prints the given string(s).
func (c Color) Sprintf(format string, a ...interface{}) string {
return colorize(fmt.Sprintf(format, a...), c.EscapeSeq())
}
// Colors represents an array of Color objects to render with.
// Example: Colors{FgCyan, BgBlack}
type Colors []Color
var (
// colorsSeqMap caches the escape sequence for a set of colors
colorsSeqMap = sync.Map{}
)
// EscapeSeq returns the ANSI escape sequence for the colors set.
func (c Colors) EscapeSeq() string {
if len(c) == 0 {
return ""
}
colorsKey := fmt.Sprintf("%#v", c)
escapeSeq, ok := colorsSeqMap.Load(colorsKey)
if !ok || escapeSeq == "" {
colorNums := make([]string, len(c))
for idx, color := range c {
colorNums[idx] = strconv.Itoa(int(color))
}
escapeSeq = EscapeStart + strings.Join(colorNums, ";") + EscapeStop
colorsSeqMap.Store(colorsKey, escapeSeq)
}
return escapeSeq.(string)
}
// HTMLProperty returns the "class" attribute for the colors.
func (c Colors) HTMLProperty() string {
if len(c) == 0 {
return ""
}
var classes []string
for _, color := range c {
if class, ok := colorCSSClassMap[color]; ok {
classes = append(classes, class)
}
}
if len(classes) > 1 {
sort.Strings(classes)
}
return fmt.Sprintf("class=\"%s\"", strings.Join(classes, " "))
}
// Sprint colorizes and prints the given string(s).
func (c Colors) Sprint(a ...interface{}) string {
return colorize(fmt.Sprint(a...), c.EscapeSeq())
}
// Sprintf formats and colorizes and prints the given string(s).
func (c Colors) Sprintf(format string, a ...interface{}) string {
return colorize(fmt.Sprintf(format, a...), c.EscapeSeq())
}
func colorize(s string, escapeSeq string) string {
if !colorsEnabled || escapeSeq == "" {
return s
}
return Escape(s, escapeSeq)
}

View File

@@ -0,0 +1,48 @@
package text
var (
// colorCSSClassMap contains the equivalent CSS-class for all colors
colorCSSClassMap = map[Color]string{
Bold: "bold",
Faint: "faint",
Italic: "italic",
Underline: "underline",
BlinkSlow: "blink-slow",
BlinkRapid: "blink-rapid",
ReverseVideo: "reverse-video",
Concealed: "concealed",
CrossedOut: "crossed-out",
FgBlack: "fg-black",
FgRed: "fg-red",
FgGreen: "fg-green",
FgYellow: "fg-yellow",
FgBlue: "fg-blue",
FgMagenta: "fg-magenta",
FgCyan: "fg-cyan",
FgWhite: "fg-white",
FgHiBlack: "fg-hi-black",
FgHiRed: "fg-hi-red",
FgHiGreen: "fg-hi-green",
FgHiYellow: "fg-hi-yellow",
FgHiBlue: "fg-hi-blue",
FgHiMagenta: "fg-hi-magenta",
FgHiCyan: "fg-hi-cyan",
FgHiWhite: "fg-hi-white",
BgBlack: "bg-black",
BgRed: "bg-red",
BgGreen: "bg-green",
BgYellow: "bg-yellow",
BgBlue: "bg-blue",
BgMagenta: "bg-magenta",
BgCyan: "bg-cyan",
BgWhite: "bg-white",
BgHiBlack: "bg-hi-black",
BgHiRed: "bg-hi-red",
BgHiGreen: "bg-hi-green",
BgHiYellow: "bg-hi-yellow",
BgHiBlue: "bg-hi-blue",
BgHiMagenta: "bg-hi-magenta",
BgHiCyan: "bg-hi-cyan",
BgHiWhite: "bg-hi-white",
}
)

39
vendor/github.com/jedib0t/go-pretty/v6/text/cursor.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package text
import (
"fmt"
)
// Cursor helps move the cursor on the console in multiple directions.
type Cursor rune
const (
// CursorDown helps move the Cursor Down X lines
CursorDown Cursor = 'B'
// CursorLeft helps move the Cursor Left X characters
CursorLeft Cursor = 'D'
// CursorRight helps move the Cursor Right X characters
CursorRight Cursor = 'C'
// CursorUp helps move the Cursor Up X lines
CursorUp Cursor = 'A'
// EraseLine helps erase all characters to the Right of the Cursor in the
// current line
EraseLine Cursor = 'K'
)
// Sprint prints the Escape Sequence to move the Cursor once.
func (c Cursor) Sprint() string {
return fmt.Sprintf("%s%c", EscapeStart, c)
}
// Sprintn prints the Escape Sequence to move the Cursor "n" times.
func (c Cursor) Sprintn(n int) string {
if c == EraseLine {
return c.Sprint()
}
return fmt.Sprintf("%s%d%c", EscapeStart, n, c)
}

12
vendor/github.com/jedib0t/go-pretty/v6/text/filter.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
package text
// Filter filters the slice 's' to items which return truth when passed to 'f'.
func Filter(s []string, f func(string) bool) []string {
var out []string
for _, item := range s {
if f(item) {
out = append(out, item)
}
}
return out
}

100
vendor/github.com/jedib0t/go-pretty/v6/text/format.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package text
import (
"strings"
"unicode"
)
// Format lets you transform the text in supported methods while keeping escape
// sequences in the string intact and untouched.
type Format int
// Format enumerations
const (
FormatDefault Format = iota // default_Case
FormatLower // lower
FormatTitle // Title
FormatUpper // UPPER
)
// Apply converts the text as directed.
func (tc Format) Apply(text string) string {
switch tc {
case FormatLower:
return strings.ToLower(text)
case FormatTitle:
return toTitle(text)
case FormatUpper:
return toUpper(text)
default:
return text
}
}
func toTitle(text string) string {
prev, inEscSeq := ' ', false
return strings.Map(
func(r rune) rune {
if r == EscapeStartRune {
inEscSeq = true
}
if !inEscSeq {
if isSeparator(prev) {
prev = r
r = unicode.ToUpper(r)
} else {
prev = r
}
}
if inEscSeq && r == EscapeStopRune {
inEscSeq = false
}
return r
},
text,
)
}
func toUpper(text string) string {
inEscSeq := false
return strings.Map(
func(r rune) rune {
if r == EscapeStartRune {
inEscSeq = true
}
if !inEscSeq {
r = unicode.ToUpper(r)
}
if inEscSeq && r == EscapeStopRune {
inEscSeq = false
}
return r
},
text,
)
}
// isSeparator returns true if the given rune is a separator. This function is
// lifted straight out of the standard library @ strings/strings.go.
func isSeparator(r rune) bool {
// ASCII alphanumerics and underscore are not separators
if r <= 0x7F {
switch {
case '0' <= r && r <= '9':
return false
case 'a' <= r && r <= 'z':
return false
case 'A' <= r && r <= 'Z':
return false
case r == '_':
return false
}
return true
}
// Letters and digits are not separators
if unicode.IsLetter(r) || unicode.IsDigit(r) {
return false
}
// Otherwise, all we can do for now is treat spaces as separators.
return unicode.IsSpace(r)
}

203
vendor/github.com/jedib0t/go-pretty/v6/text/string.go generated vendored Normal file
View File

@@ -0,0 +1,203 @@
package text
import (
"strings"
"unicode/utf8"
"github.com/mattn/go-runewidth"
)
// Constants
const (
EscapeReset = EscapeStart + "0" + EscapeStop
EscapeStart = "\x1b["
EscapeStartRune = rune(27) // \x1b
EscapeStop = "m"
EscapeStopRune = 'm'
)
// InsertEveryN inserts the rune every N characters in the string. For ex.:
// InsertEveryN("Ghost", '-', 1) == "G-h-o-s-t"
// InsertEveryN("Ghost", '-', 2) == "Gh-os-t"
// InsertEveryN("Ghost", '-', 3) == "Gho-st"
// InsertEveryN("Ghost", '-', 4) == "Ghos-t"
// InsertEveryN("Ghost", '-', 5) == "Ghost"
func InsertEveryN(str string, runeToInsert rune, n int) string {
if n <= 0 {
return str
}
sLen := RuneCount(str)
var out strings.Builder
out.Grow(sLen + (sLen / n))
outLen, isEscSeq := 0, false
for idx, c := range str {
if c == EscapeStartRune {
isEscSeq = true
}
if !isEscSeq && outLen > 0 && (outLen%n) == 0 && idx != sLen {
out.WriteRune(runeToInsert)
}
out.WriteRune(c)
if !isEscSeq {
outLen += RuneWidth(c)
}
if isEscSeq && c == EscapeStopRune {
isEscSeq = false
}
}
return out.String()
}
// LongestLineLen returns the length of the longest "line" within the
// argument string. For ex.:
// LongestLineLen("Ghost!\nCome back here!\nRight now!") == 15
func LongestLineLen(str string) int {
maxLength, currLength, isEscSeq := 0, 0, false
for _, c := range str {
if c == EscapeStartRune {
isEscSeq = true
} else if isEscSeq && c == EscapeStopRune {
isEscSeq = false
continue
}
if c == '\n' {
if currLength > maxLength {
maxLength = currLength
}
currLength = 0
} else if !isEscSeq {
currLength += RuneWidth(c)
}
}
if currLength > maxLength {
maxLength = currLength
}
return maxLength
}
// Pad pads the given string with as many characters as needed to make it as
// long as specified (maxLen). This function does not count escape sequences
// while calculating length of the string. Ex.:
// Pad("Ghost", 0, ' ') == "Ghost"
// Pad("Ghost", 3, ' ') == "Ghost"
// Pad("Ghost", 5, ' ') == "Ghost"
// Pad("Ghost", 7, ' ') == "Ghost "
// Pad("Ghost", 10, '.') == "Ghost....."
func Pad(str string, maxLen int, paddingChar rune) string {
strLen := RuneCount(str)
if strLen < maxLen {
str += strings.Repeat(string(paddingChar), maxLen-strLen)
}
return str
}
// RepeatAndTrim repeats the given string until it is as long as maxRunes.
// For ex.:
// RepeatAndTrim("Ghost", 0) == ""
// RepeatAndTrim("Ghost", 5) == "Ghost"
// RepeatAndTrim("Ghost", 7) == "GhostGh"
// RepeatAndTrim("Ghost", 10) == "GhostGhost"
func RepeatAndTrim(str string, maxRunes int) string {
if maxRunes == 0 {
return ""
} else if maxRunes == utf8.RuneCountInString(str) {
return str
}
repeatedS := strings.Repeat(str, int(maxRunes/utf8.RuneCountInString(str))+1)
return Trim(repeatedS, maxRunes)
}
// RuneCount is similar to utf8.RuneCountInString, except for the fact that it
// ignores escape sequences while counting. For ex.:
// RuneCount("") == 0
// RuneCount("Ghost") == 5
// RuneCount("\x1b[33mGhost\x1b[0m") == 5
// RuneCount("\x1b[33mGhost\x1b[0") == 5
func RuneCount(str string) int {
count, isEscSeq := 0, false
for _, c := range str {
if c == EscapeStartRune {
isEscSeq = true
} else if isEscSeq {
if c == EscapeStopRune {
isEscSeq = false
}
} else {
count += RuneWidth(c)
}
}
return count
}
// RuneWidth returns the mostly accurate character-width of the rune. This is
// not 100% accurate as the character width is usually dependant on the
// typeface (font) used in the console/terminal. For ex.:
// RuneWidth('A') == 1
// RuneWidth('ツ') == 2
// RuneWidth('⊙') == 1
// RuneWidth('︿') == 2
// RuneWidth(0x27) == 0
func RuneWidth(r rune) int {
return runewidth.RuneWidth(r)
}
// Snip returns the given string with a fixed length. For ex.:
// Snip("Ghost", 0, "~") == "Ghost"
// Snip("Ghost", 1, "~") == "~"
// Snip("Ghost", 3, "~") == "Gh~"
// Snip("Ghost", 5, "~") == "Ghost"
// Snip("Ghost", 7, "~") == "Ghost "
// Snip("\x1b[33mGhost\x1b[0m", 7, "~") == "\x1b[33mGhost\x1b[0m "
func Snip(str string, length int, snipIndicator string) string {
if length > 0 {
lenStr := RuneCount(str)
if lenStr > length {
lenStrFinal := length - RuneCount(snipIndicator)
return Trim(str, lenStrFinal) + snipIndicator
}
}
return str
}
// Trim trims a string to the given length while ignoring escape sequences. For
// ex.:
// Trim("Ghost", 3) == "Gho"
// Trim("Ghost", 6) == "Ghost"
// Trim("\x1b[33mGhost\x1b[0m", 3) == "\x1b[33mGho\x1b[0m"
// Trim("\x1b[33mGhost\x1b[0m", 6) == "\x1b[33mGhost\x1b[0m"
func Trim(str string, maxLen int) string {
if maxLen <= 0 {
return ""
}
var out strings.Builder
out.Grow(maxLen)
outLen, isEscSeq, lastEscSeq := 0, false, strings.Builder{}
for _, sChr := range str {
out.WriteRune(sChr)
if sChr == EscapeStartRune {
isEscSeq = true
lastEscSeq.Reset()
lastEscSeq.WriteRune(sChr)
} else if isEscSeq {
lastEscSeq.WriteRune(sChr)
if sChr == EscapeStopRune {
isEscSeq = false
}
} else {
outLen++
if outLen == maxLen {
break
}
}
}
if lastEscSeq.Len() > 0 && lastEscSeq.String() != EscapeReset {
out.WriteString(EscapeReset)
}
return out.String()
}

View File

@@ -0,0 +1,201 @@
package text
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
)
// Transformer related constants
const (
unixTimeMinMilliseconds = int64(10000000000)
unixTimeMinMicroseconds = unixTimeMinMilliseconds * 1000
unixTimeMinNanoSeconds = unixTimeMinMicroseconds * 1000
)
// Transformer related variables
var (
colorsNumberPositive = Colors{FgHiGreen}
colorsNumberNegative = Colors{FgHiRed}
colorsNumberZero = Colors{}
colorsURL = Colors{Underline, FgBlue}
rfc3339Milli = "2006-01-02T15:04:05.000Z07:00"
rfc3339Micro = "2006-01-02T15:04:05.000000Z07:00"
possibleTimeLayouts = []string{
time.RFC3339,
rfc3339Milli, // strfmt.DateTime.String()'s default layout
rfc3339Micro,
time.RFC3339Nano,
}
)
// Transformer helps format the contents of an object to the user's liking.
type Transformer func(val interface{}) string
// NewNumberTransformer returns a number Transformer that:
// * transforms the number as directed by 'format' (ex.: %.2f)
// * colors negative values Red
// * colors positive values Green
func NewNumberTransformer(format string) Transformer {
return func(val interface{}) string {
if number, ok := val.(int); ok {
return transformInt(format, int64(number))
}
if number, ok := val.(int8); ok {
return transformInt(format, int64(number))
}
if number, ok := val.(int16); ok {
return transformInt(format, int64(number))
}
if number, ok := val.(int32); ok {
return transformInt(format, int64(number))
}
if number, ok := val.(int64); ok {
return transformInt(format, int64(number))
}
if number, ok := val.(uint); ok {
return transformUint(format, uint64(number))
}
if number, ok := val.(uint8); ok {
return transformUint(format, uint64(number))
}
if number, ok := val.(uint16); ok {
return transformUint(format, uint64(number))
}
if number, ok := val.(uint32); ok {
return transformUint(format, uint64(number))
}
if number, ok := val.(uint64); ok {
return transformUint(format, uint64(number))
}
if number, ok := val.(float32); ok {
return transformFloat(format, float64(number))
}
if number, ok := val.(float64); ok {
return transformFloat(format, float64(number))
}
return fmt.Sprint(val)
}
}
func transformInt(format string, val int64) string {
if val < 0 {
return colorsNumberNegative.Sprintf("-"+format, -val)
}
if val > 0 {
return colorsNumberPositive.Sprintf(format, val)
}
return colorsNumberZero.Sprintf(format, val)
}
func transformUint(format string, val uint64) string {
if val > 0 {
return colorsNumberPositive.Sprintf(format, val)
}
return colorsNumberZero.Sprintf(format, val)
}
func transformFloat(format string, val float64) string {
if val < 0 {
return colorsNumberNegative.Sprintf("-"+format, -val)
}
if val > 0 {
return colorsNumberPositive.Sprintf(format, val)
}
return colorsNumberZero.Sprintf(format, val)
}
// NewJSONTransformer returns a Transformer that can format a JSON string or an
// object into pretty-indented JSON-strings.
func NewJSONTransformer(prefix string, indent string) Transformer {
return func(val interface{}) string {
if valStr, ok := val.(string); ok {
var b bytes.Buffer
if err := json.Indent(&b, []byte(strings.TrimSpace(valStr)), prefix, indent); err == nil {
return string(b.Bytes())
}
} else if b, err := json.MarshalIndent(val, prefix, indent); err == nil {
return string(b)
}
return fmt.Sprintf("%#v", val)
}
}
// NewTimeTransformer returns a Transformer that can format a timestamp (a
// time.Time) into a well-defined time format defined using the provided layout
// (ex.: time.RFC3339).
//
// If a non-nil location value is provided, the time will be localized to that
// location (use time.Local to get localized timestamps).
func NewTimeTransformer(layout string, location *time.Location) Transformer {
return func(val interface{}) string {
formatTime := func(t time.Time) string {
rsp := ""
if t.Unix() > 0 {
if location != nil {
t = t.In(location)
}
rsp = t.Format(layout)
}
return rsp
}
rsp := fmt.Sprint(val)
if valTime, ok := val.(time.Time); ok {
rsp = formatTime(valTime)
} else {
// cycle through some supported layouts to see if the string form
// of the object matches any of these layouts
for _, possibleTimeLayout := range possibleTimeLayouts {
if valTime, err := time.Parse(possibleTimeLayout, rsp); err == nil {
rsp = formatTime(valTime)
break
}
}
}
return rsp
}
}
// NewUnixTimeTransformer returns a Transformer that can format a unix-timestamp
// into a well-defined time format as defined by 'layout'. This can handle
// unix-time in Seconds, MilliSeconds, Microseconds and Nanoseconds.
//
// If a non-nil location value is provided, the time will be localized to that
// location (use time.Local to get localized timestamps).
func NewUnixTimeTransformer(layout string, location *time.Location) Transformer {
timeTransformer := NewTimeTransformer(layout, location)
formatUnixTime := func(unixTime int64) string {
if unixTime >= unixTimeMinNanoSeconds {
unixTime = unixTime / time.Second.Nanoseconds()
} else if unixTime >= unixTimeMinMicroseconds {
unixTime = unixTime / (time.Second.Nanoseconds() / 1000)
} else if unixTime >= unixTimeMinMilliseconds {
unixTime = unixTime / (time.Second.Nanoseconds() / 1000000)
}
return timeTransformer(time.Unix(unixTime, 0))
}
return func(val interface{}) string {
if unixTime, ok := val.(int64); ok {
return formatUnixTime(unixTime)
} else if unixTimeStr, ok := val.(string); ok {
if unixTime, err := strconv.ParseInt(unixTimeStr, 10, 64); err == nil {
return formatUnixTime(unixTime)
}
}
return fmt.Sprint(val)
}
}
// NewURLTransformer returns a Transformer that can format and pretty print a string
// that contains an URL (the text is underlined and colored Blue).
func NewURLTransformer() Transformer {
return func(val interface{}) string {
return colorsURL.Sprint(val)
}
}

67
vendor/github.com/jedib0t/go-pretty/v6/text/valign.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
package text
import "strings"
// VAlign denotes how text is to be aligned vertically.
type VAlign int
// VAlign enumerations
const (
VAlignDefault VAlign = iota // same as VAlignTop
VAlignTop // "top\n\n"
VAlignMiddle // "\nmiddle\n"
VAlignBottom // "\n\nbottom"
)
// Apply aligns the lines vertically. For ex.:
// * VAlignTop.Apply({"Game", "Of", "Thrones"}, 5)
// returns {"Game", "Of", "Thrones", "", ""}
// * VAlignMiddle.Apply({"Game", "Of", "Thrones"}, 5)
// returns {"", "Game", "Of", "Thrones", ""}
// * VAlignBottom.Apply({"Game", "Of", "Thrones"}, 5)
// returns {"", "", "Game", "Of", "Thrones"}
func (va VAlign) Apply(lines []string, maxLines int) []string {
if len(lines) == maxLines {
return lines
} else if len(lines) > maxLines {
maxLines = len(lines)
}
insertIdx := 0
if va == VAlignMiddle {
insertIdx = int(maxLines-len(lines)) / 2
} else if va == VAlignBottom {
insertIdx = maxLines - len(lines)
}
linesOut := strings.Split(strings.Repeat("\n", maxLines-1), "\n")
for idx, line := range lines {
linesOut[idx+insertIdx] = line
}
return linesOut
}
// ApplyStr aligns the string (of 1 or more lines) vertically. For ex.:
// * VAlignTop.ApplyStr("Game\nOf\nThrones", 5)
// returns {"Game", "Of", "Thrones", "", ""}
// * VAlignMiddle.ApplyStr("Game\nOf\nThrones", 5)
// returns {"", "Game", "Of", "Thrones", ""}
// * VAlignBottom.ApplyStr("Game\nOf\nThrones", 5)
// returns {"", "", "Game", "Of", "Thrones"}
func (va VAlign) ApplyStr(text string, maxLines int) []string {
return va.Apply(strings.Split(text, "\n"), maxLines)
}
// HTMLProperty returns the equivalent HTML vertical-align tag property.
func (va VAlign) HTMLProperty() string {
switch va {
case VAlignTop:
return "valign=\"top\""
case VAlignMiddle:
return "valign=\"middle\""
case VAlignBottom:
return "valign=\"bottom\""
default:
return ""
}
}

256
vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go generated vendored Normal file
View File

@@ -0,0 +1,256 @@
package text
import (
"strings"
"unicode/utf8"
)
// WrapHard wraps a string to the given length using a newline. Handles strings
// with ANSI escape sequences (such as text color) without breaking the text
// formatting. Breaks all words that go beyond the line boundary.
//
// For examples, refer to the unit-tests or GoDoc examples.
func WrapHard(str string, wrapLen int) string {
if wrapLen <= 0 {
return ""
}
str = strings.Replace(str, "\t", " ", -1)
sLen := utf8.RuneCountInString(str)
if sLen <= wrapLen {
return str
}
out := &strings.Builder{}
out.Grow(sLen + (sLen / wrapLen))
for idx, paragraph := range strings.Split(str, "\n\n") {
if idx > 0 {
out.WriteString("\n\n")
}
wrapHard(paragraph, wrapLen, out)
}
return out.String()
}
// WrapSoft wraps a string to the given length using a newline. Handles strings
// with ANSI escape sequences (such as text color) without breaking the text
// formatting. Tries to move words that go beyond the line boundary to the next
// line.
//
// For examples, refer to the unit-tests or GoDoc examples.
func WrapSoft(str string, wrapLen int) string {
if wrapLen <= 0 {
return ""
}
str = strings.Replace(str, "\t", " ", -1)
sLen := utf8.RuneCountInString(str)
if sLen <= wrapLen {
return str
}
out := &strings.Builder{}
out.Grow(sLen + (sLen / wrapLen))
for idx, paragraph := range strings.Split(str, "\n\n") {
if idx > 0 {
out.WriteString("\n\n")
}
wrapSoft(paragraph, wrapLen, out)
}
return out.String()
}
// WrapText is very similar to WrapHard except for one minor difference. Unlike
// WrapHard which discards line-breaks and respects only paragraph-breaks, this
// function respects line-breaks too.
//
// For examples, refer to the unit-tests or GoDoc examples.
func WrapText(str string, wrapLen int) string {
if wrapLen <= 0 {
return ""
}
var out strings.Builder
sLen := utf8.RuneCountInString(str)
out.Grow(sLen + (sLen / wrapLen))
lineIdx, isEscSeq, lastEscSeq := 0, false, ""
for _, char := range str {
if char == EscapeStartRune {
isEscSeq = true
lastEscSeq = ""
}
if isEscSeq {
lastEscSeq += string(char)
}
appendChar(char, wrapLen, &lineIdx, isEscSeq, lastEscSeq, &out)
if isEscSeq && char == EscapeStopRune {
isEscSeq = false
}
if lastEscSeq == EscapeReset {
lastEscSeq = ""
}
}
if lastEscSeq != "" && lastEscSeq != EscapeReset {
out.WriteString(EscapeReset)
}
return out.String()
}
func appendChar(char rune, wrapLen int, lineLen *int, inEscSeq bool, lastSeenEscSeq string, out *strings.Builder) {
// handle reaching the end of the line as dictated by wrapLen or by finding
// a newline character
if (*lineLen == wrapLen && !inEscSeq && char != '\n') || (char == '\n') {
if lastSeenEscSeq != "" {
// terminate escape sequence and the line; and restart the escape
// sequence in the next line
out.WriteString(EscapeReset)
out.WriteRune('\n')
out.WriteString(lastSeenEscSeq)
} else {
// just start a new line
out.WriteRune('\n')
}
// reset line index to 0th character
*lineLen = 0
}
// if the rune is not a new line, output it
if char != '\n' {
out.WriteRune(char)
// increment the line index if not in the middle of an escape sequence
if !inEscSeq {
*lineLen++
}
}
}
func appendWord(word string, lineIdx *int, lastSeenEscSeq string, wrapLen int, out *strings.Builder) {
inEscSeq := false
for _, char := range word {
if char == EscapeStartRune {
inEscSeq = true
lastSeenEscSeq = ""
}
if inEscSeq {
lastSeenEscSeq += string(char)
}
appendChar(char, wrapLen, lineIdx, inEscSeq, lastSeenEscSeq, out)
if inEscSeq && char == EscapeStopRune {
inEscSeq = false
}
if lastSeenEscSeq == EscapeReset {
lastSeenEscSeq = ""
}
}
}
func extractOpenEscapeSeq(str string) string {
escapeSeq, inEscSeq := "", false
for _, char := range str {
if char == EscapeStartRune {
inEscSeq = true
escapeSeq = ""
}
if inEscSeq {
escapeSeq += string(char)
}
if char == EscapeStopRune {
inEscSeq = false
}
}
if escapeSeq == EscapeReset {
escapeSeq = ""
}
return escapeSeq
}
func terminateLine(wrapLen int, lineLen *int, lastSeenEscSeq string, out *strings.Builder) {
if *lineLen < wrapLen {
out.WriteString(strings.Repeat(" ", wrapLen-*lineLen))
}
// something is already on the line; terminate it
if lastSeenEscSeq != "" {
out.WriteString(EscapeReset)
}
out.WriteRune('\n')
out.WriteString(lastSeenEscSeq)
*lineLen = 0
}
func terminateOutput(lastSeenEscSeq string, out *strings.Builder) {
if lastSeenEscSeq != "" && lastSeenEscSeq != EscapeReset && !strings.HasSuffix(out.String(), EscapeReset) {
out.WriteString(EscapeReset)
}
}
func wrapHard(paragraph string, wrapLen int, out *strings.Builder) {
lineLen, lastSeenEscSeq := 0, ""
words := strings.Fields(paragraph)
for wordIdx, word := range words {
escSeq := extractOpenEscapeSeq(word)
if escSeq != "" {
lastSeenEscSeq = escSeq
}
if lineLen > 0 {
out.WriteRune(' ')
lineLen++
}
wordLen := RuneCount(word)
if lineLen+wordLen <= wrapLen { // word fits within the line
out.WriteString(word)
lineLen += wordLen
} else { // word doesn't fit within the line; hard-wrap
appendWord(word, &lineLen, lastSeenEscSeq, wrapLen, out)
}
// end of line; but more words incoming
if lineLen == wrapLen && wordIdx < len(words)-1 {
terminateLine(wrapLen, &lineLen, lastSeenEscSeq, out)
}
}
terminateOutput(lastSeenEscSeq, out)
}
func wrapSoft(paragraph string, wrapLen int, out *strings.Builder) {
lineLen, lastSeenEscSeq := 0, ""
words := strings.Fields(paragraph)
for wordIdx, word := range words {
escSeq := extractOpenEscapeSeq(word)
if escSeq != "" {
lastSeenEscSeq = escSeq
}
spacing, spacingLen := "", 0
if lineLen > 0 {
spacing, spacingLen = " ", 1
}
wordLen := RuneCount(word)
if lineLen+spacingLen+wordLen <= wrapLen { // word fits within the line
out.WriteString(spacing)
out.WriteString(word)
lineLen += spacingLen + wordLen
} else { // word doesn't fit within the line
if lineLen > 0 { // something is already on the line; terminate it
terminateLine(wrapLen, &lineLen, lastSeenEscSeq, out)
}
if wordLen <= wrapLen { // word fits within a single line
out.WriteString(word)
lineLen = wordLen
} else { // word doesn't fit within a single line; hard-wrap
appendWord(word, &lineLen, lastSeenEscSeq, wrapLen, out)
}
}
// end of line; but more words incoming
if lineLen == wrapLen && wordIdx < len(words)-1 {
terminateLine(wrapLen, &lineLen, lastSeenEscSeq, out)
}
}
terminateOutput(lastSeenEscSeq, out)
}