Skip to content

Commit

Permalink
table: auto expand columns with Style().Size.WidthMin (#335)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t authored Oct 5, 2024
1 parent 183dee4 commit c27402a
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 22 deletions.
1 change: 1 addition & 0 deletions table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Pretty-print tables into ASCII/Unicode strings.
- Limit the length of
- Rows (`SetAllowedRowLength`)
- Columns (`ColumnConfig.Width*`)
- Auto-size Rows (`Style().Size.WidthMin` and `Style().Size.WidthMax`)
- Page results by a specified number of Lines (`SetPageSize`)
- Alignment - Horizontal & Vertical
- Auto (horizontal) Align (numeric columns aligned Right)
Expand Down
13 changes: 8 additions & 5 deletions table/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func (t *Table) renderLine(out *strings.Builder, row rowStr, hint renderHint) {

// use a brand-new strings.Builder if a row length limit has been set
var outLine *strings.Builder
if t.allowedRowLength > 0 {
if t.style.Size.WidthMax > 0 {
outLine = &strings.Builder{}
} else {
outLine = out
Expand Down Expand Up @@ -227,8 +227,8 @@ func (t *Table) renderLine(out *strings.Builder, row rowStr, hint renderHint) {

func (t *Table) renderLineMergeOutputs(out *strings.Builder, outLine *strings.Builder) {
outLineStr := outLine.String()
if text.RuneWidthWithoutEscSequences(outLineStr) > t.allowedRowLength {
trimLength := t.allowedRowLength - utf8.RuneCountInString(t.style.Box.UnfinishedRow)
if text.RuneWidthWithoutEscSequences(outLineStr) > t.style.Size.WidthMax {
trimLength := t.style.Size.WidthMax - utf8.RuneCountInString(t.style.Box.UnfinishedRow)
if trimLength > 0 {
out.WriteString(text.Trim(outLineStr, trimLength))
out.WriteString(t.style.Box.UnfinishedRow)
Expand Down Expand Up @@ -385,8 +385,11 @@ func (t *Table) renderTitle(out *strings.Builder) {
colors := t.style.Title.Colors
colorsBorder := t.getBorderColors(renderHint{isTitleRow: true})
rowLength := t.maxRowLength
if t.allowedRowLength != 0 && t.allowedRowLength < rowLength {
rowLength = t.allowedRowLength
if wm := t.style.Size.WidthMax; wm > 0 && wm < rowLength {
rowLength = wm
}
if wm := t.style.Size.WidthMin; wm > 0 && wm > rowLength {
rowLength = wm
}
if t.style.Options.DrawBorder {
lenBorder := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.TopLeft+t.style.Box.TopRight)
Expand Down
62 changes: 46 additions & 16 deletions table/render_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func (t *Table) initForRender() {

// find the longest continuous line in each column
t.initForRenderColumnLengths()
t.initForRenderMaxRowLength()
t.initForRenderPaddedColumns()

// generate a separator row and calculate maximum row length
t.initForRenderRowSeparator()
Expand Down Expand Up @@ -172,6 +174,50 @@ func (t *Table) initForRenderHideColumns() {
t.columnConfigMap = columnConfigMap
}

func (t *Table) initForRenderMaxRowLength() {
t.maxRowLength = 0
if t.autoIndex {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft)
t.maxRowLength += len(fmt.Sprint(len(t.rows)))
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingRight)
if t.style.Options.SeparateColumns {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator)
}
}
if t.style.Options.SeparateColumns {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator) * (t.numColumns - 1)
}
for _, maxColumnLength := range t.maxColumnLengths {
maxColumnLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight)
t.maxRowLength += maxColumnLength
}
if t.style.Options.DrawBorder {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right)
}
}

func (t *Table) initForRenderPaddedColumns() {
paddingSize := t.style.Size.WidthMin - t.maxRowLength
for paddingSize > 0 {
// distribute padding equally among all columns
numColumnsPadded := 0
for colIdx := 0; paddingSize > 0 && colIdx < t.numColumns; colIdx++ {
colWidthMax := t.getColumnWidthMax(colIdx)
if colWidthMax == 0 || t.maxColumnLengths[colIdx] < colWidthMax {
t.maxColumnLengths[colIdx]++
numColumnsPadded++
paddingSize--
}
}

// avoid endless looping because all columns are at max size and cannot
// be expanded any further
if numColumnsPadded == 0 {
break
}
}
}

func (t *Table) initForRenderRows() {
// auto-index: calc the index column's max length
t.autoIndexVIndexMaxLength = len(fmt.Sprint(len(t.rowsRaw)))
Expand Down Expand Up @@ -206,27 +252,11 @@ func (t *Table) initForRenderRowsStringify(rows []Row, hint renderHint) []rowStr
}

func (t *Table) initForRenderRowSeparator() {
t.maxRowLength = 0
if t.autoIndex {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft)
t.maxRowLength += len(fmt.Sprint(len(t.rows)))
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingRight)
if t.style.Options.SeparateColumns {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator)
}
}
if t.style.Options.SeparateColumns {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator) * (t.numColumns - 1)
}
t.rowSeparator = make(rowStr, t.numColumns)
for colIdx, maxColumnLength := range t.maxColumnLengths {
maxColumnLength += text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight)
t.maxRowLength += maxColumnLength
t.rowSeparator[colIdx] = text.RepeatAndTrim(t.style.Box.MiddleHorizontal, maxColumnLength)
}
if t.style.Options.DrawBorder {
t.maxRowLength += text.RuneWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right)
}
}

func (t *Table) initForRenderSortRows() {
Expand Down
Loading

0 comments on commit c27402a

Please sign in to comment.