1package tui
2
3import (
4 "fmt"
5
6 tea "github.com/charmbracelet/bubbletea"
7 "github.com/charmbracelet/lipgloss"
8 "github.com/charmbracelet/soft-serve/internal/config"
9 br "github.com/charmbracelet/soft-serve/internal/tui/bubbles/repo"
10 "github.com/charmbracelet/soft-serve/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}