forked from toolshed/abra
chore: make deps, go mod vendor
This commit is contained in:
131
vendor/github.com/charmbracelet/lipgloss/table/table.go
generated
vendored
131
vendor/github.com/charmbracelet/lipgloss/table/table.go
generated
vendored
@ -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)
|
||||
|
Reference in New Issue
Block a user