mirror of
https://github.com/zoriya/bubbles.git
synced 2026-08-05 12:46:14 +00:00
test(table): add style and border tests
This commit is contained in:
+275
-105
@@ -1,166 +1,336 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/charmbracelet/lipgloss/v2"
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
"github.com/charmbracelet/lipgloss/v2/table"
|
||||
"github.com/charmbracelet/x/exp/golden"
|
||||
)
|
||||
|
||||
// Reusable inputs
|
||||
|
||||
var niceMargins = lipgloss.NewStyle().Padding(0, 1)
|
||||
var headers = []string{"Rank", "City", "Country", "Population"}
|
||||
var rows = [][]string{
|
||||
{"1", "Tokyo", "Japan", "37,274,000"},
|
||||
{"2", "Delhi", "India", "32,065,760"},
|
||||
{"3", "Shanghai", "China", "28,516,904"},
|
||||
{"4", "Dhaka", "Bangladesh", "22,478,116"},
|
||||
{"5", "São Paulo", "Brazil", "22,429,800"},
|
||||
{"6", "Mexico City", "Mexico", "22,085,140"},
|
||||
{"7", "Cairo", "Egypt", "21,750,020"},
|
||||
{"8", "Beijing", "China", "21,333,332"},
|
||||
{"9", "Mumbai", "India", "20,961,472"},
|
||||
{"10", "Osaka", "Japan", "19,059,856"},
|
||||
{"11", "Chongqing", "China", "16,874,740"},
|
||||
{"12", "Karachi", "Pakistan", "16,839,950"},
|
||||
{"13", "Istanbul", "Turkey", "15,636,243"},
|
||||
{"14", "Kinshasa", "DR Congo", "15,628,085"},
|
||||
{"15", "Lagos", "Nigeria", "15,387,639"},
|
||||
{"16", "Buenos Aires", "Argentina", "15,369,919"},
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
headers := []string{"Rank", "City", "Country", "Population"}
|
||||
rows := [][]string{
|
||||
{"1", "Tokyo", "Japan", "37,274,000"},
|
||||
{"2", "Delhi", "India", "32,065,760"},
|
||||
{"3", "Shanghai", "China", "28,516,904"},
|
||||
{"4", "Dhaka", "Bangladesh", "22,478,116"},
|
||||
{"5", "São Paulo", "Brazil", "22,429,800"},
|
||||
{"6", "Mexico City", "Mexico", "22,085,140"},
|
||||
{"7", "Cairo", "Egypt", "21,750,020"},
|
||||
{"8", "Beijing", "China", "21,333,332"},
|
||||
{"9", "Mumbai", "India", "20,961,472"},
|
||||
{"10", "Osaka", "Japan", "19,059,856"},
|
||||
}
|
||||
t.Run("new with options", func(t *testing.T) {
|
||||
tb := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithHeight(10),
|
||||
)
|
||||
tb.View()
|
||||
})
|
||||
t.Run("new, no options", func(t *testing.T) {
|
||||
tb := New().SetHeaders(headers...).SetRows(rows...)
|
||||
tb.View()
|
||||
})
|
||||
}
|
||||
|
||||
func TestFromValues(t *testing.T) {
|
||||
input := "foo1,bar1\nfoo2,bar2\nfoo3,bar3"
|
||||
table := New(WithColumns([]Column{{Title: "Foo"}, {Title: "Bar"}}))
|
||||
table := New(WithHeaders("Foo", "Bar"))
|
||||
table.FromValues(input, ",")
|
||||
|
||||
if len(table.rows) != 3 {
|
||||
t.Fatalf("expect table to have 3 rows but it has %d", len(table.rows))
|
||||
}
|
||||
|
||||
expect := []Row{
|
||||
expect := [][]string{
|
||||
{"foo1", "bar1"},
|
||||
{"foo2", "bar2"},
|
||||
{"foo3", "bar3"},
|
||||
}
|
||||
if !deepEqual(table.rows, expect) {
|
||||
if !reflect.DeepEqual(table.rows, expect) {
|
||||
t.Fatal("table rows is not equals to the input")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromValuesWithTabSeparator(t *testing.T) {
|
||||
input := "foo1.\tbar1\nfoo,bar,baz\tbar,2"
|
||||
table := New(WithColumns([]Column{{Title: "Foo"}, {Title: "Bar"}}))
|
||||
table := New(WithHeaders("Foo", "Bar"))
|
||||
table.FromValues(input, "\t")
|
||||
|
||||
if len(table.rows) != 2 {
|
||||
t.Fatalf("expect table to have 2 rows but it has %d", len(table.rows))
|
||||
}
|
||||
|
||||
expect := []Row{
|
||||
expect := [][]string{
|
||||
{"foo1.", "bar1"},
|
||||
{"foo,bar,baz", "bar,2"},
|
||||
}
|
||||
if !deepEqual(table.rows, expect) {
|
||||
if !reflect.DeepEqual(table.rows, expect) {
|
||||
t.Fatal("table rows is not equals to the input")
|
||||
}
|
||||
}
|
||||
|
||||
func deepEqual(a, b []Row) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
func TestTableAlignment(t *testing.T) {
|
||||
headers := []string{
|
||||
"Name",
|
||||
"Country of Origin",
|
||||
"Dunk-able",
|
||||
}
|
||||
for i, r := range a {
|
||||
for j, f := range r {
|
||||
if f != b[i][j] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
rows := [][]string{
|
||||
{"Chocolate Digestives", "UK", "Yes"},
|
||||
{"Tim Tams", "Australia", "No"},
|
||||
{"Hobnobs", "UK", "Yes"},
|
||||
}
|
||||
return true
|
||||
t.Run("No border", func(t *testing.T) {
|
||||
biscuits := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
).
|
||||
// Remove default border.
|
||||
SetBorder(false).
|
||||
// Remove default border under header.
|
||||
BorderHeader(false).
|
||||
// Strip styles.
|
||||
SetStyleFunc(func(_, _ int) lipgloss.Style {
|
||||
return niceMargins
|
||||
})
|
||||
golden.RequireEqual(t, []byte(biscuits.View()))
|
||||
})
|
||||
t.Run("With border", func(t *testing.T) {
|
||||
// TODO how do we style header border?
|
||||
// s.Header = s.Header.
|
||||
// BorderStyle(lipgloss.NormalBorder()).
|
||||
// BorderForeground(lipgloss.Color("240")).
|
||||
// Bold(false)
|
||||
|
||||
biscuits := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
).
|
||||
// Strip styles
|
||||
SetStyleFunc(func(_, _ int) lipgloss.Style {
|
||||
return niceMargins
|
||||
})
|
||||
golden.RequireEqual(t, []byte(biscuits.View()))
|
||||
})
|
||||
}
|
||||
|
||||
var cols = []Column{
|
||||
{Title: "col1", Width: 10},
|
||||
{Title: "col2", Width: 10},
|
||||
{Title: "col3", Width: 10},
|
||||
}
|
||||
// Test Styles
|
||||
|
||||
func TestRenderRow(t *testing.T) {
|
||||
func TestOverwriteStyles(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
table *Model
|
||||
expected string
|
||||
name string
|
||||
styles Styles
|
||||
}{
|
||||
{
|
||||
name: "simple row",
|
||||
table: &Model{
|
||||
rows: []Row{{"Foooooo", "Baaaaar", "Baaaaaz"}},
|
||||
cols: cols,
|
||||
styles: Styles{Cell: lipgloss.NewStyle()},
|
||||
},
|
||||
expected: "Foooooo Baaaaar Baaaaaz ",
|
||||
},
|
||||
{
|
||||
name: "simple row with truncations",
|
||||
table: &Model{
|
||||
rows: []Row{{"Foooooooooo", "Baaaaaaaaar", "Quuuuuuuuux"}},
|
||||
cols: cols,
|
||||
styles: Styles{Cell: lipgloss.NewStyle()},
|
||||
},
|
||||
expected: "Foooooooo…Baaaaaaaa…Quuuuuuuu…",
|
||||
},
|
||||
{
|
||||
name: "simple row avoiding truncations",
|
||||
table: &Model{
|
||||
rows: []Row{{"Fooooooooo", "Baaaaaaaar", "Quuuuuuuux"}},
|
||||
cols: cols,
|
||||
styles: Styles{Cell: lipgloss.NewStyle()},
|
||||
},
|
||||
expected: "FoooooooooBaaaaaaaarQuuuuuuuux",
|
||||
},
|
||||
|
||||
{"clear styles", Styles{
|
||||
Selected: lipgloss.NewStyle(),
|
||||
Header: lipgloss.NewStyle(),
|
||||
Cell: lipgloss.NewStyle(),
|
||||
}},
|
||||
{"new styles", Styles{
|
||||
Selected: niceMargins.Foreground(lipgloss.Color("68")),
|
||||
Header: niceMargins,
|
||||
Cell: niceMargins,
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
row := tc.table.renderRow(0)
|
||||
if row != tc.expected {
|
||||
t.Fatalf("\n\nWant: \n%s\n\nGot: \n%s\n", tc.expected, row)
|
||||
}
|
||||
tb := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithFocused(true),
|
||||
WithHeight(10),
|
||||
)
|
||||
tb.OverwriteStyles(tc.styles)
|
||||
golden.RequireEqual(t, []byte(tb.View()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableAlignment(t *testing.T) {
|
||||
t.Run("No border", func(t *testing.T) {
|
||||
biscuits := New(
|
||||
WithHeight(5),
|
||||
WithColumns([]Column{
|
||||
{Title: "Name", Width: 25},
|
||||
{Title: "Country of Origin", Width: 16},
|
||||
{Title: "Dunk-able", Width: 12},
|
||||
}),
|
||||
WithRows([]Row{
|
||||
{"Chocolate Digestives", "UK", "Yes"},
|
||||
{"Tim Tams", "Australia", "No"},
|
||||
{"Hobnobs", "UK", "Yes"},
|
||||
}),
|
||||
)
|
||||
got := ansiStrip(biscuits.View())
|
||||
golden.RequireEqual(t, []byte(got))
|
||||
})
|
||||
t.Run("With border", func(t *testing.T) {
|
||||
baseStyle := lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.NormalBorder()).
|
||||
BorderForeground(lipgloss.Color("240"))
|
||||
func TestSetStyles(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
styles Styles
|
||||
}{
|
||||
{"empty styles; do nothing", Styles{
|
||||
Selected: lipgloss.NewStyle(),
|
||||
Header: lipgloss.NewStyle(),
|
||||
Cell: lipgloss.NewStyle(),
|
||||
}},
|
||||
{"new styles", Styles{
|
||||
Selected: niceMargins.Background(lipgloss.Color("68")),
|
||||
Header: niceMargins,
|
||||
Cell: niceMargins,
|
||||
}},
|
||||
}
|
||||
|
||||
s := DefaultStyles()
|
||||
s.Header = s.Header.
|
||||
BorderStyle(lipgloss.NormalBorder()).
|
||||
BorderForeground(lipgloss.Color("240")).
|
||||
BorderBottom(true).
|
||||
Bold(false)
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
table := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithFocused(true),
|
||||
WithHeight(10),
|
||||
)
|
||||
|
||||
biscuits := New(
|
||||
WithHeight(5),
|
||||
WithColumns([]Column{
|
||||
{Title: "Name", Width: 25},
|
||||
{Title: "Country of Origin", Width: 16},
|
||||
{Title: "Dunk-able", Width: 12},
|
||||
}),
|
||||
WithRows([]Row{
|
||||
{"Chocolate Digestives", "UK", "Yes"},
|
||||
{"Tim Tams", "Australia", "No"},
|
||||
{"Hobnobs", "UK", "Yes"},
|
||||
}),
|
||||
WithStyles(s),
|
||||
table.SetStyles(tc.styles)
|
||||
golden.RequireEqual(t, []byte(table.View()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetStyleFunc(t *testing.T) {
|
||||
t.Run("Clear styles with StyleFunc", func(t *testing.T) {
|
||||
tb := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithFocused(true),
|
||||
WithHeight(10),
|
||||
)
|
||||
got := ansiStrip(baseStyle.Render(biscuits.View()))
|
||||
golden.RequireEqual(t, []byte(got))
|
||||
tb.SetStyleFunc(table.StyleFunc(func(row, col int) lipgloss.Style {
|
||||
if row == tb.Cursor() {
|
||||
return niceMargins.Background(lipgloss.Color("68"))
|
||||
}
|
||||
return niceMargins
|
||||
}))
|
||||
golden.RequireEqual(t, []byte(tb.View()))
|
||||
})
|
||||
}
|
||||
|
||||
func ansiStrip(s string) string {
|
||||
// Replace all \r\n with \n
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
return ansi.Strip(s)
|
||||
func TestSetBorder(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
borders []bool
|
||||
}{
|
||||
{"unset all borders", []bool{false}},
|
||||
{"set all borders", []bool{true}},
|
||||
{"vertical borders only", []bool{true, false}},
|
||||
{"no top border", []bool{false, true, true}},
|
||||
{"no left border", []bool{true, true, true, false}},
|
||||
{"row separator and no right border", []bool{true, false, true, true, true}},
|
||||
{"set row and column separators", []bool{false, false, false, false, true, true}},
|
||||
{"invalid number of arguments", []bool{true, false, false, false, false, true, true}},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tb := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithFocused(true),
|
||||
WithHeight(10),
|
||||
).SetBorder(tc.borders...)
|
||||
golden.RequireEqual(t, []byte(tb.View()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Examples
|
||||
|
||||
func ExampleOption() {
|
||||
var niceMargins = lipgloss.NewStyle().Padding(0, 1)
|
||||
var headers = []string{"Rank", "City", "Country", "Population"}
|
||||
var rows = [][]string{
|
||||
{"1", "Tokyo", "Japan", "37,274,000"},
|
||||
{"2", "Delhi", "India", "32,065,760"},
|
||||
{"3", "Shanghai", "China", "28,516,904"},
|
||||
{"4", "Dhaka", "Bangladesh", "22,478,116"},
|
||||
{"5", "São Paulo", "Brazil", "22,429,800"},
|
||||
{"6", "Mexico City", "Mexico", "22,085,140"},
|
||||
{"7", "Cairo", "Egypt", "21,750,020"},
|
||||
{"8", "Beijing", "China", "21,333,332"},
|
||||
{"9", "Mumbai", "India", "20,961,472"},
|
||||
{"10", "Osaka", "Japan", "19,059,856"},
|
||||
}
|
||||
t := New(
|
||||
WithHeaders(headers...),
|
||||
WithRows(rows...),
|
||||
WithFocused(true),
|
||||
WithHeight(10),
|
||||
).OverwriteStyles(Styles{
|
||||
Selected: niceMargins,
|
||||
Header: niceMargins,
|
||||
Cell: niceMargins,
|
||||
})
|
||||
fmt.Println(t.View())
|
||||
// Output:
|
||||
//┌───────────────────────────────────────────┐
|
||||
//│ Rank City Country Population │
|
||||
//├───────────────────────────────────────────┤
|
||||
//│ 1 Tokyo Japan 37,274,000 │
|
||||
//│ 2 Delhi India 32,065,760 │
|
||||
//│ 3 Shanghai China 28,516,904 │
|
||||
//│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
//│ 5 São Paulo Brazil 22,429,800 │
|
||||
//│ … … … … │
|
||||
//└───────────────────────────────────────────┘
|
||||
}
|
||||
|
||||
func ExampleModel_SetRows() {
|
||||
var niceMargins = lipgloss.NewStyle().Padding(0, 1)
|
||||
var headers = []string{"Rank", "City", "Country", "Population"}
|
||||
var rows = [][]string{
|
||||
{"1", "Tokyo", "Japan", "37,274,000"},
|
||||
{"2", "Delhi", "India", "32,065,760"},
|
||||
{"3", "Shanghai", "China", "28,516,904"},
|
||||
{"4", "Dhaka", "Bangladesh", "22,478,116"},
|
||||
{"5", "São Paulo", "Brazil", "22,429,800"},
|
||||
{"6", "Mexico City", "Mexico", "22,085,140"},
|
||||
{"7", "Cairo", "Egypt", "21,750,020"},
|
||||
{"8", "Beijing", "China", "21,333,332"},
|
||||
{"9", "Mumbai", "India", "20,961,472"},
|
||||
{"10", "Osaka", "Japan", "19,059,856"},
|
||||
}
|
||||
tb := New().
|
||||
SetHeaders(headers...).
|
||||
SetRows(rows...).
|
||||
SetHeight(10).
|
||||
OverwriteStyles(Styles{
|
||||
Selected: niceMargins,
|
||||
Header: niceMargins,
|
||||
Cell: niceMargins,
|
||||
})
|
||||
fmt.Println(tb.View())
|
||||
// Output:
|
||||
//┌───────────────────────────────────────────┐
|
||||
//│ Rank City Country Population │
|
||||
//├───────────────────────────────────────────┤
|
||||
//│ 1 Tokyo Japan 37,274,000 │
|
||||
//│ 2 Delhi India 32,065,760 │
|
||||
//│ 3 Shanghai China 28,516,904 │
|
||||
//│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
//│ 5 São Paulo Brazil 22,429,800 │
|
||||
//│ … … … … │
|
||||
//└───────────────────────────────────────────┘
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────┐
|
||||
│RankCity Country Population│
|
||||
├────────────────────────────────────┤
|
||||
│1 Tokyo Japan 37,274,000│
|
||||
│2 Delhi India 32,065,760│
|
||||
│3 Shanghai China 28,516,904│
|
||||
│4 Dhaka Bangladesh22,478,116│
|
||||
│5 São Paulo Brazil 22,429,800│
|
||||
│… … … … │
|
||||
└────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Rank City Country Population │
|
||||
├────────────────────────────────────────────┤
|
||||
│ [38;5;68m1[m [38;5;68mTokyo[m [38;5;68mJapan[m [38;5;68m37,274,000[m │
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────────────┐
|
||||
│ [1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m │
|
||||
├────────────────────────────────────────────┤
|
||||
│ [1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m │
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
────────────────────────────────────────────┐
|
||||
[1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m │
|
||||
────────────────────────────────────────────┤
|
||||
[1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m │
|
||||
2 Delhi India 32,065,760 │
|
||||
3 Shanghai China 28,516,904 │
|
||||
4 Dhaka Bangladesh 22,478,116 │
|
||||
5 São Paulo Brazil 22,429,800 │
|
||||
… … … … │
|
||||
────────────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
│ [1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m │
|
||||
├────────────────────────────────────────────┤
|
||||
│ [1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m │
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ 6 Mexico City Mexico 22,085,140 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
[1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m
|
||||
────────────────────────────────────────────
|
||||
[1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m
|
||||
2 Delhi India 32,065,760
|
||||
3 Shanghai China 28,516,904
|
||||
4 Dhaka Bangladesh 22,478,116
|
||||
5 São Paulo Brazil 22,429,800
|
||||
6 Mexico City Mexico 22,085,140
|
||||
… … … …
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
────────────────────────────────────────────
|
||||
[1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m
|
||||
────────────────────────────────────────────
|
||||
[1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m
|
||||
2 Delhi India 32,065,760
|
||||
3 Shanghai China 28,516,904
|
||||
4 Dhaka Bangladesh 22,478,116
|
||||
5 São Paulo Brazil 22,429,800
|
||||
… … … …
|
||||
────────────────────────────────────────────
|
||||
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Rank City Country Population │
|
||||
├────────────────────────────────────────────┤
|
||||
│[48;5;68m [m[48;5;68m1[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68mTokyo[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68mJapan[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68m37,274,000[m[48;5;68m [m│
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────────────┐
|
||||
│ [1mRank[m [1mCity[m [1mCountry[m [1mPopulation[m │
|
||||
├────────────────────────────────────────────┤
|
||||
│ [1;38;5;212m1[m [1;38;5;212mTokyo[m [1;38;5;212mJapan[m [1;38;5;212m37,274,000[m │
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Rank City Country Population │
|
||||
├────────────────────────────────────────────┤
|
||||
│[48;5;68m [m[48;5;68m1[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68mTokyo[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68mJapan[m[48;5;68m [m[48;5;68m [m[48;5;68m [m[48;5;68m37,274,000[m[48;5;68m [m│
|
||||
│ 2 Delhi India 32,065,760 │
|
||||
│ 3 Shanghai China 28,516,904 │
|
||||
│ 4 Dhaka Bangladesh 22,478,116 │
|
||||
│ 5 São Paulo Brazil 22,429,800 │
|
||||
│ … … … … │
|
||||
└────────────────────────────────────────────┘
|
||||
+4
-5
@@ -1,5 +1,4 @@
|
||||
Name Country of Orig… Dunk-able
|
||||
Chocolate Digestives UK Yes
|
||||
Tim Tams Australia No
|
||||
Hobnobs UK Yes
|
||||
|
||||
Name Country of Origin Dunk-able
|
||||
Chocolate Digestives UK Yes
|
||||
Tim Tams Australia No
|
||||
Hobnobs UK Yes
|
||||
+7
-8
@@ -1,8 +1,7 @@
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ Name Country of Orig… Dunk-able │
|
||||
│───────────────────────────────────────────────────────────│
|
||||
│ Chocolate Digestives UK Yes │
|
||||
│ Tim Tams Australia No │
|
||||
│ Hobnobs UK Yes │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────────────────────────────┐
|
||||
│ Name Country of Origin Dunk-able │
|
||||
├────────────────────────────────────────────────────┤
|
||||
│ Chocolate Digestives UK Yes │
|
||||
│ Tim Tams Australia No │
|
||||
│ Hobnobs UK Yes │
|
||||
└────────────────────────────────────────────────────┘
|
||||
Reference in New Issue
Block a user