mirror of
https://github.com/charmbracelet/huh.git
synced 2025-11-08 23:04:52 -06:00
170 lines
3.6 KiB
Go
170 lines
3.6 KiB
Go
package huh
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// A Layout is responsible for laying out groups in a form.
|
|
type Layout interface {
|
|
View(f *Form) string
|
|
GroupWidth(f *Form, g *Group, w int) int
|
|
}
|
|
|
|
// LayoutDefault is the default layout shows a single group at a time.
|
|
var LayoutDefault Layout = &layoutDefault{}
|
|
|
|
// LayoutStack is a layout stacks all groups on top of each other.
|
|
var LayoutStack Layout = &layoutStack{}
|
|
|
|
// LayoutColumns layout distributes groups in even columns.
|
|
func LayoutColumns(columns int) Layout {
|
|
return &layoutColumns{columns: columns}
|
|
}
|
|
|
|
// LayoutGrid layout distributes groups in a grid.
|
|
func LayoutGrid(rows int, columns int) Layout {
|
|
return &layoutGrid{rows: rows, columns: columns}
|
|
}
|
|
|
|
type layoutDefault struct{}
|
|
|
|
func (l *layoutDefault) View(f *Form) string {
|
|
return f.selector.Selected().View()
|
|
}
|
|
|
|
func (l *layoutDefault) GroupWidth(_ *Form, _ *Group, w int) int {
|
|
return w
|
|
}
|
|
|
|
type layoutColumns struct {
|
|
columns int
|
|
}
|
|
|
|
func (l *layoutColumns) visibleGroups(f *Form) []*Group {
|
|
segmentIndex := f.selector.Index() / l.columns
|
|
start := segmentIndex * l.columns
|
|
end := start + l.columns
|
|
|
|
total := f.selector.Total()
|
|
if end > total {
|
|
end = total
|
|
}
|
|
|
|
var groups []*Group
|
|
f.selector.Range(func(i int, group *Group) bool {
|
|
if i >= start && i < end {
|
|
groups = append(groups, group)
|
|
return true
|
|
}
|
|
return true
|
|
})
|
|
|
|
return groups
|
|
}
|
|
|
|
func (l *layoutColumns) View(f *Form) string {
|
|
groups := l.visibleGroups(f)
|
|
if len(groups) == 0 {
|
|
return ""
|
|
}
|
|
|
|
columns := make([]string, 0, len(groups))
|
|
for _, group := range groups {
|
|
columns = append(columns, group.Content())
|
|
}
|
|
|
|
header := f.selector.Selected().Header()
|
|
footer := f.selector.Selected().Footer()
|
|
|
|
return strings.Join([]string{
|
|
header,
|
|
lipgloss.JoinHorizontal(lipgloss.Left, columns...),
|
|
footer,
|
|
}, "\n")
|
|
}
|
|
|
|
func (l *layoutColumns) GroupWidth(_ *Form, _ *Group, w int) int {
|
|
return w / l.columns
|
|
}
|
|
|
|
type layoutStack struct{}
|
|
|
|
func (l *layoutStack) View(f *Form) string {
|
|
var columns []string
|
|
f.selector.Range(func(_ int, group *Group) bool {
|
|
columns = append(columns, group.Content(), "")
|
|
return true
|
|
})
|
|
|
|
if footer := f.selector.Selected().Footer(); footer != "" {
|
|
columns = append(columns, footer)
|
|
}
|
|
return strings.Join(columns, "\n")
|
|
}
|
|
|
|
func (l *layoutStack) GroupWidth(_ *Form, _ *Group, w int) int {
|
|
return w
|
|
}
|
|
|
|
type layoutGrid struct {
|
|
rows, columns int
|
|
}
|
|
|
|
func (l *layoutGrid) visibleGroups(f *Form) [][]*Group {
|
|
total := l.rows * l.columns
|
|
segmentIndex := f.selector.Index() / total
|
|
start := segmentIndex * total
|
|
end := start + total
|
|
|
|
if glen := f.selector.Total(); end > glen {
|
|
end = glen
|
|
}
|
|
|
|
var visible []*Group
|
|
f.selector.Range(func(i int, group *Group) bool {
|
|
if i >= start && i < end {
|
|
visible = append(visible, group)
|
|
return true
|
|
}
|
|
return true
|
|
})
|
|
grid := make([][]*Group, l.rows)
|
|
for i := 0; i < l.rows; i++ {
|
|
startRow := i * l.columns
|
|
endRow := startRow + l.columns
|
|
if startRow >= len(visible) {
|
|
break
|
|
}
|
|
if endRow > len(visible) {
|
|
endRow = len(visible)
|
|
}
|
|
grid[i] = visible[startRow:endRow]
|
|
}
|
|
return grid
|
|
}
|
|
|
|
func (l *layoutGrid) View(f *Form) string {
|
|
grid := l.visibleGroups(f)
|
|
if len(grid) == 0 {
|
|
return ""
|
|
}
|
|
|
|
rows := make([]string, 0, len(grid))
|
|
for _, row := range grid {
|
|
var columns []string
|
|
for _, group := range row {
|
|
columns = append(columns, group.Content())
|
|
}
|
|
rows = append(rows, lipgloss.JoinHorizontal(lipgloss.Left, columns...), "")
|
|
}
|
|
footer := f.selector.Selected().Footer()
|
|
|
|
return strings.Join(append(rows, footer), "\n")
|
|
}
|
|
|
|
func (l *layoutGrid) GroupWidth(_ *Form, _ *Group, w int) int {
|
|
return w / l.columns
|
|
}
|