2024-09-07 10:36:44 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2024-09-07 16:31:10 -07:00
|
|
|
"sort"
|
2024-09-07 21:13:35 -07:00
|
|
|
"strings"
|
2024-09-07 10:36:44 -07:00
|
|
|
|
2024-09-07 15:23:46 -07:00
|
|
|
"github.com/charmbracelet/bubbles/help"
|
|
|
|
"github.com/charmbracelet/bubbles/key"
|
2024-09-07 16:31:10 -07:00
|
|
|
"github.com/charmbracelet/bubbles/spinner"
|
2024-09-07 21:13:35 -07:00
|
|
|
"github.com/charmbracelet/bubbles/viewport"
|
2024-09-07 10:36:44 -07:00
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
2024-09-07 14:38:48 -07:00
|
|
|
gloss "github.com/charmbracelet/lipgloss"
|
2024-09-07 16:01:47 -07:00
|
|
|
"github.com/charmbracelet/lipgloss/list"
|
2024-09-07 14:38:48 -07:00
|
|
|
"golang.org/x/term"
|
2024-09-07 10:36:44 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type menu struct {
|
2024-09-07 18:01:05 -07:00
|
|
|
order []string
|
2024-09-07 15:23:46 -07:00
|
|
|
current int
|
|
|
|
keys keyMap
|
|
|
|
help help.Model
|
|
|
|
inputStyle gloss.Style
|
2024-09-07 16:31:10 -07:00
|
|
|
spinner spinner.Model
|
2024-09-07 16:34:18 -07:00
|
|
|
quitting bool
|
2024-09-07 21:13:35 -07:00
|
|
|
viewport viewport.Model
|
|
|
|
width int
|
|
|
|
height int
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
|
2024-09-07 18:01:05 -07:00
|
|
|
const (
|
|
|
|
softwareInstructionsFile = "/Users/marley/hackin/install.fairie/home/.chezmoidata.yaml"
|
|
|
|
softwareGroup = "_Full-Desktop"
|
|
|
|
)
|
2024-09-07 17:29:34 -07:00
|
|
|
|
2024-09-07 10:36:44 -07:00
|
|
|
func initialModel() menu {
|
2024-09-07 16:31:10 -07:00
|
|
|
s := spinner.New()
|
|
|
|
s.Spinner = spinner.MiniDot
|
|
|
|
s.Style = gloss.NewStyle().Foreground(gloss.Color("3"))
|
2024-09-07 21:13:35 -07:00
|
|
|
width, height, _ := term.GetSize(int(os.Stdout.Fd()))
|
2024-09-07 16:31:10 -07:00
|
|
|
|
2024-09-07 10:36:44 -07:00
|
|
|
return menu{
|
2024-09-07 21:13:35 -07:00
|
|
|
current: 150,
|
2024-09-07 16:34:18 -07:00
|
|
|
keys: keys,
|
|
|
|
help: help.New(),
|
|
|
|
spinner: s,
|
|
|
|
quitting: false,
|
2024-09-07 21:13:35 -07:00
|
|
|
width: width,
|
|
|
|
height: height,
|
2024-09-07 15:23:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type keyMap struct {
|
|
|
|
Quit key.Binding
|
|
|
|
}
|
|
|
|
|
|
|
|
var keys = keyMap{
|
|
|
|
Quit: key.NewBinding(
|
|
|
|
key.WithKeys("q", "esc", "ctrl+c"),
|
|
|
|
key.WithHelp("q", "quit"),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k keyMap) ShortHelp() []key.Binding {
|
|
|
|
return []key.Binding{k.Quit}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k keyMap) FullHelp() [][]key.Binding {
|
|
|
|
keys := k.ShortHelp()
|
|
|
|
|
|
|
|
return [][]key.Binding{
|
|
|
|
keys,
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-07 18:01:05 -07:00
|
|
|
type softwareListMsg []string
|
2024-09-07 14:38:48 -07:00
|
|
|
|
|
|
|
type errMsg struct{ err error }
|
|
|
|
|
|
|
|
func (e errMsg) Error() string { return e.err.Error() }
|
|
|
|
|
2024-09-07 10:36:44 -07:00
|
|
|
func (m menu) Init() tea.Cmd {
|
2024-09-07 18:01:05 -07:00
|
|
|
return tea.Batch(getSoftwareList(softwareInstructionsFile), m.spinner.Tick)
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m menu) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
2024-09-07 16:31:10 -07:00
|
|
|
var cmd tea.Cmd
|
|
|
|
var cmds []tea.Cmd
|
|
|
|
|
2024-09-07 10:36:44 -07:00
|
|
|
switch msg := msg.(type) {
|
2024-09-07 14:38:48 -07:00
|
|
|
|
2024-09-07 18:01:05 -07:00
|
|
|
case softwareListMsg:
|
|
|
|
m.order = msg
|
2024-09-07 14:38:48 -07:00
|
|
|
|
2024-09-07 10:36:44 -07:00
|
|
|
case tea.KeyMsg:
|
2024-09-07 21:13:35 -07:00
|
|
|
switch {
|
|
|
|
case key.Matches(msg, keys.Quit):
|
2024-09-07 16:34:18 -07:00
|
|
|
m.quitting = true
|
2024-09-07 10:36:44 -07:00
|
|
|
return m, tea.Quit
|
|
|
|
}
|
2024-09-07 16:31:10 -07:00
|
|
|
|
|
|
|
case spinner.TickMsg:
|
|
|
|
m.spinner, cmd = m.spinner.Update(msg)
|
|
|
|
cmds = append(cmds, cmd)
|
2024-09-07 21:13:35 -07:00
|
|
|
|
|
|
|
case tea.WindowSizeMsg:
|
|
|
|
m.width, m.height, _ = term.GetSize(int(os.Stdout.Fd()))
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
|
2024-09-07 16:31:10 -07:00
|
|
|
return m, tea.Batch(cmds...)
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m menu) View() string {
|
2024-09-07 15:43:19 -07:00
|
|
|
borderStyle := gloss.NewStyle().
|
|
|
|
BorderStyle(gloss.RoundedBorder()).
|
|
|
|
BorderForeground(gloss.Color("5")).
|
|
|
|
Padding(0, 1)
|
|
|
|
|
|
|
|
mainStyle := borderStyle.
|
2024-09-07 21:13:35 -07:00
|
|
|
Width(int(float64(m.width) * 0.65))
|
2024-09-07 15:43:19 -07:00
|
|
|
|
|
|
|
sidebarStyle := borderStyle.
|
2024-09-07 21:13:35 -07:00
|
|
|
Width(int(float64(m.width) * 0.3))
|
|
|
|
|
|
|
|
topPadding := 1
|
2024-09-07 14:38:48 -07:00
|
|
|
|
2024-09-07 15:23:46 -07:00
|
|
|
mainContent := ""
|
2024-09-07 16:01:47 -07:00
|
|
|
|
2024-09-07 21:13:35 -07:00
|
|
|
helpView := m.help.View(m.keys)
|
|
|
|
|
2024-09-07 16:01:47 -07:00
|
|
|
softwareListEnumerator := func(l list.Items, i int) string {
|
|
|
|
if m.current == i {
|
2024-09-07 16:31:10 -07:00
|
|
|
return m.spinner.View()
|
2024-09-07 16:01:47 -07:00
|
|
|
} else if m.current > i {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
software := list.New().Enumerator(softwareListEnumerator)
|
2024-09-07 14:38:48 -07:00
|
|
|
|
2024-09-07 21:13:35 -07:00
|
|
|
sidebarHeight := m.height - 3 - gloss.Height(helpView) - topPadding
|
|
|
|
|
|
|
|
if len(m.order) > 0 {
|
|
|
|
start := max(m.current-10, 0)
|
|
|
|
end := min(start+sidebarHeight, len(m.order))
|
|
|
|
|
|
|
|
if (end - start) < sidebarHeight {
|
|
|
|
start = (len(m.order) - sidebarHeight)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range m.order[start:end] {
|
|
|
|
software.Item(item)
|
|
|
|
}
|
2024-09-07 15:23:46 -07:00
|
|
|
}
|
|
|
|
|
2024-09-07 16:01:47 -07:00
|
|
|
sidebarContent := software.String()
|
|
|
|
|
2024-09-07 14:38:48 -07:00
|
|
|
main := mainStyle.Render(mainContent)
|
|
|
|
sidebar := sidebarStyle.Render(sidebarContent)
|
2024-09-07 10:36:44 -07:00
|
|
|
|
2024-09-07 14:38:48 -07:00
|
|
|
content := gloss.JoinHorizontal(gloss.Top, main, sidebar)
|
2024-09-07 10:36:44 -07:00
|
|
|
|
2024-09-07 21:13:35 -07:00
|
|
|
top := strings.Repeat("\n", topPadding)
|
2024-09-07 16:34:18 -07:00
|
|
|
last := ""
|
|
|
|
if m.quitting {
|
|
|
|
last = "\n"
|
|
|
|
}
|
|
|
|
|
2024-09-07 21:13:35 -07:00
|
|
|
page := gloss.JoinVertical(gloss.Left, top, content, helpView, last)
|
2024-09-07 15:23:46 -07:00
|
|
|
|
2024-09-07 21:13:35 -07:00
|
|
|
return gloss.PlaceHorizontal(m.width, gloss.Center, page)
|
2024-09-07 10:36:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2024-09-07 19:41:17 -07:00
|
|
|
p := tea.NewProgram(initialModel(), tea.WithAltScreen())
|
2024-09-07 10:36:44 -07:00
|
|
|
|
|
|
|
if _, err := p.Run(); err != nil {
|
|
|
|
fmt.Printf("There's been an error: %v", err)
|
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
2024-09-07 17:29:34 -07:00
|
|
|
|
|
|
|
func sortMapKeys(m SoftwarePackages) []string {
|
|
|
|
keys := make([]string, 0, len(m))
|
|
|
|
|
|
|
|
for k := range m {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(keys)
|
|
|
|
|
|
|
|
return keys
|
|
|
|
}
|