build(deps): bump github.com/olekukonko/tablewriter from 1.0.7 to 1.0.8

Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 1.0.7 to 1.0.8.
- [Commits](https://github.com/olekukonko/tablewriter/compare/v1.0.7...v1.0.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2025-07-04 14:56:06 +00:00
committed by GitHub
parent e96a0b8c5e
commit b1ca895a20
21 changed files with 823 additions and 321 deletions
+37 -34
View File
@@ -2,6 +2,7 @@ package renderer
import (
"github.com/olekukonko/ll"
"github.com/olekukonko/tablewriter/pkg/twwidth"
"io"
"strings"
@@ -42,7 +43,7 @@ func NewBlueprint(configs ...tw.Rendition) *Blueprint {
// Merge user settings with default settings
cfg.Settings = mergeSettings(cfg.Settings, userCfg.Settings)
}
return &Blueprint{config: cfg}
return &Blueprint{config: cfg, logger: ll.New("blueprint")}
}
// Close performs cleanup (no-op in this implementation).
@@ -106,7 +107,7 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
}
if prefix != tw.Empty || suffix != tw.Empty {
line.WriteString(prefix + suffix + tw.NewLine)
totalLineWidth = tw.DisplayWidth(prefix) + tw.DisplayWidth(suffix)
totalLineWidth = twwidth.Width(prefix) + twwidth.Width(suffix)
f.w.Write([]byte(line.String()))
}
f.logger.Debugf("Line: Handled empty row/widths case (total width %d)", totalLineWidth)
@@ -119,13 +120,13 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
targetTotalWidth += ctx.Row.Widths.Get(colIdx)
}
if f.config.Borders.Left.Enabled() {
targetTotalWidth += tw.DisplayWidth(f.config.Symbols.Column())
targetTotalWidth += twwidth.Width(f.config.Symbols.Column())
}
if f.config.Borders.Right.Enabled() {
targetTotalWidth += tw.DisplayWidth(f.config.Symbols.Column())
targetTotalWidth += twwidth.Width(f.config.Symbols.Column())
}
if f.config.Settings.Separators.BetweenColumns.Enabled() && len(sortedKeys) > 1 {
targetTotalWidth += tw.DisplayWidth(f.config.Symbols.Column()) * (len(sortedKeys) - 1)
targetTotalWidth += twwidth.Width(f.config.Symbols.Column()) * (len(sortedKeys) - 1)
}
// Add left border if enabled
@@ -133,7 +134,7 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
if f.config.Borders.Left.Enabled() {
leftBorder := jr.RenderLeft()
line.WriteString(leftBorder)
leftBorderWidth = tw.DisplayWidth(leftBorder)
leftBorderWidth = twwidth.Width(leftBorder)
totalLineWidth += leftBorderWidth
f.logger.Debugf("Line: Left border='%s' (f.width %d)", leftBorder, leftBorderWidth)
}
@@ -156,11 +157,11 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
// Adjust colWidth to account for wider borders
adjustedColWidth := colWidth
if f.config.Borders.Left.Enabled() && keyIndex == 0 {
adjustedColWidth -= leftBorderWidth - tw.DisplayWidth(f.config.Symbols.Column())
adjustedColWidth -= leftBorderWidth - twwidth.Width(f.config.Symbols.Column())
}
if f.config.Borders.Right.Enabled() && keyIndex == len(visibleColIndices)-1 {
rightBorderWidth := tw.DisplayWidth(jr.RenderRight(currentColIdx))
adjustedColWidth -= rightBorderWidth - tw.DisplayWidth(f.config.Symbols.Column())
rightBorderWidth := twwidth.Width(jr.RenderRight(currentColIdx))
adjustedColWidth -= rightBorderWidth - twwidth.Width(f.config.Symbols.Column())
}
if adjustedColWidth < 0 {
adjustedColWidth = 0
@@ -172,7 +173,7 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
totalLineWidth += adjustedColWidth
f.logger.Debugf("Line: Rendered spaces='%s' (f.width %d) for col %d", spaces, adjustedColWidth, currentColIdx)
} else {
segmentWidth := tw.DisplayWidth(segment)
segmentWidth := twwidth.Width(segment)
if segmentWidth == 0 {
segmentWidth = 1 // Avoid division by zero
f.logger.Warnf("Line: Segment='%s' has zero width, using 1", segment)
@@ -183,11 +184,11 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
repeat = 1
}
repeatedSegment := strings.Repeat(segment, repeat)
actualWidth := tw.DisplayWidth(repeatedSegment)
actualWidth := twwidth.Width(repeatedSegment)
if actualWidth > adjustedColWidth {
// Truncate if too long
repeatedSegment = tw.TruncateString(repeatedSegment, adjustedColWidth)
actualWidth = tw.DisplayWidth(repeatedSegment)
repeatedSegment = twwidth.Truncate(repeatedSegment, adjustedColWidth)
actualWidth = twwidth.Width(repeatedSegment)
f.logger.Debugf("Line: Truncated segment='%s' to width %d", repeatedSegment, actualWidth)
} else if actualWidth < adjustedColWidth {
// Pad with segment character to match adjustedColWidth
@@ -195,7 +196,7 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
for i := 0; i < remainingWidth/segmentWidth; i++ {
repeatedSegment += segment
}
actualWidth = tw.DisplayWidth(repeatedSegment)
actualWidth = twwidth.Width(repeatedSegment)
if actualWidth < adjustedColWidth {
repeatedSegment = tw.PadRight(repeatedSegment, tw.Space, adjustedColWidth)
actualWidth = adjustedColWidth
@@ -214,13 +215,13 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
nextColIdx := visibleColIndices[keyIndex+1]
junction := jr.RenderJunction(currentColIdx, nextColIdx)
// Use center symbol (❀) or column separator (|) to match data rows
if tw.DisplayWidth(junction) != tw.DisplayWidth(f.config.Symbols.Column()) {
if twwidth.Width(junction) != twwidth.Width(f.config.Symbols.Column()) {
junction = f.config.Symbols.Center()
if tw.DisplayWidth(junction) != tw.DisplayWidth(f.config.Symbols.Column()) {
if twwidth.Width(junction) != twwidth.Width(f.config.Symbols.Column()) {
junction = f.config.Symbols.Column()
}
}
junctionWidth := tw.DisplayWidth(junction)
junctionWidth := twwidth.Width(junction)
line.WriteString(junction)
totalLineWidth += junctionWidth
f.logger.Debugf("Line: Junction between %d and %d: '%s' (f.width %d)", currentColIdx, nextColIdx, junction, junctionWidth)
@@ -232,7 +233,7 @@ func (f *Blueprint) Line(ctx tw.Formatting) {
if f.config.Borders.Right.Enabled() && len(visibleColIndices) > 0 {
lastIdx := visibleColIndices[len(visibleColIndices)-1]
rightBorder := jr.RenderRight(lastIdx)
rightBorderWidth = tw.DisplayWidth(rightBorder)
rightBorderWidth = twwidth.Width(rightBorder)
line.WriteString(rightBorder)
totalLineWidth += rightBorderWidth
f.logger.Debugf("Line: Right border='%s' (f.width %d)", rightBorder, rightBorderWidth)
@@ -276,7 +277,7 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al
content, width, align, padding.Left, padding.Right)
// Calculate display width of content
runeWidth := tw.DisplayWidth(content)
runeWidth := twwidth.Width(content)
// Set default padding characters
leftPadChar := padding.Left
@@ -292,8 +293,8 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al
//}
// Calculate padding widths
padLeftWidth := tw.DisplayWidth(leftPadChar)
padRightWidth := tw.DisplayWidth(rightPadChar)
padLeftWidth := twwidth.Width(leftPadChar)
padRightWidth := twwidth.Width(rightPadChar)
// Calculate available width for content
availableContentWidth := width - padLeftWidth - padRightWidth
@@ -304,8 +305,8 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al
// Truncate content if it exceeds available width
if runeWidth > availableContentWidth {
content = tw.TruncateString(content, availableContentWidth)
runeWidth = tw.DisplayWidth(content)
content = twwidth.Truncate(content, availableContentWidth)
runeWidth = twwidth.Width(content)
f.logger.Debugf("Truncated content to fit %d: '%s' (new width %d)", availableContentWidth, content, runeWidth)
}
@@ -363,10 +364,10 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al
}
output := result.String()
finalWidth := tw.DisplayWidth(output)
finalWidth := twwidth.Width(output)
// Adjust output to match target width
if finalWidth > width {
output = tw.TruncateString(output, width)
output = twwidth.Truncate(output, width)
f.logger.Debugf("formatCell: Truncated output to width %d", width)
} else if finalWidth < width {
output = tw.PadRight(output, tw.Space, width)
@@ -374,9 +375,9 @@ func (f *Blueprint) formatCell(content string, width int, padding tw.Padding, al
}
// Log warning if final width doesn't match target
if f.logger.Enabled() && tw.DisplayWidth(output) != width {
if f.logger.Enabled() && twwidth.Width(output) != width {
f.logger.Debugf("formatCell Warning: Final width %d does not match target %d for result '%s'",
tw.DisplayWidth(output), width, output)
twwidth.Width(output), width, output)
}
f.logger.Debugf("Formatted cell final result: '%s' (target width %d)", output, width)
@@ -407,14 +408,14 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) {
totalLineWidth := 0 // Track total display width
if prefix != tw.Empty {
output.WriteString(prefix)
totalLineWidth += tw.DisplayWidth(prefix)
f.logger.Debugf("renderLine: Prefix='%s' (f.width %d)", prefix, tw.DisplayWidth(prefix))
totalLineWidth += twwidth.Width(prefix)
f.logger.Debugf("renderLine: Prefix='%s' (f.width %d)", prefix, twwidth.Width(prefix))
}
colIndex := 0
separatorDisplayWidth := 0
if f.config.Settings.Separators.BetweenColumns.Enabled() {
separatorDisplayWidth = tw.DisplayWidth(columnSeparator)
separatorDisplayWidth = twwidth.Width(columnSeparator)
}
// Process each column
@@ -542,7 +543,7 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) {
formattedCell := f.formatCell(cellData, visualWidth, padding, align)
if len(formattedCell) > 0 {
output.WriteString(formattedCell)
cellWidth := tw.DisplayWidth(formattedCell)
cellWidth := twwidth.Width(formattedCell)
totalLineWidth += cellWidth
f.logger.Debugf("renderLine: Rendered col %d, formattedCell='%s' (f.width %d), totalLineWidth=%d", colIndex, formattedCell, cellWidth, totalLineWidth)
}
@@ -561,17 +562,19 @@ func (f *Blueprint) renderLine(ctx tw.Formatting) {
// Add suffix and adjust total width
if output.Len() > len(prefix) || f.config.Borders.Right.Enabled() {
output.WriteString(suffix)
totalLineWidth += tw.DisplayWidth(suffix)
f.logger.Debugf("renderLine: Suffix='%s' (f.width %d)", suffix, tw.DisplayWidth(suffix))
totalLineWidth += twwidth.Width(suffix)
f.logger.Debugf("renderLine: Suffix='%s' (f.width %d)", suffix, twwidth.Width(suffix))
}
output.WriteString(tw.NewLine)
f.w.Write([]byte(output.String()))
f.logger.Debugf("renderLine: Final rendered line: '%s' (total width %d)", strings.TrimSuffix(output.String(), tw.NewLine), totalLineWidth)
}
// Rendition updates the Blueprint's configuration.
func (f *Blueprint) Rendition(config tw.Rendition) {
f.config = mergeRendition(f.config, config)
f.logger.Debugf("Blueprint.Rendition updated. New internal config: %+v", f.config)
f.logger.Debugf("Blueprint.Rendition updated. New config: %+v", f.config)
}
// Ensure Blueprint implements tw.Renditioning
+14 -14
View File
@@ -4,6 +4,7 @@ import (
"github.com/fatih/color"
"github.com/olekukonko/ll"
"github.com/olekukonko/ll/lh"
"github.com/olekukonko/tablewriter/pkg/twwidth"
"io"
"strings"
@@ -254,7 +255,7 @@ func (c *Colorized) Line(ctx tw.Formatting) {
line.WriteString(strings.Repeat(tw.Space, colWidth))
} else {
// Calculate how many times to repeat the segment
segmentWidth := tw.DisplayWidth(segment)
segmentWidth := twwidth.Width(segment)
if segmentWidth <= 0 {
segmentWidth = 1
}
@@ -266,7 +267,7 @@ func (c *Colorized) Line(ctx tw.Formatting) {
line.WriteString(drawnSegment)
// Adjust for width discrepancies
actualDrawnWidth := tw.DisplayWidth(drawnSegment)
actualDrawnWidth := twwidth.Width(drawnSegment)
if actualDrawnWidth < colWidth {
missingWidth := colWidth - actualDrawnWidth
spaces := strings.Repeat(tw.Space, missingWidth)
@@ -373,7 +374,7 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al
}
// Calculate visual width of content
contentVisualWidth := tw.DisplayWidth(content)
contentVisualWidth := twwidth.Width(content)
// Set default padding characters
padLeftCharStr := padding.Left
@@ -386,8 +387,8 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al
}
// Calculate padding widths
definedPadLeftWidth := tw.DisplayWidth(padLeftCharStr)
definedPadRightWidth := tw.DisplayWidth(padRightCharStr)
definedPadLeftWidth := twwidth.Width(padLeftCharStr)
definedPadRightWidth := twwidth.Width(padRightCharStr)
// Calculate available width for content and alignment
availableForContentAndAlign := width - definedPadLeftWidth - definedPadRightWidth
if availableForContentAndAlign < 0 {
@@ -396,8 +397,8 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al
// Truncate content if it exceeds available width
if contentVisualWidth > availableForContentAndAlign {
content = tw.TruncateString(content, availableForContentAndAlign)
contentVisualWidth = tw.DisplayWidth(content)
content = twwidth.Truncate(content, availableForContentAndAlign)
contentVisualWidth = twwidth.Width(content)
c.logger.Debugf("Truncated content to fit %d: '%s' (new width %d)", availableForContentAndAlign, content, contentVisualWidth)
}
@@ -472,12 +473,12 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al
output := sb.String()
// Adjust output width if necessary
currentVisualWidth := tw.DisplayWidth(output)
currentVisualWidth := twwidth.Width(output)
if currentVisualWidth != width {
c.logger.Debugf("formatCell MISMATCH: content='%s', target_w=%d. Calculated parts width = %d. String: '%s'",
content, width, currentVisualWidth, output)
if currentVisualWidth > width {
output = tw.TruncateString(output, width)
output = twwidth.Truncate(output, width)
} else {
paddingSpacesStr := strings.Repeat(tw.Space, width-currentVisualWidth)
if len(tint.BG) > 0 {
@@ -486,10 +487,10 @@ func (c *Colorized) formatCell(content string, width int, padding tw.Padding, al
output += paddingSpacesStr
}
}
c.logger.Debugf("formatCell Post-Correction: Target %d, New Visual width %d. Output: '%s'", width, tw.DisplayWidth(output), output)
c.logger.Debugf("formatCell Post-Correction: Target %d, New Visual width %d. Output: '%s'", width, twwidth.Width(output), output)
}
c.logger.Debugf("Formatted cell final result: '%s' (target width %d, display width %d)", output, width, tw.DisplayWidth(output))
c.logger.Debugf("Formatted cell final result: '%s' (target width %d, display width %d)", output, width, twwidth.Width(output))
return output
}
@@ -529,7 +530,7 @@ func (c *Colorized) renderLine(ctx tw.Formatting, line []string, tint Tint) {
separatorString := tw.Empty
if c.config.Settings.Separators.BetweenColumns.Enabled() {
separatorString = c.config.Separator.Apply(c.config.Symbols.Column())
separatorDisplayWidth = tw.DisplayWidth(c.config.Symbols.Column())
separatorDisplayWidth = twwidth.Width(c.config.Symbols.Column())
}
// Process each column
@@ -693,8 +694,7 @@ func (c *Colorized) renderLine(ctx tw.Formatting, line []string, tint Tint) {
// Rendition updates the parts of ColorizedConfig that correspond to tw.Rendition
// by merging the provided newRendition. Color-specific Tints are not modified.
func (c *Colorized) Rendition(newRendition tw.Rendition) { // Method name matches interface
c.logger.Debug("Colorized.Rendition called. Current B/Sym/Set: B:%+v, Sym:%T, S:%+v. Override: %+v",
c.config.Borders, c.config.Symbols, c.config.Settings, newRendition)
c.logger.Debug("Colorized.Rendition called. Current B/Sym/Set: B:%+v, Sym:%T, S:%+v. Override: %+v", c.config.Borders, c.config.Symbols, c.config.Settings, newRendition)
currentRenditionPart := tw.Rendition{
Borders: c.config.Borders,
+1
View File
@@ -63,6 +63,7 @@ func NewHTML(configs ...HTMLConfig) *HTML {
tableStarted: false,
tbodyStarted: false,
tfootStarted: false,
logger: ll.New("html"),
}
}
+11 -10
View File
@@ -2,6 +2,7 @@ package renderer
import (
"github.com/olekukonko/ll"
"github.com/olekukonko/tablewriter/pkg/twwidth"
"io"
"strings"
@@ -35,7 +36,7 @@ func NewMarkdown(configs ...tw.Rendition) *Markdown {
if len(configs) > 0 {
cfg = mergeMarkdownConfig(cfg, configs[0])
}
return &Markdown{config: cfg}
return &Markdown{config: cfg, logger: ll.New("markdown")}
}
// mergeMarkdownConfig combines user-provided config with Markdown defaults, enforcing Markdown-specific settings.
@@ -157,7 +158,7 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding
//if m.config.Settings.TrimWhitespace.Enabled() {
// content = strings.TrimSpace(content)
//}
contentVisualWidth := tw.DisplayWidth(content)
contentVisualWidth := twwidth.Width(content)
// Use specified padding characters or default to spaces
padLeftChar := padding.Left
@@ -170,8 +171,8 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding
}
// Calculate padding widths
padLeftCharWidth := tw.DisplayWidth(padLeftChar)
padRightCharWidth := tw.DisplayWidth(padRightChar)
padLeftCharWidth := twwidth.Width(padLeftChar)
padRightCharWidth := twwidth.Width(padRightChar)
minWidth := tw.Max(3, contentVisualWidth+padLeftCharWidth+padRightCharWidth)
targetWidth := tw.Max(width, minWidth)
@@ -212,7 +213,7 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding
result := leftPadStr + content + rightPadStr
// Adjust width if needed
finalWidth := tw.DisplayWidth(result)
finalWidth := twwidth.Width(result)
if finalWidth != targetWidth {
m.logger.Debugf("Markdown formatCell MISMATCH: content='%s', target_w=%d, paddingL='%s', paddingR='%s', align=%s -> result='%s', result_w=%d",
content, targetWidth, padding.Left, padding.Right, align, result, finalWidth)
@@ -229,9 +230,9 @@ func (m *Markdown) formatCell(content string, width int, align tw.Align, padding
result += adjStr
}
} else {
result = tw.TruncateString(result, targetWidth)
result = twwidth.Truncate(result, targetWidth)
}
m.logger.Debugf("Markdown formatCell Corrected: target_w=%d, result='%s', new_w=%d", targetWidth, result, tw.DisplayWidth(result))
m.logger.Debugf("Markdown formatCell Corrected: target_w=%d, result='%s', new_w=%d", targetWidth, result, twwidth.Width(result))
}
m.logger.Debugf("Markdown formatCell: content='%s', width=%d, align=%s, paddingL='%s', paddingR='%s' -> '%s' (target %d)",
@@ -262,11 +263,11 @@ func (m *Markdown) formatSeparator(width int, align tw.Align) string {
}
result := sb.String()
currentLen := tw.DisplayWidth(result)
currentLen := twwidth.Width(result)
if currentLen < targetWidth {
result += strings.Repeat("-", targetWidth-currentLen)
} else if currentLen > targetWidth {
result = tw.TruncateString(result, targetWidth)
result = twwidth.Truncate(result, targetWidth)
}
m.logger.Debugf("Markdown formatSeparator: width=%d, align=%s -> '%s'", width, align, result)
@@ -314,7 +315,7 @@ func (m *Markdown) renderMarkdownLine(line []string, ctx tw.Formatting, isHeader
output.WriteString(prefix)
colIndex := 0
separatorWidth := tw.DisplayWidth(separator)
separatorWidth := twwidth.Width(separator)
for colIndex < numCols {
cellCtx, ok := ctx.Row.Current[colIndex]
+11 -46
View File
@@ -1,6 +1,7 @@
package renderer
import (
"github.com/olekukonko/tablewriter/pkg/twwidth"
"io"
"strings"
@@ -106,17 +107,9 @@ func (o *Ocean) Header(headers [][]string, ctx tw.Formatting) {
if !o.widthsFinalized {
o.tryFinalizeWidths(ctx)
}
// The batch renderer (table.go/renderHeader) will call Line() for the top border
// and for the header separator if its main config t.config says so.
// So, Ocean.Header should *not* draw these itself when in batch mode.
// For true streaming, table.go's streamRenderHeader would make these Line() calls.
// Decision: Ocean.Header *only* renders header content.
// Lines (top border, header separator) are managed by the caller (batch or stream logic in table.go).
if !o.widthsFinalized {
o.logger.Error("Ocean.Header: Cannot render content, widths are not finalized.")
// o.headerContentRendered = true; // No, content wasn't rendered.
return
}
@@ -133,10 +126,7 @@ func (o *Ocean) Header(headers [][]string, ctx tw.Formatting) {
o.headerContentRendered = true
} else {
o.logger.Debug("Ocean.Header: No actual header content lines to render.")
// If header is empty, table.go's renderHeader might still call Line() for the separator.
// o.headerContentRendered remains false if no content.
}
// DO NOT draw the header separator line here. Let table.go's renderHeader or streamRenderHeader call o.Line().
}
func (o *Ocean) Row(row []string, ctx tw.Formatting) {
@@ -145,15 +135,6 @@ func (o *Ocean) Row(row []string, ctx tw.Formatting) {
if !o.widthsFinalized {
o.tryFinalizeWidths(ctx)
}
// Top border / header separator logic:
// If this is the very first output, table.go's batch renderHeader (or streamRenderHeader)
// should have already called Line() for top border and header separator.
// If Header() was called but rendered no content, table.go's renderHeader would still call Line() for the separator.
// If Header() was never called by table.go (e.g. streaming rows directly after Start()),
// then table.go's streamAppendRow needs to handle initial lines.
// Decision: Ocean.Row *only* renders row content.
if !o.widthsFinalized {
o.logger.Error("Ocean.Row: Cannot render content, widths are not finalized.")
return
@@ -171,11 +152,6 @@ func (o *Ocean) Footer(footers [][]string, ctx tw.Formatting) {
o.tryFinalizeWidths(ctx)
o.logger.Warn("Ocean.Footer: Widths finalized at Footer stage (unusual).")
}
// Separator line before footer:
// This should be handled by table.go's renderFooter or streamRenderFooter calling o.Line().
// Decision: Ocean.Footer *only* renders footer content.
if !o.widthsFinalized {
o.logger.Error("Ocean.Footer: Cannot render content, widths are not finalized.")
return
@@ -194,24 +170,19 @@ func (o *Ocean) Footer(footers [][]string, ctx tw.Formatting) {
} else {
o.logger.Debug("Ocean.Footer: No actual footer content lines to render.")
}
// DO NOT draw the bottom border here. Let table.go's main Close or batch renderFooter call o.Line().
}
func (o *Ocean) Line(ctx tw.Formatting) {
// This method is now called EXTERNALLY by table.go's batch or stream logic
// to draw all horizontal lines (top border, header sep, footer sep, bottom border).
if !o.widthsFinalized {
// If Line is called before widths are known (e.g. table.go's batch renderHeader trying to draw top border)
// we must try to finalize widths from this context.
o.tryFinalizeWidths(ctx)
if !o.widthsFinalized {
o.logger.Error("Ocean.Line: Called but widths could not be finalized. Skipping line rendering.")
return
}
}
// Ensure Line uses the consistent fixedWidths for drawing
ctx.Row.Widths = o.fixedWidths
o.logger.Debugf("Ocean.Line DRAWING: Level=%v, Loc=%s, Pos=%s, IsSubRow=%t, WidthsLen=%d", ctx.Level, ctx.Row.Location, ctx.Row.Position, ctx.IsSubRow, ctx.Row.Widths.Len())
jr := NewJunction(JunctionContext{
@@ -262,7 +233,7 @@ func (o *Ocean) Line(ctx tw.Formatting) {
if segmentChar == tw.Empty {
segmentChar = o.config.Symbols.Row()
}
segmentDisplayWidth := tw.DisplayWidth(segmentChar)
segmentDisplayWidth := twwidth.Width(segmentChar)
if segmentDisplayWidth <= 0 {
segmentDisplayWidth = 1
}
@@ -296,12 +267,6 @@ func (o *Ocean) Line(ctx tw.Formatting) {
func (o *Ocean) Close() error {
o.logger.Debug("Ocean.Close() called.")
// The actual bottom border drawing is expected to be handled by table.go's
// batch render logic (renderFooter) or stream logic (streamRenderBottomBorder)
// by making an explicit call to o.Line() with the correct context.
// Ocean.Close() itself does not draw the bottom border to avoid duplication.
// Only reset state.
o.resetState()
return nil
}
@@ -374,7 +339,7 @@ func (o *Ocean) renderContentLine(ctx tw.Formatting, lineData []string) {
}
if k < hSpan-1 && o.config.Settings.Separators.BetweenColumns.Enabled() {
currentMergeTotalRenderWidth += tw.DisplayWidth(o.config.Symbols.Column())
currentMergeTotalRenderWidth += twwidth.Width(o.config.Symbols.Column())
}
}
actualCellWidthToRender = currentMergeTotalRenderWidth
@@ -428,7 +393,7 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t
return tw.Empty
}
contentDisplayWidth := tw.DisplayWidth(content)
contentDisplayWidth := twwidth.Width(content)
padLeftChar := padding.Left
if padLeftChar == tw.Empty {
@@ -439,8 +404,8 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t
padRightChar = tw.Space
}
padLeftDisplayWidth := tw.DisplayWidth(padLeftChar)
padRightDisplayWidth := tw.DisplayWidth(padRightChar)
padLeftDisplayWidth := twwidth.Width(padLeftChar)
padRightDisplayWidth := twwidth.Width(padRightChar)
spaceForContentAndAlignment := cellVisualWidth - padLeftDisplayWidth - padRightDisplayWidth
if spaceForContentAndAlignment < 0 {
@@ -448,8 +413,8 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t
}
if contentDisplayWidth > spaceForContentAndAlignment {
content = tw.TruncateString(content, spaceForContentAndAlignment)
contentDisplayWidth = tw.DisplayWidth(content)
content = twwidth.Truncate(content, spaceForContentAndAlignment)
contentDisplayWidth = twwidth.Width(content)
}
remainingSpace := spaceForContentAndAlignment - contentDisplayWidth
@@ -477,7 +442,7 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t
sb.WriteString(PR)
sb.WriteString(padRightChar)
currentFormattedWidth := tw.DisplayWidth(sb.String())
currentFormattedWidth := twwidth.Width(sb.String())
if currentFormattedWidth < cellVisualWidth {
if align == tw.AlignRight {
prefixSpaces := strings.Repeat(tw.Space, cellVisualWidth-currentFormattedWidth)
@@ -490,7 +455,7 @@ func (o *Ocean) formatCellContent(content string, cellVisualWidth int, padding t
} else if currentFormattedWidth > cellVisualWidth {
tempStr := sb.String()
sb.Reset()
sb.WriteString(tw.TruncateString(tempStr, cellVisualWidth))
sb.WriteString(twwidth.Truncate(tempStr, cellVisualWidth))
o.logger.Warnf("formatCellContent: Final string '%s' (width %d) exceeded target %d. Force truncated.", tempStr, currentFormattedWidth, cellVisualWidth)
}
return sb.String()
+1
View File
@@ -138,6 +138,7 @@ func NewSVG(configs ...SVGConfig) *SVG {
allVisualLineData: make([][][]string, 3),
allVisualLineCtx: make([][]tw.Formatting, 3),
vMergeTrack: make(map[int]int),
logger: ll.New("svg"),
}
for i := 0; i < 3; i++ {
r.allVisualLineData[i] = make([][]string, 0)