From 6f7b5b313d338a717b3c3b4be04784b5da912190 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:33:08 +0000 Subject: [PATCH] chore(deps): bump github.com/jedib0t/go-pretty/v6 from 6.5.9 to 6.6.5 Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.5.9 to 6.6.5. - [Release notes](https://github.com/jedib0t/go-pretty/releases) - [Commits](https://github.com/jedib0t/go-pretty/compare/v6.5.9...v6.6.5) --- updated-dependencies: - dependency-name: github.com/jedib0t/go-pretty/v6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../jedib0t/go-pretty/v6/table/README.md | 1 + .../jedib0t/go-pretty/v6/table/pager.go | 70 ++++++ .../go-pretty/v6/table/pager_options.go | 11 + .../jedib0t/go-pretty/v6/table/render.go | 21 +- .../jedib0t/go-pretty/v6/table/render_init.go | 128 ++++++++--- .../jedib0t/go-pretty/v6/table/row.go | 43 ++++ .../jedib0t/go-pretty/v6/table/style.go | 79 +++++-- .../jedib0t/go-pretty/v6/table/table.go | 166 +++++++++++---- .../jedib0t/go-pretty/v6/table/util.go | 43 ++++ .../jedib0t/go-pretty/v6/table/writer.go | 10 +- .../jedib0t/go-pretty/v6/text/align.go | 2 +- .../jedib0t/go-pretty/v6/text/ansi.go | 2 +- .../jedib0t/go-pretty/v6/text/direction.go | 9 +- .../jedib0t/go-pretty/v6/text/escape.go | 50 ----- .../go-pretty/v6/text/escape_seq_parser.go | 201 ++++++++++++++++++ .../jedib0t/go-pretty/v6/text/string.go | 118 +++++++--- .../jedib0t/go-pretty/v6/text/wrap.go | 76 ++----- vendor/modules.txt | 2 +- 20 files changed, 788 insertions(+), 250 deletions(-) create mode 100644 vendor/github.com/jedib0t/go-pretty/v6/table/pager.go create mode 100644 vendor/github.com/jedib0t/go-pretty/v6/table/pager_options.go create mode 100644 vendor/github.com/jedib0t/go-pretty/v6/table/row.go delete mode 100644 vendor/github.com/jedib0t/go-pretty/v6/text/escape.go create mode 100644 vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go diff --git a/go.mod b/go.mod index cfa0edb8c..1f7e8f8b3 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // v1.7.2 github.com/imdario/mergo v0.3.16 - github.com/jedib0t/go-pretty/v6 v6.5.9 + github.com/jedib0t/go-pretty/v6 v6.6.5 github.com/matcornic/hermes/v2 v2.1.0 github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 github.com/microcosm-cc/bluemonday v1.0.27 diff --git a/go.sum b/go.sum index 427c9fb3f..17ac26590 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= -github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU= -github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= +github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3NgSqAo= +github.com/jedib0t/go-pretty/v6 v6.6.5/go.mod h1:Uq/HrbhuFty5WSVNfjpQQe47x16RwVGXIveNGEyGtHs= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/README.md b/vendor/github.com/jedib0t/go-pretty/v6/table/README.md index e7d3e1b76..3375bd3c7 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/README.md +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/README.md @@ -13,6 +13,7 @@ Pretty-print tables into ASCII/Unicode strings. - Limit the length of - Rows (`SetAllowedRowLength`) - Columns (`ColumnConfig.Width*`) + - Auto-size Rows (`Style().Size.WidthMin` and `Style().Size.WidthMax`) - Page results by a specified number of Lines (`SetPageSize`) - Alignment - Horizontal & Vertical - Auto (horizontal) Align (numeric columns aligned Right) diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/pager.go b/vendor/github.com/jedib0t/go-pretty/v6/table/pager.go new file mode 100644 index 000000000..f4585b297 --- /dev/null +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/pager.go @@ -0,0 +1,70 @@ +package table + +import ( + "io" +) + +// Pager lets you interact with the table rendering in a paged manner. +type Pager interface { + // GoTo moves to the given 1-indexed page number. + GoTo(pageNum int) string + // Location returns the current page number in 1-indexed form. + Location() int + // Next moves to the next available page and returns the same. + Next() string + // Prev moves to the previous available page and returns the same. + Prev() string + // Render returns the current page. + Render() string + // SetOutputMirror sets up the writer to which Render() will write the + // output other than returning. + SetOutputMirror(mirror io.Writer) +} + +type pager struct { + index int // 0-indexed + pages []string + outputMirror io.Writer + size int +} + +func (p *pager) GoTo(pageNum int) string { + if pageNum < 1 { + pageNum = 1 + } + if pageNum > len(p.pages) { + pageNum = len(p.pages) + } + p.index = pageNum - 1 + return p.pages[p.index] +} + +func (p *pager) Location() int { + return p.index + 1 +} + +func (p *pager) Next() string { + if p.index < len(p.pages)-1 { + p.index++ + } + return p.pages[p.index] +} + +func (p *pager) Prev() string { + if p.index > 0 { + p.index-- + } + return p.pages[p.index] +} + +func (p *pager) Render() string { + pageToWrite := p.pages[p.index] + if p.outputMirror != nil { + _, _ = p.outputMirror.Write([]byte(pageToWrite)) + } + return pageToWrite +} + +func (p *pager) SetOutputMirror(mirror io.Writer) { + p.outputMirror = mirror +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/pager_options.go b/vendor/github.com/jedib0t/go-pretty/v6/table/pager_options.go new file mode 100644 index 000000000..f46ebc128 --- /dev/null +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/pager_options.go @@ -0,0 +1,11 @@ +package table + +// PagerOption helps control Paging. +type PagerOption func(t *Table) + +// PageSize sets the size of each page rendered. +func PageSize(pageSize int) PagerOption { + return func(t *Table) { + t.pager.size = pageSize + } +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render.go index 428dffe4c..2fd759e62 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/render.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render.go @@ -185,7 +185,7 @@ func (t *Table) renderLine(out *strings.Builder, row rowStr, hint renderHint) { // use a brand-new strings.Builder if a row length limit has been set var outLine *strings.Builder - if t.allowedRowLength > 0 { + if t.style.Size.WidthMax > 0 { outLine = &strings.Builder{} } else { outLine = out @@ -214,7 +214,7 @@ func (t *Table) renderLine(out *strings.Builder, row rowStr, hint renderHint) { // the header all over again with a spacing line if hint.isRegularNonSeparatorRow() { t.numLinesRendered++ - if t.pageSize > 0 && t.numLinesRendered%t.pageSize == 0 && !hint.isLastLineOfLastRow() { + if t.pager.size > 0 && t.numLinesRendered%t.pager.size == 0 && !hint.isLastLineOfLastRow() { t.renderRowsFooter(out) t.renderRowsBorderBottom(out) out.WriteString(t.style.Box.PageSeparator) @@ -227,8 +227,8 @@ func (t *Table) renderLine(out *strings.Builder, row rowStr, hint renderHint) { func (t *Table) renderLineMergeOutputs(out *strings.Builder, outLine *strings.Builder) { outLineStr := outLine.String() - if text.RuneWidthWithoutEscSequences(outLineStr) > t.allowedRowLength { - trimLength := t.allowedRowLength - utf8.RuneCountInString(t.style.Box.UnfinishedRow) + if text.StringWidthWithoutEscSequences(outLineStr) > t.style.Size.WidthMax { + trimLength := t.style.Size.WidthMax - utf8.RuneCountInString(t.style.Box.UnfinishedRow) if trimLength > 0 { out.WriteString(text.Trim(outLineStr, trimLength)) out.WriteString(t.style.Box.UnfinishedRow) @@ -385,19 +385,22 @@ func (t *Table) renderTitle(out *strings.Builder) { colors := t.style.Title.Colors colorsBorder := t.getBorderColors(renderHint{isTitleRow: true}) rowLength := t.maxRowLength - if t.allowedRowLength != 0 && t.allowedRowLength < rowLength { - rowLength = t.allowedRowLength + if wm := t.style.Size.WidthMax; wm > 0 && wm < rowLength { + rowLength = wm + } + if wm := t.style.Size.WidthMin; wm > 0 && wm > rowLength { + rowLength = wm } if t.style.Options.DrawBorder { - lenBorder := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.TopLeft+t.style.Box.TopRight) + lenBorder := rowLength - text.StringWidthWithoutEscSequences(t.style.Box.TopLeft+t.style.Box.TopRight) out.WriteString(colorsBorder.Sprint(t.style.Box.TopLeft)) out.WriteString(colorsBorder.Sprint(text.RepeatAndTrim(t.style.Box.MiddleHorizontal, lenBorder))) out.WriteString(colorsBorder.Sprint(t.style.Box.TopRight)) } - lenText := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft+t.style.Box.PaddingRight) + lenText := rowLength - text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft+t.style.Box.PaddingRight) if t.style.Options.DrawBorder { - lenText -= text.RuneWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right) + lenText -= text.StringWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right) } titleText := text.WrapText(t.title, lenText) for _, titleLine := range strings.Split(titleText, "\n") { diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render_init.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render_init.go index 226afe92e..8a7a0f452 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/render_init.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render_init.go @@ -3,6 +3,7 @@ package table import ( "fmt" "strings" + "unicode" "github.com/jedib0t/go-pretty/v6/text" ) @@ -77,7 +78,7 @@ func (t *Table) extractMaxColumnLengthsFromRow(row rowStr, mci mergedColumnIndic func (t *Table) extractMaxColumnLengthsFromRowForMergedColumns(colIdx int, mergedColumnLength int, mci mergedColumnIndices) { numMergedColumns := mci.len(colIdx) - mergedColumnLength -= (numMergedColumns - 1) * text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator) + mergedColumnLength -= (numMergedColumns - 1) * text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator) maxLengthSplitAcrossColumns := mergedColumnLength / numMergedColumns if maxLengthSplitAcrossColumns > t.maxColumnLengths[colIdx] { t.maxColumnLengths[colIdx] = maxLengthSplitAcrossColumns @@ -104,6 +105,8 @@ func (t *Table) initForRender() { // find the longest continuous line in each column t.initForRenderColumnLengths() + t.initForRenderMaxRowLength() + t.initForRenderPaddedColumns() // generate a separator row and calculate maximum row length t.initForRenderRowSeparator() @@ -171,14 +174,55 @@ func (t *Table) initForRenderHideColumns() { t.columnConfigMap = columnConfigMap } +func (t *Table) initForRenderMaxRowLength() { + t.maxRowLength = 0 + if t.autoIndex { + t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft) + t.maxRowLength += len(fmt.Sprint(len(t.rows))) + t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingRight) + if t.style.Options.SeparateColumns { + t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator) + } + } + if t.style.Options.SeparateColumns { + t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator) * (t.numColumns - 1) + } + for _, maxColumnLength := range t.maxColumnLengths { + maxColumnLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight) + t.maxRowLength += maxColumnLength + } + if t.style.Options.DrawBorder { + t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right) + } +} + +func (t *Table) initForRenderPaddedColumns() { + paddingSize := t.style.Size.WidthMin - t.maxRowLength + for paddingSize > 0 { + // distribute padding equally among all columns + numColumnsPadded := 0 + for colIdx := 0; paddingSize > 0 && colIdx < t.numColumns; colIdx++ { + colWidthMax := t.getColumnWidthMax(colIdx) + if colWidthMax == 0 || t.maxColumnLengths[colIdx] < colWidthMax { + t.maxColumnLengths[colIdx]++ + numColumnsPadded++ + paddingSize-- + } + } + + // avoid endless looping because all columns are at max size and cannot + // be expanded any further + if numColumnsPadded == 0 { + break + } + } +} + func (t *Table) initForRenderRows() { // auto-index: calc the index column's max length t.autoIndexVIndexMaxLength = len(fmt.Sprint(len(t.rowsRaw))) // stringify all the rows to make it easy to render - if t.rowPainter != nil { - t.rowsColors = make([]text.Colors, len(t.rowsRaw)) - } t.rows = t.initForRenderRowsStringify(t.rowsRaw, renderHint{}) t.rowsFooter = t.initForRenderRowsStringify(t.rowsFooterRaw, renderHint{isFooterRow: true}) t.rowsHeader = t.initForRenderRowsStringify(t.rowsHeaderRaw, renderHint{isHeaderRow: true}) @@ -186,6 +230,9 @@ func (t *Table) initForRenderRows() { // sort the rows as requested t.initForRenderSortRows() + // find the row colors (if any) + t.initForRenderRowPainterColors() + // suppress columns without any content t.initForRenderSuppressColumns() @@ -196,36 +243,48 @@ func (t *Table) initForRenderRows() { func (t *Table) initForRenderRowsStringify(rows []Row, hint renderHint) []rowStr { rowsStr := make([]rowStr, len(rows)) for idx, row := range rows { - if t.rowPainter != nil && hint.isRegularRow() { - t.rowsColors[idx] = t.rowPainter(row) - } + hint.rowNumber = idx + 1 rowsStr[idx] = t.analyzeAndStringify(row, hint) } return rowsStr } -func (t *Table) initForRenderRowSeparator() { - t.maxRowLength = 0 - if t.autoIndex { - t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft) - t.maxRowLength += len(fmt.Sprint(len(t.rows))) - t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingRight) - if t.style.Options.SeparateColumns { - t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator) - } +func (t *Table) initForRenderRowPainterColors() { + if !t.hasRowPainter() { + return } - if t.style.Options.SeparateColumns { - t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator) * (t.numColumns - 1) + + // generate the colors + t.rowsColors = make([]text.Colors, len(t.rowsRaw)) + for idx, row := range t.rowsRaw { + idxColors := idx + if len(t.sortedRowIndices) > 0 { + // override with the sorted row index + for j := 0; j < len(t.sortedRowIndices); j++ { + if t.sortedRowIndices[j] == idx { + idxColors = j + break + } + } + } + + if t.rowPainter != nil { + t.rowsColors[idxColors] = t.rowPainter(row) + } else if t.rowPainterWithAttributes != nil { + t.rowsColors[idxColors] = t.rowPainterWithAttributes(row, RowAttributes{ + Number: idx + 1, + NumberSorted: idxColors + 1, + }) + } } +} + +func (t *Table) initForRenderRowSeparator() { t.rowSeparator = make(rowStr, t.numColumns) for colIdx, maxColumnLength := range t.maxColumnLengths { - maxColumnLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight) - t.maxRowLength += maxColumnLength + maxColumnLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight) t.rowSeparator[colIdx] = text.RepeatAndTrim(t.style.Box.MiddleHorizontal, maxColumnLength) } - if t.style.Options.DrawBorder { - t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right) - } } func (t *Table) initForRenderSortRows() { @@ -234,28 +293,27 @@ func (t *Table) initForRenderSortRows() { } // sort the rows - sortedRowIndices := t.getSortedRowIndices() + t.sortedRowIndices = t.getSortedRowIndices() sortedRows := make([]rowStr, len(t.rows)) for idx := range t.rows { - sortedRows[idx] = t.rows[sortedRowIndices[idx]] + sortedRows[idx] = t.rows[t.sortedRowIndices[idx]] } t.rows = sortedRows - - // sort the rowsColors - if len(t.rowsColors) > 0 { - sortedRowsColors := make([]text.Colors, len(t.rows)) - for idx := range t.rows { - sortedRowsColors[idx] = t.rowsColors[sortedRowIndices[idx]] - } - t.rowsColors = sortedRowsColors - } } func (t *Table) initForRenderSuppressColumns() { shouldSuppressColumn := func(colIdx int) bool { for _, row := range t.rows { if colIdx < len(row) && row[colIdx] != "" { - return false + // Columns may contain non-printable characters. For example + // the text.Direction modifiers. These should not be considered + // when deciding to suppress a column. + for _, r := range row[colIdx] { + if unicode.IsPrint(r) { + return false + } + } + return true } } return true diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/row.go b/vendor/github.com/jedib0t/go-pretty/v6/table/row.go new file mode 100644 index 000000000..3c165fcab --- /dev/null +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/row.go @@ -0,0 +1,43 @@ +package table + +import ( + "fmt" + + "github.com/jedib0t/go-pretty/v6/text" +) + +// Row defines a single row in the Table. +type Row []interface{} + +func (r Row) findColumnNumber(colName string) int { + for colIdx, col := range r { + if fmt.Sprint(col) == colName { + return colIdx + 1 + } + } + return 0 +} + +// RowAttributes contains properties about the Row during the render. +type RowAttributes struct { + Number int // Row Number (1-indexed) as appended + NumberSorted int // Row number (1-indexed) after sorting +} + +// RowPainter is a custom function that takes a Row as input and returns the +// text.Colors{} to use on the entire row +type RowPainter func(row Row) text.Colors + +// RowPainterWithAttributes is the same as RowPainter but passes in additional +// attributes from render time +type RowPainterWithAttributes func(row Row, attr RowAttributes) text.Colors + +// rowStr defines a single row in the Table comprised of just string objects. +type rowStr []string + +// areEqual returns true if the contents of the 2 given columns are the same +func (row rowStr) areEqual(colIdx1 int, colIdx2 int) bool { + return colIdx1 >= 0 && colIdx1 < len(row) && + colIdx2 >= 0 && colIdx2 < len(row) && + row[colIdx1] == row[colIdx2] +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/style.go b/vendor/github.com/jedib0t/go-pretty/v6/table/style.go index cb850e88b..aaed2c27f 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/style.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/style.go @@ -13,6 +13,7 @@ type Style struct { Format FormatOptions // formatting options for the rows and columns HTML HTMLOptions // rendering options for HTML mode Options Options // misc. options for the table + Size SizeOptions // size (width) options for the table Title TitleOptions // formation options for the title text } @@ -34,6 +35,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } @@ -54,6 +56,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } @@ -67,6 +70,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsDark, } @@ -80,6 +84,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBright, } @@ -93,6 +98,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlueOnBlack, } @@ -106,6 +112,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsCyanOnBlack, } @@ -119,6 +126,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsGreenOnBlack, } @@ -132,6 +140,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsMagentaOnBlack, } @@ -145,6 +154,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsYellowOnBlack, } @@ -158,6 +168,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsRedOnBlack, } @@ -171,6 +182,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnBlue, } @@ -184,6 +196,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnCyan, } @@ -197,6 +210,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnGreen, } @@ -210,6 +224,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnMagenta, } @@ -223,6 +238,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnRed, } @@ -236,6 +252,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsNoBordersAndSeparators, + Size: SizeOptionsDefault, Title: TitleOptionsBlackOnYellow, } @@ -256,6 +273,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } @@ -276,6 +294,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } @@ -296,6 +315,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } @@ -316,6 +336,7 @@ var ( Format: FormatOptionsDefault, HTML: DefaultHTMLOptions, Options: OptionsDefault, + Size: SizeOptionsDefault, Title: TitleOptionsDefault, } ) @@ -358,7 +379,7 @@ var ( BottomLeft: "+", BottomRight: "+", BottomSeparator: "+", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("+")), + EmptySeparator: " ", Left: "|", LeftSeparator: "+", MiddleHorizontal: "-", @@ -389,7 +410,7 @@ var ( BottomLeft: "┗", BottomRight: "┛", BottomSeparator: "┻", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("╋")), + EmptySeparator: " ", Left: "┃", LeftSeparator: "┣", MiddleHorizontal: "━", @@ -420,7 +441,7 @@ var ( BottomLeft: "╚", BottomRight: "╝", BottomSeparator: "╩", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("╬")), + EmptySeparator: " ", Left: "║", LeftSeparator: "╠", MiddleHorizontal: "═", @@ -451,7 +472,7 @@ var ( BottomLeft: "└", BottomRight: "┘", BottomSeparator: "┴", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("┼")), + EmptySeparator: " ", Left: "│", LeftSeparator: "├", MiddleHorizontal: "─", @@ -482,7 +503,7 @@ var ( BottomLeft: "╰", BottomRight: "╯", BottomSeparator: "┴", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("┼")), + EmptySeparator: " ", Left: "│", LeftSeparator: "├", MiddleHorizontal: "─", @@ -513,7 +534,7 @@ var ( BottomLeft: "\\", BottomRight: "/", BottomSeparator: "v", - EmptySeparator: text.RepeatAndTrim(" ", text.RuneWidthWithoutEscSequences("+")), + EmptySeparator: " ", Left: "[", LeftSeparator: "{", MiddleHorizontal: "--", @@ -669,17 +690,29 @@ var ( // FormatOptions defines the text-formatting to perform on parts of the Table. type FormatOptions struct { - Direction text.Direction // (forced) BiDi direction for each Column - Footer text.Format // footer row(s) text format - Header text.Format // header row(s) text format - Row text.Format // (data) row(s) text format + Direction text.Direction // (forced) BiDi direction for each Column + Footer text.Format // default text format + FooterAlign text.Align // default horizontal align + FooterVAlign text.VAlign // default vertical align + Header text.Format // default text format + HeaderAlign text.Align // default horizontal align + HeaderVAlign text.VAlign // default vertical align + Row text.Format // default text format + RowAlign text.Align // default horizontal align + RowVAlign text.VAlign // default vertical align } // FormatOptionsDefault defines sensible formatting options. var FormatOptionsDefault = FormatOptions{ - Footer: text.FormatUpper, - Header: text.FormatUpper, - Row: text.FormatDefault, + Footer: text.FormatUpper, + FooterAlign: text.AlignDefault, + FooterVAlign: text.VAlignDefault, + Header: text.FormatUpper, + HeaderAlign: text.AlignDefault, + HeaderVAlign: text.VAlignDefault, + Row: text.FormatDefault, + RowAlign: text.AlignDefault, + RowVAlign: text.VAlignDefault, } // HTMLOptions defines the global options to control HTML rendering. @@ -798,6 +831,26 @@ var ( } ) +// SizeOptions defines the way to control the width of the table output. +type SizeOptions struct { + // WidthMax is the maximum allotted width for the full row; + // any content beyond this will be truncated using the text + // in Style.Box.UnfinishedRow + WidthMax int + // WidthMin is the minimum allotted width for the full row; + // columns will be auto-expanded until the overall width + // is met + WidthMin int +} + +var ( + // SizeOptionsDefault defines sensible size options - basically NONE. + SizeOptionsDefault = SizeOptions{ + WidthMax: 0, + WidthMin: 0, + } +) + // TitleOptions defines the way the title text is to be rendered. type TitleOptions struct { Align text.Align diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/table.go b/vendor/github.com/jedib0t/go-pretty/v6/table/table.go index 6776333c1..ea2fae68f 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/table.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/table.go @@ -4,35 +4,12 @@ import ( "fmt" "io" "strings" + "time" "unicode" "github.com/jedib0t/go-pretty/v6/text" ) -// Row defines a single row in the Table. -type Row []interface{} - -func (r Row) findColumnNumber(colName string) int { - for colIdx, col := range r { - if fmt.Sprint(col) == colName { - return colIdx + 1 - } - } - return 0 -} - -// RowPainter is a custom function that takes a Row as input and returns the -// text.Colors{} to use on the entire row -type RowPainter func(row Row) text.Colors - -// rowStr defines a single row in the Table comprised of just string objects. -type rowStr []string - -// areEqual returns true if the contents of the 2 given columns are the same -func (row rowStr) areEqual(colIdx1 int, colIdx2 int) bool { - return colIdx1 >= 0 && colIdx2 < len(row) && row[colIdx1] == row[colIdx2] -} - // Table helps print a 2-dimensional array in a human-readable pretty-table. type Table struct { // allowedRowLength is the max allowed length for a row (or line of output) @@ -68,14 +45,12 @@ type Table struct { numLinesRendered int // outputMirror stores an io.Writer where the "Render" functions would write outputMirror io.Writer - // pageSize stores the maximum lines to render before rendering the header - // again (to denote a page break) - useful when you are dealing with really - // long tables - pageSize int + // pager controls how the output is separated into pages + pager pager // rows stores the rows that make up the body (in string form) rows []rowStr // rowsColors stores the text.Colors over-rides for each row as defined by - // rowPainter + // rowPainter or rowPainterWithAttributes rowsColors []text.Colors // rowsConfigs stores RowConfig for each row rowsConfigMap map[int]RowConfig @@ -96,6 +71,8 @@ type Table struct { // rowPainter is a custom function that given a Row, returns the colors to // use on the entire row rowPainter RowPainter + // rowPainterWithAttributes is same as rowPainter, but with attributes + rowPainterWithAttributes RowPainterWithAttributes // rowSeparator is a dummy row that contains the separator columns (dashes // that make up the separator between header/body/footer rowSeparator rowStr @@ -104,13 +81,15 @@ type Table struct { separators map[int]bool // sortBy stores a map of Column sortBy []SortBy + // sortedRowIndices is the output of sorting + sortedRowIndices []int // style contains all the strings used to draw the table, and more style *Style // suppressEmptyColumns hides columns which have no content on all regular // rows suppressEmptyColumns bool - // supressTrailingSpaces removes all trailing spaces from the end of the last column - supressTrailingSpaces bool + // suppressTrailingSpaces removes all trailing spaces from the end of the last column + suppressTrailingSpaces bool // title contains the text to appear above the table title string } @@ -187,11 +166,56 @@ func (t *Table) AppendSeparator() { } } +// ImportGrid helps import 1d or 2d arrays as rows. +func (t *Table) ImportGrid(grid interface{}) bool { + rows := objAsSlice(grid) + if rows == nil { + return false + } + addedRows := false + for _, row := range rows { + rowAsSlice := objAsSlice(row) + if rowAsSlice != nil { + t.AppendRow(rowAsSlice) + } else if row != nil { + t.AppendRow(Row{row}) + } + addedRows = true + } + return addedRows +} + // Length returns the number of rows to be rendered. func (t *Table) Length() int { return len(t.rowsRaw) } +// Pager returns an object that splits the table output into pages and +// lets you move back and forth through them. +func (t *Table) Pager(opts ...PagerOption) Pager { + for _, opt := range opts { + opt(t) + } + + // use a temporary page separator for splitting up the pages + tempPageSep := fmt.Sprintf("%p // page separator // %d", t.rows, time.Now().UnixNano()) + + // backup + origOutputMirror, origPageSep := t.outputMirror, t.Style().Box.PageSeparator + // restore on exit + defer func() { + t.outputMirror = origOutputMirror + t.Style().Box.PageSeparator = origPageSep + }() + // override + t.outputMirror = nil + t.Style().Box.PageSeparator = tempPageSep + // render + t.pager.pages = strings.Split(t.Render(), tempPageSep) + + return &t.pager +} + // ResetFooters resets and clears all the Footer rows appended earlier. func (t *Table) ResetFooters() { t.rowsFooterRaw = nil @@ -211,6 +235,8 @@ func (t *Table) ResetRows() { // SetAllowedRowLength sets the maximum allowed length or a row (or line of // output) when rendered as a table. Rows that are longer than this limit will // be "snipped" to the length. Length has to be a positive value to take effect. +// +// Deprecated: in favor if Style().Size.WidthMax func (t *Table) SetAllowedRowLength(length int) { t.allowedRowLength = length } @@ -252,6 +278,7 @@ func (t *Table) SetIndexColumn(colNum int) { // in addition to returning a string. func (t *Table) SetOutputMirror(mirror io.Writer) { t.outputMirror = mirror + t.pager.SetOutputMirror(mirror) } // SetPageSize sets the maximum number of lines to render before rendering the @@ -259,15 +286,40 @@ func (t *Table) SetOutputMirror(mirror io.Writer) { // long list of rows that can span pages. Please note that the pagination logic // will not consider Header/Footer lines for paging. func (t *Table) SetPageSize(numLines int) { - t.pageSize = numLines + t.pager.size = numLines } -// SetRowPainter sets the RowPainter function which determines the colors to use -// on a row. Before rendering, this function is invoked on all rows and the -// color of each row is determined. This color takes precedence over other ways -// to set color (ColumnConfig.Color*, SetColor*()). -func (t *Table) SetRowPainter(painter RowPainter) { - t.rowPainter = painter +// SetRowPainter sets up the function which determines the colors to use on a +// row. Before rendering, this function is invoked on all rows and the color +// of each row is determined. This color takes precedence over other ways to +// set color (ColumnConfig.Color*, SetColor*()). +func (t *Table) SetRowPainter(painter interface{}) { + // TODO: fix interface on major version bump to accept only + // one type of RowPainter: RowPainterWithAttributes renamed to RowPainter + + // reset both so only one is set at any given time + t.rowPainter = nil + t.rowPainterWithAttributes = nil + + // if called as SetRowPainter(RowPainter(func...)) + switch painter.(type) { + case RowPainter: + t.rowPainter = painter.(RowPainter) + return + case RowPainterWithAttributes: + t.rowPainterWithAttributes = painter.(RowPainterWithAttributes) + return + } + + // if called as SetRowPainter(func...) + switch fmt.Sprintf("%T", painter) { + case "func(table.Row) text.Colors": + t.rowPainter = painter.(func(row Row) text.Colors) + return + case "func(table.Row, table.RowAttributes) text.Colors": + t.rowPainterWithAttributes = painter.(func(row Row, attr RowAttributes) text.Colors) + return + } } // SetStyle overrides the DefaultStyle with the provided one. @@ -293,6 +345,11 @@ func (t *Table) Style() *Style { tempStyle := StyleDefault t.style = &tempStyle } + // override WidthMax with allowedRowLength until allowedRowLength is + // removed from code + if t.allowedRowLength > 0 { + t.style.Size.WidthMax = t.allowedRowLength + } return t.style } @@ -304,7 +361,7 @@ func (t *Table) SuppressEmptyColumns() { // SuppressTrailingSpaces removes all trailing spaces from the output. func (t *Table) SuppressTrailingSpaces() { - t.supressTrailingSpaces = true + t.suppressTrailingSpaces = true } func (t *Table) getAlign(colIdx int, hint renderHint) text.Align { @@ -323,6 +380,12 @@ func (t *Table) getAlign(colIdx int, hint renderHint) text.Align { align = text.AlignRight } else if hint.isAutoIndexRow { align = text.AlignCenter + } else if hint.isHeaderRow { + align = t.style.Format.HeaderAlign + } else if hint.isFooterRow { + align = t.style.Format.FooterAlign + } else { + align = t.style.Format.RowAlign } } return align @@ -403,7 +466,7 @@ func (t *Table) getColumnColors(colIdx int, hint renderHint) text.Colors { return colors } } - if t.rowPainter != nil && hint.isRegularNonSeparatorRow() && !t.isIndexColumn(colIdx, hint) { + if t.hasRowPainter() && hint.isRegularNonSeparatorRow() && !t.isIndexColumn(colIdx, hint) { if colors := t.rowsColors[hint.rowNumber-1]; colors != nil { return colors } @@ -540,9 +603,9 @@ func (t *Table) getFormat(hint renderHint) text.Format { func (t *Table) getMaxColumnLengthForMerging(colIdx int) int { maxColumnLength := t.maxColumnLengths[colIdx] - maxColumnLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingRight + t.style.Box.PaddingLeft) + maxColumnLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingRight + t.style.Box.PaddingLeft) if t.style.Options.SeparateColumns { - maxColumnLength += text.RuneWidthWithoutEscSequences(t.style.Box.EmptySeparator) + maxColumnLength += text.StringWidthWithoutEscSequences(t.style.Box.EmptySeparator) } return maxColumnLength } @@ -638,6 +701,15 @@ func (t *Table) getVAlign(colIdx int, hint renderHint) text.VAlign { vAlign = cfg.VAlign } } + if vAlign == text.VAlignDefault { + if hint.isHeaderRow { + vAlign = t.style.Format.HeaderVAlign + } else if hint.isFooterRow { + vAlign = t.style.Format.FooterVAlign + } else { + vAlign = t.style.Format.RowVAlign + } + } return vAlign } @@ -650,6 +722,10 @@ func (t *Table) hasHiddenColumns() bool { return false } +func (t *Table) hasRowPainter() bool { + return t.rowPainter != nil || t.rowPainterWithAttributes != nil +} + func (t *Table) hideColumns() map[int]int { colIdxMap := make(map[int]int) numColumns := 0 @@ -689,7 +765,7 @@ func (t *Table) isIndexColumn(colIdx int, hint renderHint) bool { func (t *Table) render(out *strings.Builder) string { outStr := out.String() - if t.supressTrailingSpaces { + if t.suppressTrailingSpaces { var trimmed []string for _, line := range strings.Split(outStr, "\n") { trimmed = append(trimmed, strings.TrimRightFunc(line, unicode.IsSpace)) @@ -786,8 +862,8 @@ func (t *Table) shouldSeparateRows(rowIdx int, numRows int) bool { } pageSize := numRows - if t.pageSize > 0 { - pageSize = t.pageSize + if t.pager.size > 0 { + pageSize = t.pager.size } if rowIdx%pageSize == pageSize-1 { // last row of page return false diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/util.go b/vendor/github.com/jedib0t/go-pretty/v6/table/util.go index aa710125e..6b7a6585d 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/util.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/util.go @@ -67,3 +67,46 @@ func (m mergedColumnIndices) safeAppend(colIdx, otherColIdx int) { } m[otherColIdx][colIdx] = true } + +func objAsSlice(in interface{}) []interface{} { + var out []interface{} + if in != nil { + // dereference pointers + val := reflect.ValueOf(in) + if val.Kind() == reflect.Ptr && !val.IsNil() { + in = val.Elem().Interface() + } + + if objIsSlice(in) { + v := reflect.ValueOf(in) + for i := 0; i < v.Len(); i++ { + // dereference pointers + v2 := v.Index(i) + if v2.Kind() == reflect.Ptr && !v2.IsNil() { + v2 = reflect.ValueOf(v2.Elem().Interface()) + } + + out = append(out, v2.Interface()) + } + } + } + + // remove trailing nil pointers + tailIdx := len(out) + for i := len(out) - 1; i >= 0; i-- { + val := reflect.ValueOf(out[i]) + if val.Kind() != reflect.Ptr || !val.IsNil() { + break + } + tailIdx = i + } + return out[:tailIdx] +} + +func objIsSlice(in interface{}) bool { + if in == nil { + return false + } + k := reflect.TypeOf(in).Kind() + return k == reflect.Slice || k == reflect.Array +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/writer.go b/vendor/github.com/jedib0t/go-pretty/v6/table/writer.go index f993d8675..51eee8c72 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/table/writer.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/table/writer.go @@ -11,7 +11,9 @@ type Writer interface { AppendRow(row Row, configs ...RowConfig) AppendRows(rows []Row, configs ...RowConfig) AppendSeparator() + ImportGrid(grid interface{}) bool Length() int + Pager(opts ...PagerOption) Pager Render() string RenderCSV() string RenderHTML() string @@ -20,14 +22,12 @@ type Writer interface { ResetFooters() ResetHeaders() ResetRows() - SetAllowedRowLength(length int) SetAutoIndex(autoIndex bool) SetCaption(format string, a ...interface{}) SetColumnConfigs(configs []ColumnConfig) SetIndexColumn(colNum int) SetOutputMirror(mirror io.Writer) - SetPageSize(numLines int) - SetRowPainter(painter RowPainter) + SetRowPainter(painter interface{}) SetStyle(style Style) SetTitle(format string, a ...interface{}) SortBy(sortBy []SortBy) @@ -35,8 +35,12 @@ type Writer interface { SuppressEmptyColumns() SuppressTrailingSpaces() + // deprecated; in favor if Style().Size.WidthMax + SetAllowedRowLength(length int) // deprecated; in favor of Style().HTML.CSSClass SetHTMLCSSClass(cssClass string) + // deprecated; in favor of Pager() + SetPageSize(numLines int) } // NewWriter initializes and returns a Writer. diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/align.go b/vendor/github.com/jedib0t/go-pretty/v6/text/align.go index 2a1068a86..189531dc6 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/align.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/align.go @@ -40,7 +40,7 @@ func (a Align) Apply(text string, maxLength int) string { text = aComputed.trimString(text) sLen := utf8.RuneCountInString(text) - sLenWoE := RuneWidthWithoutEscSequences(text) + sLenWoE := StringWidthWithoutEscSequences(text) numEscChars := sLen - sLenWoE // now, align the text diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go b/vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go index 6a396b1e6..6f13b656a 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/ansi.go @@ -39,7 +39,7 @@ func Escape(str string, escapeSeq string) string { // 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(RuneWidthWithoutEscSequences(str)) + out.Grow(StringWidthWithoutEscSequences(str)) isEscSeq := false for _, sChr := range str { diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/direction.go b/vendor/github.com/jedib0t/go-pretty/v6/text/direction.go index 25eccc21f..d0a74f183 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/direction.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/direction.go @@ -11,14 +11,19 @@ const ( RightToLeft ) +const ( + RuneL2R = '\u202a' + RuneR2L = '\u202b' +) + // Modifier returns a character to force the given direction for the text that // follows the modifier. func (d Direction) Modifier() string { switch d { case LeftToRight: - return "\u202a" + return string(RuneL2R) case RightToLeft: - return "\u202b" + return string(RuneR2L) } return "" } diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/escape.go b/vendor/github.com/jedib0t/go-pretty/v6/text/escape.go deleted file mode 100644 index abccef75e..000000000 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/escape.go +++ /dev/null @@ -1,50 +0,0 @@ -package text - -import "strings" - -// Constants -const ( - CSIStartRune = rune(91) // [ - CSIStopRune = 'm' - EscapeReset = EscapeStart + "0" + EscapeStop - EscapeStart = "\x1b[" - EscapeStartRune = rune(27) // \x1b - EscapeStop = "m" - EscapeStopRune = 'm' - OSIStartRune = rune(93) // ] - OSIStopRune = '\\' -) - -type escKind int - -const ( - escKindUnknown escKind = iota - escKindCSI - escKindOSI -) - -type escSeq struct { - isIn bool - content strings.Builder - kind escKind -} - -func (e *escSeq) InspectRune(r rune) { - if !e.isIn && r == EscapeStartRune { - e.isIn = true - e.kind = escKindUnknown - e.content.Reset() - e.content.WriteRune(r) - } else if e.isIn { - switch { - case e.kind == escKindUnknown && r == CSIStartRune: - e.kind = escKindCSI - case e.kind == escKindUnknown && r == OSIStartRune: - e.kind = escKindOSI - case e.kind == escKindCSI && r == CSIStopRune || e.kind == escKindOSI && r == OSIStopRune: - e.isIn = false - e.kind = escKindUnknown - } - e.content.WriteRune(r) - } -} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go b/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go new file mode 100644 index 000000000..ab618acce --- /dev/null +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go @@ -0,0 +1,201 @@ +package text + +import ( + "fmt" + "sort" + "strconv" + "strings" +) + +// Constants +const ( + EscapeReset = EscapeResetCSI + EscapeResetCSI = EscapeStartCSI + "0" + EscapeStopCSI + EscapeResetOSI = EscapeStartOSI + "0" + EscapeStopOSI + EscapeStart = EscapeStartCSI + EscapeStartCSI = "\x1b[" + EscapeStartOSI = "\x1b]" + EscapeStartRune = rune(27) // \x1b + EscapeStartRuneCSI = '[' // [ + EscapeStartRuneOSI = ']' // ] + EscapeStop = EscapeStopCSI + EscapeStopCSI = "m" + EscapeStopOSI = "\\" + EscapeStopRune = EscapeStopRuneCSI + EscapeStopRuneCSI = 'm' + EscapeStopRuneOSI = '\\' +) + +// Deprecated Constants +const ( + CSIStartRune = EscapeStartRuneCSI + CSIStopRune = EscapeStopRuneCSI + OSIStartRune = EscapeStartRuneOSI + OSIStopRune = EscapeStopRuneOSI +) + +type escSeqKind int + +const ( + escSeqKindUnknown escSeqKind = iota + escSeqKindCSI + escSeqKindOSI +) + +type escSeqParser struct { + codes map[int]bool + + // consume specific + inEscSeq bool + escSeqKind escSeqKind + escapeSeq string +} + +func (s *escSeqParser) Codes() []int { + codes := make([]int, 0) + for code, val := range s.codes { + if val { + codes = append(codes, code) + } + } + sort.Ints(codes) + return codes +} + +func (s *escSeqParser) Consume(char rune) { + if !s.inEscSeq && char == EscapeStartRune { + s.inEscSeq = true + s.escSeqKind = escSeqKindUnknown + s.escapeSeq = "" + } else if s.inEscSeq && s.escSeqKind == escSeqKindUnknown { + if char == EscapeStartRuneCSI { + s.escSeqKind = escSeqKindCSI + } else if char == EscapeStartRuneOSI { + s.escSeqKind = escSeqKindOSI + } + } + + if s.inEscSeq { + s.escapeSeq += string(char) + + if s.isEscapeStopRune(char) { + s.ParseSeq(s.escapeSeq, s.escSeqKind) + s.Reset() + } + } +} + +func (s *escSeqParser) InSequence() bool { + return s.inEscSeq +} + +func (s *escSeqParser) IsOpen() bool { + return len(s.codes) > 0 +} + +func (s *escSeqParser) Reset() { + s.inEscSeq = false + s.escSeqKind = escSeqKindUnknown + s.escapeSeq = "" +} + +const ( + escCodeResetAll = 0 + escCodeResetIntensity = 22 + escCodeResetItalic = 23 + escCodeResetUnderline = 24 + escCodeResetBlink = 25 + escCodeResetReverse = 27 + escCodeResetCrossedOut = 29 + escCodeBold = 1 + escCodeDim = 2 + escCodeItalic = 3 + escCodeUnderline = 4 + escCodeBlinkSlow = 5 + escCodeBlinkRapid = 6 + escCodeReverse = 7 + escCodeConceal = 8 + escCodeCrossedOut = 9 +) + +func (s *escSeqParser) ParseSeq(seq string, seqKind escSeqKind) { + if s.codes == nil { + s.codes = make(map[int]bool) + } + + if seqKind == escSeqKindOSI { + seq = strings.Replace(seq, EscapeStartOSI, "", 1) + seq = strings.Replace(seq, EscapeStopOSI, "", 1) + } else { // escSeqKindCSI + seq = strings.Replace(seq, EscapeStartCSI, "", 1) + seq = strings.Replace(seq, EscapeStopCSI, "", 1) + } + + codes := strings.Split(seq, ";") + for _, code := range codes { + code = strings.TrimSpace(code) + if codeNum, err := strconv.Atoi(code); err == nil { + switch codeNum { + case escCodeResetAll: + s.codes = make(map[int]bool) // clear everything + case escCodeResetIntensity: + delete(s.codes, escCodeBold) + delete(s.codes, escCodeDim) + case escCodeResetItalic: + delete(s.codes, escCodeItalic) + case escCodeResetUnderline: + delete(s.codes, escCodeUnderline) + case escCodeResetBlink: + delete(s.codes, escCodeBlinkSlow) + delete(s.codes, escCodeBlinkRapid) + case escCodeResetReverse: + delete(s.codes, escCodeReverse) + case escCodeResetCrossedOut: + delete(s.codes, escCodeCrossedOut) + default: + s.codes[codeNum] = true + } + } + } +} + +func (s *escSeqParser) ParseString(str string) string { + s.escapeSeq, s.inEscSeq, s.escSeqKind = "", false, escSeqKindUnknown + for _, char := range str { + s.Consume(char) + } + return s.Sequence() +} + +func (s *escSeqParser) Sequence() string { + out := strings.Builder{} + if s.IsOpen() { + out.WriteString(EscapeStart) + for idx, code := range s.Codes() { + if idx > 0 { + out.WriteRune(';') + } + out.WriteString(fmt.Sprint(code)) + } + out.WriteString(EscapeStop) + } + + return out.String() +} + +const ( + escapeStartConcealOSI = "\x1b]8;" + escapeStopConcealOSI = "\x1b\\" +) + +func (s *escSeqParser) isEscapeStopRune(char rune) bool { + if strings.HasPrefix(s.escapeSeq, escapeStartConcealOSI) { + if strings.HasSuffix(s.escapeSeq, escapeStopConcealOSI) { + return true + } + } else if (s.escSeqKind == escSeqKindCSI && char == EscapeStopRuneCSI) || + (s.escSeqKind == escSeqKindOSI && char == EscapeStopRuneOSI) { + return true + } + return false +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go index dbc32425e..fa28a4c03 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go @@ -5,6 +5,7 @@ import ( "unicode/utf8" "github.com/mattn/go-runewidth" + "golang.org/x/text/width" ) // RuneWidth stuff @@ -24,22 +25,22 @@ func InsertEveryN(str string, runeToInsert rune, n int) string { return str } - sLen := RuneWidthWithoutEscSequences(str) + sLen := StringWidthWithoutEscSequences(str) var out strings.Builder out.Grow(sLen + (sLen / n)) - outLen, eSeq := 0, escSeq{} + outLen, esp := 0, escSeqParser{} for idx, c := range str { - if eSeq.isIn { - eSeq.InspectRune(c) + if esp.InSequence() { + esp.Consume(c) out.WriteRune(c) continue } - eSeq.InspectRune(c) - if !eSeq.isIn && outLen > 0 && (outLen%n) == 0 && idx != sLen { + esp.Consume(c) + if !esp.InSequence() && outLen > 0 && (outLen%n) == 0 && idx != sLen { out.WriteRune(runeToInsert) } out.WriteRune(c) - if !eSeq.isIn { + if !esp.InSequence() { outLen += RuneWidth(c) } } @@ -51,19 +52,21 @@ func InsertEveryN(str string, runeToInsert rune, n int) string { // // LongestLineLen("Ghost!\nCome back here!\nRight now!") == 15 func LongestLineLen(str string) int { - maxLength, currLength, eSeq := 0, 0, escSeq{} + maxLength, currLength, esp := 0, 0, escSeqParser{} + //fmt.Println(str) for _, c := range str { - if eSeq.isIn { - eSeq.InspectRune(c) + //fmt.Printf("%03d | %03d | %c | %5v | %v | %#v\n", idx, c, c, esp.inEscSeq, esp.Codes(), esp.escapeSeq) + if esp.InSequence() { + esp.Consume(c) continue } - eSeq.InspectRune(c) + esp.Consume(c) if c == '\n' { if currLength > maxLength { maxLength = currLength } currLength = 0 - } else if !eSeq.isIn { + } else if !esp.InSequence() { currLength += RuneWidth(c) } } @@ -100,7 +103,7 @@ func OverrideRuneWidthEastAsianWidth(val bool) { // Pad("Ghost", 7, ' ') == "Ghost " // Pad("Ghost", 10, '.') == "Ghost....." func Pad(str string, maxLen int, paddingChar rune) string { - strLen := RuneWidthWithoutEscSequences(str) + strLen := StringWidthWithoutEscSequences(str) if strLen < maxLen { str += strings.Repeat(string(paddingChar), maxLen-strLen) } @@ -178,7 +181,7 @@ func RepeatAndTrim(str string, maxRunes int) string { // // Deprecated: in favor of RuneWidthWithoutEscSequences func RuneCount(str string) int { - return RuneWidthWithoutEscSequences(str) + return StringWidthWithoutEscSequences(str) } // RuneWidth returns the mostly accurate character-width of the rune. This is @@ -201,19 +204,10 @@ func RuneWidth(r rune) int { // RuneWidthWithoutEscSequences("Ghost") == 5 // RuneWidthWithoutEscSequences("\x1b[33mGhost\x1b[0m") == 5 // RuneWidthWithoutEscSequences("\x1b[33mGhost\x1b[0") == 5 +// +// deprecated: use StringWidthWithoutEscSequences instead func RuneWidthWithoutEscSequences(str string) int { - count, eSeq := 0, escSeq{} - for _, c := range str { - if eSeq.isIn { - eSeq.InspectRune(c) - continue - } - eSeq.InspectRune(c) - if !eSeq.isIn { - count += RuneWidth(c) - } - } - return count + return StringWidthWithoutEscSequences(str) } // Snip returns the given string with a fixed length. For ex.: @@ -226,15 +220,48 @@ func RuneWidthWithoutEscSequences(str string) int { // Snip("\x1b[33mGhost\x1b[0m", 7, "~") == "\x1b[33mGhost\x1b[0m " func Snip(str string, length int, snipIndicator string) string { if length > 0 { - lenStr := RuneWidthWithoutEscSequences(str) + lenStr := StringWidthWithoutEscSequences(str) if lenStr > length { - lenStrFinal := length - RuneWidthWithoutEscSequences(snipIndicator) + lenStrFinal := length - StringWidthWithoutEscSequences(snipIndicator) return Trim(str, lenStrFinal) + snipIndicator } } return str } +// StringWidth is similar to RuneWidth, except it works on a string. For +// ex.: +// +// StringWidth("Ghost 生命"): 10 +// StringWidth("\x1b[33mGhost 生命\x1b[0m"): 19 +func StringWidth(str string) int { + return rwCondition.StringWidth(str) +} + +// StringWidthWithoutEscSequences is similar to RuneWidth, except for the fact +// that it ignores escape sequences while counting. For ex.: +// +// StringWidthWithoutEscSequences("") == 0 +// StringWidthWithoutEscSequences("Ghost") == 5 +// StringWidthWithoutEscSequences("\x1b[33mGhost\x1b[0m") == 5 +// StringWidthWithoutEscSequences("\x1b[33mGhost\x1b[0") == 5 +// StringWidthWithoutEscSequences("Ghost 生命"): 10 +// StringWidthWithoutEscSequences("\x1b[33mGhost 生命\x1b[0m"): 10 +func StringWidthWithoutEscSequences(str string) int { + count, esp := 0, escSeqParser{} + for _, c := range str { + if esp.InSequence() { + esp.Consume(c) + continue + } + esp.Consume(c) + if !esp.InSequence() { + count += RuneWidth(c) + } + } + return count +} + // Trim trims a string to the given length while ignoring escape sequences. For // ex.: // @@ -250,15 +277,15 @@ func Trim(str string, maxLen int) string { var out strings.Builder out.Grow(maxLen) - outLen, eSeq := 0, escSeq{} + outLen, esp := 0, escSeqParser{} for _, sChr := range str { - if eSeq.isIn { - eSeq.InspectRune(sChr) + if esp.InSequence() { + esp.Consume(sChr) out.WriteRune(sChr) continue } - eSeq.InspectRune(sChr) - if eSeq.isIn { + esp.Consume(sChr) + if esp.InSequence() { out.WriteRune(sChr) continue } @@ -270,3 +297,28 @@ func Trim(str string, maxLen int) string { } return out.String() } + +// Widen is like width.Widen.String() but ignores escape sequences. For ex: +// +// Widen("Ghost 生命"): "Ghost\u3000生命" +// Widen("\x1b[33mGhost 生命\x1b[0m"): "\x1b[33mGhost\u3000生命\x1b[0m" +func Widen(str string) string { + sb := strings.Builder{} + sb.Grow(len(str)) + + esp := escSeqParser{} + for _, c := range str { + if esp.InSequence() { + sb.WriteRune(c) + esp.Consume(c) + continue + } + esp.Consume(c) + if !esp.InSequence() { + sb.WriteString(width.Widen.String(string(c))) + } else { + sb.WriteRune(c) + } + } + return sb.String() +} diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go b/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go index a55cb514c..8ad848550 100644 --- a/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go +++ b/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go @@ -2,7 +2,6 @@ package text import ( "strings" - "unicode/utf8" ) // WrapHard wraps a string to the given length using a newline. Handles strings @@ -15,7 +14,7 @@ func WrapHard(str string, wrapLen int) string { return "" } str = strings.Replace(str, "\t", " ", -1) - sLen := utf8.RuneCountInString(str) + sLen := StringWidthWithoutEscSequences(str) if sLen <= wrapLen { return str } @@ -43,7 +42,7 @@ func WrapSoft(str string, wrapLen int) string { return "" } str = strings.Replace(str, "\t", " ", -1) - sLen := utf8.RuneCountInString(str) + sLen := StringWidthWithoutEscSequences(str) if sLen <= wrapLen { return str } @@ -69,32 +68,21 @@ func WrapText(str string, wrapLen int) string { if wrapLen <= 0 { return "" } + str = strings.Replace(str, "\t", " ", -1) + sLen := StringWidthWithoutEscSequences(str) + if sLen <= wrapLen { + return str + } - var out strings.Builder - sLen := utf8.RuneCountInString(str) + out := &strings.Builder{} 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 = "" + for idx, line := range strings.Split(str, "\n") { + if idx > 0 { + out.WriteString("\n") } + wrapHard(line, wrapLen, out) } - if lastEscSeq != "" && lastEscSeq != EscapeReset { - out.WriteString(EscapeReset) - } + return out.String() } @@ -122,7 +110,7 @@ func appendChar(char rune, wrapLen int, lineLen *int, inEscSeq bool, lastSeenEsc // increment the line index if not in the middle of an escape sequence if !inEscSeq { - *lineLen++ + *lineLen += RuneWidth(char) } } } @@ -149,26 +137,6 @@ func appendWord(word string, lineIdx *int, lastSeenEscSeq string, wrapLen int, o } } -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)) @@ -189,19 +157,19 @@ func terminateOutput(lastSeenEscSeq string, out *strings.Builder) { } func wrapHard(paragraph string, wrapLen int, out *strings.Builder) { + esp := escSeqParser{} lineLen, lastSeenEscSeq := 0, "" words := strings.Fields(paragraph) for wordIdx, word := range words { - escSeq := extractOpenEscapeSeq(word) - if escSeq != "" { - lastSeenEscSeq = escSeq + if openEscSeq := esp.ParseString(word); openEscSeq != "" { + lastSeenEscSeq = openEscSeq } if lineLen > 0 { out.WriteRune(' ') lineLen++ } - wordLen := RuneWidthWithoutEscSequences(word) + wordLen := StringWidthWithoutEscSequences(word) if lineLen+wordLen <= wrapLen { // word fits within the line out.WriteString(word) lineLen += wordLen @@ -218,16 +186,16 @@ func wrapHard(paragraph string, wrapLen int, out *strings.Builder) { } func wrapSoft(paragraph string, wrapLen int, out *strings.Builder) { + esp := escSeqParser{} lineLen, lastSeenEscSeq := 0, "" words := strings.Fields(paragraph) for wordIdx, word := range words { - escSeq := extractOpenEscapeSeq(word) - if escSeq != "" { - lastSeenEscSeq = escSeq + if openEscSeq := esp.ParseString(word); openEscSeq != "" { + lastSeenEscSeq = openEscSeq } spacing, spacingLen := wrapSoftSpacing(lineLen) - wordLen := RuneWidthWithoutEscSequences(word) + wordLen := StringWidthWithoutEscSequences(word) if lineLen+spacingLen+wordLen <= wrapLen { // word fits within the line out.WriteString(spacing) out.WriteString(word) diff --git a/vendor/modules.txt b/vendor/modules.txt index 758f557ce..23a741330 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -293,7 +293,7 @@ github.com/imdario/mergo # github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 ## explicit github.com/jaytaylor/html2text -# github.com/jedib0t/go-pretty/v6 v6.5.9 +# github.com/jedib0t/go-pretty/v6 v6.6.5 ## explicit; go 1.17 github.com/jedib0t/go-pretty/v6/table github.com/jedib0t/go-pretty/v6/text