Skip to content

Commit

Permalink
feat: enumerator index at 0
Browse files Browse the repository at this point in the history
  • Loading branch information
maaslalani committed Nov 28, 2023
1 parent 7b1d672 commit bee9edf
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 57 deletions.
33 changes: 12 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,15 @@ Lists have the ability to nest.

```go
l := list.New(
"A", list.New("Apricot"),
"B", list.New("Bergamot orange"),
"C", list.New("Citron", "Clymenia"),
"A", list.New("Artichoke"),
"B", list.New("Baking Flour", "Bananas", "Barley", "Bean Sprouts"),
"C", list.New("Cashew Apple", "Cashews", "Coconut Milk", "Curry Paste", "Currywurst"),
"D", list.New("Dill", "Dragonfruit", "Dried Shrimp"),
"E", list.New("Eggs"),
"F", list.New("Fish Cake", "Furikake"),
"J", list.New("Jicama"),
"K", list.New("Kohlrabi"),
"L", list.New("Leeks", "Lentils", "Licorice Root"),
)
```

Expand Down Expand Up @@ -553,7 +559,7 @@ you may also define your own custom enumerator:

```go
var DuckDuckGooseEnumerator Enumerator = func(l *List, i int) string {
if l.item[i] == "Goose" {
if l.At(i) == "Goose" {
return ""
}
return " "
Expand Down Expand Up @@ -582,29 +588,14 @@ Print the list:

### Building

You can also build lists incrementally:
You can also build lists incrementally (with `.Item()`):

```go
l := list.New()

for i := 0; i < 10; i++ {
for i := 0; i < repeat; i++ {
l.Item("Lip Gloss")
}

fmt.Println(l)
```

```
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
• Lip Gloss
```

***
Expand Down
20 changes: 20 additions & 0 deletions examples/list/duckduckgoose/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss/list"
)

func DuckDuckGooseEnumerator(l *list.List, i int) string {
if l.At(i) == "Goose" {
return "→ "
}
return " "
}

func main() {
l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck")
l.Enumerator(DuckDuckGooseEnumerator)
fmt.Println(l)
}
2 changes: 1 addition & 1 deletion examples/list/grocery/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var purchased = []string{

func GroceryEnumerator(l *list.List, i int) string {
for _, p := range purchased {
if l.Items[i-1] == p {
if l.At(i) == p {
return "✓"
}
}
Expand Down
28 changes: 28 additions & 0 deletions examples/list/roman/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/list"
)

func main() {
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("250")).MarginRight(1)
baseStyle := lipgloss.NewStyle().Margin(1, 2)

l := list.New(
"Glossier",
"Claire’s Boutique",
"Nyx",
"Mac",
"Milk",
).
Enumerator(list.Roman).
EnumeratorStyle(enumeratorStyle).
BaseStyle(baseStyle).
ItemStyle(itemStyle)

fmt.Println(l)
}
12 changes: 12 additions & 0 deletions examples/list/simple/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss/list"
)

func main() {
l := list.New("A", "B", "C")
fmt.Println(l)
}
20 changes: 10 additions & 10 deletions list/enumerations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ const abcLen = 26
// c. Baz
// d. Qux.
func Alphabet(_ *List, i int) string {
if i > abcLen*abcLen+abcLen {
return fmt.Sprintf("%c%c%c.", 'A'+(i-1)/abcLen/abcLen-1, 'A'+((i-1)/abcLen)%abcLen-1, 'A'+(i-1)%abcLen)
if i >= abcLen*abcLen+abcLen {
return fmt.Sprintf("%c%c%c.", 'A'+i/abcLen/abcLen-1, 'A'+(i/abcLen)%abcLen-1, 'A'+i%abcLen)
}
if i > abcLen {
return fmt.Sprintf("%c%c.", 'A'+(i-1)/abcLen-1, 'A'+(i-1)%abcLen)
if i >= abcLen {
return fmt.Sprintf("%c%c.", 'A'+i/abcLen-1, 'A'+(i)%abcLen)
}
return fmt.Sprintf("%c.", 'A'+(i-1)%abcLen)
return fmt.Sprintf("%c.", 'A'+i%abcLen)
}

// Arabic is the enumeration for arabic numerals listing.
Expand All @@ -34,7 +34,7 @@ func Alphabet(_ *List, i int) string {
// 3. Baz
// 4. Qux.
func Arabic(_ *List, i int) string {
return fmt.Sprintf("%d.", i)
return fmt.Sprintf("%d.", i+1)
}

// Roman is the enumeration for roman numerals listing.
Expand All @@ -50,7 +50,7 @@ func Roman(_ *List, i int) string {
result strings.Builder
)
for v, value := range arabic {
for i >= value {
for i >= value-1 {
i -= value
result.WriteString(roman[v])
}
Expand All @@ -77,16 +77,16 @@ func Bullet(_ *List, _ int) string {
// └─ Qux.
func Tree(l *List, index int) string {
// out of bounds?
if index < 0 || index > len(l.Items) {
if index < 0 || index > len(l.items) {
return ""
}

switch index {
// is last item of list.
case len(l.Items):
case len(l.items) - 1:
return "└─"
default:
switch l.Items[index].(type) {
switch l.items[index+1].(type) {
case *List:
return "└─"
default:
Expand Down
25 changes: 17 additions & 8 deletions list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ type List struct {
enumerator Enumerator
hide bool
indent int
Items []any
items []any
style Style
}

// New returns a new list.
func New(items ...any) *List {
return &List{
Items: items,
items: items,

enumerator: Bullet,
indent: 0,
Expand All @@ -43,10 +43,19 @@ func New(items ...any) *List {

// Item appends an item to a list.
func (l *List) Item(item any) *List {
l.Items = append(l.Items, item)
l.items = append(l.items, item)
return l
}

// At returns the item at index.
func (l *List) At(i int) any {
if i < 0 || i >= len(l.items) {
return ""
}

return l.items[i]
}

// Enumerator sets the enumeration type.
func (l *List) Enumerator(enumerator Enumerator) *List {
l.enumerator = enumerator
Expand Down Expand Up @@ -107,21 +116,21 @@ func (l *List) String() string {

// find the longest enumerator value of this list.
var maxLen int
for i := 0; i < len(l.Items); i++ {
enum := l.style.Enumerator.Render(l.enumerator(l, i+1))
for i := 0; i < len(l.items); i++ {
enum := l.style.Enumerator.Render(l.enumerator(l, i))
maxLen = max(runewidth.StringWidth(enum), maxLen)
}

var s strings.Builder
for i, item := range l.Items {
for i, item := range l.items {
switch item := item.(type) {
case *List:
if item.indent <= 0 {
item = item.Indent(l.indent + indentIncrement)
}
s.WriteString(item.String())
default:
enum := l.style.Enumerator.Render(l.enumerator(l, i+1))
enum := l.style.Enumerator.Render(l.enumerator(l, i))
enumLen := runewidth.StringWidth(enum)
s.WriteString(strings.Repeat(" ", l.indent))
s.WriteString(strings.Repeat(" ", maxLen-enumLen))
Expand All @@ -130,7 +139,7 @@ func (l *List) String() string {
s.WriteRune('\n')
}
}
return s.String()
return l.style.Base.Render(s.String())
}

func max(a, b int) int {
Expand Down
34 changes: 17 additions & 17 deletions list/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,23 +317,23 @@ func TestBullet(t *testing.T) {
i int
exp string
}{
{Alphabet, 1, "A"},
{Alphabet, 26, "Z"},
{Alphabet, 27, "AA"},
{Alphabet, 52, "AZ"},
{Alphabet, 53, "BA"},
{Alphabet, 80, "CB"},
{Alphabet, 702, "ZZ"},
{Alphabet, 703, "AAA"},
{Alphabet, 802, "ADV"},
{Alphabet, 1001, "ALM"},
{Roman, 1, "I"},
{Roman, 26, "XXVI"},
{Roman, 27, "XXVII"},
{Roman, 51, "LI"},
{Roman, 101, "CI"},
{Roman, 702, "DCCII"},
{Roman, 1001, "MI"},
{Alphabet, 0, "A"},
{Alphabet, 25, "Z"},
{Alphabet, 26, "AA"},
{Alphabet, 51, "AZ"},
{Alphabet, 52, "BA"},
{Alphabet, 79, "CB"},
{Alphabet, 701, "ZZ"},
{Alphabet, 702, "AAA"},
{Alphabet, 801, "ADV"},
{Alphabet, 1000, "ALM"},
{Roman, 0, "I"},
{Roman, 25, "XXVI"},
{Roman, 26, "XXVII"},
{Roman, 50, "LI"},
{Roman, 100, "CI"},
{Roman, 701, "DCCII"},
{Roman, 1000, "MI"},
}

for _, test := range tests {
Expand Down

0 comments on commit bee9edf

Please sign in to comment.