Files
QSfera/vendor/github.com/olekukonko/tablewriter/config.go
T
dependabot[bot]andGitHub 70fc6eb40b build(deps): bump github.com/olekukonko/tablewriter from 0.0.5 to 1.0.6
Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 0.0.5 to 1.0.6.
- [Commits](https://github.com/olekukonko/tablewriter/compare/v0.0.5...v1.0.6)

---
updated-dependencies:
- dependency-name: github.com/olekukonko/tablewriter
  dependency-version: 1.0.6
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 15:04:23 +00:00

1152 lines
37 KiB
Go

// Package tablewriter provides functionality for creating and formatting tables with customizable configurations.
package tablewriter
import (
"github.com/olekukonko/ll" // Logging library for debug output
"github.com/olekukonko/tablewriter/tw" // Table writer core types and utilities
"io" // Input/output interfaces
"reflect" // Reflection for type handling
)
// ColumnConfigBuilder is used to configure settings for a specific column across all table sections (header, row, footer).
type ColumnConfigBuilder struct {
parent *ConfigBuilder // Reference to the parent ConfigBuilder for chaining
col int // Index of the column being configured
}
// Build returns the parent ConfigBuilder to allow method chaining.
func (c *ColumnConfigBuilder) Build() *ConfigBuilder {
return c.parent
}
// WithAlignment sets the text alignment for a specific column in the header section only.
// Invalid alignments are ignored, and the method returns the builder for chaining.
func (c *ColumnConfigBuilder) WithAlignment(align tw.Align) *ColumnConfigBuilder {
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
return c
}
// Ensure the ColumnAligns slice is large enough to accommodate the column index
if len(c.parent.config.Header.ColumnAligns) <= c.col {
newAligns := make([]tw.Align, c.col+1)
copy(newAligns, c.parent.config.Header.ColumnAligns)
c.parent.config.Header.ColumnAligns = newAligns
}
c.parent.config.Header.ColumnAligns[c.col] = align
return c
}
// WithMaxWidth sets the maximum width for a specific column across all sections (header, row, footer).
// Negative widths are ignored, and the method returns the builder for chaining.
func (c *ColumnConfigBuilder) WithMaxWidth(width int) *ColumnConfigBuilder {
if width < 0 {
return c
}
// Initialize PerColumn maps if they don't exist
if c.parent.config.Header.ColMaxWidths.PerColumn == nil {
c.parent.config.Header.ColMaxWidths.PerColumn = make(map[int]int)
c.parent.config.Row.ColMaxWidths.PerColumn = make(map[int]int)
c.parent.config.Footer.ColMaxWidths.PerColumn = make(map[int]int)
}
c.parent.config.Header.ColMaxWidths.PerColumn[c.col] = width
c.parent.config.Row.ColMaxWidths.PerColumn[c.col] = width
c.parent.config.Footer.ColMaxWidths.PerColumn[c.col] = width
return c
}
// Config represents the overall configuration for a table, including settings for header, rows, footer, and behavior.
type Config struct {
MaxWidth int // Maximum width of the entire table (0 for unlimited)
Header tw.CellConfig // Configuration for the header section
Row tw.CellConfig // Configuration for the row section
Footer tw.CellConfig // Configuration for the footer section
Debug bool // Enables debug logging when true
Stream tw.StreamConfig // Configuration specific to streaming mode
Behavior Behavior // Behavioral settings like auto-hiding and trimming
}
// ConfigBuilder provides a fluent interface for building a Config struct with both direct and nested configuration methods.
type ConfigBuilder struct {
config Config // The configuration being built
}
// Build finalizes and returns the Config struct after all modifications.
func (b *ConfigBuilder) Build() Config {
return b.config
}
// Footer returns a builder for advanced configuration of the footer section.
func (b *ConfigBuilder) Footer() *FooterConfigBuilder {
return &FooterConfigBuilder{
parent: b,
config: &b.config.Footer,
section: "footer",
}
}
// ForColumn returns a builder for configuring a specific column across all sections.
func (b *ConfigBuilder) ForColumn(col int) *ColumnConfigBuilder {
return &ColumnConfigBuilder{
parent: b,
col: col,
}
}
// Header returns a builder for advanced configuration of the header section.
func (b *ConfigBuilder) Header() *HeaderConfigBuilder {
return &HeaderConfigBuilder{
parent: b,
config: &b.config.Header,
section: "header",
}
}
// Row returns a builder for advanced configuration of the row section.
func (b *ConfigBuilder) Row() *RowConfigBuilder {
return &RowConfigBuilder{
parent: b,
config: &b.config.Row,
section: "row",
}
}
// WithAutoHide enables or disables automatic hiding of empty columns (ignored in streaming mode).
func (b *ConfigBuilder) WithAutoHide(state tw.State) *ConfigBuilder {
b.config.Behavior.AutoHide = state
return b
}
// WithDebug enables or disables debug logging for the table.
func (b *ConfigBuilder) WithDebug(debug bool) *ConfigBuilder {
b.config.Debug = debug
return b
}
// WithFooterAlignment sets the text alignment for all footer cells.
// Invalid alignments are ignored.
func (b *ConfigBuilder) WithFooterAlignment(align tw.Align) *ConfigBuilder {
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
return b
}
b.config.Footer.Formatting.Alignment = align
return b
}
// WithFooterAutoFormat enables or disables automatic formatting (e.g., title case) for footer cells.
func (b *ConfigBuilder) WithFooterAutoFormat(autoFormat tw.State) *ConfigBuilder {
b.config.Footer.Formatting.AutoFormat = autoFormat
return b
}
// WithFooterAutoWrap sets the wrapping behavior for footer cells (e.g., truncate, normal, break).
// Invalid wrap modes are ignored.
func (b *ConfigBuilder) WithFooterAutoWrap(autoWrap int) *ConfigBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return b
}
b.config.Footer.Formatting.AutoWrap = autoWrap
return b
}
// WithFooterGlobalPadding sets the global padding for all footer cells.
func (b *ConfigBuilder) WithFooterGlobalPadding(padding tw.Padding) *ConfigBuilder {
b.config.Footer.Padding.Global = padding
return b
}
// WithFooterMaxWidth sets the maximum content width for footer cells.
// Negative values are ignored.
func (b *ConfigBuilder) WithFooterMaxWidth(maxWidth int) *ConfigBuilder {
if maxWidth < 0 {
return b
}
b.config.Footer.ColMaxWidths.Global = maxWidth
return b
}
// WithFooterMergeMode sets the merge behavior for footer cells (e.g., horizontal, hierarchical).
// Invalid merge modes are ignored.
func (b *ConfigBuilder) WithFooterMergeMode(mergeMode int) *ConfigBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return b
}
b.config.Footer.Formatting.MergeMode = mergeMode
return b
}
// WithHeaderAlignment sets the text alignment for all header cells.
// Invalid alignments are ignored.
func (b *ConfigBuilder) WithHeaderAlignment(align tw.Align) *ConfigBuilder {
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
return b
}
b.config.Header.Formatting.Alignment = align
return b
}
// WithHeaderAutoFormat enables or disables automatic formatting (e.g., title case) for header cells.
func (b *ConfigBuilder) WithHeaderAutoFormat(autoFormat tw.State) *ConfigBuilder {
b.config.Header.Formatting.AutoFormat = autoFormat
return b
}
// WithHeaderAutoWrap sets the wrapping behavior for header cells (e.g., truncate, normal).
// Invalid wrap modes are ignored.
func (b *ConfigBuilder) WithHeaderAutoWrap(autoWrap int) *ConfigBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return b
}
b.config.Header.Formatting.AutoWrap = autoWrap
return b
}
// WithHeaderGlobalPadding sets the global padding for all header cells.
func (b *ConfigBuilder) WithHeaderGlobalPadding(padding tw.Padding) *ConfigBuilder {
b.config.Header.Padding.Global = padding
return b
}
// WithHeaderMaxWidth sets the maximum content width for header cells.
// Negative values are ignored.
func (b *ConfigBuilder) WithHeaderMaxWidth(maxWidth int) *ConfigBuilder {
if maxWidth < 0 {
return b
}
b.config.Header.ColMaxWidths.Global = maxWidth
return b
}
// WithHeaderMergeMode sets the merge behavior for header cells (e.g., horizontal, vertical).
// Invalid merge modes are ignored.
func (b *ConfigBuilder) WithHeaderMergeMode(mergeMode int) *ConfigBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return b
}
b.config.Header.Formatting.MergeMode = mergeMode
return b
}
// WithMaxWidth sets the maximum width for the entire table (0 means unlimited).
// Negative values are treated as 0.
func (b *ConfigBuilder) WithMaxWidth(width int) *ConfigBuilder {
if width < 0 {
b.config.MaxWidth = 0
} else {
b.config.MaxWidth = width
}
return b
}
// WithRowAlignment sets the text alignment for all row cells.
// Invalid alignments are ignored.
func (b *ConfigBuilder) WithRowAlignment(align tw.Align) *ConfigBuilder {
if align != tw.AlignLeft && align != tw.AlignRight && align != tw.AlignCenter && align != tw.AlignNone {
return b
}
b.config.Row.Formatting.Alignment = align
return b
}
// WithRowAutoFormat enables or disables automatic formatting for row cells.
func (b *ConfigBuilder) WithRowAutoFormat(autoFormat tw.State) *ConfigBuilder {
b.config.Row.Formatting.AutoFormat = autoFormat
return b
}
// WithRowAutoWrap sets the wrapping behavior for row cells (e.g., truncate, normal).
// Invalid wrap modes are ignored.
func (b *ConfigBuilder) WithRowAutoWrap(autoWrap int) *ConfigBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return b
}
b.config.Row.Formatting.AutoWrap = autoWrap
return b
}
// WithRowGlobalPadding sets the global padding for all row cells.
func (b *ConfigBuilder) WithRowGlobalPadding(padding tw.Padding) *ConfigBuilder {
b.config.Row.Padding.Global = padding
return b
}
// WithRowMaxWidth sets the maximum content width for row cells.
// Negative values are ignored.
func (b *ConfigBuilder) WithRowMaxWidth(maxWidth int) *ConfigBuilder {
if maxWidth < 0 {
return b
}
b.config.Row.ColMaxWidths.Global = maxWidth
return b
}
// WithRowMergeMode sets the merge behavior for row cells (e.g., horizontal, hierarchical).
// Invalid merge modes are ignored.
func (b *ConfigBuilder) WithRowMergeMode(mergeMode int) *ConfigBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return b
}
b.config.Row.Formatting.MergeMode = mergeMode
return b
}
// WithTrimSpace enables or disables automatic trimming of leading/trailing spaces.
// Ignored in streaming mode.
func (b *ConfigBuilder) WithTrimSpace(state tw.State) *ConfigBuilder {
b.config.Behavior.TrimSpace = state
return b
}
// FooterConfigBuilder provides advanced configuration options for the footer section.
type FooterConfigBuilder struct {
parent *ConfigBuilder // Reference to the parent ConfigBuilder
config *tw.CellConfig // Footer configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent ConfigBuilder for chaining.
func (f *FooterConfigBuilder) Build() *ConfigBuilder {
return f.parent
}
// Formatting returns a builder for configuring footer formatting settings.
func (f *FooterConfigBuilder) Formatting() *FooterFormattingBuilder {
return &FooterFormattingBuilder{
parent: f,
config: &f.config.Formatting,
section: f.section,
}
}
// Padding returns a builder for configuring footer padding settings.
func (f *FooterConfigBuilder) Padding() *FooterPaddingBuilder {
return &FooterPaddingBuilder{
parent: f,
config: &f.config.Padding,
section: f.section,
}
}
// FooterFormattingBuilder configures formatting options for the footer section.
type FooterFormattingBuilder struct {
parent *FooterConfigBuilder // Reference to the parent FooterConfigBuilder
config *tw.CellFormatting // Formatting configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent FooterConfigBuilder for chaining.
func (ff *FooterFormattingBuilder) Build() *FooterConfigBuilder {
return ff.parent
}
// WithAlignment sets the text alignment for footer cells.
// Invalid alignments are ignored.
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
}
// WithAutoFormat enables or disables automatic formatting for footer cells.
func (ff *FooterFormattingBuilder) WithAutoFormat(autoFormat tw.State) *FooterFormattingBuilder {
ff.config.AutoFormat = autoFormat
return ff
}
// WithAutoWrap sets the wrapping behavior for footer cells.
// Invalid wrap modes are ignored.
func (ff *FooterFormattingBuilder) WithAutoWrap(autoWrap int) *FooterFormattingBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return ff
}
ff.config.AutoWrap = autoWrap
return ff
}
// WithMaxWidth sets the maximum content width for footer cells.
// Negative values are ignored.
//func (ff *FooterFormattingBuilder) WithMaxWidth(maxWidth int) *FooterFormattingBuilder {
// if maxWidth < 0 {
// return ff
// }
// ff.config.Foo = maxWidth
// return ff
//}
// WithNewarkMode sets the merge behavior for footer cells (likely a typo, should be WithMergeMode).
// Invalid merge modes are ignored.
func (ff *FooterFormattingBuilder) WithNewarkMode(mergeMode int) *FooterFormattingBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return ff
}
ff.config.MergeMode = mergeMode
return ff
}
// FooterPaddingBuilder configures padding options for the footer section.
type FooterPaddingBuilder struct {
parent *FooterConfigBuilder // Reference to the parent FooterConfigBuilder
config *tw.CellPadding // Padding configuration being modified
section string // Section name for logging/debugging
}
// AddColumnPadding adds padding for a specific column in the footer.
func (fp *FooterPaddingBuilder) AddColumnPadding(padding tw.Padding) *FooterPaddingBuilder {
fp.config.PerColumn = append(fp.config.PerColumn, padding)
return fp
}
// Build returns the parent FooterConfigBuilder for chaining.
func (fp *FooterPaddingBuilder) Build() *FooterConfigBuilder {
return fp.parent
}
// WithGlobal sets the global padding for all footer cells.
func (fp *FooterPaddingBuilder) WithGlobal(padding tw.Padding) *FooterPaddingBuilder {
fp.config.Global = padding
return fp
}
// WithPerColumn sets per-column padding for the footer.
func (fp *FooterPaddingBuilder) WithPerColumn(padding []tw.Padding) *FooterPaddingBuilder {
fp.config.PerColumn = padding
return fp
}
// HeaderConfigBuilder provides advanced configuration options for the header section.
type HeaderConfigBuilder struct {
parent *ConfigBuilder // Reference to the parent ConfigBuilder
config *tw.CellConfig // Header configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent ConfigBuilder for chaining.
func (h *HeaderConfigBuilder) Build() *ConfigBuilder {
return h.parent
}
// Formatting returns a builder for configuring header formatting settings.
func (h *HeaderConfigBuilder) Formatting() *HeaderFormattingBuilder {
return &HeaderFormattingBuilder{
parent: h,
config: &h.config.Formatting,
section: h.section,
}
}
// Padding returns a builder for configuring header padding settings.
func (h *HeaderConfigBuilder) Padding() *HeaderPaddingBuilder {
return &HeaderPaddingBuilder{
parent: h,
config: &h.config.Padding,
section: h.section,
}
}
// HeaderFormattingBuilder configures formatting options for the header section.
type HeaderFormattingBuilder struct {
parent *HeaderConfigBuilder // Reference to the parent HeaderConfigBuilder
config *tw.CellFormatting // Formatting configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent HeaderConfigBuilder for chaining.
func (hf *HeaderFormattingBuilder) Build() *HeaderConfigBuilder {
return hf.parent
}
// WithAlignment sets the text alignment for header cells.
// Invalid alignments are ignored.
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
}
// WithAutoFormat enables or disables automatic formatting for header cells.
func (hf *HeaderFormattingBuilder) WithAutoFormat(autoFormat tw.State) *HeaderFormattingBuilder {
hf.config.AutoFormat = autoFormat
return hf
}
// WithAutoWrap sets the wrapping behavior for header cells.
// Invalid wrap modes are ignored.
func (hf *HeaderFormattingBuilder) WithAutoWrap(autoWrap int) *HeaderFormattingBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return hf
}
hf.config.AutoWrap = autoWrap
return hf
}
// WithMaxWidth sets the maximum content width for header cells.
// Negative values are ignored.
//func (hf *HeaderFormattingBuilder) WithMaxWidth(maxWidth int) *HeaderFormattingBuilder {
// if maxWidth < 0 {
// return hf
// }
// hf.config.MaxWidth = maxWidth
// return hf
//}
// WithMergeMode sets the merge behavior for header cells.
// Invalid merge modes are ignored.
func (hf *HeaderFormattingBuilder) WithMergeMode(mergeMode int) *HeaderFormattingBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return hf
}
hf.config.MergeMode = mergeMode
return hf
}
// HeaderPaddingBuilder configures padding options for the header section.
type HeaderPaddingBuilder struct {
parent *HeaderConfigBuilder // Reference to the parent HeaderConfigBuilder
config *tw.CellPadding // Padding configuration being modified
section string // Section name for logging/debugging
}
// AddColumnPadding adds padding for a specific column in the header.
func (hp *HeaderPaddingBuilder) AddColumnPadding(padding tw.Padding) *HeaderPaddingBuilder {
hp.config.PerColumn = append(hp.config.PerColumn, padding)
return hp
}
// Build returns the parent HeaderConfigBuilder for chaining.
func (hp *HeaderPaddingBuilder) Build() *HeaderConfigBuilder {
return hp.parent
}
// WithGlobal sets the global padding for all header cells.
func (hp *HeaderPaddingBuilder) WithGlobal(padding tw.Padding) *HeaderPaddingBuilder {
hp.config.Global = padding
return hp
}
// WithPerColumn sets per-column padding for the header.
func (hp *HeaderPaddingBuilder) WithPerColumn(padding []tw.Padding) *HeaderPaddingBuilder {
hp.config.PerColumn = padding
return hp
}
// Option defines a function type for configuring a Table instance.
type Option func(target *Table)
// RowConfigBuilder provides advanced configuration options for the row section.
type RowConfigBuilder struct {
parent *ConfigBuilder // Reference to the parent ConfigBuilder
config *tw.CellConfig // Row configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent ConfigBuilder for chaining.
func (r *RowConfigBuilder) Build() *ConfigBuilder {
return r.parent
}
// Formatting returns a builder for configuring row formatting settings.
func (r *RowConfigBuilder) Formatting() *RowFormattingBuilder {
return &RowFormattingBuilder{
parent: r,
config: &r.config.Formatting,
section: r.section,
}
}
// Padding returns a builder for configuring row padding settings.
func (r *RowConfigBuilder) Padding() *RowPaddingBuilder {
return &RowPaddingBuilder{
parent: r,
config: &r.config.Padding,
section: r.section,
}
}
// RowFormattingBuilder configures formatting options for the row section.
type RowFormattingBuilder struct {
parent *RowConfigBuilder // Reference to the parent RowConfigBuilder
config *tw.CellFormatting // Formatting configuration being modified
section string // Section name for logging/debugging
}
// Build returns the parent RowConfigBuilder for chaining.
func (rf *RowFormattingBuilder) Build() *RowConfigBuilder {
return rf.parent
}
// WithAlignment sets the text alignment for row cells.
// Invalid alignments are ignored.
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
}
// WithAutoFormat enables or disables automatic formatting for row cells.
func (rf *RowFormattingBuilder) WithAutoFormat(autoFormat tw.State) *RowFormattingBuilder {
rf.config.AutoFormat = autoFormat
return rf
}
// WithAutoWrap sets the wrapping behavior for row cells.
// Invalid wrap modes are ignored.
func (rf *RowFormattingBuilder) WithAutoWrap(autoWrap int) *RowFormattingBuilder {
if autoWrap < tw.WrapNone || autoWrap > tw.WrapBreak {
return rf
}
rf.config.AutoWrap = autoWrap
return rf
}
// WithMergeMode sets the merge behavior for row cells.
// Invalid merge modes are ignored.
func (rf *RowFormattingBuilder) WithMergeMode(mergeMode int) *RowFormattingBuilder {
if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
return rf
}
rf.config.MergeMode = mergeMode
return rf
}
// RowPaddingBuilder configures padding options for the row section.
type RowPaddingBuilder struct {
parent *RowConfigBuilder // Reference to the parent RowConfigBuilder
config *tw.CellPadding // Padding configuration being modified
section string // Section name for logging/debugging
}
// AddColumnPadding adds padding for a specific column in the rows.
func (rp *RowPaddingBuilder) AddColumnPadding(padding tw.Padding) *RowPaddingBuilder {
rp.config.PerColumn = append(rp.config.PerColumn, padding)
return rp
}
// Build returns the parent RowConfigBuilder for chaining.
func (rp *RowPaddingBuilder) Build() *RowConfigBuilder {
return rp.parent
}
// WithGlobal sets the global padding for all row cells.
func (rp *RowPaddingBuilder) WithGlobal(padding tw.Padding) *RowPaddingBuilder {
rp.config.Global = padding
return rp
}
// WithPerColumn sets per-column padding for the rows.
func (rp *RowPaddingBuilder) WithPerColumn(padding []tw.Padding) *RowPaddingBuilder {
rp.config.PerColumn = padding
return rp
}
// NewConfigBuilder creates a new ConfigBuilder initialized with default settings.
func NewConfigBuilder() *ConfigBuilder {
return &ConfigBuilder{
config: defaultConfig(),
}
}
// 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
}
// 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.Stream.Widths.Global = width
if target.logger != nil {
target.logger.Debugf("Option: WithColumnMax applied to Table: %v", width)
}
}
}
// WithTableMax sets a global maximum table width for the table
// Negative values are ignored, and the change is logged if debugging is enabled.
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)
}
}
}
// WithColumnWidths sets per-column widths for the table in streaming mode.
// Negative widths are removed, and the change is logged if debugging is enabled.
func WithColumnWidths(widths map[int]int) Option {
return func(target *Table) {
for k, v := range widths {
if v < 0 {
delete(widths, k)
}
}
target.config.Stream.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.")
}
}
}
// 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)
}
}
}
// 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.Formatting.Alignment = align
if target.logger != nil {
target.logger.Debugf("Option: WithHeaderAlignment applied to Table: %v", align)
}
}
}
// 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.")
}
}
}
// 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()
t.logger.Debug("Stringer updated, cache cleared")
}
}
// WithStringerCache enables caching for the stringer function.
func WithStringerCache() Option {
return func(t *Table) {
t.stringerCacheEnabled = true
}
}
// WithSymbols sets the symbols used for table drawing and updates the renderer's configuration.
// Logs the change if debugging is enabled.
func WithSymbols(symbols tw.Symbols) Option {
return func(target *Table) {
if target.renderer != nil {
cfg := target.renderer.Config()
cfg.Symbols = symbols
if target.logger != nil {
target.logger.Debug("Option: WithSymbols applied to Table.")
}
}
}
}
// 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)
}
}
}
func WithHeaderAutoFormat(state tw.State) Option {
return func(target *Table) {
target.config.Header.Formatting.AutoFormat = 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) // Fixed 'state' to '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) // Fixed log message and 'state' to 'control'
}
}
}
// WithAlignment sets the default column alignment for the header, rows, and footer.
func WithAlignment(alignment tw.Alignment) Option {
return func(target *Table) {
target.config.Header.ColumnAligns = alignment
target.config.Row.ColumnAligns = alignment
target.config.Footer.ColumnAligns = alignment
}
}
// WithPadding sets the global padding for the header, rows, and footer.
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
}
}
// 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.
func WithRendition(rendition tw.Rendition) Option {
return func(target *Table) {
if target.renderer == nil {
target.logger.Warn("Option: WithRendition: No renderer set on table.")
return
}
if ru, ok := target.renderer.(tw.Renditioning); ok {
ru.Rendition(rendition)
target.logger.Debugf("Option: WithRendition: Applied to renderer via Renditioning.SetRendition(): %+v", rendition)
} else {
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 {
defaultPadding := tw.Padding{Left: tw.Space, Right: tw.Space, Top: tw.Empty, Bottom: tw.Empty}
return Config{
MaxWidth: 0,
Header: tw.CellConfig{
Formatting: tw.CellFormatting{
AutoWrap: tw.WrapTruncate,
Alignment: tw.AlignCenter,
AutoFormat: tw.On,
MergeMode: tw.MergeNone,
},
Padding: tw.CellPadding{
Global: defaultPadding,
},
},
Row: tw.CellConfig{
Formatting: tw.CellFormatting{
AutoWrap: tw.WrapNormal,
Alignment: tw.AlignLeft,
AutoFormat: tw.Off,
MergeMode: tw.MergeNone,
},
Padding: tw.CellPadding{
Global: defaultPadding,
},
},
Footer: tw.CellConfig{
Formatting: tw.CellFormatting{
AutoWrap: tw.WrapNormal,
Alignment: tw.AlignRight,
AutoFormat: tw.Off,
MergeMode: tw.MergeNone,
},
Padding: tw.CellPadding{
Global: defaultPadding,
},
},
Stream: tw.StreamConfig{},
Debug: false,
Behavior: 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 != (tw.Padding{}) {
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 != (tw.Padding{}) {
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
}
}
}
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.Empty && 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.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
}
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
}
}
}
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
}