bartender/main.go

237 lines
5.2 KiB
Go
Raw Normal View History

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 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 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"
"gopkg.in/yaml.v3"
2024-09-07 10:36:44 -07:00
)
2024-09-07 14:38:48 -07:00
var width, height, _ = term.GetSize(int(os.Stdout.Fd()))
2024-09-07 10:36:44 -07:00
type menu struct {
2024-09-07 15:23:46 -07:00
order SoftwarePackages
current int
keys keyMap
help help.Model
inputStyle gloss.Style
2024-09-07 16:31:10 -07:00
spinner spinner.Model
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 10:36:44 -07:00
return menu{
2024-09-07 16:01:47 -07:00
current: 3,
2024-09-07 15:43:19 -07:00
keys: keys,
help: help.New(),
2024-09-07 16:31:10 -07:00
spinner: s,
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
}
}
type YamlStructure struct {
InstallerPreferences InstallerPreferences `yaml:"installerPreferences"`
SoftwarePackages SoftwarePackages `yaml:"softwarePackages"`
}
type InstallerPreferences struct {
Apt []string `yaml:"apt"`
Darwin []string `yaml:"darwin"`
Dnf []string `yaml:"dnf"`
Freebsd []string `yaml:"freebsd"`
Pacman []string `yaml:"pacman"`
Ubuntu []string `yaml:"ubuntu"`
Windows []string `yaml:"windows"`
Zypper []string `yaml:"zypper"`
2024-09-07 14:38:48 -07:00
}
type SoftwarePackages map[string]SoftwareDef
type SoftwareDef struct {
Bin *string `yaml:"_bin"`
Desc string `yaml:"_desc"`
Deps *[]string `yaml:"_deps"`
Docs *string `yaml:"_docs"`
Github *string `yaml:"_github"`
Home *string `yaml:"_home"`
Name string `yaml:"_name"`
Apk *string `yaml:"apk"`
Appimage *string `yaml:"appimage"`
Basher *string `yaml:"basher"`
Binary *osNames `yaml:"binary"`
Bpkg *string `yaml:"bpkg"`
Brew *string `yaml:"brew"`
Cargo *string `yaml:"cargo"`
Cask *string `yaml:"cask"`
Crew *string `yaml:"crew"`
Choco *string `yaml:"choco"`
Dnf *string `yaml:"dnf"`
Flatpak *string `yaml:"flatpak"`
Gem *string `yaml:"gem"`
Go *string `yaml:"go"`
Krew *string `yaml:"krew"`
Nix *string `yaml:"nix"`
Npm *string `yaml:"npm"`
Pacman *string `yaml:"pacman"`
Pipx *string `yaml:"pipx"`
PkgFreebsd *string `yaml:"pkg-freebsd"`
PkgTermux *string `yaml:"pkg-termux"`
Port *string `yaml:"port"`
Scoop *string `yaml:"scoop"`
Script *string `yaml:"string"`
Snap *string `yaml:"snap"`
Whalebrew *string `yaml:"whalebrew"`
Winget *string `yaml:"winget"`
Xbps *string `yaml:"xbps"`
Yay *string `yaml:"yay"`
Zypper *string `yaml:"zypper"`
}
type osNames struct {
Darwin *string `yaml:"darwin"`
Linux *string `yaml:"linux"`
Windows *string `yaml:"windows"`
2024-09-07 14:38:48 -07:00
}
type yamlMsg YamlStructure
type errMsg struct{ err error }
func (e errMsg) Error() string { return e.err.Error() }
func readYaml() tea.Msg {
fileData, fileErr := os.ReadFile("/Users/marley/hackin/install.fairie/software-custom.yml")
if fileErr != nil {
return errMsg{fileErr}
}
var parsedYaml YamlStructure
yamlErr := yaml.Unmarshal(fileData, &parsedYaml)
if yamlErr != nil {
return errMsg{yamlErr}
}
return yamlMsg(parsedYaml)
}
2024-09-07 10:36:44 -07:00
func (m menu) Init() tea.Cmd {
2024-09-07 16:31:10 -07:00
return tea.Batch(readYaml, 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
case yamlMsg:
m.order = msg.SoftwarePackages
2024-09-07 15:23:46 -07:00
return m, nil
2024-09-07 14:38:48 -07:00
2024-09-07 10:36:44 -07:00
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
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 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.
Width(int(float64(width) * 0.65))
sidebarStyle := borderStyle.
Width(int(float64(width) * 0.3))
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
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 16:31:10 -07:00
keys := make([]string, 0, len(m.order))
for k := range m.order {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
software.Item(m.order[k].Name)
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 15:23:46 -07:00
helpView := m.help.View(m.keys)
page := gloss.JoinVertical(gloss.Left, content, helpView)
return gloss.PlaceHorizontal(width, gloss.Center, page)
2024-09-07 10:36:44 -07:00
}
func main() {
p := tea.NewProgram(initialModel())
if _, err := p.Run(); err != nil {
fmt.Printf("There's been an error: %v", err)
os.Exit(1)
}
}