mirror of
https://github.com/mudler/luet.git
synced 2025-09-08 18:49:39 +00:00
Update vendor
This commit is contained in:
21
vendor/github.com/jedib0t/go-pretty/v6/LICENSE
generated
vendored
Normal file
21
vendor/github.com/jedib0t/go-pretty/v6/LICENSE
generated
vendored
Normal 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
30
vendor/github.com/jedib0t/go-pretty/v6/list/README.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
## List
|
||||
[](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
174
vendor/github.com/jedib0t/go-pretty/v6/list/list.go
generated
vendored
Normal 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
110
vendor/github.com/jedib0t/go-pretty/v6/list/render.go
generated
vendored
Normal 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)))
|
||||
}
|
||||
}
|
||||
}
|
70
vendor/github.com/jedib0t/go-pretty/v6/list/render_html.go
generated
vendored
Normal file
70
vendor/github.com/jedib0t/go-pretty/v6/list/render_html.go
generated
vendored
Normal 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
|
||||
}
|
29
vendor/github.com/jedib0t/go-pretty/v6/list/render_markdown.go
generated
vendored
Normal file
29
vendor/github.com/jedib0t/go-pretty/v6/list/render_markdown.go
generated
vendored
Normal 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
295
vendor/github.com/jedib0t/go-pretty/v6/list/style.go
generated
vendored
Normal 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
25
vendor/github.com/jedib0t/go-pretty/v6/list/writer.go
generated
vendored
Normal 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
137
vendor/github.com/jedib0t/go-pretty/v6/text/align.go
generated
vendored
Normal 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
55
vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go
generated
vendored
Normal 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()
|
||||
}
|
7
vendor/github.com/jedib0t/go-pretty/v6/text/ansi_unix.go
generated
vendored
Normal file
7
vendor/github.com/jedib0t/go-pretty/v6/text/ansi_unix.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build !windows
|
||||
|
||||
package text
|
||||
|
||||
func areANSICodesSupported() bool {
|
||||
return true
|
||||
}
|
31
vendor/github.com/jedib0t/go-pretty/v6/text/ansi_windows.go
generated
vendored
Normal file
31
vendor/github.com/jedib0t/go-pretty/v6/text/ansi_windows.go
generated
vendored
Normal 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
183
vendor/github.com/jedib0t/go-pretty/v6/text/color.go
generated
vendored
Normal 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)
|
||||
}
|
48
vendor/github.com/jedib0t/go-pretty/v6/text/color_html.go
generated
vendored
Normal file
48
vendor/github.com/jedib0t/go-pretty/v6/text/color_html.go
generated
vendored
Normal 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
39
vendor/github.com/jedib0t/go-pretty/v6/text/cursor.go
generated
vendored
Normal 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
12
vendor/github.com/jedib0t/go-pretty/v6/text/filter.go
generated
vendored
Normal 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
100
vendor/github.com/jedib0t/go-pretty/v6/text/format.go
generated
vendored
Normal 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
203
vendor/github.com/jedib0t/go-pretty/v6/text/string.go
generated
vendored
Normal 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()
|
||||
}
|
201
vendor/github.com/jedib0t/go-pretty/v6/text/transformer.go
generated
vendored
Normal file
201
vendor/github.com/jedib0t/go-pretty/v6/text/transformer.go
generated
vendored
Normal 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
67
vendor/github.com/jedib0t/go-pretty/v6/text/valign.go
generated
vendored
Normal 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
256
vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go
generated
vendored
Normal 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)
|
||||
}
|
Reference in New Issue
Block a user