diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d834ea6f..2a558df7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @meowgorithm @muesli +* @meowgorithm @aymanbagabas diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..f649dfde --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: goreleaser + +on: + push: + tags: + - v*.*.* + +concurrency: + group: goreleaser + cancel-in-progress: true + +jobs: + goreleaser: + uses: charmbracelet/meta/.github/workflows/goreleaser.yml@main + secrets: + docker_username: ${{ secrets.DOCKERHUB_USERNAME }} + docker_token: ${{ secrets.DOCKERHUB_TOKEN }} + gh_pat: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + goreleaser_key: ${{ secrets.GORELEASER_KEY }} + twitter_consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }} + twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }} + twitter_access_token: ${{ secrets.TWITTER_ACCESS_TOKEN }} + twitter_access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + mastodon_client_id: ${{ secrets.MASTODON_CLIENT_ID }} + mastodon_client_secret: ${{ secrets.MASTODON_CLIENT_SECRET }} + mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }} + discord_webhook_id: ${{ secrets.DISCORD_WEBHOOK_ID }} + discord_webhook_token: ${{ secrets.DISCORD_WEBHOOK_TOKEN }} +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 00000000..c61970e0 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,5 @@ +includes: + - from_url: + url: charmbracelet/meta/main/goreleaser-lib.yaml +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json + diff --git a/README.md b/README.md index 9fbb84ad..4f214341 100644 --- a/README.md +++ b/README.md @@ -455,114 +455,9 @@ fmt.Println(t) For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table). -## Rendering Trees - -Lip Gloss ships with a tree rendering sub-package. - -```go -import "github.com/charmbracelet/lipgloss/tree" -``` - -Define a new tree. - -```go -t := tree.New("root", "child 1", "child 2", tree.New("child 3", "child 3.1")) -``` - -Print the tree. - -```go -fmt.Println(t) - -// root -// ├── child 1 -// ├── child 2 -// └── child 3 -// └── child 3.1 -``` - -### Customization - -Trees can be customized via their enumeration function as well as using -`lipgloss.Style`s. - -```go -style1 := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) -style2 := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).MarginRight(1) - -t := tree.New(). - Items( - "Glossier", - "Claire’s Boutique", - tree.New(). - Root("Nyx"). - Items("Qux", "Quux"). - EnumeratorStyle(style2), - "Mac", - "Milk", - ). - EnumeratorStyle(style1) -``` - -Print the tree: - -

- Tree example -

-You may also define custom enumerator implementations: - -```go -t := tree.New(). - Items( - "Glossier", - "Claire’s Boutique", - tree.New(). - Root("Nyx"). - Items( - "Qux", - "Quux", - ), - "Mac", - "Milk", - ). - Enumerator(func(tree.Data, int) (string, string) { - return "->", "->" - }) -``` - -Print the tree. - -

- Tree example -

- -### Building - -If you need, you can also build trees incrementally: - -```go -t := tree.New("") - -for i := 0; i < repeat; i++ { - t.Item("Lip Gloss") -} -``` - - ## Rendering Lists Lip Gloss ships with a list rendering sub-package. -Implementation-wise, lists are still trees. -The `list` package provides many common `Enumerator` implementations, as well as -some syntactic sugar. ```go import "github.com/charmbracelet/lipgloss/list" @@ -584,77 +479,89 @@ fmt.Println(l) // • C ``` +Lists have the ability to nest. + +```go +l := list.New( + "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"), +) +``` + +Print the list. + +```go +fmt.Println(l) +``` -### Customization +

+image +

Lists can be customized via their enumeration function as well as using `lipgloss.Style`s. ```go enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) -itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).MarginRight(1) +itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1) l := list.New( - "Glossier", - "Claire’s Boutique", - "Nyx", - "Mac", - "Milk", + "Glossier", + "Claire’s Boutique", + "Nyx", + "Mac", + "Milk", ). - Enumerator(list.Roman). - EnumeratorStyle(enumeratorStyle). - ItemStyle(itemStyle) + Enumerator(list.Roman). + EnumeratorStyle(enumeratorStyle). + ItemStyle(itemStyle) ``` Print the list.

- List example +List example

+ In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`), you may also define your own custom enumerator: ```go -var DuckDuckGooseEnumerator Enumerator = func(l *List, i int) string { - if l.At(i) == "Goose" { - return "Honk →" - } - return "" -} -``` +l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck") -Use it in a list: +func DuckDuckGooseEnumerator(l list.Items, i int) string { + if l.At(i).Value() == "Goose" { + return "Honk →" + } + return "" +} -```go -l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck") -l.Enumerator(DuckDuckGooseEnumerator) +l = l.Enumerator(DuckDuckGooseEnumerator) ``` Print the list:

- image +image

-### Building - -If you need, you can also build trees incrementally: +If you need, you can also build lists incrementally: ```go l := list.New() for i := 0; i < repeat; i++ { - l.Item("Lip Gloss") + l.Item("Lip Gloss") } ``` + --- ## FAQ diff --git a/examples/go.mod b/examples/go.mod index f0ffe899..e5a6c2bf 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -4,8 +4,6 @@ go 1.19 replace github.com/charmbracelet/lipgloss => ../ -replace github.com/charmbracelet/lipgloss/tree => ../tree - replace github.com/charmbracelet/lipgloss/list => ../list require ( @@ -23,7 +21,7 @@ require ( github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/keygen v0.5.0 // indirect - github.com/charmbracelet/x/ansi v0.1.1 // indirect + github.com/charmbracelet/x/ansi v0.1.4 // indirect github.com/charmbracelet/x/conpty v0.1.0 // indirect github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 // indirect github.com/charmbracelet/x/input v0.1.0 // indirect @@ -32,7 +30,7 @@ require ( github.com/charmbracelet/x/windows v0.1.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gliderlabs/ssh v0.3.4 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect diff --git a/examples/go.sum b/examples/go.sum index 4df86e47..5c40edd1 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -9,8 +9,8 @@ github.com/charmbracelet/ssh v0.0.0-20240604154955-a40c6a0d028f h1:DnNHMcvpjh51p github.com/charmbracelet/ssh v0.0.0-20240604154955-a40c6a0d028f/go.mod h1:LmMZag2g7ILMmWtDmU7dIlctUopwmb73KpPzj0ip1uk= github.com/charmbracelet/wish v0.5.0 h1:FkkdNBFqrLABR1ciNrAL2KCxoyWfKhXnIGZw6GfAtPg= github.com/charmbracelet/wish v0.5.0/go.mod h1:5GAn5SrDSZ7cgKjnC+3kDmiIo7I6k4/AYiRzC4+tpCk= -github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= -github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= +github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= @@ -33,8 +33,8 @@ github.com/gliderlabs/ssh v0.3.4 h1:+AXBtim7MTKaLVPgvE+3mhewYRawNLTd+jEEz/wExZw= github.com/gliderlabs/ssh v0.3.4/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= diff --git a/examples/list/sublist/main.go b/examples/list/sublist/main.go index 56246e1e..3f0a48cd 100644 --- a/examples/list/sublist/main.go +++ b/examples/list/sublist/main.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/table" - "github.com/charmbracelet/lipgloss/tree" "github.com/lucasb-eyer/go-colorful" ) @@ -119,16 +118,16 @@ func main() { Item("Lip Gloss"). Item("Lip Gloss"). Item( - tree.New(). + list.New(). EnumeratorStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(colors[4][0])).MarginRight(1)). - Child("\nStyle Definitions for Nice Terminal Layouts\n─────"). - Child("From Charm"). - Child("https://github.com/charmbracelet/lipgloss"). - Child( - tree.New(). + Item("\nStyle Definitions for Nice Terminal Layouts\n─────"). + Item("From Charm"). + Item("https://github.com/charmbracelet/lipgloss"). + Item( + list.New(). EnumeratorStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(colors[3][0])).MarginRight(1)). - Child("Emperors: Julio-Claudian dynasty"). - Child( + Item("Emperors: Julio-Claudian dynasty"). + Item( lipgloss.NewStyle().Padding(1).Render( list.New( "Augustus", @@ -139,7 +138,7 @@ func main() { ).Enumerator(list.Roman).String(), ), ). - Child( + Item( lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("#FAFAFA")). @@ -151,7 +150,7 @@ func main() { Width(40). Render(history), ). - Child( + Item( table.New(). Width(30). BorderStyle(purple.MarginRight(0)). @@ -174,8 +173,8 @@ func main() { Row("Orange", "2"). Row("Strawberry", "12"), ). - Child("Documents"). - Child( + Item("Documents"). + Item( list.New(). Enumerator(func(_ list.Items, i int) string { if i == 1 { @@ -200,9 +199,9 @@ func main() { Item("Baz Document\n" + faint.Render("10 minutes ago")). Item("Qux Document\n" + faint.Render("1 month ago")), ). - Child("EOF"), + Item("EOF"), ). - Child("go get github.com/charmbracelet/lipgloss/list\n"), + Item("go get github.com/charmbracelet/lipgloss/list\n"), ). Item("See ya later"), ), diff --git a/examples/tree/background/main.go b/examples/tree/background/main.go deleted file mode 100644 index 0955383d..00000000 --- a/examples/tree/background/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/tree" -) - -func main() { - enumeratorStyle := lipgloss.NewStyle(). - Background(lipgloss.Color("0")). - Padding(0, 1) - - headerItemStyle := lipgloss.NewStyle(). - Background(lipgloss.Color("#ee6ff8")). - Foreground(lipgloss.Color("#ecfe65")). - Bold(true). - Padding(0, 1) - - itemStyle := headerItemStyle.Background(lipgloss.Color("0")) - - t := tree.New(). - ItemStyle(itemStyle). - EnumeratorStyle(enumeratorStyle). - Root("# Table of Contents"). - Child( - tree.New(). - Root("## Chapter 1"). - Child("Chapter 1.1"). - Child("Chapter 1.2"), - ). - Child( - tree.New(). - Root("## Chapter 2"). - Child("Chapter 2.1"). - Child("Chapter 2.2"), - ) - - fmt.Println(t) -} diff --git a/examples/tree/files/main.go b/examples/tree/files/main.go deleted file mode 100644 index 2f274ad9..00000000 --- a/examples/tree/files/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/tree" -) - -func main() { - enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("240")).PaddingRight(1) - itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).Bold(true).PaddingRight(1) - - t := tree.New().Root(".").EnumeratorStyle(enumeratorStyle).ItemStyle(itemStyle) - _ = filepath.Walk(".", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - t.Child(tree.New().Root(path)) - } - return nil - }) - - fmt.Println(t) -} diff --git a/examples/tree/rounded/main.go b/examples/tree/rounded/main.go deleted file mode 100644 index 2ab3e6c5..00000000 --- a/examples/tree/rounded/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/tree" -) - -func main() { - itemStyle := lipgloss.NewStyle().MarginRight(1) - enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8")).MarginRight(1) - - t := tree.New(). - Root("Groceries"). - Child( - tree.New(). - Root("Fruits"). - Child( - "Blood Orange", - "Papaya", - "Dragonfruit", - "Yuzu", - ), - tree.New(). - Root("Items"). - Child( - "Cat Food", - "Nutella", - "Powdered Sugar", - ), - tree.New(). - Root("Veggies"). - Child( - "Leek", - "Artichoke", - ), - ).ItemStyle(itemStyle).EnumeratorStyle(enumeratorStyle).Enumerator(tree.RoundedEnumerator) - - fmt.Println(t) -} diff --git a/examples/tree/simple/main.go b/examples/tree/simple/main.go deleted file mode 100644 index f636224e..00000000 --- a/examples/tree/simple/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/charmbracelet/lipgloss/tree" -) - -func main() { - t := tree.New(). - Root("."). - Child("Item 1"). - Child( - tree.New(). - Root("Item 2"). - Child("Item 2.1"). - Child("Item 2.2"). - Child("Item 2.3"), - ). - Child( - tree.New(). - Root("Item 3"). - Child("Item 3.1"). - Child("Item 3.2"), - ) - - fmt.Println(t) -} diff --git a/examples/tree/simple/tree.go b/examples/tree/simple/tree.go new file mode 100644 index 00000000..83d9de5e --- /dev/null +++ b/examples/tree/simple/tree.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + + "github.com/charmbracelet/lipgloss/list" +) + +func main() { + t := tree().Items( + ".", + "Item 1", + "Item 2", + "Item 2.1", + "Item 2.2", + "Item 2.3", + tree().Items( + "Item 3", + "Item 3.1", + "Item 3.2", + ), + ) + + fmt.Printf(".\n%s\n", t) +} + +func tree() *list.List { + return list.New(). + Indenter(list.TreeIndenter). + Enumerator(list.Tree) +} diff --git a/examples/tree/styles/main.go b/examples/tree/styles/main.go deleted file mode 100644 index 2a24b363..00000000 --- a/examples/tree/styles/main.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/tree" -) - -func main() { - purple := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) - pink := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1) - - t := tree.New(). - Child( - "Glossier", - "Claire’s Boutique", - tree.New(). - Root("Nyx"). - Child("Lip Gloss", "Foundation"). - EnumeratorStyle(pink), - "Mac", - "Milk", - ). - EnumeratorStyle(purple) - fmt.Println(t) -} diff --git a/go.mod b/go.mod index 2a3fe544..6d7053a9 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,13 @@ module github.com/charmbracelet/lipgloss retract v0.7.0 // v0.7.0 introduces a bug that causes some apps to freeze. +retract v0.11.1 // v0.11.1 uses a broken version of x/ansi StringWidth that causes some lines to wrap incorrectly. + go 1.18 require ( github.com/aymanbagabas/go-udiff v0.2.0 - github.com/charmbracelet/x/ansi v0.1.1 + github.com/charmbracelet/x/ansi v0.1.4 github.com/charmbracelet/x/term v0.1.1 github.com/lucasb-eyer/go-colorful v1.2.0 github.com/rivo/uniseg v0.4.7 diff --git a/go.sum b/go.sum index 8e1589e2..220995d7 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= -github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= -github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= +github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= diff --git a/tree/children.go b/internal/tree/children.go similarity index 100% rename from tree/children.go rename to internal/tree/children.go diff --git a/tree/enumerator.go b/internal/tree/enumerator.go similarity index 100% rename from tree/enumerator.go rename to internal/tree/enumerator.go diff --git a/tree/renderer.go b/internal/tree/renderer.go similarity index 100% rename from tree/renderer.go rename to internal/tree/renderer.go diff --git a/tree/tree.go b/internal/tree/tree.go similarity index 100% rename from tree/tree.go rename to internal/tree/tree.go diff --git a/tree/tree_test.go b/internal/tree/tree_test.go similarity index 99% rename from tree/tree_test.go rename to internal/tree/tree_test.go index d540bcf3..654b5b4f 100644 --- a/tree/tree_test.go +++ b/internal/tree/tree_test.go @@ -7,9 +7,9 @@ import ( "github.com/aymanbagabas/go-udiff" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/internal/tree" "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/table" - "github.com/charmbracelet/lipgloss/tree" ) func TestTree(t *testing.T) { diff --git a/list/enumerator.go b/list/enumerator.go index 0a42b9d9..ce55b1e7 100644 --- a/list/enumerator.go +++ b/list/enumerator.go @@ -25,6 +25,22 @@ import ( // Or, define your own. type Enumerator func(items Items, index int) string +// Indenter indents the children of a tree. +// +// Indenters allow for displaying nested tree items with connecting borders +// to sibling nodes. +// +// For example, the default indenter would be: +// +// func TreeIndenter(children Children, index int) string { +// if children.Length()-1 == index { +// return "│ " +// } +// +// return " " +// } +type Indenter func(items Items, index int) string + // Alphabet is the enumeration for alphabetical listing. // // a. Foo @@ -104,3 +120,33 @@ func Asterisk(Items, int) string { func Dash(Items, int) string { return "-" } + +// Tree enumerates a tree. +// +// ├── Foo +// ├── Bar +// ├── Baz +// └── Qux. +func Tree(items Items, index int) string { + if items.Length()-1 == index { + return "└──" + } + return "├──" +} + +// DefaultIndenter indents a tree for nested trees and multiline content. +// +// ├── Foo +// ├── Bar +// │ ├── Qux +// │ ├── Quux +// │ │ ├── Foo +// │ │ └── Bar +// │ └── Quuux +// └── Baz. +func TreeIndenter(items Items, index int) string { + if items.Length()-1 == index { + return " " + } + return "│ " +} diff --git a/list/list.go b/list/list.go index 50459e0d..30aa6ed8 100644 --- a/list/list.go +++ b/list/list.go @@ -24,7 +24,7 @@ package list import ( "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/tree" + "github.com/charmbracelet/lipgloss/internal/tree" ) // List represents a list of items that can be displayed. Lists can contain @@ -49,7 +49,9 @@ type List struct{ tree *tree.Tree } // anything you want, really. func New(items ...any) *List { l := &List{tree: tree.New()} - return l.Items(items...).Enumerator(Bullet) + return l.Items(items...). + Enumerator(Bullet). + Indenter(func(Items, int) string { return " " }) } // Items represents the list items. @@ -145,6 +147,36 @@ func (l *List) EnumeratorStyleFunc(f StyleFunc) *List { return l } +// Indenter sets the indenter implementation. This is used to change the way +// the tree is indented. The default indentor places a border connecting sibling +// elements and no border for the last child. +// +// └── Foo +// └── Bar +// └── Baz +// └── Qux +// └── Quux +// +// You can define your own indenter. +// +// func ArrowIndenter(children tree.Children, index int) string { +// return "→ " +// } +// +// → Foo +// → → Bar +// → → → Baz +// → → → → Qux +// → → → → → Quux +func (l *List) Indenter(indenter Indenter) *List { + l.tree.Indenter( + func(children tree.Children, index int) string { + return indenter(children, index) + }, + ) + return l +} + // ItemStyle sets the item style for all items. // // To set the item style conditionally based on the item value or index, @@ -225,6 +257,5 @@ func (l *List) Items(items ...any) *List { // Baz. Baz func (l *List) Enumerator(enumerator Enumerator) *List { l.tree.Enumerator(func(c tree.Children, i int) string { return enumerator(c, i) }) - l.tree.Indenter(func(tree.Children, int) string { return " " }) return l } diff --git a/list/list_test.go b/list/list_test.go index b5a0a947..d745f480 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -7,8 +7,8 @@ import ( "github.com/aymanbagabas/go-udiff" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/internal/tree" "github.com/charmbracelet/lipgloss/list" - "github.com/charmbracelet/lipgloss/tree" ) // XXX: can't write multi-line examples if the underlying string uses diff --git a/unset.go b/unset.go index 19d93370..1086e722 100644 --- a/unset.go +++ b/unset.go @@ -249,7 +249,15 @@ func (s Style) UnsetBorderBackground() Style { // UnsetBorderTopBackgroundColor removes the top border background color rule, // if set. +// +// Deprecated: This function simply calls Style.UnsetBorderTopBackground. func (s Style) UnsetBorderTopBackgroundColor() Style { + return s.UnsetBorderTopBackground() +} + +// UnsetBorderTopBackground removes the top border background color rule, +// if set. +func (s Style) UnsetBorderTopBackground() Style { s.unset(borderTopBackgroundKey) return s }