Skip to content

Commit

Permalink
Table Data Interface (#228)
Browse files Browse the repository at this point in the history
* wip: provide model interface for table data

* refactor: rename Model to Data

* refactor: add `Row` method

* refactor: use `Row` method

* fix: examples to Data interface

---------

Co-authored-by: Christian Muehlhaeuser <muesli@gmail.com>
  • Loading branch information
maaslalani and muesli committed Oct 4, 2023
1 parent 2687d82 commit 160eb4f
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 132 deletions.
4 changes: 2 additions & 2 deletions examples/table/chess/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func main() {
re := lipgloss.NewRenderer(os.Stdout)
labelStyle := re.NewStyle().Foreground(lipgloss.Color("241"))

board := [][]any{
board := [][]string{
{"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"},
{"♟", "♟", "♟", "♟", "♟", "♟", "♟", "♟"},
{" ", " ", " ", " ", " ", " ", " ", " "},
Expand All @@ -28,7 +28,7 @@ func main() {
Border(lipgloss.NormalBorder()).
BorderRow(true).
BorderColumn(true).
Rows(board...).
Rows(table.Rows(board...)).
StyleFunc(func(row, col int) lipgloss.Style {
return lipgloss.NewStyle().Padding(0, 1)
})
Expand Down
4 changes: 2 additions & 2 deletions examples/table/languages/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func main() {
BorderStyle = lipgloss.NewStyle().Foreground(purple)
)

rows := [][]any{
rows := [][]string{
{"Chinese", "您好", "你好"},
{"Japanese", "こんにちは", "やあ"},
{"Arabic", "أهلين", "أهلا"},
Expand Down Expand Up @@ -67,7 +67,7 @@ func main() {
return style
}).
Headers("LANGUAGE", "FORMAL", "INFORMAL").
Rows(rows...).
Rows(table.Rows(rows...)).
Width(18)

fmt.Println(t)
Expand Down
12 changes: 6 additions & 6 deletions examples/table/mindy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func main() {
labelStyle := re.NewStyle().Width(3).Align(lipgloss.Right)
swatchStyle := re.NewStyle().Width(6)

data := [][]any{}
data := [][]string{}
for i := 0; i < 13; i += 8 {
data = append(data, makeRow(i, i+5))
}
Expand All @@ -32,7 +32,7 @@ func main() {

t := table.New().
Border(lipgloss.HiddenBorder()).
Rows(data...).
Rows(table.Rows(data...)).
StyleFunc(func(row, col int) lipgloss.Style {
color := lipgloss.Color(fmt.Sprint(data[row-1][col-col%2]))
switch {
Expand All @@ -48,10 +48,10 @@ func main() {

const rowLength = 12

func makeRow(start, end int) []any {
var row []any
func makeRow(start, end int) []string {
var row []string
for i := start; i <= end; i++ {
row = append(row, i)
row = append(row, fmt.Sprint(i))
row = append(row, "")
}
for i := len(row); i < rowLength; i++ {
Expand All @@ -60,6 +60,6 @@ func makeRow(start, end int) []any {
return row
}

func makeEmptyRow() []any {
func makeEmptyRow() []string {
return makeRow(0, -1)
}
62 changes: 31 additions & 31 deletions examples/table/pokemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,35 @@ func main() {
}

headers := []any{"#", "Name", "Type 1", "Type 2", "Japanese", "Official Rom."}
data := [][]any{
{1, "Bulbasaur", "Grass", "Poison", "フシギダネ", "Bulbasaur"},
{2, "Ivysaur", "Grass", "Poison", "フシギソウ", "Ivysaur"},
{3, "Venusaur", "Grass", "Poison", "フシギバナ", "Venusaur"},
{4, "Charmander", "Fire", "", "ヒトカゲ", "Hitokage"},
{5, "Charmeleon", "Fire", "", "リザード", "Lizardo"},
{6, "Charizard", "Fire", "Flying", "リザードン", "Lizardon"},
{7, "Squirtle", "Water", "", "ゼニガメ", "Zenigame"},
{8, "Wartortle", "Water", "", "カメール", "Kameil"},
{9, "Blastoise", "Water", "", "カメックス", "Kamex"},
{10, "Caterpie", "Bug", "", "キャタピー", "Caterpie"},
{11, "Metapod", "Bug", "", "トランセル", "Trancell"},
{12, "Butterfree", "Bug", "Flying", "バタフリー", "Butterfree"},
{13, "Weedle", "Bug", "Poison", "ビードル", "Beedle"},
{14, "Kakuna", "Bug", "Poison", "コクーン", "Cocoon"},
{15, "Beedrill", "Bug", "Poison", "スピアー", "Spear"},
{16, "Pidgey", "Normal", "Flying", "ポッポ", "Poppo"},
{17, "Pidgeotto", "Normal", "Flying", "ピジョン", "Pigeon"},
{18, "Pidgeot", "Normal", "Flying", "ピジョット", "Pigeot"},
{19, "Rattata", "Normal", "", "コラッタ", "Koratta"},
{20, "Raticate", "Normal", "", "ラッタ", "Ratta"},
{21, "Spearow", "Normal", "Flying", "オニスズメ", "Onisuzume"},
{22, "Fearow", "Normal", "Flying", "オニドリル", "Onidrill"},
{23, "Ekans", "Poison", "", "アーボ", "Arbo"},
{24, "Arbok", "Poison", "", "アーボック", "Arbok"},
{25, "Pikachu", "Electric", "", "ピカチュウ", "Pikachu"},
{26, "Raichu", "Electric", "", "ライチュウ", "Raichu"},
{27, "Sandshrew", "Ground", "", "サンド", "Sand"},
{28, "Sandslash", "Ground", "", "サンドパン", "Sandpan"},
data := [][]string{
{"1", "Bulbasaur", "Grass", "Poison", "フシギダネ", "Bulbasaur"},
{"2", "Ivysaur", "Grass", "Poison", "フシギソウ", "Ivysaur"},
{"3", "Venusaur", "Grass", "Poison", "フシギバナ", "Venusaur"},
{"4", "Charmander", "Fire", "", "ヒトカゲ", "Hitokage"},
{"5", "Charmeleon", "Fire", "", "リザード", "Lizardo"},
{"6", "Charizard", "Fire", "Flying", "リザードン", "Lizardon"},
{"7", "Squirtle", "Water", "", "ゼニガメ", "Zenigame"},
{"8", "Wartortle", "Water", "", "カメール", "Kameil"},
{"9", "Blastoise", "Water", "", "カメックス", "Kamex"},
{"10", "Caterpie", "Bug", "", "キャタピー", "Caterpie"},
{"11", "Metapod", "Bug", "", "トランセル", "Trancell"},
{"12", "Butterfree", "Bug", "Flying", "バタフリー", "Butterfree"},
{"13", "Weedle", "Bug", "Poison", "ビードル", "Beedle"},
{"14", "Kakuna", "Bug", "Poison", "コクーン", "Cocoon"},
{"15", "Beedrill", "Bug", "Poison", "スピアー", "Spear"},
{"16", "Pidgey", "Normal", "Flying", "ポッポ", "Poppo"},
{"17", "Pidgeotto", "Normal", "Flying", "ピジョン", "Pigeon"},
{"18", "Pidgeot", "Normal", "Flying", "ピジョット", "Pigeot"},
{"19", "Rattata", "Normal", "", "コラッタ", "Koratta"},
{"20", "Raticate", "Normal", "", "ラッタ", "Ratta"},
{"21", "Spearow", "Normal", "Flying", "オニスズメ", "Onisuzume"},
{"22", "Fearow", "Normal", "Flying", "オニドリル", "Onidrill"},
{"23", "Ekans", "Poison", "", "アーボ", "Arbo"},
{"24", "Arbok", "Poison", "", "アーボック", "Arbok"},
{"25", "Pikachu", "Electric", "", "ピカチュウ", "Pikachu"},
{"26", "Raichu", "Electric", "", "ライチュウ", "Raichu"},
{"27", "Sandshrew", "Ground", "", "サンド", "Sand"},
{"28", "Sandslash", "Ground", "", "サンドパン", "Sandpan"},
}

CapitalizeHeaders := func(data []any) []any {
Expand All @@ -69,8 +69,8 @@ func main() {
Border(lipgloss.NormalBorder()).
BorderStyle(re.NewStyle().Foreground(lipgloss.Color("238"))).
Headers(CapitalizeHeaders(headers)...).
Width(40).
Rows(data...).
Width(80).
Rows(table.Rows(data...)).
StyleFunc(func(row, col int) lipgloss.Style {
if row == 0 {
return headerStyle
Expand Down
133 changes: 133 additions & 0 deletions table/rows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package table

// Data is the interface that wraps the basic methods of a table model.
type Data interface {
Row(row int) Row
Append(row Row)
Count() int
Columns() int
}

// Row represents one line in the table.
type Row interface {
Column(col int) string
Length() int
}

// StringData is a string-based implementation of the Data interface.
type StringData struct {
rows []Row
columns int
}

// Rows creates a new StringData with the given number of columns.
func Rows(rows ...[]string) *StringData {
m := StringData{columns: 0}

for _, row := range rows {
m.columns = max(m.columns, len(row))
m.rows = append(m.rows, StringRow(row))
}

return &m
}

// Append appends the given row to the table.
func (m *StringData) Append(row Row) {
m.columns = max(m.columns, row.Length())
m.rows = append(m.rows, row)
}

// Row returns the row at the given index.
func (m *StringData) Row(row int) Row {
return m.rows[row]
}

// Columns returns the number of columns in the table.
func (m *StringData) Columns() int {
return m.columns
}

// Item appends the given row to the table.
func (m *StringData) Item(rows ...string) *StringData {
m.columns = max(m.columns, len(rows))
m.rows = append(m.rows, StringRow(rows))
return m
}

// Count returns the number of rows in the table.
func (m *StringData) Count() int {
return len(m.rows)
}

// StringRow is a simple implementation of the Row interface.
type StringRow []string

// Value returns the value of the column at the given index.
func (r StringRow) Column(col int) string {
if col >= len(r) {
return ""
}

return r[col]
}

// Value returns the value of the column at the given index.
func (r StringRow) Length() int {
return len(r)
}

// Filter applies a filter on some data.
type Filter struct {
data Data
filter func(row Row) bool
}

// NewFilter initializes a new Filter.
func NewFilter(data Data) *Filter {
return &Filter{data: data}
}

// Filter applies the given filter function to the data.
func (m *Filter) Filter(f func(row Row) bool) *Filter {
m.filter = f
return m
}

// Row returns the row at the given index.
func (m *Filter) Row(row int) Row {
j := 0
for i := 0; i < m.data.Count(); i++ {
if m.filter(m.data.Row(i)) {
if j == row {
return m.data.Row(i)
}

j++
}
}

return nil
}

// Append appends the given row to the table.
func (m *Filter) Append(row Row) {
m.data.Append(row)
}

// Columns returns the number of columns in the table.
func (m *Filter) Columns() int {
return m.data.Columns()
}

// Count returns the number of rows in the table.
func (m *Filter) Count() int {
j := 0
for i := 0; i < m.data.Count(); i++ {
if m.filter(m.data.Row(i)) {
j++
}
}

return j
}
Loading

0 comments on commit 160eb4f

Please sign in to comment.