diff --git a/table/README.md b/table/README.md index ede66f8..5889847 100644 --- a/table/README.md +++ b/table/README.md @@ -20,6 +20,7 @@ Pretty-print tables into ASCII/Unicode strings. - Custom (vertical) VAlign per column with multi-line cell support (`ColumnConfig.VAlign*`) - Mirror output to an `io.Writer` (ex. `os.StdOut`) (`SetOutputMirror`) - Sort by one or more Columns (`SortBy`) + - Suppress/hide columns with no content (`SuppressEmptyColumns`) - Customizable Cell rendering per Column (`ColumnConfig.Transformer*`) - Hide any columns that you don't want displayed (`ColumnConfig.Hidden`) - Reset Headers/Rows/Footers at will to reuse the same Table Writer (`Reset*`) diff --git a/table/render_test.go b/table/render_test.go index 58a0162..6590007 100644 --- a/table/render_test.go +++ b/table/render_test.go @@ -1140,6 +1140,44 @@ func TestTable_Render_Styles(t *testing.T) { } } +func TestTable_Render_SuppressEmptyColumns(t *testing.T) { + tw := NewWriter() + tw.AppendHeader(testHeader) + tw.AppendRows([]Row{ + {1, "Arya", "", 3000}, + {20, "Jon", "", 2000, "You know nothing, Jon Snow!"}, + {300, "Tyrion", "", 5000}, + }) + tw.AppendRow(Row{11, "Sansa", "", 6000}) + tw.AppendFooter(Row{"", "", "TOTAL", 10000}) + tw.SetStyle(StyleLight) + + expectedOut := `┌─────┬────────────┬───────────┬────────┬─────────────────────────────┐ +│ # │ FIRST NAME │ LAST NAME │ SALARY │ │ +├─────┼────────────┼───────────┼────────┼─────────────────────────────┤ +│ 1 │ Arya │ │ 3000 │ │ +│ 20 │ Jon │ │ 2000 │ You know nothing, Jon Snow! │ +│ 300 │ Tyrion │ │ 5000 │ │ +│ 11 │ Sansa │ │ 6000 │ │ +├─────┼────────────┼───────────┼────────┼─────────────────────────────┤ +│ │ │ TOTAL │ 10000 │ │ +└─────┴────────────┴───────────┴────────┴─────────────────────────────┘` + assert.Equal(t, expectedOut, tw.Render()) + + tw.SuppressEmptyColumns() + expectedOut = `┌─────┬────────────┬────────┬─────────────────────────────┐ +│ # │ FIRST NAME │ SALARY │ │ +├─────┼────────────┼────────┼─────────────────────────────┤ +│ 1 │ Arya │ 3000 │ │ +│ 20 │ Jon │ 2000 │ You know nothing, Jon Snow! │ +│ 300 │ Tyrion │ 5000 │ │ +│ 11 │ Sansa │ 6000 │ │ +├─────┼────────────┼────────┼─────────────────────────────┤ +│ │ │ 10000 │ │ +└─────┴────────────┴────────┴─────────────────────────────┘` + assert.Equal(t, expectedOut, tw.Render()) +} + func TestTable_Render_TableWithinTable(t *testing.T) { twInner := NewWriter() twInner.AppendHeader(testHeader) diff --git a/table/table.go b/table/table.go index 2872217..ae49725 100644 --- a/table/table.go +++ b/table/table.go @@ -94,6 +94,9 @@ type Table struct { sortBy []SortBy // style contains all the strings used to draw the table, and more style *Style + // suppressEmptyColumns hides columns which have no content on all regular + // rows + suppressEmptyColumns bool // title contains the text to appear above the table title string } @@ -278,6 +281,12 @@ func (t *Table) Style() *Style { return t.style } +// SuppressEmptyColumns hides columns when the column is empty in ALL the +// regular rows. +func (t *Table) SuppressEmptyColumns() { + t.suppressEmptyColumns = true +} + func (t *Table) analyzeAndStringify(row Row, hint renderHint) rowStr { // update t.numColumns if this row is the longest seen till now if len(row) > t.numColumns { @@ -699,6 +708,9 @@ func (t *Table) initForRenderRows() { // sort the rows as requested t.initForRenderSortRows() + // suppress columns without any content + t.initForRenderSuppressColumns() + // strip out hidden columns t.initForRenderHideColumns() } @@ -761,6 +773,27 @@ func (t *Table) initForRenderSortRows() { } } +func (t *Table) initForRenderSuppressColumns() { + shouldSuppressColumn := func(colIdx int) bool { + for _, row := range t.rows { + if colIdx < len(row) && row[colIdx] != "" { + return false + } + } + return true + } + + if t.suppressEmptyColumns { + for colIdx := 0; colIdx < t.numColumns; colIdx++ { + if shouldSuppressColumn(colIdx) { + cc := t.columnConfigMap[colIdx] + cc.Hidden = true + t.columnConfigMap[colIdx] = cc + } + } + } +} + func (t *Table) isIndexColumn(colIdx int, hint renderHint) bool { return t.indexColumn == colIdx+1 || hint.isAutoIndexColumn } diff --git a/table/writer.go b/table/writer.go index 2c52231..c70ba33 100644 --- a/table/writer.go +++ b/table/writer.go @@ -31,6 +31,7 @@ type Writer interface { SetTitle(format string, a ...interface{}) SortBy(sortBy []SortBy) Style() *Style + SuppressEmptyColumns() // deprecated; in favor of Style().HTML.CSSClass SetHTMLCSSClass(cssClass string)