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