diff --git a/table/README.md b/table/README.md index 956b652..a9813bb 100644 --- a/table/README.md +++ b/table/README.md @@ -7,7 +7,7 @@ Pretty-print tables into ASCII/Unicode strings. - Add Header(s) and Footer(s) (`AppendHeader`/`AppendFooter`) - Add a Separator manually after any Row (`AppendSeparator`) - Auto Index Rows (1, 2, 3 ...) and Columns (A, B, C, ...) (`SetAutoIndex`) - - Auto Merge + - Auto Merge (_not supported in CSV/HTML/Markdown/TSV modes_) - Cells in a Row (`RowConfig.AutoMerge`) - Columns (`ColumnConfig.AutoMerge`) - Limit the length of @@ -37,6 +37,7 @@ Pretty-print tables into ASCII/Unicode strings. - CSV - HTML Table (with custom CSS Class) - Markdown Table + - TSV ``` +---------------------------------------------------------------------+ diff --git a/table/render_test.go b/table/render_test.go index b11bdd0..7018bc0 100644 --- a/table/render_test.go +++ b/table/render_test.go @@ -950,7 +950,10 @@ func TestTable_Render_Sorted(t *testing.T) { tw.AppendRow(Row{11, "Sansa", "Stark", 6000}) tw.AppendFooter(testFooter) tw.SetStyle(StyleLight) - tw.SortBy([]SortBy{{Name: "Last Name", Mode: Asc}, {Name: "First Name", Mode: Asc}}) + tw.SortBy([]SortBy{ + {Name: "Last Name", Mode: Asc}, + {Name: "First Name", Mode: Asc}, + }) compareOutput(t, tw.Render(), `┌─────┬────────────┬───────────┬────────┬─────────────────────────────┐ │ # │ FIRST NAME │ LAST NAME │ SALARY │ │ @@ -962,7 +965,12 @@ func TestTable_Render_Sorted(t *testing.T) { ├─────┼────────────┼───────────┼────────┼─────────────────────────────┤ │ │ │ TOTAL │ 10000 │ │ └─────┴────────────┴───────────┴────────┴─────────────────────────────┘`) - tw.SortBy([]SortBy{{Number: 5, Mode: Dsc}, {Name: "Last Name", Mode: Asc}, {Name: "First Name", Mode: Asc}}) + + tw.SortBy([]SortBy{ + {Number: 5, Mode: Dsc}, + {Name: "Last Name", Mode: Asc}, + {Name: "First Name", Mode: Asc}, + }) compareOutput(t, tw.Render(), `┌─────┬────────────┬───────────┬────────┬─────────────────────────────┐ │ # │ FIRST NAME │ LAST NAME │ SALARY │ │ ├─────┼────────────┼───────────┼────────┼─────────────────────────────┤ @@ -975,6 +983,124 @@ func TestTable_Render_Sorted(t *testing.T) { └─────┴────────────┴───────────┴────────┴─────────────────────────────┘`) } +func TestTable_Render_SortedAlphaNumeric(t *testing.T) { + tw := NewWriter() + tw.AppendHeader(Row{"#", "Name", "Prefix", "Number", "Class"}) + tw.SetColumnConfigs([]ColumnConfig{ + {Number: 1, Align: text.AlignRight, AlignHeader: text.AlignCenter}, + {Number: 2, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, + {Number: 3, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, + {Number: 4, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, + {Number: 5, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, + }) + tw.AppendRows([]Row{ + {0, "defiant", "NCC", 1764, "Constitution"}, + {1, "Defiant", "nx", 74205, "Defiant"}, + {2, "entente", "ncc", 2120, "Dreadnought"}, + {3, "Enterprise", "NCC", 1701, "Constitution"}, + {4, "Farragut", "NCC", 1647, "(Farragut-Type)"}, + {5, "farragut", "NCC", 60597, "Nebula"}, + {6, "Bonaventure", "", "10283NCC", "(Bonaventure-Typ)"}, + {7, "IKS Ch'Tang", "", "-----------", "Bird-of-Prey"}, + {8, "IKS Drovana", "", "-----------", "Vor'cha-Klasse"}, + {9, "IKS Buruk", "", "-----------", "Bird-of-Prey"}, + }) + tw.SetStyle(StyleLight) + + tw.SortBy([]SortBy{ + {Name: "Name", Mode: Asc, IgnoreCase: false}, + }) + compareOutput(t, tw.Render(), `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ +│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ +├───┼─────────────┼────────┼─────────────┼───────────────────┤ +│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ +│ 1 │ Defiant │ nx │ 74205 │ Defiant │ +│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ +│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ +│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ +│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ +│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ +│ 0 │ defiant │ NCC │ 1764 │ Constitution │ +│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ +│ 5 │ farragut │ NCC │ 60597 │ Nebula │ +└───┴─────────────┴────────┴─────────────┴───────────────────┘`) + + tw.SortBy([]SortBy{ + {Name: "Name", Mode: Asc, IgnoreCase: true}, + }) + compareOutput(t, tw.Render(), `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ +│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ +├───┼─────────────┼────────┼─────────────┼───────────────────┤ +│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ +│ 1 │ Defiant │ nx │ 74205 │ Defiant │ +│ 0 │ defiant │ NCC │ 1764 │ Constitution │ +│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ +│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ +│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ +│ 5 │ farragut │ NCC │ 60597 │ Nebula │ +│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ +│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ +│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ +└───┴─────────────┴────────┴─────────────┴───────────────────┘`) + + tw.SortBy([]SortBy{ + {Name: "Prefix", Mode: Asc, IgnoreCase: true}, + {Name: "Number", Mode: AscNumericAlpha}, + }) + compareOutput(t, tw.Render(), `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ +│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ +├───┼─────────────┼────────┼─────────────┼───────────────────┤ +│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ +│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ +│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ +│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ +│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ +│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ +│ 0 │ defiant │ NCC │ 1764 │ Constitution │ +│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ +│ 5 │ farragut │ NCC │ 60597 │ Nebula │ +│ 1 │ Defiant │ nx │ 74205 │ Defiant │ +└───┴─────────────┴────────┴─────────────┴───────────────────┘`) + + tw.SortBy([]SortBy{ + {Name: "Number", Mode: AscNumericAlpha}, + {Name: "Name", Mode: Asc}, + }) + compareOutput(t, tw.Render(), `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ +│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ +├───┼─────────────┼────────┼─────────────┼───────────────────┤ +│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ +│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ +│ 0 │ defiant │ NCC │ 1764 │ Constitution │ +│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ +│ 5 │ farragut │ NCC │ 60597 │ Nebula │ +│ 1 │ Defiant │ nx │ 74205 │ Defiant │ +│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ +│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ +│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ +│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ +└───┴─────────────┴────────┴─────────────┴───────────────────┘`) + + tw.SortBy([]SortBy{ + {Name: "Number", Mode: DscAlphaNumeric, IgnoreCase: true}, + {Name: "Name", Mode: Asc}, + }) + compareOutput(t, tw.Render(), `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ +│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ +├───┼─────────────┼────────┼─────────────┼───────────────────┤ +│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ +│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ +│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ +│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ +│ 1 │ Defiant │ nx │ 74205 │ Defiant │ +│ 5 │ farragut │ NCC │ 60597 │ Nebula │ +│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ +│ 0 │ defiant │ NCC │ 1764 │ Constitution │ +│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ +│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ +└───┴─────────────┴────────┴─────────────┴───────────────────┘`) +} + func TestTable_Render_Separator(t *testing.T) { tw := NewWriter() tw.AppendHeader(testHeader) diff --git a/table/sort.go b/table/sort.go index 51520bb..7a47765 100644 --- a/table/sort.go +++ b/table/sort.go @@ -109,9 +109,9 @@ func (rs rowsSorter) Swap(i, j int) { } func (rs rowsSorter) Less(i, j int) bool { + shouldContinue, returnValue := false, false realI, realJ := rs.sortedIndices[i], rs.sortedIndices[j] - lastSort := len(rs.sortBy) - 1 - for sortIdx, sortBy := range rs.sortBy { + for _, sortBy := range rs.sortBy { // extract the values/cells from the rows for comparison rowI, rowJ, colIdx := rs.rows[realI], rs.rows[realJ], sortBy.Number-1 iVal, jVal := "", "" @@ -123,12 +123,12 @@ func (rs rowsSorter) Less(i, j int) bool { } // compare and choose whether to continue - shouldContinue, returnValue := less(iVal, jVal, sortBy) - if !shouldContinue || lastSort == sortIdx { - return returnValue + shouldContinue, returnValue = less(iVal, jVal, sortBy) + if !shouldContinue { + break } } - return false + return returnValue } func less(iVal string, jVal string, sb SortBy) (bool, bool) { diff --git a/table/table_test.go b/table/table_test.go index bfe23e9..9addf88 100644 --- a/table/table_test.go +++ b/table/table_test.go @@ -290,92 +290,6 @@ func TestTable_SetAutoIndex(t *testing.T) { │ │ │ │ │ │ This is known. │ └───┴─────┴────────────┴───────────┴────────┴─────────────────────────────┘` assert.Equal(t, expectedOut, table.Render()) - tw := NewWriter() - tw.AppendHeader(Row{"#", "Name", "Prefix", "Number", "Class"}) - tw.SetColumnConfigs([]ColumnConfig{ - {Number: 1, Align: text.AlignRight, AlignHeader: text.AlignCenter}, - {Number: 2, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, - {Number: 3, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, - {Number: 4, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, - {Number: 5, Align: text.AlignAuto, AlignHeader: text.AlignCenter}, - }) - tw.AppendRows([]Row{ - {0, "defiant", "NCC", 1764, "Constitution"}, - {1, "Defiant", "nx", 74205, "Defiant"}, - {2, "entente", "ncc", 2120, "Dreadnought"}, - {3, "Enterprise", "NCC", 1701, "Constitution"}, - {4, "Farragut", "NCC", 1647, "(Farragut-Type)"}, - {5, "farragut", "NCC", 60597, "Nebula"}, - {6, "Bonaventure", "", "10283NCC", "(Bonaventure-Typ)"}, - {7, "IKS Ch'Tang", "", "-----------", "Bird-of-Prey"}, - {8, "IKS Drovana", "", "-----------", "Vor'cha-Klasse"}, - {9, "IKS Buruk", "", "-----------", "Bird-of-Prey"}, - }) - tw.SetStyle(StyleLight) - tw.SortBy([]SortBy{{Name: "Name", Mode: Asc, IgnoreCase: false}}) - assert.Equal(t, `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ -│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ -├───┼─────────────┼────────┼─────────────┼───────────────────┤ -│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ -│ 1 │ Defiant │ nx │ 74205 │ Defiant │ -│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ -│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ -│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ -│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ -│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ -│ 0 │ defiant │ NCC │ 1764 │ Constitution │ -│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ -│ 5 │ farragut │ NCC │ 60597 │ Nebula │ -└───┴─────────────┴────────┴─────────────┴───────────────────┘`, tw.Render()) - - tw.SortBy([]SortBy{{Name: "Name", Mode: Asc, IgnoreCase: true}}) - assert.Equal(t, `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ -│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ -├───┼─────────────┼────────┼─────────────┼───────────────────┤ -│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ -│ 1 │ Defiant │ nx │ 74205 │ Defiant │ -│ 0 │ defiant │ NCC │ 1764 │ Constitution │ -│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ -│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ -│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ -│ 5 │ farragut │ NCC │ 60597 │ Nebula │ -│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ -│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ -│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ -└───┴─────────────┴────────┴─────────────┴───────────────────┘`, tw.Render()) - - tw.SortBy([]SortBy{{Name: "Prefix", Mode: Asc, IgnoreCase: true}, {Name: "Number", Mode: AscNumericAlpha}}) - assert.Equal(t, `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ -│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ -├───┼─────────────┼────────┼─────────────┼───────────────────┤ -│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ -│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ -│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ -│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ -│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ -│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ -│ 0 │ defiant │ NCC │ 1764 │ Constitution │ -│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ -│ 5 │ farragut │ NCC │ 60597 │ Nebula │ -│ 1 │ Defiant │ nx │ 74205 │ Defiant │ -└───┴─────────────┴────────┴─────────────┴───────────────────┘`, tw.Render()) - - tw.SortBy([]SortBy{{Name: "Number", Mode: AscNumericAlpha}, {Name: "Name", Mode: Asc}}) - assert.Equal(t, `┌───┬─────────────┬────────┬─────────────┬───────────────────┐ -│ # │ NAME │ PREFIX │ NUMBER │ CLASS │ -├───┼─────────────┼────────┼─────────────┼───────────────────┤ -│ 4 │ Farragut │ NCC │ 1647 │ (Farragut-Type) │ -│ 3 │ Enterprise │ NCC │ 1701 │ Constitution │ -│ 0 │ defiant │ NCC │ 1764 │ Constitution │ -│ 2 │ entente │ ncc │ 2120 │ Dreadnought │ -│ 5 │ farragut │ NCC │ 60597 │ Nebula │ -│ 1 │ Defiant │ nx │ 74205 │ Defiant │ -│ 9 │ IKS Buruk │ │ ----------- │ Bird-of-Prey │ -│ 7 │ IKS Ch'Tang │ │ ----------- │ Bird-of-Prey │ -│ 8 │ IKS Drovana │ │ ----------- │ Vor'cha-Klasse │ -│ 6 │ Bonaventure │ │ 10283NCC │ (Bonaventure-Typ) │ -└───┴─────────────┴────────┴─────────────┴───────────────────┘`, tw.Render()) - } func TestTable_SetCaption(t *testing.T) {