From f4eaa8bd5b4d2c1d2025890263aa0dabf4d5debb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 18:29:04 +0000 Subject: [PATCH] build(deps): bump github.com/olekukonko/tablewriter from 1.0.9 to 1.1.0 Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 1.0.9 to 1.1.0. - [Commits](https://github.com/olekukonko/tablewriter/compare/v1.0.9...v1.1.0) --- updated-dependencies: - dependency-name: github.com/olekukonko/tablewriter dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../olekukonko/tablewriter/.golangci.yml | 55 +++++++ .../olekukonko/tablewriter/README.md | 8 +- .../olekukonko/tablewriter/config.go | 7 +- .../olekukonko/tablewriter/option.go | 52 +++++-- .../tablewriter/pkg/twwidth/width.go | 18 +-- .../tablewriter/renderer/blueprint.go | 44 +++--- .../tablewriter/renderer/colorized.go | 36 ++--- .../olekukonko/tablewriter/renderer/fn.go | 4 +- .../olekukonko/tablewriter/renderer/html.go | 5 +- .../tablewriter/renderer/markdown.go | 34 ++--- .../olekukonko/tablewriter/renderer/ocean.go | 26 ++-- .../olekukonko/tablewriter/renderer/svg.go | 15 +- .../olekukonko/tablewriter/stream.go | 21 +-- .../olekukonko/tablewriter/tablewriter.go | 136 +++++++++++------- .../olekukonko/tablewriter/tw/cell.go | 1 - .../olekukonko/tablewriter/tw/fn.go | 18 ++- .../olekukonko/tablewriter/tw/mapper.go | 26 ++-- .../olekukonko/tablewriter/tw/preset.go | 9 +- .../olekukonko/tablewriter/tw/renderer.go | 3 +- .../olekukonko/tablewriter/tw/slicer.go | 39 ++--- .../olekukonko/tablewriter/tw/types.go | 35 ++++- .../github.com/olekukonko/tablewriter/zoo.go | 70 ++++----- vendor/modules.txt | 2 +- 25 files changed, 387 insertions(+), 283 deletions(-) create mode 100644 vendor/github.com/olekukonko/tablewriter/.golangci.yml diff --git a/go.mod b/go.mod index 605ae0d13b..982d25d175 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/nats-io/nats-server/v2 v2.12.0 github.com/nats-io/nats.go v1.46.0 github.com/oklog/run v1.2.0 - github.com/olekukonko/tablewriter v1.0.9 + github.com/olekukonko/tablewriter v1.1.0 github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 diff --git a/go.sum b/go.sum index 8157db24d1..e5deba5ae5 100644 --- a/go.sum +++ b/go.sum @@ -914,8 +914,8 @@ github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXI github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= -github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY= +github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= diff --git a/vendor/github.com/olekukonko/tablewriter/.golangci.yml b/vendor/github.com/olekukonko/tablewriter/.golangci.yml new file mode 100644 index 0000000000..5e3cc48c27 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/.golangci.yml @@ -0,0 +1,55 @@ +# See for configurations: https://golangci-lint.run/usage/configuration/ +version: 2 +# See: https://golangci-lint.run/usage/formatters/ +formatters: + default: none + enable: + - gofmt # https://pkg.go.dev/cmd/gofmt + - gofumpt # https://github.com/mvdan/gofumpt + + settings: + gofmt: + simplify: true # Simplify code: gofmt with `-s` option. + + gofumpt: + # Module path which contains the source code being formatted. + # Default: "" + module-path: github.com/olekukonko/tablewriter # Should match with module in go.mod + # Choose whether to use the extra rules. + # Default: false + extra-rules: true + +# See: https://golangci-lint.run/usage/linters/ +linters: + default: none + enable: + - staticcheck + - govet + - gocritic + # - unused # TODO: There are many unused functions, should I directly remove those ? + - ineffassign + - unconvert + - mirror + - usestdlibvars + - loggercheck + - exptostd + - godot + - perfsprint + + # See: https://golangci-lint.run/usage/false-positives/ + exclusion: + # paths: + # rules: + + settings: + staticcheck: + checks: + - all + - "-SA1019" # disabled because it warns about deprecated: kept for compatibility will be removed soon + - "-ST1019" # disabled because it warns about deprecated: kept for compatibility will be removed soon + - "-ST1021" # disabled because it warns to have comment on exported packages + - "-ST1000" # disabled because it warns to have comment on exported functions + - "-ST1020" # disabled because it warns to have at least one file in a package should have a package comment + + godot: + period: false diff --git a/vendor/github.com/olekukonko/tablewriter/README.md b/vendor/github.com/olekukonko/tablewriter/README.md index 2ce07851be..16d288233d 100644 --- a/vendor/github.com/olekukonko/tablewriter/README.md +++ b/vendor/github.com/olekukonko/tablewriter/README.md @@ -28,7 +28,7 @@ go get github.com/olekukonko/tablewriter@v0.0.5 #### Latest Version The latest stable version ```bash -go get github.com/olekukonko/tablewriter@v1.0.9 +go get github.com/olekukonko/tablewriter@v1.1.0 ``` **Warning:** Version `v1.0.0` contains missing functionality and should not be used. @@ -62,7 +62,7 @@ func main() { data := [][]string{ {"Package", "Version", "Status"}, {"tablewriter", "v0.0.5", "legacy"}, - {"tablewriter", "v1.0.9", "latest"}, + {"tablewriter", "v1.1.0", "latest"}, } table := tablewriter.NewWriter(os.Stdout) @@ -77,7 +77,7 @@ func main() { │ PACKAGE │ VERSION │ STATUS │ ├─────────────┼─────────┼────────┤ │ tablewriter │ v0.0.5 │ legacy │ -│ tablewriter │ v1.0.9 │ latest │ +│ tablewriter │ v1.1.0 │ latest │ └─────────────┴─────────┴────────┘ ``` @@ -1081,6 +1081,8 @@ func (t Time) Format() string { - `AutoFormat` changes See [#261](https://github.com/olekukonko/tablewriter/issues/261) +## What is new +- `Counting` changes See [#294](https://github.com/olekukonko/tablewriter/issues/294) ## Command-Line Tool diff --git a/vendor/github.com/olekukonko/tablewriter/config.go b/vendor/github.com/olekukonko/tablewriter/config.go index 93f7fa34dc..ddad9bd188 100644 --- a/vendor/github.com/olekukonko/tablewriter/config.go +++ b/vendor/github.com/olekukonko/tablewriter/config.go @@ -14,6 +14,7 @@ type Config struct { Stream tw.StreamConfig Behavior tw.Behavior Widths tw.CellWidth + Counter tw.Counter } // ConfigBuilder provides a fluent interface for building Config @@ -199,11 +200,7 @@ func (b *ConfigBuilder) WithHeaderMergeMode(mergeMode int) *ConfigBuilder { // WithMaxWidth sets the maximum width for the entire table (0 means unlimited). // Negative values are treated as 0. func (b *ConfigBuilder) WithMaxWidth(width int) *ConfigBuilder { - if width < 0 { - b.config.MaxWidth = 0 - } else { - b.config.MaxWidth = width - } + b.config.MaxWidth = max(width, 0) return b } diff --git a/vendor/github.com/olekukonko/tablewriter/option.go b/vendor/github.com/olekukonko/tablewriter/option.go index f1ea70b184..2c1f3a2c15 100644 --- a/vendor/github.com/olekukonko/tablewriter/option.go +++ b/vendor/github.com/olekukonko/tablewriter/option.go @@ -1,11 +1,12 @@ package tablewriter import ( + "reflect" + "github.com/mattn/go-runewidth" "github.com/olekukonko/ll" "github.com/olekukonko/tablewriter/pkg/twwidth" "github.com/olekukonko/tablewriter/tw" - "reflect" ) // Option defines a function type for configuring a Table instance. @@ -498,6 +499,17 @@ func WithTrimSpace(state tw.State) Option { } } +// WithTrimLine sets whether empty visual lines within a cell are trimmed. +// Logs the change if debugging is enabled. +func WithTrimLine(state tw.State) Option { + return func(target *Table) { + target.config.Behavior.TrimLine = state + if target.logger != nil { + target.logger.Debugf("Option: WithTrimLine applied to Table: %v", state) + } + } +} + // WithHeaderAutoFormat enables or disables automatic formatting for header cells. // Logs the change if debugging is enabled. func WithHeaderAutoFormat(state tw.State) Option { @@ -607,10 +619,8 @@ func WithRendition(rendition tw.Rendition) Option { if target.logger != nil { target.logger.Debugf("Option: WithRendition: Applied to renderer via Renditioning.SetRendition(): %+v", rendition) } - } else { - if target.logger != nil { - target.logger.Warnf("Option: WithRendition: Current renderer type %T does not implement tw.Renditioning. Rendition may not be applied as expected.", target.renderer) - } + } else if target.logger != nil { + target.logger.Warnf("Option: WithRendition: Current renderer type %T does not implement tw.Renditioning. Rendition may not be applied as expected.", target.renderer) } } } @@ -654,15 +664,38 @@ func WithSymbols(symbols tw.Symbols) Option { if target.logger != nil { target.logger.Debugf("Option: WithRendition: Applied to renderer via Renditioning.SetRendition(): %+v", cfg) } - } else { - if target.logger != nil { - target.logger.Warnf("Option: WithRendition: Current renderer type %T does not implement tw.Renditioning. Rendition may not be applied as expected.", target.renderer) - } + } else if target.logger != nil { + target.logger.Warnf("Option: WithRendition: Current renderer type %T does not implement tw.Renditioning. Rendition may not be applied as expected.", target.renderer) } } } } +// WithCounters enables line counting by wrapping the table's writer. +// If a custom counter (that implements tw.Counter) is provided, it will be used. +// If the provided counter is nil, a default tw.LineCounter will be used. +// The final count can be retrieved via the table.Lines() method after Render() is called. +func WithCounters(counters ...tw.Counter) Option { + return func(target *Table) { + // Iterate through the provided counters and add any non-nil ones. + for _, c := range counters { + if c != nil { + target.counters = append(target.counters, c) + } + } + } +} + +// WithLineCounter enables the default line counter. +// A new instance of tw.LineCounter is added to the table's list of counters. +// The total count can be retrieved via the table.Lines() method after Render() is called. +func WithLineCounter() Option { + return func(target *Table) { + // Important: Create a new instance so tables don't share counters. + target.counters = append(target.counters, &tw.LineCounter{}) + } +} + // defaultConfig returns a default Config with sensible settings for headers, rows, footers, and behavior. func defaultConfig() Config { return Config{ @@ -717,6 +750,7 @@ func defaultConfig() Config { Behavior: tw.Behavior{ AutoHide: tw.Off, TrimSpace: tw.On, + TrimLine: tw.On, Structs: tw.Struct{ AutoHeader: tw.Off, Tags: []string{"json", "db"}, diff --git a/vendor/github.com/olekukonko/tablewriter/pkg/twwidth/width.go b/vendor/github.com/olekukonko/tablewriter/pkg/twwidth/width.go index d46ce4a882..3b9634b026 100644 --- a/vendor/github.com/olekukonko/tablewriter/pkg/twwidth/width.go +++ b/vendor/github.com/olekukonko/tablewriter/pkg/twwidth/width.go @@ -2,10 +2,11 @@ package twwidth import ( "bytes" - "github.com/mattn/go-runewidth" "regexp" "strings" "sync" + + "github.com/mattn/go-runewidth" ) // condition holds the global runewidth configuration, including East Asian width settings. @@ -35,15 +36,15 @@ var widthCache map[cacheKey]int // including CSI (Control Sequence Introducer) and OSC (Operating System Command) sequences. // The returned regex can be used to strip ANSI codes from strings. func Filter() *regexp.Regexp { - var regESC = "\x1b" // ASCII escape character - var regBEL = "\x07" // ASCII bell character + regESC := "\x1b" // ASCII escape character + regBEL := "\x07" // ASCII bell character // ANSI string terminator: either ESC+\ or BEL - var regST = "(" + regexp.QuoteMeta(regESC+"\\") + "|" + regexp.QuoteMeta(regBEL) + ")" + regST := "(" + regexp.QuoteMeta(regESC+"\\") + "|" + regexp.QuoteMeta(regBEL) + ")" // Control Sequence Introducer (CSI): ESC[ followed by parameters and a final byte - var regCSI = regexp.QuoteMeta(regESC+"[") + "[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]" + regCSI := regexp.QuoteMeta(regESC+"[") + "[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]" // Operating System Command (OSC): ESC] followed by arbitrary content until a terminator - var regOSC = regexp.QuoteMeta(regESC+"]") + ".*?" + regST + regOSC := regexp.QuoteMeta(regESC+"]") + ".*?" + regST // Combine CSI and OSC patterns into a single regex return regexp.MustCompile("(" + regCSI + "|" + regOSC + ")") @@ -257,11 +258,12 @@ func Truncate(s string, maxWidth int, suffix ...string) string { terminated := false if seqLen >= 2 { introducer := seqBytes[1] - if introducer == '[' { + switch introducer { + case '[': if seqLen >= 3 && r >= 0x40 && r <= 0x7E { terminated = true } - } else if introducer == ']' { + case ']': if r == '\x07' { terminated = true } else if seqLen > 1 && seqBytes[seqLen-2] == '\x1b' && r == '\\' { // Check for ST: \x1b\ diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/blueprint.go b/vendor/github.com/olekukonko/tablewriter/renderer/blueprint.go index 8cfb2a1920..48638fb23e 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/blueprint.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/blueprint.go @@ -1,11 +1,12 @@ package renderer import ( - "github.com/olekukonko/ll" - "github.com/olekukonko/tablewriter/pkg/twwidth" "io" "strings" + "github.com/olekukonko/ll" + "github.com/olekukonko/tablewriter/pkg/twwidth" + "github.com/olekukonko/tablewriter/tw" ) @@ -283,7 +284,7 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al leftPadChar := padding.Left rightPadChar := padding.Right - //if f.config.Settings.Cushion.Enabled() || f.config.Settings.Cushion.Default() { + // if f.config.Settings.Cushion.Enabled() || f.config.Settings.Cushion.Default() { // if leftPadChar == tw.Empty { // leftPadChar = tw.Space // } @@ -297,10 +298,7 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al padRightWidth := twwidth.Width(rightPadChar) // Calculate available width for content - availableContentWidth := width - padLeftWidth - padRightWidth - if availableContentWidth < 0 { - availableContentWidth = 0 - } + availableContentWidth := max(width-padLeftWidth-padRightWidth, 0) f.logger.Debugf("Available content width: %d", availableContentWidth) // Truncate content if it exceeds available width @@ -311,10 +309,7 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al } // Calculate total padding needed - totalPaddingWidth := width - runeWidth - if totalPaddingWidth < 0 { - totalPaddingWidth = 0 - } + totalPaddingWidth := max(width-runeWidth, 0) f.logger.Debugf("Total padding width: %d", totalPaddingWidth) var result strings.Builder @@ -435,7 +430,7 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) { prevWidth := ctx.Row.Widths.Get(colIndex - 1) prevCellCtx, prevOk := ctx.Row.Current[colIndex-1] prevIsHMergeEnd := prevOk && prevCellCtx.Merge.Horizontal.Present && prevCellCtx.Merge.Horizontal.End - if (prevWidth > 0 || prevIsHMergeEnd) && (!ok || !(cellCtx.Merge.Horizontal.Present && !cellCtx.Merge.Horizontal.Start)) { + if (prevWidth > 0 || prevIsHMergeEnd) && (!ok || (!cellCtx.Merge.Horizontal.Present || cellCtx.Merge.Horizontal.Start)) { shouldAddSeparator = true } } @@ -454,10 +449,7 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) { if ctx.Row.Position == tw.Row { dynamicTotalWidth := 0 for k := 0; k < span && colIndex+k < numCols; k++ { - normWidth := ctx.NormalizedWidths.Get(colIndex + k) - if normWidth < 0 { - normWidth = 0 - } + normWidth := max(ctx.NormalizedWidths.Get(colIndex+k), 0) dynamicTotalWidth += normWidth if k > 0 && separatorDisplayWidth > 0 && ctx.NormalizedWidths.Get(colIndex+k) > 0 { dynamicTotalWidth += separatorDisplayWidth @@ -501,21 +493,24 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) { // Set cell padding and alignment padding := cellCtx.Padding align := cellCtx.Align - if align == tw.AlignNone { - if ctx.Row.Position == tw.Header { + switch align { + case tw.AlignNone: + switch ctx.Row.Position { + case tw.Header: align = tw.AlignCenter - } else if ctx.Row.Position == tw.Footer { + case tw.Footer: align = tw.AlignRight - } else { + default: align = tw.AlignLeft } f.logger.Debugf("renderLine: col %d (data: '%s') using renderer default align '%s' for position %s.", colIndex, cellCtx.Data, align, ctx.Row.Position) - } else if align == tw.Skip { - if ctx.Row.Position == tw.Header { + case tw.Skip: + switch ctx.Row.Position { + case tw.Header: align = tw.AlignCenter - } else if ctx.Row.Position == tw.Footer { + case tw.Footer: align = tw.AlignRight - } else { + default: align = tw.AlignLeft } f.logger.Debugf("renderLine: col %d (data: '%s') cellCtx.Align was Skip/empty, falling back to basic default '%s'.", colIndex, cellCtx.Data, align) @@ -587,7 +582,6 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) { func (f *Blueprint) Rendition(config tw.Rendition) { f.config = mergeRendition(f.config, config) f.logger.Debugf("Blueprint.Rendition updated. New config: %+v", f.config) - } // Ensure Blueprint implements tw.Renditioning diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/colorized.go b/vendor/github.com/olekukonko/tablewriter/renderer/colorized.go index 5eaa19248f..9bee749312 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/colorized.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/colorized.go @@ -1,12 +1,13 @@ package renderer import ( + "io" + "strings" + "github.com/fatih/color" "github.com/olekukonko/ll" "github.com/olekukonko/ll/lh" "github.com/olekukonko/tablewriter/pkg/twwidth" - "io" - "strings" "github.com/olekukonko/tablewriter/tw" ) @@ -378,22 +379,19 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al // Set default padding characters padLeftCharStr := padding.Left - if padLeftCharStr == tw.Empty { - padLeftCharStr = tw.Space - } + // if padLeftCharStr == tw.Empty { + // padLeftCharStr = tw.Space + //} padRightCharStr := padding.Right - if padRightCharStr == tw.Empty { - padRightCharStr = tw.Space - } + // if padRightCharStr == tw.Empty { + // padRightCharStr = tw.Space + //} // Calculate padding widths definedPadLeftWidth := twwidth.Width(padLeftCharStr) definedPadRightWidth := twwidth.Width(padRightCharStr) // Calculate available width for content and alignment - availableForContentAndAlign := width - definedPadLeftWidth - definedPadRightWidth - if availableForContentAndAlign < 0 { - availableForContentAndAlign = 0 - } + availableForContentAndAlign := max(width-definedPadLeftWidth-definedPadRightWidth, 0) // Truncate content if it exceeds available width if contentVisualWidth > availableForContentAndAlign { @@ -403,10 +401,7 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al } // Calculate remaining space for alignment - remainingSpaceForAlignment := availableForContentAndAlign - contentVisualWidth - if remainingSpaceForAlignment < 0 { - remainingSpaceForAlignment = 0 - } + remainingSpaceForAlignment := max(availableForContentAndAlign-contentVisualWidth, 0) // Apply alignment padding leftAlignmentPadSpaces := tw.Empty @@ -539,7 +534,7 @@ func (c *Colorized) renderLine(ctx tw.Formatting, line []string, tint Tint) { shouldAddSeparator := false if i > 0 && c.config.Settings.Separators.BetweenColumns.Enabled() { cellCtx, ok := ctx.Row.Current[i] - if !ok || !(cellCtx.Merge.Horizontal.Present && !cellCtx.Merge.Horizontal.Start) { + if !ok || (!cellCtx.Merge.Horizontal.Present || cellCtx.Merge.Horizontal.Start) { shouldAddSeparator = true } } @@ -574,10 +569,7 @@ func (c *Colorized) renderLine(ctx tw.Formatting, line []string, tint Tint) { dynamicTotalWidth := 0 for k := 0; k < span && i+k < numCols; k++ { colToSum := i + k - normWidth := ctx.NormalizedWidths.Get(colToSum) - if normWidth < 0 { - normWidth = 0 - } + normWidth := max(ctx.NormalizedWidths.Get(colToSum), 0) dynamicTotalWidth += normWidth if k > 0 && separatorDisplayWidth > 0 { dynamicTotalWidth += separatorDisplayWidth @@ -633,7 +625,7 @@ func (c *Colorized) renderLine(ctx tw.Formatting, line []string, tint Tint) { } // Override alignment for footer merges or TOTAL pattern if (ctx.Row.Position == tw.Footer && isHMergeStart) || isTotalPattern { - if align != tw.AlignRight { + if align == tw.AlignNone { c.logger.Debugf("renderLine: Applying AlignRight override for Footer HMerge/TOTAL pattern at col %d. Original/default align was: %s", i, align) align = tw.AlignRight } diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/fn.go b/vendor/github.com/olekukonko/tablewriter/renderer/fn.go index 3bda04f4dd..cb6a768bc6 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/fn.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/fn.go @@ -2,6 +2,7 @@ package renderer import ( "fmt" + "github.com/fatih/color" "github.com/olekukonko/tablewriter/tw" ) @@ -82,7 +83,6 @@ func defaultColorized() ColorizedConfig { // defaultOceanRendererConfig returns a base tw.Rendition for the Ocean renderer. func defaultOceanRendererConfig() tw.Rendition { - return tw.Rendition{ Borders: tw.Border{ Left: tw.On, Right: tw.On, Top: tw.On, Bottom: tw.On, @@ -190,7 +190,7 @@ func mergeSettings(defaults, overrides tw.Settings) tw.Settings { defaults.CompactMode = overrides.CompactMode } - //if overrides.Cushion != tw.Unknown { + // if overrides.Cushion != tw.Unknown { // defaults.Cushion = overrides.Cushion //} diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/html.go b/vendor/github.com/olekukonko/tablewriter/renderer/html.go index 62430a171b..d02594b9ce 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/html.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/html.go @@ -3,11 +3,12 @@ package renderer import ( "errors" "fmt" - "github.com/olekukonko/ll" "html" "io" "strings" + "github.com/olekukonko/ll" + "github.com/olekukonko/tablewriter/tw" ) @@ -82,7 +83,7 @@ func (h *HTML) Config() tw.Rendition { } // debugLog appends a formatted message to the debug trace if debugging is enabled. -//func (h *HTML) debugLog(format string, a ...interface{}) { +// func (h *HTML) debugLog(format string, a ...interface{}) { // if h.debug { // msg := fmt.Sprintf(format, a...) // h.trace = append(h.trace, fmt.Sprintf("[HTML] %s", msg)) diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/markdown.go b/vendor/github.com/olekukonko/tablewriter/renderer/markdown.go index a565cc3878..936889de37 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/markdown.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/markdown.go @@ -1,11 +1,12 @@ package renderer import ( - "github.com/olekukonko/ll" - "github.com/olekukonko/tablewriter/pkg/twwidth" "io" "strings" + "github.com/olekukonko/ll" + "github.com/olekukonko/tablewriter/pkg/twwidth" + "github.com/olekukonko/tablewriter/tw" ) @@ -95,7 +96,6 @@ func (m *Markdown) Row(row []string, ctx tw.Formatting) { m.resolveAlignment(ctx) m.logger.Debugf("Rendering row with data=%v, widths=%v, previous=%v, current=%v, next=%v", row, ctx.Row.Widths, ctx.Row.Previous, ctx.Row.Current, ctx.Row.Next) m.renderMarkdownLine(row, ctx, false) - } // Footer renders the Markdown table footer. @@ -155,7 +155,7 @@ func (m *Markdown) resolveAlignment(ctx tw.Formatting) tw.Alignment { // formatCell formats a Markdown cell's content with padding and alignment, ensuring at least 3 characters wide. func (m *Markdown) formatCell(content string, width int, align tw.Align, padding tw.Padding) string { - //if m.config.Settings.TrimWhitespace.Enabled() { + // if m.config.Settings.TrimWhitespace.Enabled() { // content = strings.TrimSpace(content) //} contentVisualWidth := twwidth.Width(content) @@ -177,10 +177,7 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding targetWidth := tw.Max(width, minWidth) // Calculate padding - totalPaddingNeeded := targetWidth - contentVisualWidth - if totalPaddingNeeded < 0 { - totalPaddingNeeded = 0 - } + totalPaddingNeeded := max(targetWidth-contentVisualWidth, 0) var leftPadStr, rightPadStr string switch align { @@ -220,13 +217,14 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding adjNeeded := targetWidth - finalWidth if adjNeeded > 0 { adjStr := strings.Repeat(tw.Space, adjNeeded) - if align == tw.AlignRight { + switch align { + case tw.AlignRight: result = adjStr + result - } else if align == tw.AlignCenter { + case tw.AlignCenter: leftAdj := adjNeeded / 2 rightAdj := adjNeeded - leftAdj result = strings.Repeat(tw.Space, leftAdj) + result + strings.Repeat(tw.Space, rightAdj) - } else { + default: result += adjStr } } else { @@ -346,10 +344,7 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader span = cellCtx.Merge.Horizontal.Span totalWidth := 0 for k := 0; k < span && colIndex+k < numCols; k++ { - colWidth := ctx.NormalizedWidths.Get(colIndex + k) - if colWidth < 0 { - colWidth = 0 - } + colWidth := max(ctx.NormalizedWidths.Get(colIndex+k), 0) totalWidth += colWidth if k > 0 && separatorWidth > 0 { totalWidth += separatorWidth @@ -388,17 +383,18 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader } // For rows, use the header's alignment if specified rowAlign := align - if headerCellCtx, headerOK := ctx.Row.Previous[colIndex]; headerOK && isHeaderSep == false { + if headerCellCtx, headerOK := ctx.Row.Previous[colIndex]; headerOK && !isHeaderSep { if headerCellCtx.Align != tw.AlignNone && headerCellCtx.Align != tw.Empty { rowAlign = headerCellCtx.Align } } if rowAlign == tw.AlignNone || rowAlign == tw.Empty { - if ctx.Row.Position == tw.Header { + switch ctx.Row.Position { + case tw.Header: rowAlign = tw.AlignCenter - } else if ctx.Row.Position == tw.Footer { + case tw.Footer: rowAlign = tw.AlignRight - } else { + default: rowAlign = tw.AlignLeft } m.logger.Debugf("renderMarkdownLine: Col %d using default align '%s'", colIndex, rowAlign) diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/ocean.go b/vendor/github.com/olekukonko/tablewriter/renderer/ocean.go index 7a943e9fdb..230220d26b 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/ocean.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/ocean.go @@ -1,17 +1,18 @@ package renderer import ( - "github.com/olekukonko/tablewriter/pkg/twwidth" "io" + "slices" "strings" + "github.com/olekukonko/tablewriter/pkg/twwidth" + "github.com/olekukonko/ll" "github.com/olekukonko/tablewriter/tw" ) // OceanConfig defines configuration specific to the Ocean renderer. -type OceanConfig struct { -} +type OceanConfig struct{} // Ocean is a streaming table renderer that writes ASCII tables. type Ocean struct { @@ -327,12 +328,9 @@ func (o *Ocean) renderContentLine(ctx tw.Formatting, lineData []string) { idxInMergeSpan := colIdx + k // Check if idxInMergeSpan is a defined column in fixedWidths foundInFixedWidths := false - for _, sortedCIdx_inner := range sortedColIndices { - if sortedCIdx_inner == idxInMergeSpan { - currentMergeTotalRenderWidth += o.fixedWidths.Get(idxInMergeSpan) - foundInFixedWidths = true - break - } + if slices.Contains(sortedColIndices, idxInMergeSpan) { + currentMergeTotalRenderWidth += o.fixedWidths.Get(idxInMergeSpan) + foundInFixedWidths = true } if !foundInFixedWidths && idxInMergeSpan <= sortedColIndices[len(sortedColIndices)-1] { o.logger.Debugf("Col %d in HMerge span not found in fixedWidths, assuming 0-width contribution.", idxInMergeSpan) @@ -407,20 +405,14 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t padLeftDisplayWidth := twwidth.Width(padLeftChar) padRightDisplayWidth := twwidth.Width(padRightChar) - spaceForContentAndAlignment := cellVisualWidth - padLeftDisplayWidth - padRightDisplayWidth - if spaceForContentAndAlignment < 0 { - spaceForContentAndAlignment = 0 - } + spaceForContentAndAlignment := max(cellVisualWidth-padLeftDisplayWidth-padRightDisplayWidth, 0) if contentDisplayWidth > spaceForContentAndAlignment { content = twwidth.Truncate(content, spaceForContentAndAlignment) contentDisplayWidth = twwidth.Width(content) } - remainingSpace := spaceForContentAndAlignment - contentDisplayWidth - if remainingSpace < 0 { - remainingSpace = 0 - } + remainingSpace := max(spaceForContentAndAlignment-contentDisplayWidth, 0) var PL, PR string switch align { diff --git a/vendor/github.com/olekukonko/tablewriter/renderer/svg.go b/vendor/github.com/olekukonko/tablewriter/renderer/svg.go index f49e2d77f4..b725754cf1 100644 --- a/vendor/github.com/olekukonko/tablewriter/renderer/svg.go +++ b/vendor/github.com/olekukonko/tablewriter/renderer/svg.go @@ -2,11 +2,12 @@ package renderer import ( "fmt" - "github.com/olekukonko/ll" "html" "io" "strings" + "github.com/olekukonko/ll" + "github.com/olekukonko/tablewriter/tw" ) @@ -512,10 +513,7 @@ func (s *SVG) renderVisualLine(visualLineData []string, ctx tw.Formatting, posit } s.dataRowCounter++ } else { - parentDataRowStripeIndex := s.dataRowCounter - 1 - if parentDataRowStripeIndex < 0 { - parentDataRowStripeIndex = 0 - } + parentDataRowStripeIndex := max(s.dataRowCounter-1, 0) if s.config.RowAltBG != tw.Empty && parentDataRowStripeIndex%2 != 0 { bgColor = s.config.RowAltBG } else { @@ -623,9 +621,10 @@ func (s *SVG) renderVisualLine(visualLineData []string, ctx tw.Formatting, posit } } textX := currentX + s.config.Padding - if cellTextAnchor == "middle" { + switch cellTextAnchor { + case "middle": textX = currentX + s.config.Padding + (rectWidth-2*s.config.Padding)/2.0 - } else if cellTextAnchor == "end" { + case "end": textX = currentX + rectWidth - s.config.Padding } textY := s.currentY + rectHeight/2.0 @@ -686,7 +685,7 @@ func (s *SVG) Start(w io.Writer) error { func (s *SVG) debug(format string, a ...interface{}) { if s.config.Debug { msg := fmt.Sprintf(format, a...) - s.trace = append(s.trace, fmt.Sprintf("[SVG] %s", msg)) + s.trace = append(s.trace, "[SVG] "+msg) } } diff --git a/vendor/github.com/olekukonko/tablewriter/stream.go b/vendor/github.com/olekukonko/tablewriter/stream.go index d1c6e99f22..a0f2a48973 100644 --- a/vendor/github.com/olekukonko/tablewriter/stream.go +++ b/vendor/github.com/olekukonko/tablewriter/stream.go @@ -1,10 +1,11 @@ package tablewriter import ( + "math" + "github.com/olekukonko/errors" "github.com/olekukonko/tablewriter/pkg/twwidth" "github.com/olekukonko/tablewriter/tw" - "math" ) // Close finalizes the table stream. @@ -92,8 +93,8 @@ func (t *Table) Start() error { return errors.Newf("renderer does not support streaming") } - //t.renderer.Start(t.writer) - //t.renderer.Logger(t.logger) + // t.renderer.Start(t.writer) + // t.renderer.Logger(t.logger) if t.hasPrinted { // Prevent calling Start() multiple times on the same stream instance. @@ -119,7 +120,7 @@ func (t *Table) Start() error { t.streamWidths = t.config.Widths.PerColumn.Clone() // Determine numCols from the highest index in PerColumn map maxColIdx := -1 - t.streamWidths.Each(func(col int, width int) { + t.streamWidths.Each(func(col, width int) { if col > maxColIdx { maxColIdx = col } @@ -331,7 +332,7 @@ func (t *Table) streamAppendRow(row interface{}) error { t.logger.Debug("streamAppendRow: Separator line rendered. Updated lastRenderedPosition to 'separator'.") } else { details := "" - if !(shouldDrawHeaderRowSeparator || shouldDrawRowRowSeparator) { + if !shouldDrawHeaderRowSeparator && !shouldDrawRowRowSeparator { details = "neither header/row nor row/row separator was flagged true" } else if t.lastRenderedPosition == tw.Position("separator") { details = "lastRenderedPosition is already 'separator'" @@ -475,7 +476,7 @@ func (t *Table) streamCalculateWidths(sampling []string, config tw.CellConfig) i determinedNumCols := 0 if t.config.Widths.PerColumn != nil && t.config.Widths.PerColumn.Len() > 0 { maxColIdx := -1 - t.config.Widths.PerColumn.Each(func(col int, width int) { + t.config.Widths.PerColumn.Each(func(col, width int) { if col > maxColIdx { maxColIdx = col } @@ -600,7 +601,7 @@ func (t *Table) streamCalculateWidths(sampling []string, config tw.CellConfig) i if t.config.Widths.Global > 0 && t.streamNumCols > 0 { t.logger.Debug("streamCalculateWidths: Applying global stream width constraint %d", t.config.Widths.Global) currentTotalColumnWidthsSum := 0 - t.streamWidths.Each(func(_ int, w int) { + t.streamWidths.Each(func(_, w int) { currentTotalColumnWidthsSum += w }) @@ -665,7 +666,7 @@ func (t *Table) streamCalculateWidths(sampling []string, config tw.CellConfig) i // Distribute remainingSpace (positive or negative) among non-zero width columns if remainingSpace != 0 && t.streamNumCols > 0 { colsToAdjust := []int{} - t.streamWidths.Each(func(col int, w int) { + t.streamWidths.Each(func(col, w int) { if w > 0 { // Only consider columns that currently have width colsToAdjust = append(colsToAdjust, col) } @@ -689,7 +690,7 @@ func (t *Table) streamCalculateWidths(sampling []string, config tw.CellConfig) i } // Final sanitization - t.streamWidths.Each(func(col int, width int) { + t.streamWidths.Each(func(col, width int) { if width < 0 { t.streamWidths.Set(col, 0) } @@ -858,7 +859,7 @@ func (t *Table) streamRenderFooter(processedFooterLines [][]string) error { // If this is the last line of the last content block (footer), and no bottom border will be drawn, // its Location should be End. isLastLineOfTableContent := (i == totalFooterLines-1) && - !(cfg.Borders.Bottom.Enabled() && cfg.Settings.Lines.ShowBottom.Enabled()) + (!cfg.Borders.Bottom.Enabled() || !cfg.Settings.Lines.ShowBottom.Enabled()) if isLastLineOfTableContent { resp.location = tw.LocationEnd t.logger.Debug("streamRenderFooter: Setting LocationEnd for last footer line as no bottom border will follow.") diff --git a/vendor/github.com/olekukonko/tablewriter/tablewriter.go b/vendor/github.com/olekukonko/tablewriter/tablewriter.go index e96cc93c6b..b15d150341 100644 --- a/vendor/github.com/olekukonko/tablewriter/tablewriter.go +++ b/vendor/github.com/olekukonko/tablewriter/tablewriter.go @@ -2,13 +2,6 @@ package tablewriter import ( "bytes" - "github.com/olekukonko/errors" - "github.com/olekukonko/ll" - "github.com/olekukonko/ll/lh" - "github.com/olekukonko/tablewriter/pkg/twwarp" - "github.com/olekukonko/tablewriter/pkg/twwidth" - "github.com/olekukonko/tablewriter/renderer" - "github.com/olekukonko/tablewriter/tw" "io" "math" "os" @@ -16,11 +9,20 @@ import ( "runtime" "strings" "sync" + + "github.com/olekukonko/errors" + "github.com/olekukonko/ll" + "github.com/olekukonko/ll/lh" + "github.com/olekukonko/tablewriter/pkg/twwarp" + "github.com/olekukonko/tablewriter/pkg/twwidth" + "github.com/olekukonko/tablewriter/renderer" + "github.com/olekukonko/tablewriter/tw" ) // Table represents a table instance with content and rendering capabilities. type Table struct { writer io.Writer // Destination for table output + counters []tw.Counter // Counters for indices rows [][][]string // Row data, supporting multi-line cells headers [][]string // Header content footers [][]string // Footer content @@ -410,7 +412,6 @@ func (t *Table) Footer(elements ...any) { // Parameter opts is a function that modifies the Table struct. // Returns the Table instance for method chaining. func (t *Table) Options(opts ...Option) *Table { - // add logger if t.logger == nil { t.logger = ll.New("table").Handler(lh.NewTextHandler(t.trace)) @@ -423,7 +424,7 @@ func (t *Table) Options(opts ...Option) *Table { // force debugging mode if set // This should be move away form WithDebug - if t.config.Debug == true { + if t.config.Debug { t.logger.Enable() t.logger.Resume() } else { @@ -510,6 +511,28 @@ func (t *Table) Render() error { return t.render() } +// Lines returns the total number of lines rendered. +// This method is only effective if the WithLineCounter() option was used during +// table initialization and must be called *after* Render(). +// It actively searches for the default tw.LineCounter among all active counters. +// It returns -1 if the line counter was not enabled. +func (t *Table) Lines() int { + for _, counter := range t.counters { + if lc, ok := counter.(*tw.LineCounter); ok { + return lc.Total() + } + } + // use -1 to indicate no line counter is attached + return -1 +} + +// Counters returns the slice of all active counter instances. +// This is useful when multiple counters are enabled. +// It must be called *after* Render(). +func (t *Table) Counters() []tw.Counter { + return t.counters +} + // Trimmer trims whitespace from a string based on the Table’s configuration. // It conditionally applies strings.TrimSpace to the input string if the TrimSpace behavior // is enabled in t.config.Behavior, otherwise returning the string unchanged. This method @@ -945,10 +968,7 @@ func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string currentLine := line breakCharWidth := twwidth.Width(tw.CharBreak) for twwidth.Width(currentLine) > effectiveContentMaxWidth { - targetWidth := effectiveContentMaxWidth - breakCharWidth - if targetWidth < 0 { - targetWidth = 0 - } + targetWidth := max(effectiveContentMaxWidth-breakCharWidth, 0) breakPoint := tw.BreakPoint(currentLine, targetWidth) runes := []rune(currentLine) if breakPoint <= 0 || breakPoint > len(runes) { @@ -1362,23 +1382,40 @@ func (t *Table) prepareWithMerges(content [][]string, config tw.CellConfig, posi // No parameters are required. // Returns an error if rendering fails in any section. func (t *Table) render() error { - t.ensureInitialized() + // Save the original writer and schedule its restoration upon function exit. + // This guarantees the table's writer is restored even if errors occur. + originalWriter := t.writer + defer func() { + t.writer = originalWriter + }() + + // If a counter is active, wrap the writer in a MultiWriter. + if len(t.counters) > 0 { + // The slice must be of type io.Writer. + // Start it with the original destination writer. + allWriters := []io.Writer{originalWriter} + + // Append each counter to the slice of writers. + for _, c := range t.counters { + allWriters = append(allWriters, c) + } + + // Create a MultiWriter that broadcasts to the original writer AND all counters. + t.writer = io.MultiWriter(allWriters...) + } + if t.config.Stream.Enable { t.logger.Warn("Render() called in streaming mode. Use Start/Append/Close methods instead.") return errors.New("render called in streaming mode; use Start/Append/Close") } - // Calculate and cache numCols for THIS batch render pass - t.batchRenderNumCols = t.maxColumns() // Calculate ONCE - t.isBatchRenderNumColsSet = true // Mark the cache as active for this render pass - t.logger.Debugf("Render(): Set batchRenderNumCols to %d and isBatchRenderNumColsSet to true.", t.batchRenderNumCols) - + // Calculate and cache the column count for this specific batch render pass. + t.batchRenderNumCols = t.maxColumns() + t.isBatchRenderNumColsSet = true defer func() { t.isBatchRenderNumColsSet = false - // t.batchRenderNumCols = 0; // Optional: reset to 0, or leave as is. - // Since isBatchRenderNumColsSet is false, its value won't be used by getNumColsToUse. t.logger.Debugf("Render(): Cleared isBatchRenderNumColsSet to false (batchRenderNumCols was %d).", t.batchRenderNumCols) }() @@ -1387,9 +1424,10 @@ func (t *Table) render() error { (t.caption.Spot >= tw.SpotTopLeft && t.caption.Spot <= tw.SpotBottomRight) var tableStringBuffer *strings.Builder - targetWriter := t.writer - originalWriter := t.writer // Save original writer for restoration if needed + targetWriter := t.writer // Can be the original writer or the MultiWriter. + // If a caption is present, the main table content must be rendered to an + // in-memory buffer first to calculate its final width. if isTopOrBottomCaption { tableStringBuffer = &strings.Builder{} targetWriter = tableStringBuffer @@ -1398,17 +1436,15 @@ func (t *Table) render() error { t.logger.Debugf("No caption detected. Rendering table core directly to writer.") } - //Render Table Core + // Point the table's writer to the target (either the final destination or the buffer). t.writer = targetWriter ctx, mctx, err := t.prepareContexts() if err != nil { - t.writer = originalWriter t.logger.Errorf("prepareContexts failed: %v", err) return errors.Newf("failed to prepare table contexts").Wrap(err) } if err := ctx.renderer.Start(t.writer); err != nil { - t.writer = originalWriter t.logger.Errorf("Renderer Start() error: %v", err) return errors.Newf("renderer start failed").Wrap(err) } @@ -1440,18 +1476,21 @@ func (t *Table) render() error { renderError = true } - t.writer = originalWriter // Restore original writer + // Restore the writer to the original for the caption-handling logic. + // This is necessary because the caption must be written to the final + // destination, not the temporary buffer used for the table body. + t.writer = originalWriter if renderError { - return firstRenderErr // Return error from core rendering if any + return firstRenderErr } - //Caption Handling & Final Output --- + // Caption Handling & Final Output if isTopOrBottomCaption { renderedTableContent := tableStringBuffer.String() t.logger.Debugf("[Render] Table core buffer length: %d", len(renderedTableContent)) - // Check if the buffer is empty AND borders are enabled + // Handle edge case where table is empty but should have borders. shouldHaveBorders := t.renderer != nil && (t.renderer.Config().Borders.Top.Enabled() || t.renderer.Config().Borders.Bottom.Enabled()) if len(renderedTableContent) == 0 && shouldHaveBorders { var sb strings.Builder @@ -1503,7 +1542,7 @@ func (t *Table) render() error { t.hasPrinted = true t.logger.Info("Render() completed.") - return nil // Success + return nil } // renderFooter renders the table's footer section with borders and padding. @@ -1677,7 +1716,7 @@ func (t *Table) renderFooter(ctx *renderContext, mctx *mergeContext) error { if hasTopPadding { hctx.rowIdx = 0 hctx.lineIdx = -1 - if !(hasContentAbove && cfg.Settings.Lines.ShowFooterLine.Enabled()) { + if !hasContentAbove || !cfg.Settings.Lines.ShowFooterLine.Enabled() { hctx.location = tw.LocationFirst } else { hctx.location = tw.LocationMiddle @@ -1699,7 +1738,7 @@ func (t *Table) renderFooter(ctx *renderContext, mctx *mergeContext) error { hctx.line = padLine(line, ctx.numCols) isFirstContentLine := i == 0 isLastContentLine := i == len(ctx.footerLines)-1 - if isFirstContentLine && !hasTopPadding && !(hasContentAbove && cfg.Settings.Lines.ShowFooterLine.Enabled()) { + if isFirstContentLine && !hasTopPadding && (!hasContentAbove || !cfg.Settings.Lines.ShowFooterLine.Enabled()) { hctx.location = tw.LocationFirst } else if isLastContentLine && !hasBottomPaddingConfig { hctx.location = tw.LocationEnd @@ -1716,7 +1755,7 @@ func (t *Table) renderFooter(ctx *renderContext, mctx *mergeContext) error { if hasBottomPaddingConfig { paddingLineContentForContext = make([]string, ctx.numCols) formattedPaddingCells := make([]string, ctx.numCols) - var representativePadChar string = " " + representativePadChar := " " ctx.logger.Debugf("Constructing Footer Bottom Padding line content strings") for j := 0; j < ctx.numCols; j++ { colWd := ctx.widths[tw.Footer].Get(j) @@ -1741,10 +1780,7 @@ func (t *Table) renderFooter(ctx *renderContext, mctx *mergeContext) error { if j == 0 || representativePadChar == " " { representativePadChar = padChar } - padWidth := twwidth.Width(padChar) - if padWidth < 1 { - padWidth = 1 - } + padWidth := max(twwidth.Width(padChar), 1) repeatCount := 0 if colWd > 0 && padWidth > 0 { repeatCount = colWd / padWidth @@ -2139,19 +2175,21 @@ func (t *Table) renderRow(ctx *renderContext, mctx *mergeContext) error { hctx.lineIdx = j hctx.line = padLine(visualLineData, ctx.numCols) - if j > 0 { - visualLineHasActualContent := false - for kCellIdx, cellContentInVisualLine := range hctx.line { - if t.Trimmer(cellContentInVisualLine) != "" { - visualLineHasActualContent = true - ctx.logger.Debug("Visual line [%d][%d] has content in cell %d: '%s'. Not skipping.", i, j, kCellIdx, cellContentInVisualLine) - break + if t.config.Behavior.TrimLine.Enabled() { + if j > 0 { + visualLineHasActualContent := false + for kCellIdx, cellContentInVisualLine := range hctx.line { + if t.Trimmer(cellContentInVisualLine) != "" { + visualLineHasActualContent = true + ctx.logger.Debug("Visual line [%d][%d] has content in cell %d: '%s'. Not skipping.", i, j, kCellIdx, cellContentInVisualLine) + break + } } - } - if !visualLineHasActualContent { - ctx.logger.Debug("Skipping visual line [%d][%d] as it's entirely blank after trimming. Line: %q", i, j, hctx.line) - continue + if !visualLineHasActualContent { + ctx.logger.Debug("Skipping visual line [%d][%d] as it's entirely blank after trimming. Line: %q", i, j, hctx.line) + continue + } } } diff --git a/vendor/github.com/olekukonko/tablewriter/tw/cell.go b/vendor/github.com/olekukonko/tablewriter/tw/cell.go index 0547f01a4c..47f0962412 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/cell.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/cell.go @@ -12,7 +12,6 @@ type CellFormatting struct { // Deprecated: kept for compatibility // will be removed soon Alignment Align // Text alignment within the cell (e.g., Left, Right, Center) - } // CellPadding defines padding settings for table cells. diff --git a/vendor/github.com/olekukonko/tablewriter/tw/fn.go b/vendor/github.com/olekukonko/tablewriter/tw/fn.go index d962ff8d2b..a8bdeacdfb 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/fn.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/fn.go @@ -3,12 +3,18 @@ package tw import ( + "math" + "strconv" + "strings" + "unicode" + "unicode/utf8" + "github.com/olekukonko/tablewriter/pkg/twwidth" - "math" // For mathematical operations like ceiling - "strconv" // For string-to-number conversions - "strings" // For string manipulation utilities - "unicode" // For Unicode character classification - "unicode/utf8" // For UTF-8 rune handling + // For mathematical operations like ceiling + // For string-to-number conversions + // For string manipulation utilities + // For Unicode character classification + // For UTF-8 rune handling ) // Title normalizes and uppercases a label string for use in headers. @@ -75,7 +81,7 @@ func PadLeft(s, pad string, width int) string { // Pad aligns a string within a specified width using a padding character. // It truncates if the string is wider than the target width. -func Pad(s string, padChar string, totalWidth int, alignment Align) string { +func Pad(s, padChar string, totalWidth int, alignment Align) string { sDisplayWidth := twwidth.Width(s) if sDisplayWidth > totalWidth { return twwidth.Truncate(s, totalWidth) // Only truncate if necessary diff --git a/vendor/github.com/olekukonko/tablewriter/tw/mapper.go b/vendor/github.com/olekukonko/tablewriter/tw/mapper.go index 8d814447ed..058d3589d0 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/mapper.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/mapper.go @@ -114,21 +114,17 @@ func (m Mapper[K, V]) Values() []V { // Each iterates over each key-value pair in the map and calls the provided function. // Does nothing if the map is nil. func (m Mapper[K, V]) Each(fn func(K, V)) { - if m != nil { - for k, v := range m { - fn(k, v) - } + for k, v := range m { + fn(k, v) } } // Filter returns a new Mapper containing only the key-value pairs that satisfy the predicate. func (m Mapper[K, V]) Filter(fn func(K, V) bool) Mapper[K, V] { result := NewMapper[K, V]() - if m != nil { - for k, v := range m { - if fn(k, v) { - result[k] = v - } + for k, v := range m { + if fn(k, v) { + result[k] = v } } return result @@ -137,10 +133,8 @@ func (m Mapper[K, V]) Filter(fn func(K, V) bool) Mapper[K, V] { // MapValues returns a new Mapper with the same keys but values transformed by the provided function. func (m Mapper[K, V]) MapValues(fn func(V) V) Mapper[K, V] { result := NewMapper[K, V]() - if m != nil { - for k, v := range m { - result[k] = fn(v) - } + for k, v := range m { + result[k] = fn(v) } return result } @@ -148,10 +142,8 @@ func (m Mapper[K, V]) MapValues(fn func(V) V) Mapper[K, V] { // Clone returns a shallow copy of the Mapper. func (m Mapper[K, V]) Clone() Mapper[K, V] { result := NewMapper[K, V]() - if m != nil { - for k, v := range m { - result[k] = v - } + for k, v := range m { + result[k] = v } return result } diff --git a/vendor/github.com/olekukonko/tablewriter/tw/preset.go b/vendor/github.com/olekukonko/tablewriter/tw/preset.go index acadc25cbe..5eebc658b3 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/preset.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/preset.go @@ -10,9 +10,6 @@ var ( SeparatorsNone = Separators{ShowHeader: Off, ShowFooter: Off, BetweenRows: Off, BetweenColumns: Off} ) -var ( - - // PaddingDefault represents standard single-space padding on left/right - // Equivalent to Padding{Left: " ", Right: " ", Overwrite: true} - PaddingDefault = Padding{Left: " ", Right: " ", Overwrite: true} -) +// PaddingDefault represents standard single-space padding on left/right +// Equivalent to Padding{Left: " ", Right: " ", Overwrite: true} +var PaddingDefault = Padding{Left: " ", Right: " ", Overwrite: true} diff --git a/vendor/github.com/olekukonko/tablewriter/tw/renderer.go b/vendor/github.com/olekukonko/tablewriter/tw/renderer.go index cf2779b201..dd5e2a94c7 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/renderer.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/renderer.go @@ -1,8 +1,9 @@ package tw import ( - "github.com/olekukonko/ll" "io" + + "github.com/olekukonko/ll" ) // Renderer defines the interface for rendering tables to an io.Writer. diff --git a/vendor/github.com/olekukonko/tablewriter/tw/slicer.go b/vendor/github.com/olekukonko/tablewriter/tw/slicer.go index 34d2463298..692d701f4b 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/slicer.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/slicer.go @@ -1,5 +1,7 @@ package tw +import "slices" + // Slicer is a generic slice type that provides additional methods for slice manipulation. type Slicer[T any] []T @@ -69,21 +71,17 @@ func (s Slicer[T]) Last() T { // Each iterates over each element in the slice and calls the provided function. // Does nothing if the slice is nil. func (s Slicer[T]) Each(fn func(T)) { - if s != nil { - for _, v := range s { - fn(v) - } + for _, v := range s { + fn(v) } } // Filter returns a new Slicer containing only elements that satisfy the predicate. func (s Slicer[T]) Filter(fn func(T) bool) Slicer[T] { result := NewSlicer[T]() - if s != nil { - for _, v := range s { - if fn(v) { - result = result.Append(v) - } + for _, v := range s { + if fn(v) { + result = result.Append(v) } } return result @@ -92,33 +90,22 @@ func (s Slicer[T]) Filter(fn func(T) bool) Slicer[T] { // Map returns a new Slicer with each element transformed by the provided function. func (s Slicer[T]) Map(fn func(T) T) Slicer[T] { result := NewSlicer[T]() - if s != nil { - for _, v := range s { - result = result.Append(fn(v)) - } + for _, v := range s { + result = result.Append(fn(v)) } return result } // Contains returns true if the slice contains an element that satisfies the predicate. func (s Slicer[T]) Contains(fn func(T) bool) bool { - if s != nil { - for _, v := range s { - if fn(v) { - return true - } - } - } - return false + return slices.ContainsFunc(s, fn) } // Find returns the first element that satisfies the predicate, along with a boolean indicating if it was found. func (s Slicer[T]) Find(fn func(T) bool) (T, bool) { - if s != nil { - for _, v := range s { - if fn(v) { - return v, true - } + for _, v := range s { + if fn(v) { + return v, true } } var zero T diff --git a/vendor/github.com/olekukonko/tablewriter/tw/types.go b/vendor/github.com/olekukonko/tablewriter/tw/types.go index c3cef6671f..54a9b86ef8 100644 --- a/vendor/github.com/olekukonko/tablewriter/tw/types.go +++ b/vendor/github.com/olekukonko/tablewriter/tw/types.go @@ -3,9 +3,12 @@ package tw import ( - "fmt" - "github.com/olekukonko/errors" + "bytes" + "io" + "strconv" "strings" + + "github.com/olekukonko/errors" ) // Custom error handling library // Position defines where formatting applies in the table (e.g., header, footer, or rows). @@ -31,6 +34,13 @@ type Formatter interface { Format() string // Returns the formatted string representation } +// Counter defines an interface that combines io.Writer with a method to retrieve a total. +// This is used by the WithCounter option to allow for counting lines, bytes, etc. +type Counter interface { + io.Writer // It must be a writer to be used in io.MultiWriter. + Total() int +} + // Align specifies the text alignment within a table cell. type Align string @@ -52,7 +62,7 @@ func (a Alignment) String() string { if i > 0 { str.WriteString("; ") } - str.WriteString(fmt.Sprint(i)) + str.WriteString(strconv.Itoa(i)) str.WriteString("=") str.WriteString(string(a)) } @@ -157,6 +167,7 @@ type Struct struct { type Behavior struct { AutoHide State // AutoHide determines whether empty columns are hidden. Ignored in streaming mode. TrimSpace State // TrimSpace enables trimming of leading and trailing spaces from cell content. + TrimLine State // TrimLine determines whether empty visual lines within a cell are collapsed. Header Control // Header specifies control settings for the table header. Footer Control // Footer specifies control settings for the table footer. @@ -212,3 +223,21 @@ func (p Padding) Empty() bool { func (p Padding) Paddable() bool { return !p.Empty() || p.Overwrite } + +// LineCounter is the default implementation of the Counter interface. +// It counts the number of newline characters written to it. +type LineCounter struct { + count int +} + +// Write implements the io.Writer interface, counting newlines in the input. +// It uses a pointer receiver to modify the internal count. +func (lc *LineCounter) Write(p []byte) (n int, err error) { + lc.count += bytes.Count(p, []byte{'\n'}) + return len(p), nil +} + +// Total implements the Counter interface, returning the final count. +func (lc *LineCounter) Total() int { + return lc.count +} diff --git a/vendor/github.com/olekukonko/tablewriter/zoo.go b/vendor/github.com/olekukonko/tablewriter/zoo.go index e0fee2cf6d..4c514e9a22 100644 --- a/vendor/github.com/olekukonko/tablewriter/zoo.go +++ b/vendor/github.com/olekukonko/tablewriter/zoo.go @@ -3,14 +3,15 @@ package tablewriter import ( "database/sql" "fmt" - "github.com/olekukonko/errors" - "github.com/olekukonko/tablewriter/pkg/twwidth" - "github.com/olekukonko/tablewriter/tw" "io" "math" "reflect" "strconv" "strings" + + "github.com/olekukonko/errors" + "github.com/olekukonko/tablewriter/pkg/twwidth" + "github.com/olekukonko/tablewriter/tw" ) // applyHierarchicalMerges applies hierarchical merges to row content. @@ -542,10 +543,7 @@ func (t *Table) buildCoreCellContexts(line []string, merges map[int]tw.MergeStat // It generates a []string where each element is the padding content for a column, using the specified padChar. func (t *Table) buildPaddingLineContents(padChar string, widths tw.Mapper[int, int], numCols int, merges map[int]tw.MergeState) []string { line := make([]string, numCols) - padWidth := twwidth.Width(padChar) - if padWidth < 1 { - padWidth = 1 - } + padWidth := max(twwidth.Width(padChar), 1) for j := 0; j < numCols; j++ { mergeState := tw.MergeState{} if merges != nil { @@ -582,9 +580,9 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { ctx.numCols, t.config.Behavior.Compact.Merge.Enabled()) // Initialize width maps - //t.headerWidths = tw.NewMapper[int, int]() - //t.rowWidths = tw.NewMapper[int, int]() - //t.footerWidths = tw.NewMapper[int, int]() + // t.headerWidths = tw.NewMapper[int, int]() + // t.rowWidths = tw.NewMapper[int, int]() + // t.footerWidths = tw.NewMapper[int, int]() // Compute content-based widths for each section for _, lines := range ctx.headerLines { @@ -720,7 +718,7 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { twwidth.Width(headerCellPadding.Left) + twwidth.Width(headerCellPadding.Right) currentSumOfColumnWidths := 0 - workingWidths.Each(func(_ int, w int) { currentSumOfColumnWidths += w }) + workingWidths.Each(func(_, w int) { currentSumOfColumnWidths += w }) numSeparatorsInFullSpan := 0 if ctx.numCols > 1 { if t.renderer != nil && t.renderer.Config().Settings.Separators.BetweenColumns.Enabled() { @@ -733,7 +731,7 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { mergedContentString, actualMergedHeaderContentPhysicalWidth, totalCurrentSpanPhysicalWidth) shortfall := actualMergedHeaderContentPhysicalWidth - totalCurrentSpanPhysicalWidth numNonZeroCols := 0 - workingWidths.Each(func(_ int, w int) { + workingWidths.Each(func(_, w int) { if w > 0 { numNonZeroCols++ } @@ -744,7 +742,7 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { if numNonZeroCols > 0 && shortfall > 0 { extraPerColumn := int(math.Ceil(float64(shortfall) / float64(numNonZeroCols))) finalSumAfterExpansion := 0 - workingWidths.Each(func(colIdx int, currentW int) { + workingWidths.Each(func(colIdx, currentW int) { if currentW > 0 || (numNonZeroCols == ctx.numCols && ctx.numCols > 0) { newWidth := currentW + extraPerColumn workingWidths.Set(colIdx, newWidth) @@ -782,7 +780,7 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { if t.config.Widths.Global > 0 { ctx.logger.Debugf("Applying global width constraint: %d", t.config.Widths.Global) currentSumOfFinalColWidths := 0 - finalWidths.Each(func(_ int, w int) { currentSumOfFinalColWidths += w }) + finalWidths.Each(func(_, w int) { currentSumOfFinalColWidths += w }) numSeparators := 0 if ctx.numCols > 1 && t.renderer != nil && t.renderer.Config().Settings.Separators.BetweenColumns.Enabled() { numSeparators = (ctx.numCols - 1) * twwidth.Width(t.renderer.Config().Symbols.Column()) @@ -790,16 +788,13 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { totalCurrentTablePhysicalWidth := currentSumOfFinalColWidths + numSeparators if totalCurrentTablePhysicalWidth > t.config.Widths.Global { ctx.logger.Debugf("Table width %d exceeds global limit %d. Shrinking.", totalCurrentTablePhysicalWidth, t.config.Widths.Global) - targetTotalColumnContentWidth := t.config.Widths.Global - numSeparators - if targetTotalColumnContentWidth < 0 { - targetTotalColumnContentWidth = 0 - } + targetTotalColumnContentWidth := max(t.config.Widths.Global-numSeparators, 0) if ctx.numCols > 0 && targetTotalColumnContentWidth < ctx.numCols { targetTotalColumnContentWidth = ctx.numCols } hardMinimums := tw.NewMapper[int, int]() sumOfHardMinimums := 0 - isHeaderContentHardToWrap := !(t.config.Header.Formatting.AutoWrap == tw.WrapNormal || t.config.Header.Formatting.AutoWrap == tw.WrapBreak) + isHeaderContentHardToWrap := t.config.Header.Formatting.AutoWrap != tw.WrapNormal && t.config.Header.Formatting.AutoWrap != tw.WrapBreak for i := 0; i < ctx.numCols; i++ { minW := 1 if isHeaderContentHardToWrap && len(ctx.headerLines) > 0 { @@ -820,7 +815,7 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { } tempSum := 0 scaledHardMinimums := tw.NewMapper[int, int]() - hardMinimums.Each(func(colIdx int, currentMinW int) { + hardMinimums.Each(func(colIdx, currentMinW int) { scaledMinW := int(math.Round(float64(currentMinW) * scaleFactorMin)) if scaledMinW < 1 && targetTotalColumnContentWidth > 0 { scaledMinW = 1 @@ -894,31 +889,29 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error { if errorInDist < 0 { adj = -1 } - if !(adj < 0 && w+adj < hardMinimums.Get(colToAdjust)) { + if adj >= 0 || w+adj >= hardMinimums.Get(colToAdjust) { finalWidths.Set(colToAdjust, w+adj) } else if adj > 0 { finalWidths.Set(colToAdjust, w+adj) } } } - } else { - if ctx.numCols > 0 { - extraPerCol := remainingWidthToDistribute / ctx.numCols - rem := remainingWidthToDistribute % ctx.numCols - for i := 0; i < ctx.numCols; i++ { - currentW := finalWidths.Get(i) - add := extraPerCol - if i < rem { - add++ - } - finalWidths.Set(i, currentW+add) + } else if ctx.numCols > 0 { + extraPerCol := remainingWidthToDistribute / ctx.numCols + rem := remainingWidthToDistribute % ctx.numCols + for i := 0; i < ctx.numCols; i++ { + currentW := finalWidths.Get(i) + add := extraPerCol + if i < rem { + add++ } + finalWidths.Set(i, currentW+add) } } } } finalSumCheck := 0 - finalWidths.Each(func(idx int, w int) { + finalWidths.Each(func(idx, w int) { if w < 1 && targetTotalColumnContentWidth > 0 { finalWidths.Set(idx, 1) } else if w < 0 { @@ -945,10 +938,7 @@ func (t *Table) calculateContentMaxWidth(colIdx int, config tw.CellConfig, padLe if isStreaming { // Existing streaming logic remains unchanged - totalColumnWidthFromStream := t.streamWidths.Get(colIdx) - if totalColumnWidthFromStream < 0 { - totalColumnWidthFromStream = 0 - } + totalColumnWidthFromStream := max(t.streamWidths.Get(colIdx), 0) effectiveContentMaxWidth = totalColumnWidthFromStream - padLeftWidth - padRightWidth if effectiveContentMaxWidth < 1 && totalColumnWidthFromStream > (padLeftWidth+padRightWidth) { effectiveContentMaxWidth = 1 @@ -1252,7 +1242,7 @@ func (t *Table) convertCellsToStrings(rowInput interface{}, cellCfg tw.CellConfi var err error switch v := rowInput.(type) { - //Directly supported slice types + // Directly supported slice types case []string: cells = v case []interface{}: // Catches variadic simple types grouped by Append @@ -1338,7 +1328,7 @@ func (t *Table) convertCellsToStrings(rowInput interface{}, cellCfg tw.CellConfi cells[i] = val.String() } - //Cases for single items that are NOT slices + // Cases for single items that are NOT slices // These are now dispatched to convertItemToCells by the default case. // Keeping direct tw.Formatter and fmt.Stringer here could be a micro-optimization // if `rowInput` is *exactly* that type (not a struct implementing it), @@ -1578,7 +1568,7 @@ func (t *Table) processVariadic(elements []any) []any { } // toStringLines converts raw cells to formatted lines for table output -func (t *Table) toStringLines(row interface{}, config tw.CellConfig) ([][]string, error) { +func (t *Table) toStringLines(row any, config tw.CellConfig) ([][]string, error) { cells, err := t.convertCellsToStrings(row, config) if err != nil { return nil, err diff --git a/vendor/modules.txt b/vendor/modules.txt index 6bf22fc80b..42a0c98773 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1165,7 +1165,7 @@ github.com/olekukonko/errors github.com/olekukonko/ll github.com/olekukonko/ll/lh github.com/olekukonko/ll/lx -# github.com/olekukonko/tablewriter v1.0.9 +# github.com/olekukonko/tablewriter v1.1.0 ## explicit; go 1.21 github.com/olekukonko/tablewriter github.com/olekukonko/tablewriter/pkg/twwarp