1package tui
  2
  3import (
  4	"fmt"
  5
  6	tea "github.com/charmbracelet/bubbletea"
  7	"github.com/charmbracelet/lipgloss"
  8	"github.com/charmbracelet/soft/internal/config"
  9	br "github.com/charmbracelet/soft/internal/tui/bubbles/repo"
 10	"github.com/charmbracelet/soft/internal/tui/bubbles/selection"
 11	gm "github.com/charmbracelet/wish/git"
 12)
 13
 14type errMsg struct{ err error }
 15
 16func (e errMsg) Error() string {
 17	return e.err.Error()
 18}
 19
 20func (b *Bubble) setupCmd() tea.Msg {
 21	if b.config == nil || b.config.Source == nil {
 22		return errMsg{err: fmt.Errorf("config not set")}
 23	}
 24	mes, err := b.menuEntriesFromSource()
 25	if err != nil {
 26		return errMsg{err}
 27	}
 28	if len(mes) == 0 {
 29		return errMsg{fmt.Errorf("no repos found")}
 30	}
 31	b.repoMenu = mes
 32	rs := make([]string, 0)
 33	for _, m := range mes {
 34		rs = append(rs, m.Name)
 35	}
 36	b.repoSelect = selection.NewBubble(rs, b.styles)
 37	b.boxes[0] = b.repoSelect
 38
 39	// Jump to an initial repo
 40	ir := -1
 41	if b.initialRepo != "" {
 42		for i, me := range b.repoMenu {
 43			if me.Repo == b.initialRepo {
 44				ir = i
 45			}
 46		}
 47	}
 48	if ir == -1 {
 49		b.boxes[1] = b.repoMenu[0].bubble
 50		b.activeBox = 0
 51	} else {
 52		b.boxes[1] = b.repoMenu[ir].bubble
 53		b.repoSelect.SelectedItem = ir
 54		b.activeBox = 1
 55	}
 56
 57	b.state = loadedState
 58	return nil
 59}
 60
 61func (b *Bubble) menuEntriesFromSource() ([]MenuEntry, error) {
 62	mes := make([]MenuEntry, 0)
 63	for _, cr := range b.config.Repos {
 64		acc := b.config.AuthRepo(cr.Repo, b.session.PublicKey())
 65		if acc == gm.NoAccess && cr.Repo != "config" {
 66			continue
 67		}
 68		me, err := b.newMenuEntry(cr.Name, cr.Repo)
 69		if err != nil {
 70			return nil, err
 71		}
 72		mes = append(mes, me)
 73	}
 74	for _, r := range b.config.Source.AllRepos() {
 75		var found bool
 76		for _, me := range mes {
 77			if me.Repo == r.Name {
 78				found = true
 79			}
 80		}
 81		if !found {
 82			acc := b.config.AuthRepo(r.Name, b.session.PublicKey())
 83			if acc == gm.NoAccess {
 84				continue
 85			}
 86			me, err := b.newMenuEntry(r.Name, r.Name)
 87			if err != nil {
 88				return nil, err
 89			}
 90			mes = append(mes, me)
 91		}
 92	}
 93	return mes, nil
 94}
 95
 96func (b *Bubble) newMenuEntry(name string, repo string) (MenuEntry, error) {
 97	var tmplConfig *config.Config
 98	if repo == "config" {
 99		tmplConfig = b.config
100	}
101	me := MenuEntry{Name: name, Repo: repo}
102	width := b.width
103	boxLeftWidth := b.styles.Menu.GetWidth() + b.styles.Menu.GetHorizontalFrameSize()
104	// TODO: also send this along with a tea.WindowSizeMsg
105	var heightMargin = lipgloss.Height(b.headerView()) +
106		lipgloss.Height(b.footerView()) +
107		b.styles.RepoBody.GetVerticalFrameSize() +
108		b.styles.App.GetVerticalMargins()
109	rb := br.NewBubble(
110		b.config.Source,
111		me.Repo,
112		b.styles,
113		width,
114		boxLeftWidth,
115		b.height,
116		heightMargin,
117		tmplConfig,
118	)
119	rb.Host = b.config.Host
120	rb.Port = b.config.Port
121	initCmd := rb.Init()
122	msg := initCmd()
123	switch msg := msg.(type) {
124	case br.ErrMsg:
125		return me, fmt.Errorf("missing %s: %s", me.Repo, msg.Error)
126	}
127	me.bubble = rb
128	return me, nil
129}