0
0
forked from toolshed/abra

chore: make deps, go mod vendor

This commit is contained in:
2024-12-02 01:45:06 +01:00
parent f664599836
commit 31fa9b1a7a
598 changed files with 37898 additions and 18309 deletions

View File

@ -14,16 +14,13 @@ issues:
linters:
enable:
# - dupl
- exhaustive
# - exhaustivestruct
- goconst
- godot
- godox
- gomnd
- mnd
- gomoddirectives
- goprintffuncname
# - lll
- misspell
- nakedret
- nestif
@ -34,13 +31,10 @@ linters:
# disable default linters, they are already enabled in .golangci.yml
disable:
- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck

View File

@ -15,12 +15,10 @@ issues:
linters:
enable:
- bodyclose
- exportloopref
- gofumpt
- goimports
- gosec
- nilerr
- predeclared
- revive
- rowserrcheck
- sqlclosecheck

View File

@ -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

View File

@ -10,7 +10,7 @@
Style definitions for nice terminal layouts. Built with TUIs in mind.
![Lip Gloss example](https://stuff.charm.sh/lipgloss/lipgloss-example.png)
![Lip Gloss example](https://github.com/user-attachments/assets/99c5c015-551b-4897-8cd1-bcaafa0aad5a)
Lip Gloss takes an expressive, declarative approach to terminal rendering.
Users familiar with CSS will feel at home with Lip Gloss.
@ -77,11 +77,11 @@ appropriate color will be chosen at runtime.
### Complete Colors
CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
CompleteColor specifies exact values for True Color, ANSI256, and ANSI color
profiles.
```go
lipgloss.CompleteColor{True: "#0000FF", ANSI256: "86", ANSI: "5"}
lipgloss.CompleteColor{TrueColor: "#0000FF", ANSI256: "86", ANSI: "5"}
```
Automatic color degradation will not be performed in this case and it will be
@ -89,7 +89,7 @@ based on the color specified.
### Complete Adaptive Colors
You can use CompleteColor with AdaptiveColor to specify the exact values for
You can use `CompleteColor` with `AdaptiveColor` to specify the exact values for
light and dark backgrounds without automatic color degradation.
```go
@ -402,7 +402,7 @@ block := lipgloss.Place(30, 80, lipgloss.Right, lipgloss.Bottom, fancyStyledPara
You can also style the whitespace. For details, see [the docs][docs].
### Rendering Tables
## Rendering Tables
Lip Gloss ships with a table rendering sub-package.
@ -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",
"Claires Boutique",
tree.New().
Root("Nyx").
Items("Qux", "Quux").
EnumeratorStyle(style2),
"Mac",
"Milk",
).
EnumeratorStyle(style1)
```
Print the tree:
<p align="center">
<img
width="600"
alt="Tree example"
src="https://github.com/charmbracelet/lipgloss/assets/245435/5a875269-f6d6-43fa-9916-5d8360e66964"
/>
</p>
You may also define custom enumerator implementations:
```go
t := tree.New().
Items(
"Glossier",
"Claires Boutique",
tree.New().
Root("Nyx").
Items(
"Qux",
"Quux",
),
"Mac",
"Milk",
).
Enumerator(func(tree.Data, int) (string, string) {
return "->", "->"
})
```
Print the tree.
<p align="center">
<img
width="600"
alt="Tree example"
src="https://github.com/charmbracelet/lipgloss/assets/245435/811e8b39-124f-48bb-b3dd-e015a65b1065"
/>
</p>
### 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,190 @@ fmt.Println(l)
// • C
```
Lists have the ability to nest.
### Customization
```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)
```
<p align="center">
<img width="600" alt="image" src="https://github.com/charmbracelet/lipgloss/assets/42545625/0dc9f440-0748-4151-a3b0-7dcf29dfcdb0">
</p>
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",
"Claires Boutique",
"Nyx",
"Mac",
"Milk",
).
Enumerator(list.Roman).
EnumeratorStyle(enumeratorStyle).
ItemStyle(itemStyle)
"Glossier",
"Claires Boutique",
"Nyx",
"Mac",
"Milk",
).
Enumerator(list.Roman).
EnumeratorStyle(enumeratorStyle).
ItemStyle(itemStyle)
```
Print the list.
<p align="center">
<img
width="600"
alt="List example"
src="https://github.com/charmbracelet/lipgloss/assets/245435/8f5e5e0b-7bf9-4e3b-a8ba-3af10825320e"
/>
<img width="600" alt="List example" src="https://github.com/charmbracelet/lipgloss/assets/42545625/360494f1-57fb-4e13-bc19-0006efe01561">
</p>
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 ""
}
```
Use it in a list:
```go
l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck")
l.Enumerator(DuckDuckGooseEnumerator)
func DuckDuckGooseEnumerator(l list.Items, i int) string {
if l.At(i).Value() == "Goose" {
return "Honk →"
}
return ""
}
l = l.Enumerator(DuckDuckGooseEnumerator)
```
Print the list:
<p align="center">
<img
width="600"
alt="image"
src="https://github.com/charmbracelet/lipgloss/assets/245435/44e37a5b-5124-4f49-a332-1756a355002e"
/>
<img width="600" alt="image" src="https://github.com/charmbracelet/lipgloss/assets/42545625/157aaf30-140d-4948-9bb4-dfba46e5b87e">
</p>
### 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")
}
```
## 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.Root(".").
Child("A", "B", "C")
```
Print the tree.
```go
fmt.Println(t)
// .
// ├── A
// ├── B
// └── C
```
Trees have the ability to nest.
```go
t := tree.Root(".").
Child("macOS").
Child(
tree.New().
Root("Linux").
Child("NixOS").
Child("Arch Linux (btw)").
Child("Void Linux"),
).
Child(
tree.New().
Root("BSD").
Child("FreeBSD").
Child("OpenBSD"),
)
```
Print the tree.
```go
fmt.Println(t)
```
<p align="center">
<img width="663" alt="Tree Example (simple)" src="https://github.com/user-attachments/assets/5ef14eb8-a5d4-4f94-8834-e15d1e714f89">
</p>
Trees can be customized via their enumeration function as well as using
`lipgloss.Style`s.
```go
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1)
rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35"))
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212"))
t := tree.
Root("⁜ Makeup").
Child(
"Glossier",
"Fenty Beauty",
tree.New().Child(
"Gloss Bomb Universal Lip Luminizer",
"Hot Cheeks Velour Blushlighter",
),
"Nyx",
"Mac",
"Milk",
).
Enumerator(tree.RoundedEnumerator).
EnumeratorStyle(enumeratorStyle).
RootStyle(rootStyle).
ItemStyle(itemStyle)
```
Print the tree.
<p align="center">
<img width="663" alt="Tree Example (makeup)" src="https://github.com/user-attachments/assets/06d12d87-744a-4c89-bd98-45de9094a97e">
</p>
The predefined enumerators for trees are `DefaultEnumerator` and `RoundedEnumerator`.
If you need, you can also build trees incrementally:
```go
t := tree.New()
for i := 0; i < repeat; i++ {
t.Child("Lip Gloss")
}
```
---
## FAQ
@ -726,6 +734,12 @@ the stylesheet-based Markdown renderer.
[glamour]: https://github.com/charmbracelet/glamour
## Contributing
See [contributing][contribute].
[contribute]: https://github.com/charmbracelet/lipgloss/contribute
## Feedback
Wed love to hear your thoughts on this project. Feel free to drop us a note!

View File

@ -307,9 +307,7 @@ func (s Style) Render(strs ...string) string {
te = te.Underline()
}
if reverse {
if reverse {
teWhitespace = teWhitespace.Reverse()
}
teWhitespace = teWhitespace.Reverse()
te = te.Reverse()
}
if blink {
@ -355,6 +353,8 @@ func (s Style) Render(strs ...string) string {
// Potentially convert tabs to spaces
str = s.maybeConvertTabs(str)
// carriage returns can cause strange behaviour when rendering.
str = strings.ReplaceAll(str, "\r\n", "\n")
// Strip newlines in single line mode
if inline {
@ -564,14 +564,14 @@ func pad(str string, n int, style *termenv.Style) string {
return b.String()
}
func max(a, b int) int { //nolint:unparam
func max(a, b int) int { //nolint:unparam,predeclared
if a > b {
return a
}
return b
}
func min(a, b int) int {
func min(a, b int) int { //nolint:predeclared
if a < b {
return a
}

View File

@ -7,6 +7,10 @@ import (
"github.com/charmbracelet/x/ansi"
)
// HeaderRow denotes the header's row index used when rendering headers. Use
// this value when looking to customize header styles in StyleFunc.
const HeaderRow int = -1
// StyleFunc is the style function that determines the style of a Cell.
//
// It takes the row and column of the cell as an input and determines the
@ -53,9 +57,10 @@ type Table struct {
headers []string
data Data
width int
height int
offset int
width int
height int
useManualHeight bool
offset int
// widths tracks the width of each column.
widths []int
@ -84,7 +89,7 @@ func New() *Table {
// ClearRows clears the table rows.
func (t *Table) ClearRows() *Table {
t.data = nil
t.data = NewStringData()
return t
}
@ -199,6 +204,7 @@ func (t *Table) Width(w int) *Table {
// Height sets the table height.
func (t *Table) Height(h int) *Table {
t.height = h
t.useManualHeight = true
return t
}
@ -210,15 +216,13 @@ func (t *Table) Offset(o int) *Table {
// String returns the table as a string.
func (t *Table) String() string {
hasHeaders := t.headers != nil && len(t.headers) > 0
hasHeaders := len(t.headers) > 0
hasRows := t.data != nil && t.data.Rows() > 0
if !hasHeaders && !hasRows {
return ""
}
var s strings.Builder
// Add empty cells to the headers, until it's the same length as the longest
// row (only if there are at headers in the first place).
if hasHeaders {
@ -235,15 +239,15 @@ func (t *Table) String() string {
// the StyleFunc after the headers and rows. Update the widths for a final
// time.
for i, cell := range t.headers {
t.widths[i] = max(t.widths[i], lipgloss.Width(t.style(0, i).Render(cell)))
t.heights[0] = max(t.heights[0], lipgloss.Height(t.style(0, i).Render(cell)))
t.widths[i] = max(t.widths[i], lipgloss.Width(t.style(HeaderRow, i).Render(cell)))
t.heights[0] = max(t.heights[0], lipgloss.Height(t.style(HeaderRow, i).Render(cell)))
}
for r := 0; r < t.data.Rows(); r++ {
for i := 0; i < t.data.Columns(); i++ {
cell := t.data.At(r, i)
rendered := t.style(r+1, i).Render(cell)
rendered := t.style(r, i).Render(cell)
t.heights[r+btoi(hasHeaders)] = max(t.heights[r+btoi(hasHeaders)], lipgloss.Height(rendered))
t.widths[i] = max(t.widths[i], lipgloss.Width(rendered))
}
@ -342,27 +346,51 @@ func (t *Table) String() string {
}
}
var sb strings.Builder
if t.borderTop {
s.WriteString(t.constructTopBorder())
s.WriteString("\n")
sb.WriteString(t.constructTopBorder())
sb.WriteString("\n")
}
if hasHeaders {
s.WriteString(t.constructHeaders())
s.WriteString("\n")
}
for r := t.offset; r < t.data.Rows(); r++ {
s.WriteString(t.constructRow(r))
sb.WriteString(t.constructHeaders())
sb.WriteString("\n")
}
var bottom string
if t.borderBottom {
s.WriteString(t.constructBottomBorder())
bottom = t.constructBottomBorder()
}
// If there are no data rows render nothing.
if t.data.Rows() > 0 {
switch {
case t.useManualHeight:
// The height of the top border. Subtract 1 for the newline.
topHeight := lipgloss.Height(sb.String()) - 1
availableLines := t.height - (topHeight + lipgloss.Height(bottom))
// if the height is larger than the number of rows, use the number
// of rows.
if availableLines > t.data.Rows() {
availableLines = t.data.Rows()
}
sb.WriteString(t.constructRows(availableLines))
default:
for r := t.offset; r < t.data.Rows(); r++ {
sb.WriteString(t.constructRow(r, false))
}
}
}
sb.WriteString(bottom)
return lipgloss.NewStyle().
MaxHeight(t.computeHeight()).
MaxWidth(t.width).Render(s.String())
MaxWidth(t.width).
Render(sb.String())
}
// computeWidth computes the width of the table in it's current configuration.
@ -376,7 +404,7 @@ func (t *Table) computeWidth() int {
// computeHeight computes the height of the table in it's current configuration.
func (t *Table) computeHeight() int {
hasHeaders := t.headers != nil && len(t.headers) > 0
hasHeaders := len(t.headers) > 0
return sum(t.heights) - 1 + btoi(hasHeaders) +
btoi(t.borderTop) + btoi(t.borderBottom) +
btoi(t.borderHeader) + t.data.Rows()*btoi(t.borderRow)
@ -433,7 +461,7 @@ func (t *Table) constructHeaders() string {
s.WriteString(t.borderStyle.Render(t.border.Left))
}
for i, header := range t.headers {
s.WriteString(t.style(0, i).
s.WriteString(t.style(HeaderRow, i).
MaxHeight(1).
Width(t.widths[i]).
MaxWidth(t.widths[i]).
@ -466,13 +494,49 @@ func (t *Table) constructHeaders() string {
return s.String()
}
func (t *Table) constructRows(availableLines int) string {
var sb strings.Builder
// The number of rows to render after removing the offset.
offsetRowCount := t.data.Rows() - t.offset
// The number of rows to render. We always render at least one row.
rowsToRender := availableLines
rowsToRender = max(rowsToRender, 1)
// Check if we need to render an overflow row.
needsOverflow := rowsToRender < offsetRowCount
// only use the offset as the starting value if there is overflow.
rowIdx := t.offset
if !needsOverflow {
// if there is no overflow, just render to the height of the table
// check there's enough content to fill the table
rowIdx = t.data.Rows() - rowsToRender
}
for rowsToRender > 0 && rowIdx < t.data.Rows() {
// Whenever the height is too small to render all rows, the bottom row will be an overflow row (ellipsis).
isOverflow := needsOverflow && rowsToRender == 1
sb.WriteString(t.constructRow(rowIdx, isOverflow))
rowIdx++
rowsToRender--
}
return sb.String()
}
// constructRow constructs the row for the table given an index and row data
// based on the current configuration.
func (t *Table) constructRow(index int) string {
// based on the current configuration. If isOverflow is true, the row is
// rendered as an overflow row (using ellipsis).
func (t *Table) constructRow(index int, isOverflow bool) string {
var s strings.Builder
hasHeaders := t.headers != nil && len(t.headers) > 0
hasHeaders := len(t.headers) > 0
height := t.heights[index+btoi(hasHeaders)]
if isOverflow {
height = 1
}
var cells []string
left := strings.Repeat(t.borderStyle.Render(t.border.Left)+"\n", height)
@ -481,14 +545,21 @@ func (t *Table) constructRow(index int) string {
}
for c := 0; c < t.data.Columns(); c++ {
cell := t.data.At(index, c)
cellWidth := t.widths[c]
cells = append(cells, t.style(index+1, c).
Height(height).
cell := "…"
if !isOverflow {
cell = t.data.At(index, c)
}
cellStyle := t.style(index, c)
cells = append(cells, cellStyle.
// Account for the margins in the cell sizing.
Height(height-cellStyle.GetVerticalMargins()).
MaxHeight(height).
Width(t.widths[c]).
Width(t.widths[c]-cellStyle.GetHorizontalMargins()).
MaxWidth(t.widths[c]).
Render(ansi.Truncate(cell, t.widths[c]*height, "…")))
Render(ansi.Truncate(cell, cellWidth*height, "…")))
if c < t.data.Columns()-1 && t.borderColumn {
cells = append(cells, left)

View File

@ -13,7 +13,7 @@ func btoi(b bool) int {
}
// max returns the greater of two integers.
func max(a, b int) int {
func max(a, b int) int { //nolint:predeclared
if a > b {
return a
}
@ -21,7 +21,7 @@ func max(a, b int) int {
}
// min returns the greater of two integers.
func min(a, b int) int {
func min(a, b int) int { //nolint:predeclared
if a < b {
return a
}