mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-13 11:57:33 -04:00
build(deps): bump github.com/olekukonko/tablewriter from 1.0.6 to 1.0.7
Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 1.0.6 to 1.0.7. - [Commits](https://github.com/olekukonko/tablewriter/compare/v1.0.6...v1.0.7) --- updated-dependencies: - dependency-name: github.com/olekukonko/tablewriter dependency-version: 1.0.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
4
go.mod
4
go.mod
@@ -58,7 +58,7 @@ require (
|
||||
github.com/nats-io/nats-server/v2 v2.11.4
|
||||
github.com/nats-io/nats.go v1.42.0
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/olekukonko/tablewriter v1.0.6
|
||||
github.com/olekukonko/tablewriter v1.0.7
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
@@ -266,7 +266,7 @@ require (
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 // indirect
|
||||
github.com/olekukonko/ll v0.0.8-0.20250516010636-22ea57d81985 // indirect
|
||||
github.com/olekukonko/ll v0.0.8 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/pablodz/inotifywaitgo v0.0.9 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -844,11 +844,11 @@ github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DV
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 h1:r3FaAI0NZK3hSmtTDrBVREhKULp8oUeqLT5Eyl2mSPo=
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.8-0.20250516010636-22ea57d81985 h1:V2wKiwjwAfRJRtUP6pC7wt4opeF14enO0du2dRV6Llo=
|
||||
github.com/olekukonko/ll v0.0.8-0.20250516010636-22ea57d81985/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/ll v0.0.8 h1:sbGZ1Fx4QxJXEqL/6IG8GEFnYojUSQ45dJVwN2FH2fc=
|
||||
github.com/olekukonko/ll v0.0.8/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.6 h1:/T45mIHc5hcEvibgzBzvMy7ruT+RjgoQRvkHbnl6OWA=
|
||||
github.com/olekukonko/tablewriter v1.0.6/go.mod h1:SJ0MV1aHb/89fLcsBMXMp30Xg3g5eGoOUu0RptEk4AU=
|
||||
github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
|
||||
github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
|
||||
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=
|
||||
|
||||
21
vendor/github.com/olekukonko/ll/global.go
generated
vendored
21
vendor/github.com/olekukonko/ll/global.go
generated
vendored
@@ -431,6 +431,15 @@ func Print(args ...any) {
|
||||
defaultLogger.Print(args...)
|
||||
}
|
||||
|
||||
// Println logs a message at Info level without format specifiers, minimizing allocations
|
||||
// by concatenating arguments with spaces. It is thread-safe via the log method.
|
||||
// Example:
|
||||
//
|
||||
// ll.Println("message", "value") // Output: [] INFO: message value [New Line]
|
||||
func Println(args ...any) {
|
||||
defaultLogger.Println(args...)
|
||||
}
|
||||
|
||||
// Printf logs a message at Info level with a format string using the default logger.
|
||||
// It formats the message and delegates to defaultLogger’s Printf method. Thread-safe via
|
||||
// the Logger’s log method.
|
||||
@@ -573,7 +582,7 @@ func Disable() *Logger {
|
||||
// x := 42
|
||||
// ll.Dbg(x) // Output: [file.go:123] x = 42
|
||||
func Dbg(any ...interface{}) {
|
||||
defaultLogger.Dbg(any...)
|
||||
defaultLogger.dbg(2, any...)
|
||||
}
|
||||
|
||||
// Dump displays a hex and ASCII representation of a value’s binary form using the default logger.
|
||||
@@ -638,3 +647,13 @@ func Line(lines ...int) *Logger {
|
||||
func Indent(depth int) *Logger {
|
||||
return defaultLogger.Indent(depth)
|
||||
}
|
||||
|
||||
// Mark logs the current file and line number where it's called, without any additional debug information.
|
||||
// It's useful for tracing execution flow without the verbosity of Dbg.
|
||||
// Example:
|
||||
//
|
||||
// logger.Mark() // *MARK*: [file.go:123]
|
||||
func Mark(names ...string) {
|
||||
defaultLogger.mark(2, names...)
|
||||
|
||||
}
|
||||
|
||||
68
vendor/github.com/olekukonko/ll/ll.go
generated
vendored
68
vendor/github.com/olekukonko/ll/ll.go
generated
vendored
@@ -232,18 +232,6 @@ func (l *Logger) Debug(args ...any) {
|
||||
l.log(lx.LevelDebug, lx.ClassText, concatSpaced(args...), nil, false)
|
||||
}
|
||||
|
||||
func (l *Logger) Debug2(args ...any) {
|
||||
// Skip logging if Debug level is not enabled
|
||||
if !l.enabled {
|
||||
return
|
||||
}
|
||||
l.log(lx.LevelDebug, lx.ClassText, concatSpaced(args...), nil, false)
|
||||
}
|
||||
|
||||
func (l *Logger) Debug3(args ...any) {
|
||||
l.log(lx.LevelDebug, lx.ClassText, concatSpaced(args...), nil, false)
|
||||
}
|
||||
|
||||
// Debugf logs a formatted message at Debug level, delegating to Debug. It is thread-safe.
|
||||
// Example:
|
||||
//
|
||||
@@ -736,6 +724,44 @@ func (l *Logger) Line(lines ...int) *Logger {
|
||||
return l
|
||||
}
|
||||
|
||||
// Mark logs the current file and line number where it's called, without any additional debug information.
|
||||
// It's useful for tracing execution flow without the verbosity of Dbg.
|
||||
// Example:
|
||||
//
|
||||
// logger.Mark() // *MARK*: [file.go:123]
|
||||
func (l *Logger) Mark(name ...string) {
|
||||
l.mark(2, name...)
|
||||
}
|
||||
|
||||
func (l *Logger) mark(skip int, names ...string) {
|
||||
// Skip logging if Info level is not enabled
|
||||
if !l.shouldLog(lx.LevelInfo) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get caller information (file, line)
|
||||
_, file, line, ok := runtime.Caller(skip)
|
||||
if !ok {
|
||||
l.log(lx.LevelError, lx.ClassText, "Mark: Unable to parse runtime caller", nil, false)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract just the filename (without full path)
|
||||
shortFile := file
|
||||
if idx := strings.LastIndex(file, "/"); idx >= 0 {
|
||||
shortFile = file[idx+1:]
|
||||
}
|
||||
|
||||
name := strings.Join(names, l.separator)
|
||||
if name == "" {
|
||||
name = "MARK"
|
||||
}
|
||||
|
||||
// Format as [filename:line]
|
||||
out := fmt.Sprintf("[*%s*]: [%s:%d]\n", name, shortFile, line)
|
||||
l.log(lx.LevelInfo, lx.ClassRaw, out, nil, false)
|
||||
}
|
||||
|
||||
// Measure benchmarks function execution, logging the duration at Info level with a
|
||||
// "duration" field. It is thread-safe via Fields and log methods.
|
||||
// Example:
|
||||
@@ -920,6 +946,24 @@ func (l *Logger) Print(args ...any) {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip logging if Info level is not enabled
|
||||
if !l.shouldLog(lx.LevelInfo) {
|
||||
return
|
||||
}
|
||||
l.log(lx.LevelNone, lx.ClassRaw, concatSpaced(args...), nil, false)
|
||||
}
|
||||
|
||||
// Println logs a message at Info level without format specifiers, minimizing allocations
|
||||
// by concatenating arguments with spaces. It is thread-safe via the log method.
|
||||
// Example:
|
||||
//
|
||||
// logger := New("app").Enable()
|
||||
// logger.Println("message", "value") // Output: [app] INFO: message value
|
||||
func (l *Logger) Println(args ...any) {
|
||||
if l.suspend {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip logging if Info level is not enabled
|
||||
if !l.shouldLog(lx.LevelInfo) {
|
||||
return
|
||||
|
||||
3042
vendor/github.com/olekukonko/tablewriter/MIGRATION.md
generated
vendored
Normal file
3042
vendor/github.com/olekukonko/tablewriter/MIGRATION.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
86
vendor/github.com/olekukonko/tablewriter/README.md
generated
vendored
86
vendor/github.com/olekukonko/tablewriter/README.md
generated
vendored
@@ -28,14 +28,14 @@ go get github.com/olekukonko/tablewriter@v0.0.5
|
||||
#### Latest Version
|
||||
The latest stable version
|
||||
```bash
|
||||
go get github.com/olekukonko/tablewriter@v1.0.6
|
||||
go get github.com/olekukonko/tablewriter@v1.0.7
|
||||
```
|
||||
|
||||
**Warning:** Version `v1.0.0` contains missing functionality and should not be used.
|
||||
|
||||
|
||||
> **Version Guidance**
|
||||
> - Production: Use `v0.0.5` (stable)
|
||||
> - Legacy: Use `v0.0.5` (stable)
|
||||
> - New Features: Use `@latest` (includes generics, super fast streaming APIs)
|
||||
> - Legacy Docs: See [README_LEGACY.md](README_LEGACY.md)
|
||||
|
||||
@@ -62,7 +62,7 @@ func main() {
|
||||
data := [][]string{
|
||||
{"Package", "Version", "Status"},
|
||||
{"tablewriter", "v0.0.5", "legacy"},
|
||||
{"tablewriter", "v1.0.6", "latest"},
|
||||
{"tablewriter", "v1.0.7", "latest"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
@@ -77,7 +77,7 @@ func main() {
|
||||
│ PACKAGE │ VERSION │ STATUS │
|
||||
├─────────────┼─────────┼────────┤
|
||||
│ tablewriter │ v0.0.5 │ legacy │
|
||||
│ tablewriter │ v1.0.6 │ latest │
|
||||
│ tablewriter │ v1.0.7 │ latest │
|
||||
└─────────────┴─────────┴────────┘
|
||||
```
|
||||
|
||||
@@ -297,7 +297,7 @@ func main() {
|
||||
}
|
||||
|
||||
table.Configure(func(config *tablewriter.Config) {
|
||||
config.Row.Formatting.Alignment = tw.AlignLeft
|
||||
config.Row.Alignment.Global = tw.AlignLeft
|
||||
})
|
||||
table.Render()
|
||||
}
|
||||
@@ -368,14 +368,12 @@ func main() {
|
||||
tablewriter.WithRenderer(renderer.NewColorized(colorCfg)),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
AutoWrap: tw.WrapNormal, // Wrap long content
|
||||
Alignment: tw.AlignLeft, // Left-align rows
|
||||
},
|
||||
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNormal}, // Wrap long content
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignLeft}, // Left-align rows
|
||||
ColMaxWidths: tw.CellWidth{Global: 25},
|
||||
},
|
||||
Footer: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignRight},
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignRight},
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -480,19 +478,13 @@ func main() {
|
||||
|
||||
table := tablewriter.NewTable(os.Stdout,
|
||||
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
|
||||
Settings: tw.Settings{
|
||||
Separators: tw.Separators{BetweenRows: tw.On},
|
||||
},
|
||||
Settings: tw.Settings{Separators: tw.Separators{BetweenRows: tw.On}},
|
||||
})),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
Header: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignCenter},
|
||||
},
|
||||
Header: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
MergeMode: tw.MergeHierarchical,
|
||||
Alignment: tw.AlignLeft,
|
||||
},
|
||||
Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical},
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignLeft},
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -546,21 +538,20 @@ func main() {
|
||||
|
||||
table := tablewriter.NewTable(os.Stdout,
|
||||
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
|
||||
Settings: tw.Settings{
|
||||
Separators: tw.Separators{BetweenRows: tw.On},
|
||||
},
|
||||
Settings: tw.Settings{Separators: tw.Separators{BetweenRows: tw.On}},
|
||||
})),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{MergeMode: tw.MergeBoth},
|
||||
ColumnAligns: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft},
|
||||
Formatting: tw.CellFormatting{MergeMode: tw.MergeBoth},
|
||||
Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
|
||||
},
|
||||
|
||||
Footer: tw.CellConfig{
|
||||
Padding: tw.CellPadding{
|
||||
Global: tw.Padding{Left: "*", Right: "*"},
|
||||
PerColumn: []tw.Padding{{}, {}, {Bottom: "^"}, {Bottom: "^"}},
|
||||
},
|
||||
ColumnAligns: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft},
|
||||
Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -617,9 +608,7 @@ func main() {
|
||||
})),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
MaxWidth: 10,
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignCenter},
|
||||
},
|
||||
Row: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
|
||||
}),
|
||||
)
|
||||
table.Append([]string{s, s})
|
||||
@@ -631,16 +620,12 @@ func main() {
|
||||
// Main table
|
||||
table := tablewriter.NewTable(os.Stdout,
|
||||
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
|
||||
Borders: tw.BorderNone,
|
||||
Settings: tw.Settings{
|
||||
Separators: tw.Separators{BetweenColumns: tw.On},
|
||||
},
|
||||
Borders: tw.BorderNone,
|
||||
Settings: tw.Settings{Separators: tw.Separators{BetweenColumns: tw.On}},
|
||||
})),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
MaxWidth: 30,
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignCenter},
|
||||
},
|
||||
Row: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
|
||||
}),
|
||||
)
|
||||
table.Append([]string{createSubTable("A"), createSubTable("B")})
|
||||
@@ -711,14 +696,11 @@ func main() {
|
||||
tablewriter.WithStringer(employeeStringer),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
Header: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignCenter, AutoFormat: tw.On},
|
||||
},
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignLeft},
|
||||
},
|
||||
Footer: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignRight},
|
||||
Formatting: tw.CellFormatting{AutoFormat: tw.On},
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignCenter},
|
||||
},
|
||||
Row: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignLeft}},
|
||||
Footer: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignRight}},
|
||||
}),
|
||||
)
|
||||
table.Header([]string{"ID", "Name", "Age", "Department", "Salary"})
|
||||
@@ -784,23 +766,17 @@ func main() {
|
||||
}
|
||||
|
||||
table := tablewriter.NewTable(os.Stdout,
|
||||
tablewriter.WithRenderer(renderer.NewHTML(os.Stdout, false, htmlCfg)),
|
||||
tablewriter.WithRenderer(renderer.NewHTML(htmlCfg)),
|
||||
tablewriter.WithConfig(tablewriter.Config{
|
||||
Header: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
Alignment: tw.AlignCenter,
|
||||
MergeMode: tw.MergeHorizontal, // Merge identical header cells
|
||||
},
|
||||
Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}, // Merge identical header cells
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignCenter},
|
||||
},
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
MergeMode: tw.MergeHorizontal, // Merge identical row cells
|
||||
Alignment: tw.AlignLeft,
|
||||
},
|
||||
},
|
||||
Footer: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{Alignment: tw.AlignRight},
|
||||
Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}, // Merge identical row cells
|
||||
Alignment: tw.CellAlignment{Global: tw.AlignLeft},
|
||||
},
|
||||
Footer: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignRight}},
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
1391
vendor/github.com/olekukonko/tablewriter/config.go
generated
vendored
1391
vendor/github.com/olekukonko/tablewriter/config.go
generated
vendored
File diff suppressed because it is too large
Load Diff
196
vendor/github.com/olekukonko/tablewriter/deprecated.go
generated
vendored
196
vendor/github.com/olekukonko/tablewriter/deprecated.go
generated
vendored
@@ -2,9 +2,27 @@ package tablewriter
|
||||
|
||||
import "github.com/olekukonko/tablewriter/tw"
|
||||
|
||||
// Deprecated: WithBorders is no longer used.
|
||||
// Border control has been moved to the renderer, which now manages its own borders.
|
||||
// This Option has no effect on the Table and may be removed in future versions.
|
||||
// WithBorders configures the table's border settings by updating the renderer's border configuration.
|
||||
// This function is deprecated and will be removed in a future version.
|
||||
//
|
||||
// Deprecated: Use [WithRendition] to configure border settings for renderers that support
|
||||
// [tw.Renditioning], or update the renderer's [tw.RenderConfig] directly via its Config() method.
|
||||
// This function has no effect if no renderer is set on the table.
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// table.Options(WithBorders(tw.Border{Top: true, Bottom: true}))
|
||||
// // New (recommended)
|
||||
// table.Options(WithRendition(tw.Rendition{Borders: tw.Border{Top: true, Bottom: true}}))
|
||||
//
|
||||
// Parameters:
|
||||
// - borders: The [tw.Border] configuration to apply to the renderer's borders.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// An [Option] that updates the renderer's border settings if a renderer is set.
|
||||
// Logs a debug message if debugging is enabled and a renderer is present.
|
||||
func WithBorders(borders tw.Border) Option {
|
||||
return func(target *Table) {
|
||||
if target.renderer != nil {
|
||||
@@ -17,16 +35,55 @@ func WithBorders(borders tw.Border) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: WithBorders is no longer supported.
|
||||
// Use [tw.Behavior] directly to configure border settings.
|
||||
// Behavior is an alias for [tw.Behavior] to configure table behavior settings.
|
||||
// This type is deprecated and will be removed in a future version.
|
||||
//
|
||||
// Deprecated: Use [tw.Behavior] directly to configure settings such as auto-hiding empty
|
||||
// columns, trimming spaces, or controlling header/footer visibility.
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// var b tablewriter.Behavior = tablewriter.Behavior{AutoHide: tw.On}
|
||||
// // New (recommended)
|
||||
// var b tw.Behavior = tw.Behavior{AutoHide: tw.On}
|
||||
type Behavior tw.Behavior
|
||||
|
||||
// Deprecated: WithRendererSettings i sno longer supported.
|
||||
// Settings is an alias for [tw.Settings] to configure renderer settings.
|
||||
// This type is deprecated and will be removed in a future version.
|
||||
//
|
||||
// Deprecated: Use [tw.Settings] directly to configure renderer settings, such as
|
||||
// separators and line styles.
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// var s tablewriter.Settings = tablewriter.Settings{Separator: "|"}
|
||||
// // New (recommended)
|
||||
// var s tw.Settings = tw.Settings{Separator: "|"}
|
||||
type Settings tw.Settings
|
||||
|
||||
// WithRendererSettings updates the renderer's settings (e.g., separators, lines).
|
||||
// Render setting has move to renders directly
|
||||
// you can also use WithRendition for renders that have rendition support
|
||||
// WithRendererSettings updates the renderer's settings, such as separators and line styles.
|
||||
// This function is deprecated and will be removed in a future version.
|
||||
//
|
||||
// Deprecated: Use [WithRendition] to update renderer settings for renderers that implement
|
||||
// [tw.Renditioning], or configure the renderer's [tw.Settings] directly via its
|
||||
// [tw.Renderer.Config] method. This function has no effect if no renderer is set.
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// table.Options(WithRendererSettings(tw.Settings{Separator: "|"}))
|
||||
// // New (recommended)
|
||||
// table.Options(WithRendition(tw.Rendition{Settings: tw.Settings{Separator: "|"}}))
|
||||
//
|
||||
// Parameters:
|
||||
// - settings: The [tw.Settings] configuration to apply to the renderer.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// An [Option] that updates the renderer's settings if a renderer is set.
|
||||
// Logs a debug message if debugging is enabled and a renderer is present.
|
||||
func WithRendererSettings(settings tw.Settings) Option {
|
||||
return func(target *Table) {
|
||||
if target.renderer != nil {
|
||||
@@ -38,3 +95,124 @@ func WithRendererSettings(settings tw.Settings) Option {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithAlignment sets the text alignment for footer cells within the formatting configuration.
|
||||
// This method is deprecated and will be removed in the next version.
|
||||
//
|
||||
// Deprecated: Use [FooterConfigBuilder.Alignment] with [AlignmentConfigBuilder.WithGlobal]
|
||||
// or [AlignmentConfigBuilder.WithPerColumn] to configure footer alignments.
|
||||
// Alternatively, apply a complete [tw.CellAlignment] configuration using
|
||||
// [WithFooterAlignmentConfig].
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// builder.Footer().Formatting().WithAlignment(tw.AlignRight)
|
||||
// // New (recommended)
|
||||
// builder.Footer().Alignment().WithGlobal(tw.AlignRight)
|
||||
// // Or
|
||||
// table.Options(WithFooterAlignmentConfig(tw.CellAlignment{Global: tw.AlignRight}))
|
||||
//
|
||||
// Parameters:
|
||||
// - align: The [tw.Align] value to set for footer cells. Valid values are
|
||||
// [tw.AlignLeft], [tw.AlignRight], [tw.AlignCenter], and [tw.AlignNone].
|
||||
// Invalid alignments are ignored.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// The [FooterFormattingBuilder] instance for method chaining.
|
||||
func (ff *FooterFormattingBuilder) WithAlignment(align tw.Align) *FooterFormattingBuilder {
|
||||
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
|
||||
return ff
|
||||
}
|
||||
ff.config.Alignment = align
|
||||
return ff
|
||||
}
|
||||
|
||||
// WithAlignment sets the text alignment for header cells within the formatting configuration.
|
||||
// This method is deprecated and will be removed in the next version.
|
||||
//
|
||||
// Deprecated: Use [HeaderConfigBuilder.Alignment] with [AlignmentConfigBuilder.WithGlobal]
|
||||
// or [AlignmentConfigBuilder.WithPerColumn] to configure header alignments.
|
||||
// Alternatively, apply a complete [tw.CellAlignment] configuration using
|
||||
// [WithHeaderAlignmentConfig].
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// builder.Header().Formatting().WithAlignment(tw.AlignCenter)
|
||||
// // New (recommended)
|
||||
// builder.Header().Alignment().WithGlobal(tw.AlignCenter)
|
||||
// // Or
|
||||
// table.Options(WithHeaderAlignmentConfig(tw.CellAlignment{Global: tw.AlignCenter}))
|
||||
//
|
||||
// Parameters:
|
||||
// - align: The [tw.Align] value to set for header cells. Valid values are
|
||||
// [tw.AlignLeft], [tw.AlignRight], [tw.AlignCenter], and [tw.AlignNone].
|
||||
// Invalid alignments are ignored.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// The [HeaderFormattingBuilder] instance for method chaining.
|
||||
func (hf *HeaderFormattingBuilder) WithAlignment(align tw.Align) *HeaderFormattingBuilder {
|
||||
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
|
||||
return hf
|
||||
}
|
||||
hf.config.Alignment = align
|
||||
return hf
|
||||
}
|
||||
|
||||
// WithAlignment sets the text alignment for row cells within the formatting configuration.
|
||||
// This method is deprecated and will be removed in the next version.
|
||||
//
|
||||
// Deprecated: Use [RowConfigBuilder.Alignment] with [AlignmentConfigBuilder.WithGlobal]
|
||||
// or [AlignmentConfigBuilder.WithPerColumn] to configure row alignments.
|
||||
// Alternatively, apply a complete [tw.CellAlignment] configuration using
|
||||
// [WithRowAlignmentConfig].
|
||||
//
|
||||
// Example migration:
|
||||
//
|
||||
// // Old (deprecated)
|
||||
// builder.Row().Formatting().WithAlignment(tw.AlignLeft)
|
||||
// // New (recommended)
|
||||
// builder.Row().Alignment().WithGlobal(tw.AlignLeft)
|
||||
// // Or
|
||||
// table.Options(WithRowAlignmentConfig(tw.CellAlignment{Global: tw.AlignLeft}))
|
||||
//
|
||||
// Parameters:
|
||||
// - align: The [tw.Align] value to set for row cells. Valid values are
|
||||
// [tw.AlignLeft], [tw.AlignRight], [tw.AlignCenter], and [tw.AlignNone].
|
||||
// Invalid alignments are ignored.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// The [RowFormattingBuilder] instance for method chaining.
|
||||
func (rf *RowFormattingBuilder) WithAlignment(align tw.Align) *RowFormattingBuilder {
|
||||
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
|
||||
return rf
|
||||
}
|
||||
rf.config.Alignment = align
|
||||
return rf
|
||||
}
|
||||
|
||||
// WithTableMax sets the maximum width of the entire table in characters.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
// The width constrains the table's rendering, potentially causing text wrapping or truncation
|
||||
// based on the configuration's wrapping settings (e.g., tw.WrapTruncate).
|
||||
// If debug logging is enabled via WithDebug(true), the applied width is logged.
|
||||
//
|
||||
// Deprecated: Use WithMaxWidth instead, which provides the same functionality with a clearer name
|
||||
// and consistent naming across the package. For example:
|
||||
//
|
||||
// tablewriter.NewTable(os.Stdout, tablewriter.WithMaxWidth(80))
|
||||
func WithTableMax(width int) Option {
|
||||
return func(target *Table) {
|
||||
if width < 0 {
|
||||
return
|
||||
}
|
||||
target.config.MaxWidth = width
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithTableMax applied to Table: %v", width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
859
vendor/github.com/olekukonko/tablewriter/option.go
generated
vendored
Normal file
859
vendor/github.com/olekukonko/tablewriter/option.go
generated
vendored
Normal file
@@ -0,0 +1,859 @@
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"github.com/olekukonko/ll"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Option defines a function type for configuring a Table instance.
|
||||
type Option func(target *Table)
|
||||
|
||||
// WithAutoHide enables or disables automatic hiding of columns with empty data rows.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithAutoHide(state tw.State) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Behavior.AutoHide = state
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithAutoHide applied to Table: %v", state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithColumnMax sets a global maximum column width for the table in streaming mode.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
func WithColumnMax(width int) Option {
|
||||
return func(target *Table) {
|
||||
if width < 0 {
|
||||
return
|
||||
}
|
||||
target.config.Widths.Global = width
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithColumnMax applied to Table: %v", width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxWidth sets a global maximum table width for the table.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
func WithMaxWidth(width int) Option {
|
||||
return func(target *Table) {
|
||||
if width < 0 {
|
||||
return
|
||||
}
|
||||
target.config.MaxWidth = width
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithTableMax applied to Table: %v", width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithWidths sets per-column widths for the table.
|
||||
// Negative widths are removed, and the change is logged if debugging is enabled.
|
||||
func WithWidths(width tw.CellWidth) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Widths = width
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithColumnWidths applied to Table: %v", width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithColumnWidths sets per-column widths for the table.
|
||||
// Negative widths are removed, and the change is logged if debugging is enabled.
|
||||
func WithColumnWidths(widths tw.Mapper[int, int]) Option {
|
||||
return func(target *Table) {
|
||||
for k, v := range widths {
|
||||
if v < 0 {
|
||||
delete(widths, k)
|
||||
}
|
||||
}
|
||||
target.config.Widths.PerColumn = widths
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithColumnWidths applied to Table: %v", widths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithConfig applies a custom configuration to the table by merging it with the default configuration.
|
||||
func WithConfig(cfg Config) Option {
|
||||
return func(target *Table) {
|
||||
target.config = mergeConfig(defaultConfig(), cfg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDebug enables or disables debug logging and adjusts the logger level accordingly.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithDebug(debug bool) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Debug = debug
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooter sets the table footers by calling the Footer method.
|
||||
func WithFooter(footers []string) Option {
|
||||
return func(target *Table) {
|
||||
target.Footer(footers)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterConfig applies a full footer configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterConfig(config tw.CellConfig) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer = config
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithFooterConfig applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterAlignmentConfig applies a footer alignment configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterAlignmentConfig(alignment tw.CellAlignment) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer.Alignment = alignment
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterAlignmentConfig applied to Table: %+v", alignment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterMergeMode sets the merge mode for footer cells.
|
||||
// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithFooterMergeMode(mergeMode int) Option {
|
||||
return func(target *Table) {
|
||||
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
|
||||
return
|
||||
}
|
||||
target.config.Footer.Formatting.MergeMode = mergeMode
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterMergeMode applied to Table: %v", mergeMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterAutoWrap sets the wrapping behavior for footer cells.
|
||||
// Invalid wrap modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithFooterAutoWrap(wrap int) Option {
|
||||
return func(target *Table) {
|
||||
if wrap < tw.WrapNone || wrap > tw.WrapBreak {
|
||||
return
|
||||
}
|
||||
target.config.Footer.Formatting.AutoWrap = wrap
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterAutoWrap applied to Table: %v", wrap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterFilter sets the filter configuration for footer cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterFilter(filter tw.CellFilter) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer.Filter = filter
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithFooterFilter applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterCallbacks sets the callback configuration for footer cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterCallbacks(callbacks tw.CellCallbacks) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer.Callbacks = callbacks
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithFooterCallbacks applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterPaddingPerColumn sets per-column padding for footer cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterPaddingPerColumn(padding []tw.Padding) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer.Padding.PerColumn = padding
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterPaddingPerColumn applied to Table: %+v", padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterMaxWidth sets the maximum content width for footer cells.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
func WithFooterMaxWidth(maxWidth int) Option {
|
||||
return func(target *Table) {
|
||||
if maxWidth < 0 {
|
||||
return
|
||||
}
|
||||
target.config.Footer.ColMaxWidths.Global = maxWidth
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterMaxWidth applied to Table: %v", maxWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeader sets the table headers by calling the Header method.
|
||||
func WithHeader(headers []string) Option {
|
||||
return func(target *Table) {
|
||||
target.Header(headers)
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderAlignment sets the text alignment for header cells.
|
||||
// Invalid alignments are ignored, and the change is logged if debugging is enabled.
|
||||
func WithHeaderAlignment(align tw.Align) Option {
|
||||
return func(target *Table) {
|
||||
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
|
||||
return
|
||||
}
|
||||
target.config.Header.Alignment.Global = align
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderAlignment applied to Table: %v", align)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderAutoWrap sets the wrapping behavior for header cells.
|
||||
// Invalid wrap modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithHeaderAutoWrap(wrap int) Option {
|
||||
return func(target *Table) {
|
||||
if wrap < tw.WrapNone || wrap > tw.WrapBreak {
|
||||
return
|
||||
}
|
||||
target.config.Header.Formatting.AutoWrap = wrap
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderAutoWrap applied to Table: %v", wrap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderMergeMode sets the merge mode for header cells.
|
||||
// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithHeaderMergeMode(mergeMode int) Option {
|
||||
return func(target *Table) {
|
||||
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
|
||||
return
|
||||
}
|
||||
target.config.Header.Formatting.MergeMode = mergeMode
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderMergeMode applied to Table: %v", mergeMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderFilter sets the filter configuration for header cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderFilter(filter tw.CellFilter) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Filter = filter
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithHeaderFilter applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderCallbacks sets the callback configuration for header cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderCallbacks(callbacks tw.CellCallbacks) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Callbacks = callbacks
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithHeaderCallbacks applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderPaddingPerColumn sets per-column padding for header cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderPaddingPerColumn(padding []tw.Padding) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Padding.PerColumn = padding
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderPaddingPerColumn applied to Table: %+v", padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderMaxWidth sets the maximum content width for header cells.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
func WithHeaderMaxWidth(maxWidth int) Option {
|
||||
return func(target *Table) {
|
||||
if maxWidth < 0 {
|
||||
return
|
||||
}
|
||||
target.config.Header.ColMaxWidths.Global = maxWidth
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderMaxWidth applied to Table: %v", maxWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowAlignment sets the text alignment for row cells.
|
||||
// Invalid alignments are ignored, and the change is logged if debugging is enabled.
|
||||
func WithRowAlignment(align tw.Align) Option {
|
||||
return func(target *Table) {
|
||||
if err := align.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
target.config.Row.Alignment.Global = align
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowAlignment applied to Table: %v", align)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowAutoWrap sets the wrapping behavior for row cells.
|
||||
// Invalid wrap modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithRowAutoWrap(wrap int) Option {
|
||||
return func(target *Table) {
|
||||
if wrap < tw.WrapNone || wrap > tw.WrapBreak {
|
||||
return
|
||||
}
|
||||
target.config.Row.Formatting.AutoWrap = wrap
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowAutoWrap applied to Table: %v", wrap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowMergeMode sets the merge mode for row cells.
|
||||
// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
|
||||
func WithRowMergeMode(mergeMode int) Option {
|
||||
return func(target *Table) {
|
||||
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
|
||||
return
|
||||
}
|
||||
target.config.Row.Formatting.MergeMode = mergeMode
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowMergeMode applied to Table: %v", mergeMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowFilter sets the filter configuration for row cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowFilter(filter tw.CellFilter) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row.Filter = filter
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithRowFilter applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowCallbacks sets the callback configuration for row cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowCallbacks(callbacks tw.CellCallbacks) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row.Callbacks = callbacks
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithRowCallbacks applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowPaddingPerColumn sets per-column padding for row cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowPaddingPerColumn(padding []tw.Padding) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row.Padding.PerColumn = padding
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowPaddingPerColumn applied to Table: %+v", padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderAlignmentConfig applies a header alignment configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderAlignmentConfig(alignment tw.CellAlignment) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Alignment = alignment
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderAlignmentConfig applied to Table: %+v", alignment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderConfig applies a full header configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderConfig(config tw.CellConfig) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header = config
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithHeaderConfig applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger sets a custom logger for the table and updates the renderer if present.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithLogger(logger *ll.Logger) Option {
|
||||
return func(target *Table) {
|
||||
target.logger = logger
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithLogger applied to Table.")
|
||||
if target.renderer != nil {
|
||||
target.renderer.Logger(target.logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRenderer sets a custom renderer for the table and attaches the logger if present.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRenderer(f tw.Renderer) Option {
|
||||
return func(target *Table) {
|
||||
target.renderer = f
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRenderer applied to Table: %T", f)
|
||||
f.Logger(target.logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowConfig applies a full row configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowConfig(config tw.CellConfig) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row = config
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithRowConfig applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowAlignmentConfig applies a row alignment configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowAlignmentConfig(alignment tw.CellAlignment) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row.Alignment = alignment
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowAlignmentConfig applied to Table: %+v", alignment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowMaxWidth sets the maximum content width for row cells.
|
||||
// Negative values are ignored, and the change is logged if debugging is enabled.
|
||||
func WithRowMaxWidth(maxWidth int) Option {
|
||||
return func(target *Table) {
|
||||
if maxWidth < 0 {
|
||||
return
|
||||
}
|
||||
target.config.Row.ColMaxWidths.Global = maxWidth
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowMaxWidth applied to Table: %v", maxWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithStreaming applies a streaming configuration to the table by merging it with the existing configuration.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithStreaming(c tw.StreamConfig) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Stream = mergeStreamConfig(target.config.Stream, c)
|
||||
if target.logger != nil {
|
||||
target.logger.Debug("Option: WithStreaming applied to Table.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithStringer sets a custom stringer function for converting row data and clears the stringer cache.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithStringer(stringer interface{}) Option {
|
||||
return func(t *Table) {
|
||||
t.stringer = stringer
|
||||
t.stringerCacheMu.Lock()
|
||||
t.stringerCache = make(map[reflect.Type]reflect.Value)
|
||||
t.stringerCacheMu.Unlock()
|
||||
if t.logger != nil {
|
||||
t.logger.Debug("Stringer updated, cache cleared")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithStringerCache enables caching for the stringer function.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithStringerCache() Option {
|
||||
return func(t *Table) {
|
||||
t.stringerCacheEnabled = true
|
||||
if t.logger != nil {
|
||||
t.logger.Debug("Option: WithStringerCache enabled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithTrimSpace sets whether leading and trailing spaces are automatically trimmed.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithTrimSpace(state tw.State) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Behavior.TrimSpace = state
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithTrimSpace 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 {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Formatting.AutoFormat = state
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderAutoFormat applied to Table: %v", state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterAutoFormat enables or disables automatic formatting for footer cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterAutoFormat(state tw.State) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Footer.Formatting.AutoFormat = state
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterAutoFormat applied to Table: %v", state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRowAutoFormat enables or disables automatic formatting for row cells.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRowAutoFormat(state tw.State) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Row.Formatting.AutoFormat = state
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithRowAutoFormat applied to Table: %v", state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaderControl sets the control behavior for the table header.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithHeaderControl(control tw.Control) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Behavior.Header = control
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithHeaderControl applied to Table: %v", control)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooterControl sets the control behavior for the table footer.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithFooterControl(control tw.Control) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Behavior.Footer = control
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithFooterControl applied to Table: %v", control)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithAlignment sets the default column alignment for the header, rows, and footer.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithAlignment(alignment tw.Alignment) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Alignment.PerColumn = alignment
|
||||
target.config.Row.Alignment.PerColumn = alignment
|
||||
target.config.Footer.Alignment.PerColumn = alignment
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithAlignment applied to Table: %+v", alignment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithBehavior applies a behavior configuration to the table.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithBehavior(behavior tw.Behavior) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Behavior = behavior
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithBehavior applied to Table: %+v", behavior)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithPadding sets the global padding for the header, rows, and footer.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithPadding(padding tw.Padding) Option {
|
||||
return func(target *Table) {
|
||||
target.config.Header.Padding.Global = padding
|
||||
target.config.Row.Padding.Global = padding
|
||||
target.config.Footer.Padding.Global = padding
|
||||
if target.logger != nil {
|
||||
target.logger.Debugf("Option: WithPadding applied to Table: %+v", padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRendition allows updating the active renderer's rendition configuration
|
||||
// by merging the provided rendition.
|
||||
// If the renderer does not implement tw.Renditioning, a warning is logged.
|
||||
// Logs the change if debugging is enabled.
|
||||
func WithRendition(rendition tw.Rendition) Option {
|
||||
return func(target *Table) {
|
||||
if target.renderer == nil {
|
||||
if target.logger != nil {
|
||||
target.logger.Warn("Option: WithRendition: No renderer set on table.")
|
||||
}
|
||||
return
|
||||
}
|
||||
if ru, ok := target.renderer.(tw.Renditioning); ok {
|
||||
ru.Rendition(rendition)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithSymbols sets the symbols used for drawing table borders and separators.
|
||||
// The symbols are applied to the table's renderer configuration, if a renderer is set.
|
||||
// If no renderer is set (target.renderer is nil), this option has no effect. .
|
||||
func WithSymbols(symbols tw.Symbols) Option {
|
||||
return func(target *Table) {
|
||||
if target.renderer != nil {
|
||||
cfg := target.renderer.Config()
|
||||
cfg.Symbols = symbols
|
||||
|
||||
if ru, ok := target.renderer.(tw.Renditioning); ok {
|
||||
ru.Rendition(cfg)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defaultConfig returns a default Config with sensible settings for headers, rows, footers, and behavior.
|
||||
func defaultConfig() Config {
|
||||
return Config{
|
||||
MaxWidth: 0,
|
||||
Header: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
AutoWrap: tw.WrapTruncate,
|
||||
AutoFormat: tw.On,
|
||||
MergeMode: tw.MergeNone,
|
||||
},
|
||||
Padding: tw.CellPadding{
|
||||
Global: tw.PaddingDefault,
|
||||
},
|
||||
Alignment: tw.CellAlignment{
|
||||
Global: tw.AlignCenter,
|
||||
PerColumn: []tw.Align{},
|
||||
},
|
||||
},
|
||||
Row: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
AutoWrap: tw.WrapNormal,
|
||||
AutoFormat: tw.Off,
|
||||
MergeMode: tw.MergeNone,
|
||||
},
|
||||
Padding: tw.CellPadding{
|
||||
Global: tw.PaddingDefault,
|
||||
},
|
||||
Alignment: tw.CellAlignment{
|
||||
Global: tw.AlignLeft,
|
||||
PerColumn: []tw.Align{},
|
||||
},
|
||||
},
|
||||
Footer: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
AutoWrap: tw.WrapNormal,
|
||||
AutoFormat: tw.Off,
|
||||
MergeMode: tw.MergeNone,
|
||||
},
|
||||
Padding: tw.CellPadding{
|
||||
Global: tw.PaddingDefault,
|
||||
},
|
||||
Alignment: tw.CellAlignment{
|
||||
Global: tw.AlignRight,
|
||||
PerColumn: []tw.Align{},
|
||||
},
|
||||
},
|
||||
Stream: tw.StreamConfig{},
|
||||
Debug: false,
|
||||
Behavior: tw.Behavior{
|
||||
AutoHide: tw.Off,
|
||||
TrimSpace: tw.On,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// mergeCellConfig merges a source CellConfig into a destination CellConfig, prioritizing non-default source values.
|
||||
// It handles deep merging for complex fields like padding and callbacks.
|
||||
func mergeCellConfig(dst, src tw.CellConfig) tw.CellConfig {
|
||||
if src.Formatting.Alignment != tw.Empty {
|
||||
dst.Formatting.Alignment = src.Formatting.Alignment
|
||||
}
|
||||
|
||||
if src.Formatting.AutoWrap != 0 {
|
||||
dst.Formatting.AutoWrap = src.Formatting.AutoWrap
|
||||
}
|
||||
if src.ColMaxWidths.Global != 0 {
|
||||
dst.ColMaxWidths.Global = src.ColMaxWidths.Global
|
||||
}
|
||||
if src.Formatting.MergeMode != 0 {
|
||||
dst.Formatting.MergeMode = src.Formatting.MergeMode
|
||||
}
|
||||
|
||||
dst.Formatting.AutoFormat = src.Formatting.AutoFormat
|
||||
|
||||
if src.Padding.Global.Paddable() {
|
||||
dst.Padding.Global = src.Padding.Global
|
||||
}
|
||||
|
||||
if len(src.Padding.PerColumn) > 0 {
|
||||
if dst.Padding.PerColumn == nil {
|
||||
dst.Padding.PerColumn = make([]tw.Padding, len(src.Padding.PerColumn))
|
||||
} else if len(src.Padding.PerColumn) > len(dst.Padding.PerColumn) {
|
||||
dst.Padding.PerColumn = append(dst.Padding.PerColumn, make([]tw.Padding, len(src.Padding.PerColumn)-len(dst.Padding.PerColumn))...)
|
||||
}
|
||||
for i, pad := range src.Padding.PerColumn {
|
||||
if pad.Paddable() {
|
||||
dst.Padding.PerColumn[i] = pad
|
||||
}
|
||||
}
|
||||
}
|
||||
if src.Callbacks.Global != nil {
|
||||
dst.Callbacks.Global = src.Callbacks.Global
|
||||
}
|
||||
if len(src.Callbacks.PerColumn) > 0 {
|
||||
if dst.Callbacks.PerColumn == nil {
|
||||
dst.Callbacks.PerColumn = make([]func(), len(src.Callbacks.PerColumn))
|
||||
} else if len(src.Callbacks.PerColumn) > len(dst.Callbacks.PerColumn) {
|
||||
dst.Callbacks.PerColumn = append(dst.Callbacks.PerColumn, make([]func(), len(src.Callbacks.PerColumn)-len(dst.Callbacks.PerColumn))...)
|
||||
}
|
||||
for i, cb := range src.Callbacks.PerColumn {
|
||||
if cb != nil {
|
||||
dst.Callbacks.PerColumn[i] = cb
|
||||
}
|
||||
}
|
||||
}
|
||||
if src.Filter.Global != nil {
|
||||
dst.Filter.Global = src.Filter.Global
|
||||
}
|
||||
if len(src.Filter.PerColumn) > 0 {
|
||||
if dst.Filter.PerColumn == nil {
|
||||
dst.Filter.PerColumn = make([]func(string) string, len(src.Filter.PerColumn))
|
||||
} else if len(src.Filter.PerColumn) > len(dst.Filter.PerColumn) {
|
||||
dst.Filter.PerColumn = append(dst.Filter.PerColumn, make([]func(string) string, len(src.Filter.PerColumn)-len(dst.Filter.PerColumn))...)
|
||||
}
|
||||
for i, filter := range src.Filter.PerColumn {
|
||||
if filter != nil {
|
||||
dst.Filter.PerColumn[i] = filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge Alignment
|
||||
if src.Alignment.Global != tw.Empty {
|
||||
dst.Alignment.Global = src.Alignment.Global
|
||||
}
|
||||
|
||||
if len(src.Alignment.PerColumn) > 0 {
|
||||
if dst.Alignment.PerColumn == nil {
|
||||
dst.Alignment.PerColumn = make([]tw.Align, len(src.Alignment.PerColumn))
|
||||
} else if len(src.Alignment.PerColumn) > len(dst.Alignment.PerColumn) {
|
||||
dst.Alignment.PerColumn = append(dst.Alignment.PerColumn, make([]tw.Align, len(src.Alignment.PerColumn)-len(dst.Alignment.PerColumn))...)
|
||||
}
|
||||
for i, align := range src.Alignment.PerColumn {
|
||||
if align != tw.Skip {
|
||||
dst.Alignment.PerColumn[i] = align
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(src.ColumnAligns) > 0 {
|
||||
if dst.ColumnAligns == nil {
|
||||
dst.ColumnAligns = make([]tw.Align, len(src.ColumnAligns))
|
||||
} else if len(src.ColumnAligns) > len(dst.ColumnAligns) {
|
||||
dst.ColumnAligns = append(dst.ColumnAligns, make([]tw.Align, len(src.ColumnAligns)-len(dst.ColumnAligns))...)
|
||||
}
|
||||
for i, align := range src.ColumnAligns {
|
||||
if align != tw.Skip {
|
||||
dst.ColumnAligns[i] = align
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(src.ColMaxWidths.PerColumn) > 0 {
|
||||
if dst.ColMaxWidths.PerColumn == nil {
|
||||
dst.ColMaxWidths.PerColumn = make(map[int]int)
|
||||
}
|
||||
for k, v := range src.ColMaxWidths.PerColumn {
|
||||
if v != 0 {
|
||||
dst.ColMaxWidths.PerColumn[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// mergeConfig merges a source Config into a destination Config, prioritizing non-default source values.
|
||||
// It performs deep merging for complex types like Header, Row, Footer, and Stream.
|
||||
func mergeConfig(dst, src Config) Config {
|
||||
if src.MaxWidth != 0 {
|
||||
dst.MaxWidth = src.MaxWidth
|
||||
}
|
||||
|
||||
dst.Debug = src.Debug || dst.Debug
|
||||
dst.Behavior.AutoHide = src.Behavior.AutoHide
|
||||
dst.Behavior.TrimSpace = src.Behavior.TrimSpace
|
||||
dst.Behavior.Compact = src.Behavior.Compact
|
||||
dst.Behavior.Header = src.Behavior.Header
|
||||
dst.Behavior.Footer = src.Behavior.Footer
|
||||
|
||||
if src.Widths.Global != 0 {
|
||||
dst.Widths.Global = src.Widths.Global
|
||||
}
|
||||
if len(src.Widths.PerColumn) > 0 {
|
||||
if dst.Widths.PerColumn == nil {
|
||||
dst.Widths.PerColumn = make(map[int]int)
|
||||
}
|
||||
for k, v := range src.Widths.PerColumn {
|
||||
if v != 0 {
|
||||
dst.Widths.PerColumn[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst.Header = mergeCellConfig(dst.Header, src.Header)
|
||||
dst.Row = mergeCellConfig(dst.Row, src.Row)
|
||||
dst.Footer = mergeCellConfig(dst.Footer, src.Footer)
|
||||
dst.Stream = mergeStreamConfig(dst.Stream, src.Stream)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// mergeStreamConfig merges a source StreamConfig into a destination StreamConfig, prioritizing non-default source values.
|
||||
func mergeStreamConfig(dst, src tw.StreamConfig) tw.StreamConfig {
|
||||
if src.Enable {
|
||||
dst.Enable = true
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// padLine pads a line to the specified column count by appending empty strings as needed.
|
||||
func padLine(line []string, numCols int) []string {
|
||||
if len(line) >= numCols {
|
||||
return line
|
||||
}
|
||||
padded := make([]string, numCols)
|
||||
copy(padded, line)
|
||||
for i := len(line); i < numCols; i++ {
|
||||
padded[i] = tw.Empty
|
||||
}
|
||||
return padded
|
||||
}
|
||||
39
vendor/github.com/olekukonko/tablewriter/renderer/markdown.go
generated
vendored
39
vendor/github.com/olekukonko/tablewriter/renderer/markdown.go
generated
vendored
@@ -140,10 +140,10 @@ func (m *Markdown) resolveAlignment(ctx tw.Formatting) tw.Alignment {
|
||||
|
||||
// build default alignment
|
||||
for i := 0; i < total; i++ {
|
||||
m.alignment = append(m.alignment, tw.AlignLeft)
|
||||
m.alignment = append(m.alignment, tw.AlignNone) // Default to AlignNone
|
||||
}
|
||||
|
||||
// add per colum alignment if it exits
|
||||
// add per column alignment if it exists
|
||||
for i := 0; i < total; i++ {
|
||||
m.alignment[i] = ctx.Row.Current[i].Align
|
||||
}
|
||||
@@ -255,9 +255,10 @@ func (m *Markdown) formatSeparator(width int, align tw.Align) string {
|
||||
sb.WriteRune(':')
|
||||
sb.WriteString(strings.Repeat("-", targetWidth-2))
|
||||
sb.WriteRune(':')
|
||||
case tw.AlignNone:
|
||||
sb.WriteString(strings.Repeat("-", targetWidth))
|
||||
default:
|
||||
sb.WriteRune(':')
|
||||
sb.WriteString(strings.Repeat("-", targetWidth-1))
|
||||
sb.WriteString(strings.Repeat("-", targetWidth)) // Fallback
|
||||
}
|
||||
|
||||
result := sb.String()
|
||||
@@ -321,12 +322,11 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader
|
||||
|
||||
defaultPadding := tw.Padding{Left: tw.Space, Right: tw.Space}
|
||||
if !ok {
|
||||
|
||||
cellCtx = tw.CellContext{
|
||||
Data: tw.Empty, Align: align, Padding: defaultPadding,
|
||||
Width: ctx.Row.Widths.Get(colIndex), Merge: tw.MergeState{},
|
||||
}
|
||||
} else if cellCtx.Padding == (tw.Padding{}) {
|
||||
} else if !cellCtx.Padding.Paddable() {
|
||||
cellCtx.Padding = defaultPadding
|
||||
}
|
||||
|
||||
@@ -339,18 +339,6 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader
|
||||
|
||||
// Calculate width and span
|
||||
span := 1
|
||||
|
||||
if align == tw.AlignNone || align == tw.Empty {
|
||||
if ctx.Row.Position == tw.Header && !isHeaderSep {
|
||||
align = tw.AlignCenter
|
||||
} else if ctx.Row.Position == tw.Footer {
|
||||
align = tw.AlignRight
|
||||
} else {
|
||||
align = tw.AlignLeft
|
||||
}
|
||||
m.logger.Debugf("renderMarkdownLine: Col %d using default align '%s'", colIndex, align)
|
||||
}
|
||||
|
||||
visualWidth := 0
|
||||
isHMergeStart := ok && cellCtx.Merge.Horizontal.Present && cellCtx.Merge.Horizontal.Start
|
||||
if isHMergeStart {
|
||||
@@ -383,10 +371,11 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader
|
||||
var formattedSegment string
|
||||
if isHeaderSep {
|
||||
// Use header's alignment from ctx.Row.Previous
|
||||
headerAlign := tw.AlignCenter // Default for headers
|
||||
headerAlign := align
|
||||
if headerCellCtx, headerOK := ctx.Row.Previous[colIndex]; headerOK {
|
||||
headerAlign = headerCellCtx.Align
|
||||
if headerAlign == tw.AlignNone || headerAlign == tw.Empty {
|
||||
// Preserve tw.AlignNone for separator
|
||||
if headerAlign != tw.AlignNone && (headerAlign == tw.Empty || headerAlign == tw.Skip) {
|
||||
headerAlign = tw.AlignCenter
|
||||
}
|
||||
}
|
||||
@@ -403,6 +392,16 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader
|
||||
rowAlign = headerCellCtx.Align
|
||||
}
|
||||
}
|
||||
if rowAlign == tw.AlignNone || rowAlign == tw.Empty {
|
||||
if ctx.Row.Position == tw.Header {
|
||||
rowAlign = tw.AlignCenter
|
||||
} else if ctx.Row.Position == tw.Footer {
|
||||
rowAlign = tw.AlignRight
|
||||
} else {
|
||||
rowAlign = tw.AlignLeft
|
||||
}
|
||||
m.logger.Debugf("renderMarkdownLine: Col %d using default align '%s'", colIndex, rowAlign)
|
||||
}
|
||||
formattedSegment = m.formatCell(content, visualWidth, rowAlign, cellCtx.Padding)
|
||||
}
|
||||
output.WriteString(formattedSegment)
|
||||
|
||||
2
vendor/github.com/olekukonko/tablewriter/renderer/ocean.go
generated
vendored
2
vendor/github.com/olekukonko/tablewriter/renderer/ocean.go
generated
vendored
@@ -340,7 +340,7 @@ func (o *Ocean) renderContentLine(ctx tw.Formatting, lineData []string) {
|
||||
if cellCtx.Align.Validate() == nil && cellCtx.Align != tw.AlignNone {
|
||||
align = cellCtx.Align
|
||||
}
|
||||
if cellCtx.Padding != (tw.Padding{}) {
|
||||
if cellCtx.Padding.Paddable() {
|
||||
padding = cellCtx.Padding
|
||||
}
|
||||
} else if colIdx < len(lineData) {
|
||||
|
||||
56
vendor/github.com/olekukonko/tablewriter/stream.go
generated
vendored
56
vendor/github.com/olekukonko/tablewriter/stream.go
generated
vendored
@@ -113,10 +113,10 @@ func (t *Table) Start() error {
|
||||
|
||||
// Calculate initial fixed widths if provided in StreamConfig.Widths
|
||||
// These widths will be used for all subsequent rendering in streaming mode.
|
||||
if t.config.Stream.Widths.PerColumn != nil && t.config.Stream.Widths.PerColumn.Len() > 0 {
|
||||
if t.config.Widths.PerColumn != nil && t.config.Widths.PerColumn.Len() > 0 {
|
||||
// Use per-column stream widths if set
|
||||
t.logger.Debugf("Using per-column stream widths from StreamConfig: %v", t.config.Stream.Widths.PerColumn)
|
||||
t.streamWidths = t.config.Stream.Widths.PerColumn.Clone()
|
||||
t.logger.Debugf("Using per-column stream widths from StreamConfig: %v", t.config.Widths.PerColumn)
|
||||
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) {
|
||||
@@ -139,14 +139,14 @@ func (t *Table) Start() error {
|
||||
t.logger.Debugf("PerColumn widths map is effectively empty or contains only negative values, streamNumCols = 0.")
|
||||
}
|
||||
|
||||
} else if t.config.Stream.Widths.Global > 0 {
|
||||
} else if t.config.Widths.Global > 0 {
|
||||
// Global width is set, but we don't know the number of columns yet.
|
||||
// Defer applying global width until the first data (Header or first Row) arrives.
|
||||
// Store a placeholder or flag indicating global width should be used.
|
||||
// The simple way for now: Keep streamWidths empty, signal the global width preference.
|
||||
// The width calculation function called later will need to check StreamConfig.Widths.Global
|
||||
// if streamWidths is empty.
|
||||
t.logger.Debugf("Global stream width %d set in StreamConfig. Will derive numCols from first data.", t.config.Stream.Widths.Global)
|
||||
t.logger.Debugf("Global stream width %d set in StreamConfig. Will derive numCols from first data.", t.config.Widths.Global)
|
||||
t.streamWidths = tw.NewMapper[int, int]() // Initialize as empty, will be populated later
|
||||
// Note: No need to store Global width value here, it's available in t.config.Stream.Widths.Global
|
||||
|
||||
@@ -451,26 +451,26 @@ func (t *Table) streamBuildCellContexts(
|
||||
// The paddingConfig should be the CellPadding config relevant to the sample data (Header/Row/Footer).
|
||||
// Returns the determined number of columns.
|
||||
// This function should only be called when t.streamWidths is currently empty.
|
||||
func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigForSampleData tw.CellConfig) int {
|
||||
func (t *Table) streamCalculateWidths(sampling []string, config tw.CellConfig) int {
|
||||
if t.streamWidths != nil && t.streamWidths.Len() > 0 {
|
||||
t.logger.Debug("streamCalculateWidths: Called when streaming widths are already set (%d columns). Reusing existing.", t.streamNumCols)
|
||||
return t.streamNumCols
|
||||
}
|
||||
|
||||
t.logger.Debug("streamCalculateWidths: Calculating streaming widths. Sample data cells: %d. Using section config: %+v", len(sampleDataLines), sectionConfigForSampleData.Formatting)
|
||||
t.logger.Debug("streamCalculateWidths: Calculating streaming widths. Sample data cells: %d. Using section config: %+v", len(sampling), config.Formatting)
|
||||
|
||||
determinedNumCols := 0
|
||||
if t.config.Stream.Widths.PerColumn != nil && t.config.Stream.Widths.PerColumn.Len() > 0 {
|
||||
if t.config.Widths.PerColumn != nil && t.config.Widths.PerColumn.Len() > 0 {
|
||||
maxColIdx := -1
|
||||
t.config.Stream.Widths.PerColumn.Each(func(col int, width int) {
|
||||
t.config.Widths.PerColumn.Each(func(col int, width int) {
|
||||
if col > maxColIdx {
|
||||
maxColIdx = col
|
||||
}
|
||||
})
|
||||
determinedNumCols = maxColIdx + 1
|
||||
t.logger.Debug("streamCalculateWidths: Determined numCols (%d) from StreamConfig.Widths.PerColumn", determinedNumCols)
|
||||
} else if len(sampleDataLines) > 0 {
|
||||
determinedNumCols = len(sampleDataLines)
|
||||
} else if len(sampling) > 0 {
|
||||
determinedNumCols = len(sampling)
|
||||
t.logger.Debug("streamCalculateWidths: Determined numCols (%d) from sample data length", determinedNumCols)
|
||||
} else {
|
||||
t.logger.Debug("streamCalculateWidths: Cannot determine numCols (no PerColumn config, no sample data)")
|
||||
@@ -482,14 +482,14 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
t.streamNumCols = determinedNumCols
|
||||
t.streamWidths = tw.NewMapper[int, int]()
|
||||
|
||||
// Use padding and autowrap from the provided sectionConfigForSampleData
|
||||
paddingForWidthCalc := sectionConfigForSampleData.Padding
|
||||
autoWrapForWidthCalc := sectionConfigForSampleData.Formatting.AutoWrap
|
||||
// Use padding and autowrap from the provided config
|
||||
paddingForWidthCalc := config.Padding
|
||||
autoWrapForWidthCalc := config.Formatting.AutoWrap
|
||||
|
||||
if t.config.Stream.Widths.PerColumn != nil && t.config.Stream.Widths.PerColumn.Len() > 0 {
|
||||
if t.config.Widths.PerColumn != nil && t.config.Widths.PerColumn.Len() > 0 {
|
||||
t.logger.Debug("streamCalculateWidths: Using widths from StreamConfig.Widths.PerColumn")
|
||||
for i := 0; i < t.streamNumCols; i++ {
|
||||
width, ok := t.config.Stream.Widths.PerColumn.OK(i)
|
||||
width, ok := t.config.Widths.PerColumn.OK(i)
|
||||
if !ok {
|
||||
width = 0
|
||||
}
|
||||
@@ -501,12 +501,12 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
t.streamWidths.Set(i, width)
|
||||
}
|
||||
} else {
|
||||
// No PerColumn config, derive from sampleDataLines intelligently
|
||||
// No PerColumn config, derive from sampling intelligently
|
||||
t.logger.Debug("streamCalculateWidths: Intelligently deriving widths from sample data content and padding.")
|
||||
tempRequiredWidths := tw.NewMapper[int, int]() // Widths from updateWidths (content + padding)
|
||||
if len(sampleDataLines) > 0 {
|
||||
if len(sampling) > 0 {
|
||||
// updateWidths calculates: DisplayWidth(content) + padLeft + padRight
|
||||
t.updateWidths(sampleDataLines, tempRequiredWidths, paddingForWidthCalc)
|
||||
t.updateWidths(sampling, tempRequiredWidths, paddingForWidthCalc)
|
||||
}
|
||||
|
||||
ellipsisWidthBuffer := 0
|
||||
@@ -522,13 +522,13 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
// We need to deconstruct it to apply logic to content_width first.
|
||||
|
||||
sampleContent := ""
|
||||
if i < len(sampleDataLines) {
|
||||
sampleContent = t.Trimmer(sampleDataLines[i])
|
||||
if i < len(sampling) {
|
||||
sampleContent = t.Trimmer(sampling[i])
|
||||
}
|
||||
sampleContentDisplayWidth := tw.DisplayWidth(sampleContent)
|
||||
|
||||
colPad := paddingForWidthCalc.Global
|
||||
if i < len(paddingForWidthCalc.PerColumn) && paddingForWidthCalc.PerColumn[i] != (tw.Padding{}) {
|
||||
if i < len(paddingForWidthCalc.PerColumn) && paddingForWidthCalc.PerColumn[i].Paddable() {
|
||||
colPad = paddingForWidthCalc.PerColumn[i]
|
||||
}
|
||||
currentPadLWidth := tw.DisplayWidth(colPad.Left)
|
||||
@@ -584,8 +584,8 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
}
|
||||
|
||||
// Apply Global Constraint (if t.config.Stream.Widths.Global > 0)
|
||||
if t.config.Stream.Widths.Global > 0 && t.streamNumCols > 0 {
|
||||
t.logger.Debug("streamCalculateWidths: Applying global stream width constraint %d", t.config.Stream.Widths.Global)
|
||||
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) {
|
||||
currentTotalColumnWidthsSum += w
|
||||
@@ -606,11 +606,11 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
totalWidthIncludingSeparators += (t.streamNumCols - 1) * separatorWidth
|
||||
}
|
||||
|
||||
if t.config.Stream.Widths.Global < totalWidthIncludingSeparators && totalWidthIncludingSeparators > 0 { // Added check for total > 0
|
||||
t.logger.Debug("streamCalculateWidths: Total calculated width (%d incl separators) exceeds global stream width (%d). Shrinking.", totalWidthIncludingSeparators, t.config.Stream.Widths.Global)
|
||||
if t.config.Widths.Global < totalWidthIncludingSeparators && totalWidthIncludingSeparators > 0 { // Added check for total > 0
|
||||
t.logger.Debug("streamCalculateWidths: Total calculated width (%d incl separators) exceeds global stream width (%d). Shrinking.", totalWidthIncludingSeparators, t.config.Widths.Global)
|
||||
|
||||
// Target sum for column widths only (global limit - total separator width)
|
||||
targetSumForColumnWidths := t.config.Stream.Widths.Global
|
||||
targetSumForColumnWidths := t.config.Widths.Global
|
||||
if t.streamNumCols > 1 {
|
||||
targetSumForColumnWidths -= (t.streamNumCols - 1) * separatorWidth
|
||||
}
|
||||
@@ -671,7 +671,7 @@ func (t *Table) streamCalculateWidths(sampleDataLines []string, sectionConfigFor
|
||||
}
|
||||
t.logger.Debug("streamCalculateWidths: Widths after scaling and distribution: %v", t.streamWidths)
|
||||
} else {
|
||||
t.logger.Debug("streamCalculateWidths: Total calculated width (%d) fits global stream width (%d). No scaling needed.", totalWidthIncludingSeparators, t.config.Stream.Widths.Global)
|
||||
t.logger.Debug("streamCalculateWidths: Total calculated width (%d) fits global stream width (%d). No scaling needed.", totalWidthIncludingSeparators, t.config.Widths.Global)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
186
vendor/github.com/olekukonko/tablewriter/tablewriter.go
generated
vendored
186
vendor/github.com/olekukonko/tablewriter/tablewriter.go
generated
vendored
@@ -133,6 +133,16 @@ func NewTable(w io.Writer, opts ...Option) *Table {
|
||||
return t
|
||||
}
|
||||
|
||||
// NewWriter creates a new table with default settings for backward compatibility.
|
||||
// It logs the creation if debugging is enabled.
|
||||
func NewWriter(w io.Writer) *Table {
|
||||
t := NewTable(w)
|
||||
if t.logger != nil {
|
||||
t.logger.Debug("NewWriter created buffered Table")
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Caption sets the table caption (legacy method).
|
||||
// Defaults to BottomCenter alignment, wrapping to table width.
|
||||
// Use SetCaptionOptions for more control.
|
||||
@@ -397,6 +407,11 @@ func (t *Table) Options(opts ...Option) *Table {
|
||||
t.logger.Suspend()
|
||||
}
|
||||
|
||||
// help resolve from deprecation
|
||||
//if t.config.Stream.Enable {
|
||||
// t.config.Widths = t.config.Stream.Widths
|
||||
//}
|
||||
|
||||
// send logger to renderer
|
||||
// this will overwrite the default logger
|
||||
t.renderer.Logger(t.logger)
|
||||
@@ -508,19 +523,40 @@ func (t *Table) appendSingle(row interface{}) error {
|
||||
// Parameter config provides alignment settings for the section.
|
||||
// Returns a map of column indices to alignment settings.
|
||||
func (t *Table) buildAligns(config tw.CellConfig) map[int]tw.Align {
|
||||
t.logger.Debugf("buildAligns INPUT: config.Formatting.Align=%s, config.ColumnAligns=%v", config.Formatting.Alignment, config.ColumnAligns)
|
||||
// Start with global alignment, preferring deprecated Formatting.Alignment
|
||||
effectiveGlobalAlign := config.Formatting.Alignment
|
||||
if effectiveGlobalAlign == tw.Empty || effectiveGlobalAlign == tw.Skip {
|
||||
effectiveGlobalAlign = config.Alignment.Global
|
||||
if config.Formatting.Alignment != tw.Empty && config.Formatting.Alignment != tw.Skip {
|
||||
t.logger.Warnf("Using deprecated CellFormatting.Alignment (%s). Migrate to CellConfig.Alignment.Global.", config.Formatting.Alignment)
|
||||
}
|
||||
}
|
||||
|
||||
// Use per-column alignments, preferring deprecated ColumnAligns
|
||||
effectivePerColumn := config.ColumnAligns
|
||||
if len(effectivePerColumn) == 0 && len(config.Alignment.PerColumn) > 0 {
|
||||
effectivePerColumn = make([]tw.Align, len(config.Alignment.PerColumn))
|
||||
copy(effectivePerColumn, config.Alignment.PerColumn)
|
||||
if len(config.ColumnAligns) > 0 {
|
||||
t.logger.Warnf("Using deprecated CellConfig.ColumnAligns (%v). Migrate to CellConfig.Alignment.PerColumn.", config.ColumnAligns)
|
||||
}
|
||||
}
|
||||
|
||||
// Log input for debugging
|
||||
t.logger.Debugf("buildAligns INPUT: deprecated Formatting.Alignment=%s, deprecated ColumnAligns=%v, config.Alignment.Global=%s, config.Alignment.PerColumn=%v",
|
||||
config.Formatting.Alignment, config.ColumnAligns, config.Alignment.Global, config.Alignment.PerColumn)
|
||||
|
||||
numColsToUse := t.getNumColsToUse()
|
||||
colAlignsResult := make(map[int]tw.Align)
|
||||
for i := 0; i < numColsToUse; i++ {
|
||||
currentAlign := config.Formatting.Alignment
|
||||
if i < len(config.ColumnAligns) {
|
||||
colSpecificAlign := config.ColumnAligns[i]
|
||||
if colSpecificAlign != tw.Empty && colSpecificAlign != tw.Skip {
|
||||
currentAlign = colSpecificAlign
|
||||
}
|
||||
currentAlign := effectiveGlobalAlign
|
||||
if i < len(effectivePerColumn) && effectivePerColumn[i] != tw.Empty && effectivePerColumn[i] != tw.Skip {
|
||||
currentAlign = effectivePerColumn[i]
|
||||
}
|
||||
// Skip validation here; rely on rendering to handle invalid alignments
|
||||
colAlignsResult[i] = currentAlign
|
||||
}
|
||||
|
||||
t.logger.Debugf("Aligns built: %v (length %d)", colAlignsResult, len(colAlignsResult))
|
||||
return colAlignsResult
|
||||
}
|
||||
@@ -532,7 +568,7 @@ func (t *Table) buildPadding(padding tw.CellPadding) map[int]tw.Padding {
|
||||
numColsToUse := t.getNumColsToUse()
|
||||
colPadding := make(map[int]tw.Padding)
|
||||
for i := 0; i < numColsToUse; i++ {
|
||||
if i < len(padding.PerColumn) && padding.PerColumn[i] != (tw.Padding{}) {
|
||||
if i < len(padding.PerColumn) && padding.PerColumn[i].Paddable() {
|
||||
colPadding[i] = padding.PerColumn[i]
|
||||
} else {
|
||||
colPadding[i] = padding.Global
|
||||
@@ -699,8 +735,12 @@ func (t *Table) maxColumns() int {
|
||||
return m
|
||||
}
|
||||
|
||||
// printTopBottomCaption prints the table's caption at the specified top or bottom position.
|
||||
// It wraps the caption text to fit the table width or a user-defined width, aligns it according
|
||||
// to the specified alignment, and writes it to the provided writer. If the caption text is empty
|
||||
// or the spot is invalid, it logs the issue and returns without printing. The function handles
|
||||
// wrapping errors by falling back to splitting on newlines or using the original text.
|
||||
func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
// Log the state of t.caption
|
||||
t.logger.Debugf("[printCaption Entry] Text=%q, Spot=%v (type %T), Align=%q, UserWidth=%d, ActualTableWidth=%d",
|
||||
t.caption.Text, t.caption.Spot, t.caption.Spot, t.caption.Align, t.caption.Width, actualTableWidth)
|
||||
|
||||
@@ -711,12 +751,11 @@ func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Determine captionWrapWidth
|
||||
var captionWrapWidth int
|
||||
if t.caption.Width > 0 {
|
||||
captionWrapWidth = t.caption.Width
|
||||
t.logger.Debugf("[printCaption] Using user-defined caption.Width %d for wrapping.", captionWrapWidth)
|
||||
} else if actualTableWidth <= 4 { // Empty or minimal table
|
||||
} else if actualTableWidth <= 4 {
|
||||
captionWrapWidth = tw.DisplayWidth(t.caption.Text)
|
||||
t.logger.Debugf("[printCaption] Empty table, no user caption.Width: Using natural caption width %d.", captionWrapWidth)
|
||||
} else {
|
||||
@@ -724,14 +763,12 @@ func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
t.logger.Debugf("[printCaption] Non-empty table, no user caption.Width: Using actualTableWidth %d for wrapping.", actualTableWidth)
|
||||
}
|
||||
|
||||
// Ensure captionWrapWidth is positive
|
||||
if captionWrapWidth <= 0 {
|
||||
captionWrapWidth = 10 // Minimum sensible width
|
||||
captionWrapWidth = 10
|
||||
t.logger.Warnf("[printCaption] captionWrapWidth was %d (<=0). Setting to minimum %d.", captionWrapWidth, 10)
|
||||
}
|
||||
t.logger.Debugf("[printCaption] Final captionWrapWidth to be used by twwarp: %d", captionWrapWidth)
|
||||
|
||||
// Wrap the caption text
|
||||
wrappedCaptionLines, count := twwarp.WrapString(t.caption.Text, captionWrapWidth)
|
||||
if count == 0 {
|
||||
t.logger.Errorf("[printCaption] Error from twwarp.WrapString (width %d): %v. Text: %q", captionWrapWidth, count, t.caption.Text)
|
||||
@@ -754,7 +791,6 @@ func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
t.logger.Debugf("[printCaption] Wrapped caption into %d lines: %v", len(wrappedCaptionLines), wrappedCaptionLines)
|
||||
}
|
||||
|
||||
// Determine padding target width
|
||||
paddingTargetWidth := actualTableWidth
|
||||
if t.caption.Width > 0 {
|
||||
paddingTargetWidth = t.caption.Width
|
||||
@@ -763,7 +799,6 @@ func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
}
|
||||
t.logger.Debugf("[printCaption] Final paddingTargetWidth for tw.Pad: %d", paddingTargetWidth)
|
||||
|
||||
// Print each wrapped line
|
||||
for i, line := range wrappedCaptionLines {
|
||||
align := t.caption.Align
|
||||
if align == "" || align == tw.AlignDefault || align == tw.AlignNone {
|
||||
@@ -791,22 +826,11 @@ func (t *Table) printTopBottomCaption(w io.Writer, actualTableWidth int) {
|
||||
// Parameters include cells to process and config for formatting rules.
|
||||
// Returns a slice of string slices representing processed lines.
|
||||
func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string {
|
||||
// force max width
|
||||
|
||||
isStreaming := t.config.Stream.Enable && t.hasPrinted
|
||||
t.logger.Debugf("prepareContent: Processing cells=%v (streaming: %v)", cells, isStreaming)
|
||||
initialInputCellCount := len(cells)
|
||||
result := make([][]string, 0)
|
||||
|
||||
// ll.Dbg(t.config.MaxWidth)
|
||||
// force max width
|
||||
if t.config.MaxWidth > 0 {
|
||||
// it has headers
|
||||
if len(cells) > 0 {
|
||||
config.ColMaxWidths.Global = int(math.Floor(float64(t.config.MaxWidth) / float64(len(cells))))
|
||||
}
|
||||
}
|
||||
|
||||
effectiveNumCols := initialInputCellCount
|
||||
if isStreaming {
|
||||
if t.streamNumCols > 0 {
|
||||
@@ -830,6 +854,16 @@ func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string
|
||||
}
|
||||
}
|
||||
|
||||
if t.config.MaxWidth > 0 && !t.config.Widths.Constrained() {
|
||||
if effectiveNumCols > 0 {
|
||||
derivedSectionGlobalMaxWidth := int(math.Floor(float64(t.config.MaxWidth) / float64(effectiveNumCols)))
|
||||
config.ColMaxWidths.Global = derivedSectionGlobalMaxWidth
|
||||
t.logger.Debugf("prepareContent: Table MaxWidth %d active and t.config.Widths not constrained. "+
|
||||
"Derived section ColMaxWidths.Global: %d for %d columns. This will be used by calculateContentMaxWidth if no higher priority constraints exist.",
|
||||
t.config.MaxWidth, config.ColMaxWidths.Global, effectiveNumCols)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < effectiveNumCols; i++ {
|
||||
cellContent := ""
|
||||
if i < len(cells) {
|
||||
@@ -841,7 +875,7 @@ func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string
|
||||
cellContent = t.Trimmer(cellContent)
|
||||
|
||||
colPad := config.Padding.Global
|
||||
if i < len(config.Padding.PerColumn) && config.Padding.PerColumn[i] != (tw.Padding{}) {
|
||||
if i < len(config.Padding.PerColumn) && config.Padding.PerColumn[i].Paddable() {
|
||||
colPad = config.Padding.PerColumn[i]
|
||||
}
|
||||
|
||||
@@ -881,50 +915,45 @@ func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string
|
||||
case tw.WrapBreak:
|
||||
wrapped := make([]string, 0)
|
||||
currentLine := line
|
||||
breakCharWidth := tw.DisplayWidth(tw.CharBreak)
|
||||
for tw.DisplayWidth(currentLine) > effectiveContentMaxWidth {
|
||||
breakPoint := tw.BreakPoint(currentLine, effectiveContentMaxWidth)
|
||||
if breakPoint <= 0 {
|
||||
t.logger.Warnf("prepareContent: WrapBreak - BreakPoint <= 0 for line '%s' at width %d. Attempting manual break.", currentLine, effectiveContentMaxWidth)
|
||||
runes := []rune(currentLine)
|
||||
targetWidth := effectiveContentMaxWidth - breakCharWidth
|
||||
if targetWidth < 0 {
|
||||
targetWidth = 0
|
||||
}
|
||||
breakPoint := tw.BreakPoint(currentLine, targetWidth)
|
||||
runes := []rune(currentLine)
|
||||
if breakPoint <= 0 || breakPoint > len(runes) {
|
||||
t.logger.Warnf("prepareContent: WrapBreak - Invalid BreakPoint %d for line '%s' at width %d. Attempting manual break.", breakPoint, currentLine, targetWidth)
|
||||
actualBreakRuneCount := 0
|
||||
tempWidth := 0
|
||||
for charIdx, r := range currentLine {
|
||||
for charIdx, r := range runes {
|
||||
runeStr := string(r)
|
||||
rw := tw.DisplayWidth(runeStr)
|
||||
if tempWidth+rw > effectiveContentMaxWidth && charIdx > 0 {
|
||||
if tempWidth+rw > targetWidth && charIdx > 0 {
|
||||
break
|
||||
}
|
||||
tempWidth += rw
|
||||
actualBreakRuneCount = charIdx + 1
|
||||
if tempWidth >= effectiveContentMaxWidth && charIdx == 0 {
|
||||
if tempWidth >= targetWidth && charIdx == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if actualBreakRuneCount == 0 && len(runes) > 0 {
|
||||
actualBreakRuneCount = 1
|
||||
}
|
||||
|
||||
if actualBreakRuneCount > 0 && actualBreakRuneCount <= len(runes) {
|
||||
wrapped = append(wrapped, string(runes[:actualBreakRuneCount])+tw.CharBreak)
|
||||
currentLine = string(runes[actualBreakRuneCount:])
|
||||
} else {
|
||||
if tw.DisplayWidth(currentLine) > 0 {
|
||||
wrapped = append(wrapped, currentLine)
|
||||
currentLine = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
} else {
|
||||
runes := []rune(currentLine)
|
||||
if breakPoint <= len(runes) {
|
||||
wrapped = append(wrapped, string(runes[:breakPoint])+tw.CharBreak)
|
||||
currentLine = string(runes[breakPoint:])
|
||||
} else {
|
||||
t.logger.Warnf("prepareContent: WrapBreak - BreakPoint (%d) out of bounds for line runes (%d). Adding full line.", breakPoint, len(runes))
|
||||
t.logger.Warnf("prepareContent: WrapBreak - Cannot break line '%s'. Adding as is.", currentLine)
|
||||
wrapped = append(wrapped, currentLine)
|
||||
currentLine = ""
|
||||
break
|
||||
}
|
||||
} else {
|
||||
wrapped = append(wrapped, string(runes[:breakPoint])+tw.CharBreak)
|
||||
currentLine = string(runes[breakPoint:])
|
||||
}
|
||||
}
|
||||
if tw.DisplayWidth(currentLine) > 0 {
|
||||
@@ -959,7 +988,8 @@ func (t *Table) prepareContent(cells []string, config tw.CellConfig) [][]string
|
||||
if i < len(result[j]) {
|
||||
result[j][i] = cellLineContent
|
||||
} else {
|
||||
t.logger.Warnf("prepareContent: Column index %d out of bounds (%d) during result matrix population.", i, len(result[j]))
|
||||
t.logger.Warnf("prepareContent: Column index %d out of bounds (%d) during result matrix population. EffectiveNumCols: %d. This indicates a logic error.",
|
||||
i, len(result[j]), effectiveNumCols)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1304,6 +1334,7 @@ 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()
|
||||
|
||||
if t.config.Stream.Enable {
|
||||
@@ -1339,9 +1370,8 @@ func (t *Table) render() error {
|
||||
t.logger.Debugf("No caption detected. Rendering table core directly to writer.")
|
||||
}
|
||||
|
||||
//Render Table Core ---
|
||||
t.writer = targetWriter // Set writer only when necessary
|
||||
|
||||
//Render Table Core
|
||||
t.writer = targetWriter
|
||||
ctx, mctx, err := t.prepareContexts()
|
||||
if err != nil {
|
||||
t.writer = originalWriter
|
||||
@@ -1387,7 +1417,6 @@ func (t *Table) render() error {
|
||||
if renderError {
|
||||
return firstRenderErr // Return error from core rendering if any
|
||||
}
|
||||
//End Render Table Core ---
|
||||
|
||||
//Caption Handling & Final Output ---
|
||||
if isTopOrBottomCaption {
|
||||
@@ -1877,17 +1906,54 @@ func (t *Table) renderHeader(ctx *renderContext, mctx *mergeContext) error {
|
||||
|
||||
if cfg.Settings.Lines.ShowHeaderLine.Enabled() && (len(ctx.rowLines) > 0 || len(ctx.footerLines) > 0) {
|
||||
ctx.logger.Debug("Rendering header separator line")
|
||||
hctx.rowIdx = 0
|
||||
hctx.lineIdx = len(ctx.headerLines) - 1
|
||||
hctx.line = padLine(ctx.headerLines[hctx.lineIdx], ctx.numCols)
|
||||
hctx.location = tw.LocationMiddle
|
||||
resp := t.buildCellContexts(ctx, mctx, hctx, colAligns, colPadding)
|
||||
|
||||
var nextSectionCells map[int]tw.CellContext
|
||||
var nextSectionWidths tw.Mapper[int, int]
|
||||
|
||||
if len(ctx.rowLines) > 0 {
|
||||
nextSectionWidths = ctx.widths[tw.Row]
|
||||
rowColAligns := t.buildAligns(t.config.Row)
|
||||
rowColPadding := t.buildPadding(t.config.Row.Padding)
|
||||
firstRowHctx := &helperContext{
|
||||
position: tw.Row,
|
||||
rowIdx: 0,
|
||||
lineIdx: 0,
|
||||
}
|
||||
if len(ctx.rowLines[0]) > 0 {
|
||||
firstRowHctx.line = padLine(ctx.rowLines[0][0], ctx.numCols)
|
||||
} else {
|
||||
firstRowHctx.line = make([]string, ctx.numCols)
|
||||
}
|
||||
firstRowResp := t.buildCellContexts(ctx, mctx, firstRowHctx, rowColAligns, rowColPadding)
|
||||
nextSectionCells = firstRowResp.cells
|
||||
} else if len(ctx.footerLines) > 0 {
|
||||
nextSectionWidths = ctx.widths[tw.Row]
|
||||
footerColAligns := t.buildAligns(t.config.Footer)
|
||||
footerColPadding := t.buildPadding(t.config.Footer.Padding)
|
||||
firstFooterHctx := &helperContext{
|
||||
position: tw.Footer,
|
||||
rowIdx: 0,
|
||||
lineIdx: 0,
|
||||
}
|
||||
if len(ctx.footerLines) > 0 {
|
||||
firstFooterHctx.line = padLine(ctx.footerLines[0], ctx.numCols)
|
||||
} else {
|
||||
firstFooterHctx.line = make([]string, ctx.numCols)
|
||||
}
|
||||
firstFooterResp := t.buildCellContexts(ctx, mctx, firstFooterHctx, footerColAligns, footerColPadding)
|
||||
nextSectionCells = firstFooterResp.cells
|
||||
} else {
|
||||
nextSectionWidths = ctx.widths[tw.Header]
|
||||
nextSectionCells = nil
|
||||
}
|
||||
|
||||
f.Line(tw.Formatting{
|
||||
Row: tw.RowContext{
|
||||
Widths: ctx.widths[tw.Header],
|
||||
Widths: nextSectionWidths,
|
||||
Current: resp.cells,
|
||||
Previous: resp.prevCells,
|
||||
Next: resp.nextCells,
|
||||
Next: nextSectionCells,
|
||||
Position: tw.Header,
|
||||
Location: tw.LocationMiddle,
|
||||
},
|
||||
|
||||
26
vendor/github.com/olekukonko/tablewriter/tw/cell.go
generated
vendored
26
vendor/github.com/olekukonko/tablewriter/tw/cell.go
generated
vendored
@@ -2,13 +2,17 @@ package tw
|
||||
|
||||
// CellFormatting holds formatting options for table cells.
|
||||
type CellFormatting struct {
|
||||
Alignment Align // Text alignment within the cell (e.g., Left, Right, Center)
|
||||
AutoWrap int // Wrapping behavior (e.g., WrapTruncate, WrapNormal)
|
||||
MergeMode int // Bitmask for merge behavior (e.g., MergeHorizontal, MergeVertical)
|
||||
AutoWrap int // Wrapping behavior (e.g., WrapTruncate, WrapNormal)
|
||||
MergeMode int // Bitmask for merge behavior (e.g., MergeHorizontal, MergeVertical)
|
||||
|
||||
// Changed form bool to State
|
||||
// See https://github.com/olekukonko/tablewriter/issues/261
|
||||
AutoFormat State // Enables automatic formatting (e.g., title case for headers)
|
||||
|
||||
// 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.
|
||||
@@ -30,17 +34,31 @@ type CellCallbacks struct {
|
||||
PerColumn []func() // Column-specific callbacks
|
||||
}
|
||||
|
||||
// CellAlignment defines alignment settings for table cells.
|
||||
type CellAlignment struct {
|
||||
Global Align // Default alignment applied to all cells
|
||||
PerColumn []Align // Column-specific alignment overrides
|
||||
}
|
||||
|
||||
// CellConfig combines formatting, padding, and callback settings for a table section.
|
||||
type CellConfig struct {
|
||||
Formatting CellFormatting // Cell formatting options
|
||||
Padding CellPadding // Padding configuration
|
||||
Callbacks CellCallbacks // Callback functions (unused)
|
||||
Filter CellFilter // Function to filter cell content (renamed from Filter Filter)
|
||||
ColumnAligns []Align // Per-column alignment overrides
|
||||
Alignment CellAlignment // Alignment configuration for cells
|
||||
ColMaxWidths CellWidth // Per-column maximum width overrides
|
||||
|
||||
// Deprecated: use Alignment.PerColumn instead. Will be removed in a future version.
|
||||
// will be removed soon
|
||||
ColumnAligns []Align // Per-column alignment overrides
|
||||
}
|
||||
|
||||
type CellWidth struct {
|
||||
Global int
|
||||
PerColumn Mapper[int, int]
|
||||
}
|
||||
|
||||
func (c CellWidth) Constrained() bool {
|
||||
return c.Global > 0 || c.PerColumn.Len() > 0
|
||||
}
|
||||
|
||||
9
vendor/github.com/olekukonko/tablewriter/tw/fn.go
generated
vendored
9
vendor/github.com/olekukonko/tablewriter/tw/fn.go
generated
vendored
@@ -245,7 +245,7 @@ func IsNumeric(s string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// SplitCamelCase splits a camelCase or PascalCase string into separate words.
|
||||
// SplitCamelCase splits a camelCase or PascalCase or snake_case string into separate words.
|
||||
// It detects transitions between uppercase, lowercase, digits, and other characters.
|
||||
func SplitCamelCase(src string) (entries []string) {
|
||||
// Validate UTF-8 input; return as single entry if invalid
|
||||
@@ -284,10 +284,11 @@ func SplitCamelCase(src string) (entries []string) {
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
}
|
||||
}
|
||||
// Convert rune groups to strings, excluding empty or whitespace-only groups
|
||||
// Convert rune groups to strings, excluding empty, underscore or whitespace-only groups
|
||||
for _, s := range runes {
|
||||
if len(s) > 0 && strings.TrimSpace(string(s)) != "" {
|
||||
entries = append(entries, string(s))
|
||||
str := string(s)
|
||||
if len(s) > 0 && strings.TrimSpace(str) != "" && str != "_" {
|
||||
entries = append(entries, str)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
18
vendor/github.com/olekukonko/tablewriter/tw/preset.go
generated
vendored
Normal file
18
vendor/github.com/olekukonko/tablewriter/tw/preset.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package tw
|
||||
|
||||
// BorderNone defines a border configuration with all sides disabled.
|
||||
var (
|
||||
// PaddingNone represents explicitly empty padding (no spacing on any side)
|
||||
// Equivalent to Padding{Overwrite: true}
|
||||
PaddingNone = Padding{Left: Empty, Right: Empty, Top: Empty, Bottom: Empty, Overwrite: true}
|
||||
BorderNone = Border{Left: Off, Right: Off, Top: Off, Bottom: Off}
|
||||
LinesNone = Lines{ShowTop: Off, ShowBottom: Off, ShowHeaderLine: Off, ShowFooterLine: Off}
|
||||
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}
|
||||
)
|
||||
23
vendor/github.com/olekukonko/tablewriter/tw/renderer.go
generated
vendored
23
vendor/github.com/olekukonko/tablewriter/tw/renderer.go
generated
vendored
@@ -108,21 +108,18 @@ type Settings struct {
|
||||
|
||||
// Border defines the visibility states of table borders.
|
||||
type Border struct {
|
||||
Left State // Left border visibility
|
||||
Right State // Right border visibility
|
||||
Top State // Top border visibility
|
||||
Bottom State // Bottom border visibility
|
||||
Left State // Left border visibility
|
||||
Right State // Right border visibility
|
||||
Top State // Top border visibility
|
||||
Bottom State // Bottom border visibility
|
||||
Overwrite bool
|
||||
}
|
||||
|
||||
// BorderNone defines a border configuration with all sides disabled.
|
||||
var (
|
||||
PaddingNone = Padding{Left: Empty, Right: Empty, Top: Empty, Bottom: Empty}
|
||||
BorderNone = Border{Left: Off, Right: Off, Top: Off, Bottom: Off}
|
||||
LinesNone = Lines{ShowTop: Off, ShowBottom: Off, ShowHeaderLine: Off, ShowFooterLine: Off}
|
||||
SeparatorsNone = Separators{ShowHeader: Off, ShowFooter: Off, BetweenRows: Off, BetweenColumns: Off}
|
||||
)
|
||||
|
||||
type StreamConfig struct {
|
||||
Enable bool
|
||||
Widths CellWidth // Cell/column widths
|
||||
|
||||
// Deprecated: Use top-level Config.Widths for streaming width control.
|
||||
// This field will be removed in a future version. It will be respected if
|
||||
// Config.Widths is not set and this field is.
|
||||
Widths CellWidth
|
||||
}
|
||||
|
||||
2
vendor/github.com/olekukonko/tablewriter/tw/tw.go
generated
vendored
2
vendor/github.com/olekukonko/tablewriter/tw/tw.go
generated
vendored
@@ -15,6 +15,8 @@ const (
|
||||
Skip = ""
|
||||
Space = " "
|
||||
NewLine = "\n"
|
||||
Column = ":"
|
||||
Dash = "-"
|
||||
)
|
||||
|
||||
// Feature State Constants
|
||||
|
||||
64
vendor/github.com/olekukonko/tablewriter/tw/types.go
generated
vendored
64
vendor/github.com/olekukonko/tablewriter/tw/types.go
generated
vendored
@@ -132,22 +132,68 @@ func (c Caption) WithWidth(width int) Caption {
|
||||
return c
|
||||
}
|
||||
|
||||
// Padding defines custom padding characters for a cell
|
||||
type Control struct {
|
||||
Hide State
|
||||
}
|
||||
|
||||
// Compact configures compact width optimization for merged cells.
|
||||
type Compact struct {
|
||||
Merge State // Merge enables compact width calculation during cell merging, optimizing space allocation.
|
||||
}
|
||||
|
||||
// Behavior defines settings that control table rendering behaviors, such as column visibility and content formatting.
|
||||
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.
|
||||
|
||||
Header Control // Header specifies control settings for the table header.
|
||||
Footer Control // Footer specifies control settings for the table footer.
|
||||
|
||||
// Compact enables optimized width calculation for merged cells, such as in horizontal merges,
|
||||
// by systematically determining the most efficient width instead of scaling by the number of columns.
|
||||
Compact Compact
|
||||
}
|
||||
|
||||
// Padding defines the spacing characters around cell content in all four directions.
|
||||
// A zero-value Padding struct will use the table's default padding unless Overwrite is true.
|
||||
type Padding struct {
|
||||
Left string
|
||||
Right string
|
||||
Top string
|
||||
Bottom string
|
||||
|
||||
// Overwrite forces tablewriter to use this padding configuration exactly as specified,
|
||||
// even when empty. When false (default), empty Padding fields will inherit defaults.
|
||||
//
|
||||
// For explicit no-padding, use the PaddingNone constant instead of setting Overwrite.
|
||||
Overwrite bool
|
||||
}
|
||||
|
||||
type Control struct {
|
||||
Hide State
|
||||
// Common padding configurations for convenience
|
||||
|
||||
// Equals reports whether two Padding configurations are identical in all fields.
|
||||
// This includes comparing the Overwrite flag as part of the equality check.
|
||||
func (p Padding) Equals(padding Padding) bool {
|
||||
return p.Left == padding.Left &&
|
||||
p.Right == padding.Right &&
|
||||
p.Top == padding.Top &&
|
||||
p.Bottom == padding.Bottom &&
|
||||
p.Overwrite == padding.Overwrite
|
||||
}
|
||||
|
||||
// Behavior defines table behavior settings that control features like auto-hiding columns and trimming spaces.
|
||||
type Behavior struct {
|
||||
AutoHide State // Controls whether empty columns are automatically hidden (ignored in streaming mode)
|
||||
TrimSpace State // Controls whether leading/trailing spaces are trimmed from cell content
|
||||
Header Control
|
||||
Footer Control
|
||||
// Empty reports whether all padding strings are empty (all fields == "").
|
||||
// Note that an Empty padding may still take effect if Overwrite is true.
|
||||
func (p Padding) Empty() bool {
|
||||
return p.Left == "" && p.Right == "" && p.Top == "" && p.Bottom == ""
|
||||
}
|
||||
|
||||
// Paddable reports whether this Padding configuration should override existing padding.
|
||||
// Returns true if either:
|
||||
// - Any padding string is non-empty (!p.Empty())
|
||||
// - Overwrite flag is true (even with all strings empty)
|
||||
//
|
||||
// This is used internally during configuration merging to determine whether to
|
||||
// apply the padding settings.
|
||||
func (p Padding) Paddable() bool {
|
||||
return !p.Empty() || p.Overwrite
|
||||
}
|
||||
|
||||
418
vendor/github.com/olekukonko/tablewriter/zoo.go
generated
vendored
418
vendor/github.com/olekukonko/tablewriter/zoo.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/olekukonko/errors"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -576,26 +577,23 @@ func (t *Table) buildPaddingLineContents(padChar string, widths tw.Mapper[int, i
|
||||
// Parameter ctx holds rendering state with width maps.
|
||||
// Returns an error if width calculation fails.
|
||||
func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error {
|
||||
ctx.logger.Debugf("calculateAndNormalizeWidths: Computing and normalizing widths for %d columns", ctx.numCols)
|
||||
ctx.logger.Debugf("calculateAndNormalizeWidths: Computing and normalizing widths for %d columns. Compact: %v",
|
||||
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 header widths
|
||||
// Compute content-based widths for each section
|
||||
for _, lines := range ctx.headerLines {
|
||||
t.updateWidths(lines, t.headerWidths, t.config.Header.Padding)
|
||||
}
|
||||
ctx.logger.Debugf("Initial Header widths: %v", t.headerWidths)
|
||||
|
||||
// Cache row widths to avoid re-iteration
|
||||
rowWidthCache := make([]tw.Mapper[int, int], len(ctx.rowLines))
|
||||
for i, row := range ctx.rowLines {
|
||||
rowWidthCache[i] = tw.NewMapper[int, int]()
|
||||
for _, line := range row {
|
||||
t.updateWidths(line, rowWidthCache[i], t.config.Row.Padding)
|
||||
// Aggregate into t.rowWidths
|
||||
for col, width := range rowWidthCache[i] {
|
||||
currentMax, _ := t.rowWidths.OK(col)
|
||||
if width > currentMax {
|
||||
@@ -604,41 +602,348 @@ func (t *Table) calculateAndNormalizeWidths(ctx *renderContext) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.logger.Debugf("Initial Row widths: %v", t.rowWidths)
|
||||
|
||||
// Compute footer widths
|
||||
for _, lines := range ctx.footerLines {
|
||||
t.updateWidths(lines, t.footerWidths, t.config.Footer.Padding)
|
||||
}
|
||||
ctx.logger.Debugf("Initial Footer widths: %v", t.footerWidths)
|
||||
ctx.logger.Debugf("Content-based widths: header=%v, row=%v, footer=%v", t.headerWidths, t.rowWidths, t.footerWidths)
|
||||
|
||||
// Initialize width maps for normalization
|
||||
ctx.widths[tw.Header] = tw.NewMapper[int, int]()
|
||||
ctx.widths[tw.Row] = tw.NewMapper[int, int]()
|
||||
ctx.widths[tw.Footer] = tw.NewMapper[int, int]()
|
||||
|
||||
// Normalize widths by taking the maximum across sections
|
||||
for i := 0; i < ctx.numCols; i++ {
|
||||
maxWidth := 0
|
||||
for _, w := range []tw.Mapper[int, int]{t.headerWidths, t.rowWidths, t.footerWidths} {
|
||||
if wd := w.Get(i); wd > maxWidth {
|
||||
maxWidth = wd
|
||||
// Analyze header merges for optimization
|
||||
var headerMergeSpans map[int]int
|
||||
if t.config.Header.Formatting.MergeMode&tw.MergeHorizontal != 0 && len(ctx.headerLines) > 0 {
|
||||
headerMergeSpans = make(map[int]int)
|
||||
visitedCols := make(map[int]bool)
|
||||
firstHeaderLine := ctx.headerLines[0]
|
||||
if len(firstHeaderLine) > 0 {
|
||||
for i := 0; i < len(firstHeaderLine); {
|
||||
if visitedCols[i] {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
var currentLogicalCellContentBuilder strings.Builder
|
||||
for _, hLine := range ctx.headerLines {
|
||||
if i < len(hLine) {
|
||||
currentLogicalCellContentBuilder.WriteString(hLine[i])
|
||||
}
|
||||
}
|
||||
currentHeaderCellContent := t.Trimmer(currentLogicalCellContentBuilder.String())
|
||||
span := 1
|
||||
for j := i + 1; j < len(firstHeaderLine); j++ {
|
||||
var nextLogicalCellContentBuilder strings.Builder
|
||||
for _, hLine := range ctx.headerLines {
|
||||
if j < len(hLine) {
|
||||
nextLogicalCellContentBuilder.WriteString(hLine[j])
|
||||
}
|
||||
}
|
||||
nextHeaderCellContent := t.Trimmer(nextLogicalCellContentBuilder.String())
|
||||
if currentHeaderCellContent == nextHeaderCellContent && currentHeaderCellContent != "" && currentHeaderCellContent != "-" {
|
||||
span++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if span > 1 {
|
||||
headerMergeSpans[i] = span
|
||||
for k := 0; k < span; k++ {
|
||||
visitedCols[i+k] = true
|
||||
}
|
||||
}
|
||||
i += span
|
||||
}
|
||||
}
|
||||
ctx.widths[tw.Header].Set(i, maxWidth)
|
||||
ctx.widths[tw.Row].Set(i, maxWidth)
|
||||
ctx.widths[tw.Footer].Set(i, maxWidth)
|
||||
if len(headerMergeSpans) > 0 {
|
||||
ctx.logger.Debugf("Header merge spans: %v", headerMergeSpans)
|
||||
}
|
||||
}
|
||||
ctx.logger.Debugf("Normalized widths: header=%v, row=%v, footer=%v", ctx.widths[tw.Header], ctx.widths[tw.Row], ctx.widths[tw.Footer])
|
||||
|
||||
// Determine natural column widths
|
||||
naturalColumnWidths := tw.NewMapper[int, int]()
|
||||
for i := 0; i < ctx.numCols; i++ {
|
||||
width := 0
|
||||
if colWidth, ok := t.config.Widths.PerColumn.OK(i); ok && colWidth >= 0 {
|
||||
width = colWidth
|
||||
ctx.logger.Debugf("Col %d width from Config.Widths.PerColumn: %d", i, width)
|
||||
} else {
|
||||
maxRowFooterWidth := tw.Max(t.rowWidths.Get(i), t.footerWidths.Get(i))
|
||||
headerCellOriginalWidth := t.headerWidths.Get(i)
|
||||
if t.config.Behavior.Compact.Merge.Enabled() &&
|
||||
t.config.Header.Formatting.MergeMode&tw.MergeHorizontal != 0 &&
|
||||
headerMergeSpans != nil {
|
||||
isColInHeaderMerge := false
|
||||
for startCol, span := range headerMergeSpans {
|
||||
if i >= startCol && i < startCol+span {
|
||||
isColInHeaderMerge = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isColInHeaderMerge {
|
||||
width = maxRowFooterWidth
|
||||
if width == 0 && headerCellOriginalWidth > 0 {
|
||||
width = headerCellOriginalWidth
|
||||
}
|
||||
ctx.logger.Debugf("Col %d (in merge) width: %d (row/footer: %d, header: %d)", i, width, maxRowFooterWidth, headerCellOriginalWidth)
|
||||
} else {
|
||||
width = tw.Max(headerCellOriginalWidth, maxRowFooterWidth)
|
||||
ctx.logger.Debugf("Col %d (not in merge) width: %d", i, width)
|
||||
}
|
||||
} else {
|
||||
width = tw.Max(tw.Max(headerCellOriginalWidth, t.rowWidths.Get(i)), t.footerWidths.Get(i))
|
||||
ctx.logger.Debugf("Col %d width (no merge): %d", i, width)
|
||||
}
|
||||
if width == 0 && (headerCellOriginalWidth > 0 || t.rowWidths.Get(i) > 0 || t.footerWidths.Get(i) > 0) {
|
||||
width = tw.Max(tw.Max(headerCellOriginalWidth, t.rowWidths.Get(i)), t.footerWidths.Get(i))
|
||||
}
|
||||
if width == 0 {
|
||||
width = 1
|
||||
}
|
||||
}
|
||||
naturalColumnWidths.Set(i, width)
|
||||
}
|
||||
ctx.logger.Debugf("Natural column widths: %v", naturalColumnWidths)
|
||||
|
||||
// Expand columns for merged header content if needed
|
||||
workingWidths := naturalColumnWidths.Clone()
|
||||
if t.config.Header.Formatting.MergeMode&tw.MergeHorizontal != 0 && headerMergeSpans != nil {
|
||||
if span, isOneBigMerge := headerMergeSpans[0]; isOneBigMerge && span == ctx.numCols && ctx.numCols > 0 {
|
||||
var firstHeaderCellLogicalContentBuilder strings.Builder
|
||||
for _, hLine := range ctx.headerLines {
|
||||
if 0 < len(hLine) {
|
||||
firstHeaderCellLogicalContentBuilder.WriteString(hLine[0])
|
||||
}
|
||||
}
|
||||
mergedContentString := t.Trimmer(firstHeaderCellLogicalContentBuilder.String())
|
||||
headerCellPadding := t.config.Header.Padding.Global
|
||||
if 0 < len(t.config.Header.Padding.PerColumn) && t.config.Header.Padding.PerColumn[0].Paddable() {
|
||||
headerCellPadding = t.config.Header.Padding.PerColumn[0]
|
||||
}
|
||||
actualMergedHeaderContentPhysicalWidth := tw.DisplayWidth(mergedContentString) +
|
||||
tw.DisplayWidth(headerCellPadding.Left) +
|
||||
tw.DisplayWidth(headerCellPadding.Right)
|
||||
currentSumOfColumnWidths := 0
|
||||
workingWidths.Each(func(_ int, w int) { currentSumOfColumnWidths += w })
|
||||
numSeparatorsInFullSpan := 0
|
||||
if ctx.numCols > 1 {
|
||||
if t.renderer != nil && t.renderer.Config().Settings.Separators.BetweenColumns.Enabled() {
|
||||
numSeparatorsInFullSpan = (ctx.numCols - 1) * tw.DisplayWidth(t.renderer.Config().Symbols.Column())
|
||||
}
|
||||
}
|
||||
totalCurrentSpanPhysicalWidth := currentSumOfColumnWidths + numSeparatorsInFullSpan
|
||||
if actualMergedHeaderContentPhysicalWidth > totalCurrentSpanPhysicalWidth {
|
||||
ctx.logger.Debugf("Merged header content '%s' (width %d) exceeds total width %d. Expanding.",
|
||||
mergedContentString, actualMergedHeaderContentPhysicalWidth, totalCurrentSpanPhysicalWidth)
|
||||
shortfall := actualMergedHeaderContentPhysicalWidth - totalCurrentSpanPhysicalWidth
|
||||
numNonZeroCols := 0
|
||||
workingWidths.Each(func(_ int, w int) {
|
||||
if w > 0 {
|
||||
numNonZeroCols++
|
||||
}
|
||||
})
|
||||
if numNonZeroCols == 0 && ctx.numCols > 0 {
|
||||
numNonZeroCols = ctx.numCols
|
||||
}
|
||||
if numNonZeroCols > 0 && shortfall > 0 {
|
||||
extraPerColumn := int(math.Ceil(float64(shortfall) / float64(numNonZeroCols)))
|
||||
finalSumAfterExpansion := 0
|
||||
workingWidths.Each(func(colIdx int, currentW int) {
|
||||
if currentW > 0 || (numNonZeroCols == ctx.numCols && ctx.numCols > 0) {
|
||||
newWidth := currentW + extraPerColumn
|
||||
workingWidths.Set(colIdx, newWidth)
|
||||
finalSumAfterExpansion += newWidth
|
||||
ctx.logger.Debugf("Col %d expanded by %d to %d", colIdx, extraPerColumn, newWidth)
|
||||
} else {
|
||||
finalSumAfterExpansion += currentW
|
||||
}
|
||||
})
|
||||
overDistributed := (finalSumAfterExpansion + numSeparatorsInFullSpan) - actualMergedHeaderContentPhysicalWidth
|
||||
if overDistributed > 0 {
|
||||
ctx.logger.Debugf("Correcting over-distribution of %d", overDistributed)
|
||||
// Sort columns for deterministic reduction
|
||||
sortedCols := workingWidths.SortedKeys()
|
||||
for i := 0; i < overDistributed; i++ {
|
||||
// Reduce from highest-indexed column
|
||||
for j := len(sortedCols) - 1; j >= 0; j-- {
|
||||
col := sortedCols[j]
|
||||
if workingWidths.Get(col) > 1 && naturalColumnWidths.Get(col) < workingWidths.Get(col) {
|
||||
workingWidths.Set(col, workingWidths.Get(col)-1)
|
||||
ctx.logger.Debugf("Reduced col %d by 1 to %d", col, workingWidths.Get(col))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.logger.Debugf("Widths after merged header expansion: %v", workingWidths)
|
||||
|
||||
// Apply global width constraint
|
||||
finalWidths := workingWidths.Clone()
|
||||
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 })
|
||||
numSeparators := 0
|
||||
if ctx.numCols > 1 && t.renderer != nil && t.renderer.Config().Settings.Separators.BetweenColumns.Enabled() {
|
||||
numSeparators = (ctx.numCols - 1) * tw.DisplayWidth(t.renderer.Config().Symbols.Column())
|
||||
}
|
||||
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
|
||||
}
|
||||
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)
|
||||
for i := 0; i < ctx.numCols; i++ {
|
||||
minW := 1
|
||||
if isHeaderContentHardToWrap && len(ctx.headerLines) > 0 {
|
||||
headerColNaturalWidthWithPadding := t.headerWidths.Get(i)
|
||||
if headerColNaturalWidthWithPadding > minW {
|
||||
minW = headerColNaturalWidthWithPadding
|
||||
}
|
||||
}
|
||||
hardMinimums.Set(i, minW)
|
||||
sumOfHardMinimums += minW
|
||||
}
|
||||
ctx.logger.Debugf("Hard minimums: %v (sum: %d)", hardMinimums, sumOfHardMinimums)
|
||||
if targetTotalColumnContentWidth < sumOfHardMinimums && sumOfHardMinimums > 0 {
|
||||
ctx.logger.Warnf("Target width %d below minimums %d. Scaling.", targetTotalColumnContentWidth, sumOfHardMinimums)
|
||||
scaleFactorMin := float64(targetTotalColumnContentWidth) / float64(sumOfHardMinimums)
|
||||
if scaleFactorMin < 0 {
|
||||
scaleFactorMin = 0
|
||||
}
|
||||
tempSum := 0
|
||||
scaledHardMinimums := tw.NewMapper[int, int]()
|
||||
hardMinimums.Each(func(colIdx int, currentMinW int) {
|
||||
scaledMinW := int(math.Round(float64(currentMinW) * scaleFactorMin))
|
||||
if scaledMinW < 1 && targetTotalColumnContentWidth > 0 {
|
||||
scaledMinW = 1
|
||||
} else if scaledMinW < 0 {
|
||||
scaledMinW = 0
|
||||
}
|
||||
scaledHardMinimums.Set(colIdx, scaledMinW)
|
||||
tempSum += scaledMinW
|
||||
})
|
||||
errorDiffMin := targetTotalColumnContentWidth - tempSum
|
||||
if errorDiffMin != 0 && scaledHardMinimums.Len() > 0 {
|
||||
sortedKeys := scaledHardMinimums.SortedKeys()
|
||||
for i := 0; i < int(math.Abs(float64(errorDiffMin))); i++ {
|
||||
keyToAdjust := sortedKeys[i%len(sortedKeys)]
|
||||
val := scaledHardMinimums.Get(keyToAdjust)
|
||||
adj := 1
|
||||
if errorDiffMin < 0 {
|
||||
adj = -1
|
||||
}
|
||||
if val+adj >= 1 || (val+adj == 0 && targetTotalColumnContentWidth == 0) {
|
||||
scaledHardMinimums.Set(keyToAdjust, val+adj)
|
||||
} else if adj > 0 {
|
||||
scaledHardMinimums.Set(keyToAdjust, val+adj)
|
||||
}
|
||||
}
|
||||
}
|
||||
finalWidths = scaledHardMinimums.Clone()
|
||||
ctx.logger.Debugf("Scaled minimums: %v", finalWidths)
|
||||
} else {
|
||||
finalWidths = hardMinimums.Clone()
|
||||
widthAllocatedByMinimums := sumOfHardMinimums
|
||||
remainingWidthToDistribute := targetTotalColumnContentWidth - widthAllocatedByMinimums
|
||||
ctx.logger.Debugf("Target: %d, minimums: %d, remaining: %d", targetTotalColumnContentWidth, widthAllocatedByMinimums, remainingWidthToDistribute)
|
||||
if remainingWidthToDistribute > 0 {
|
||||
sumOfFlexiblePotentialBase := 0
|
||||
flexibleColsOriginalWidths := tw.NewMapper[int, int]()
|
||||
for i := 0; i < ctx.numCols; i++ {
|
||||
naturalW := workingWidths.Get(i)
|
||||
minW := hardMinimums.Get(i)
|
||||
if naturalW > minW {
|
||||
sumOfFlexiblePotentialBase += (naturalW - minW)
|
||||
flexibleColsOriginalWidths.Set(i, naturalW)
|
||||
}
|
||||
}
|
||||
ctx.logger.Debugf("Flexible potential: %d, flexible widths: %v", sumOfFlexiblePotentialBase, flexibleColsOriginalWidths)
|
||||
if sumOfFlexiblePotentialBase > 0 {
|
||||
distributedExtraSum := 0
|
||||
sortedFlexKeys := flexibleColsOriginalWidths.SortedKeys()
|
||||
for _, colIdx := range sortedFlexKeys {
|
||||
naturalWOfCol := flexibleColsOriginalWidths.Get(colIdx)
|
||||
hardMinOfCol := hardMinimums.Get(colIdx)
|
||||
flexiblePartOfCol := naturalWOfCol - hardMinOfCol
|
||||
proportion := 0.0
|
||||
if sumOfFlexiblePotentialBase > 0 {
|
||||
proportion = float64(flexiblePartOfCol) / float64(sumOfFlexiblePotentialBase)
|
||||
} else if len(sortedFlexKeys) > 0 {
|
||||
proportion = 1.0 / float64(len(sortedFlexKeys))
|
||||
}
|
||||
extraForThisCol := int(math.Round(float64(remainingWidthToDistribute) * proportion))
|
||||
currentAssignedW := finalWidths.Get(colIdx)
|
||||
finalWidths.Set(colIdx, currentAssignedW+extraForThisCol)
|
||||
distributedExtraSum += extraForThisCol
|
||||
}
|
||||
errorInDist := remainingWidthToDistribute - distributedExtraSum
|
||||
ctx.logger.Debugf("Distributed %d, error: %d", distributedExtraSum, errorInDist)
|
||||
if errorInDist != 0 && len(sortedFlexKeys) > 0 {
|
||||
for i := 0; i < int(math.Abs(float64(errorInDist))); i++ {
|
||||
colToAdjust := sortedFlexKeys[i%len(sortedFlexKeys)]
|
||||
w := finalWidths.Get(colToAdjust)
|
||||
adj := 1
|
||||
if errorInDist < 0 {
|
||||
adj = -1
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finalSumCheck := 0
|
||||
finalWidths.Each(func(idx int, w int) {
|
||||
if w < 1 && targetTotalColumnContentWidth > 0 {
|
||||
finalWidths.Set(idx, 1)
|
||||
} else if w < 0 {
|
||||
finalWidths.Set(idx, 0)
|
||||
}
|
||||
finalSumCheck += finalWidths.Get(idx)
|
||||
})
|
||||
ctx.logger.Debugf("Final widths after scaling: %v (sum: %d, target: %d)", finalWidths, finalSumCheck, targetTotalColumnContentWidth)
|
||||
}
|
||||
}
|
||||
|
||||
// Assign final widths to context
|
||||
ctx.widths[tw.Header] = finalWidths.Clone()
|
||||
ctx.widths[tw.Row] = finalWidths.Clone()
|
||||
ctx.widths[tw.Footer] = finalWidths.Clone()
|
||||
ctx.logger.Debugf("Final normalized widths: header=%v, row=%v, footer=%v", ctx.widths[tw.Header], ctx.widths[tw.Row], ctx.widths[tw.Footer])
|
||||
return nil
|
||||
}
|
||||
|
||||
// calculateContentMaxWidth computes the maximum content width for a column, accounting for padding and mode-specific constraints.
|
||||
// Returns the effective content width (after subtracting padding) for the given column index.
|
||||
func (t *Table) calculateContentMaxWidth(colIdx int, config tw.CellConfig, padLeftWidth, padRightWidth int, isStreaming bool) int {
|
||||
|
||||
var effectiveContentMaxWidth int
|
||||
|
||||
if isStreaming {
|
||||
// Existing streaming logic remains unchanged
|
||||
totalColumnWidthFromStream := t.streamWidths.Get(colIdx)
|
||||
if totalColumnWidthFromStream < 0 {
|
||||
totalColumnWidthFromStream = 0
|
||||
@@ -652,28 +957,57 @@ func (t *Table) calculateContentMaxWidth(colIdx int, config tw.CellConfig, padLe
|
||||
if totalColumnWidthFromStream == 0 {
|
||||
effectiveContentMaxWidth = 0
|
||||
}
|
||||
t.logger.Debugf("calculateContentMaxWidth: Streaming col %d, TotalColWd=%d, PadL=%d, PadR=%d -> ContentMaxWd=%d",
|
||||
colIdx, totalColumnWidthFromStream, padLeftWidth, padRightWidth, effectiveContentMaxWidth)
|
||||
t.logger.Debugf("calculateContentMaxWidth: Streaming col %d, TotalColWd=%d, PadL=%d, PadR=%d -> ContentMaxWd=%d", colIdx, totalColumnWidthFromStream, padLeftWidth, padRightWidth, effectiveContentMaxWidth)
|
||||
} else {
|
||||
hasConstraint := false
|
||||
// New priority-based width constraint checking
|
||||
constraintTotalCellWidth := 0
|
||||
if config.ColMaxWidths.PerColumn != nil {
|
||||
hasConstraint := false
|
||||
|
||||
// 1. Check new Widths.PerColumn (highest priority)
|
||||
if t.config.Widths.Constrained() {
|
||||
|
||||
if colWidth, ok := t.config.Widths.PerColumn.OK(colIdx); ok && colWidth > 0 {
|
||||
constraintTotalCellWidth = colWidth
|
||||
hasConstraint = true
|
||||
t.logger.Debugf("calculateContentMaxWidth: Using Widths.PerColumn[%d] = %d",
|
||||
colIdx, constraintTotalCellWidth)
|
||||
}
|
||||
|
||||
// 2. Check new Widths.Global
|
||||
if !hasConstraint && t.config.Widths.Global > 0 {
|
||||
constraintTotalCellWidth = t.config.Widths.Global
|
||||
hasConstraint = true
|
||||
t.logger.Debugf("calculateContentMaxWidth: Using Widths.Global = %d", constraintTotalCellWidth)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fall back to legacy ColMaxWidths.PerColumn (backward compatibility)
|
||||
if !hasConstraint && config.ColMaxWidths.PerColumn != nil {
|
||||
if colMax, ok := config.ColMaxWidths.PerColumn.OK(colIdx); ok && colMax > 0 {
|
||||
constraintTotalCellWidth = colMax
|
||||
hasConstraint = true
|
||||
t.logger.Debugf("calculateContentMaxWidth: Batch col %d using config.ColMaxWidths.PerColumn (as total cell width constraint): %d", colIdx, constraintTotalCellWidth)
|
||||
t.logger.Debugf("calculateContentMaxWidth: Using legacy ColMaxWidths.PerColumn[%d] = %d",
|
||||
colIdx, constraintTotalCellWidth)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Fall back to legacy ColMaxWidths.Global
|
||||
if !hasConstraint && config.ColMaxWidths.Global > 0 {
|
||||
constraintTotalCellWidth = config.ColMaxWidths.Global
|
||||
hasConstraint = true
|
||||
t.logger.Debugf("calculateContentMaxWidth: Batch col %d using config.Formatting.MaxWidth (as total cell width constraint): %d", colIdx, constraintTotalCellWidth)
|
||||
t.logger.Debugf("calculateContentMaxWidth: Using legacy ColMaxWidths.Global = %d",
|
||||
constraintTotalCellWidth)
|
||||
}
|
||||
|
||||
// 5. Fall back to table MaxWidth if auto-wrapping
|
||||
if !hasConstraint && t.config.MaxWidth > 0 && config.Formatting.AutoWrap != tw.WrapNone {
|
||||
constraintTotalCellWidth = t.config.MaxWidth
|
||||
hasConstraint = true
|
||||
t.logger.Debugf("calculateContentMaxWidth: Batch col %d using t.config.MaxWidth (as total cell width constraint, due to AutoWrap != WrapNone): %d", colIdx, constraintTotalCellWidth)
|
||||
t.logger.Debugf("calculateContentMaxWidth: Using table MaxWidth = %d (AutoWrap enabled)",
|
||||
constraintTotalCellWidth)
|
||||
}
|
||||
|
||||
// Calculate effective width based on found constraint
|
||||
if hasConstraint {
|
||||
effectiveContentMaxWidth = constraintTotalCellWidth - padLeftWidth - padRightWidth
|
||||
if effectiveContentMaxWidth < 1 && constraintTotalCellWidth > (padLeftWidth+padRightWidth) {
|
||||
@@ -681,13 +1015,14 @@ func (t *Table) calculateContentMaxWidth(colIdx int, config tw.CellConfig, padLe
|
||||
} else if effectiveContentMaxWidth < 0 {
|
||||
effectiveContentMaxWidth = 0
|
||||
}
|
||||
t.logger.Debugf("calculateContentMaxWidth: Batch col %d, ConstraintTotalCellWidth=%d, PadL=%d, PadR=%d -> EffectiveContentMaxWidth=%d",
|
||||
colIdx, constraintTotalCellWidth, padLeftWidth, padRightWidth, effectiveContentMaxWidth)
|
||||
t.logger.Debugf("calculateContentMaxWidth: ConstraintTotalCellWidth=%d, PadL=%d, PadR=%d -> EffectiveContentMaxWidth=%d",
|
||||
constraintTotalCellWidth, padLeftWidth, padRightWidth, effectiveContentMaxWidth)
|
||||
} else {
|
||||
effectiveContentMaxWidth = 0
|
||||
t.logger.Debugf("calculateContentMaxWidth: Batch col %d, No applicable MaxWidth constraint. EffectiveContentMaxWidth set to 0 (unlimited for this stage).", colIdx)
|
||||
t.logger.Debugf("calculateContentMaxWidth: No width constraints found for column %d", colIdx)
|
||||
}
|
||||
}
|
||||
|
||||
return effectiveContentMaxWidth
|
||||
}
|
||||
|
||||
@@ -698,6 +1033,8 @@ func (t *Table) convertToStringer(input interface{}) ([]string, error) {
|
||||
return nil, errors.New("internal error: convertToStringer called with nil t.stringer")
|
||||
}
|
||||
|
||||
t.logger.Debugf("convertToString attempt %v using %v", input, t.stringer)
|
||||
|
||||
inputType := reflect.TypeOf(input)
|
||||
stringerFuncVal := reflect.ValueOf(t.stringer)
|
||||
stringerFuncType := stringerFuncVal.Type()
|
||||
@@ -1310,7 +1647,8 @@ func (t *Table) updateWidths(row []string, widths tw.Mapper[int, int], padding t
|
||||
t.logger.Debugf("Updating widths for row: %v", row)
|
||||
for i, cell := range row {
|
||||
colPad := padding.Global
|
||||
if i < len(padding.PerColumn) && padding.PerColumn[i] != (tw.Padding{}) {
|
||||
|
||||
if i < len(padding.PerColumn) && padding.PerColumn[i].Paddable() {
|
||||
colPad = padding.PerColumn[i]
|
||||
t.logger.Debugf(" Col %d: Using per-column padding: L:'%s' R:'%s'", i, colPad.Left, colPad.Right)
|
||||
} else {
|
||||
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -1034,12 +1034,12 @@ github.com/oklog/run
|
||||
# github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6
|
||||
## explicit; go 1.21
|
||||
github.com/olekukonko/errors
|
||||
# github.com/olekukonko/ll v0.0.8-0.20250516010636-22ea57d81985
|
||||
# github.com/olekukonko/ll v0.0.8
|
||||
## explicit; go 1.21
|
||||
github.com/olekukonko/ll
|
||||
github.com/olekukonko/ll/lh
|
||||
github.com/olekukonko/ll/lx
|
||||
# github.com/olekukonko/tablewriter v1.0.6
|
||||
# github.com/olekukonko/tablewriter v1.0.7
|
||||
## explicit; go 1.21
|
||||
github.com/olekukonko/tablewriter
|
||||
github.com/olekukonko/tablewriter/pkg/twwarp
|
||||
|
||||
Reference in New Issue
Block a user