1package git
2
3import (
4 tea "github.com/charmbracelet/bubbletea"
5 "github.com/charmbracelet/lipgloss"
6 "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/about"
7 "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/log"
8 "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/refs"
9 "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/tree"
10 "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/types"
11 "github.com/charmbracelet/soft-serve/internal/tui/style"
12 "github.com/go-git/go-git/v5/plumbing"
13)
14
15const (
16 repoNameMaxWidth = 32
17)
18
19type pageState int
20
21const (
22 aboutPage pageState = iota
23 refsPage
24 logPage
25 treePage
26)
27
28type Bubble struct {
29 state pageState
30 repo types.Repo
31 height int
32 heightMargin int
33 width int
34 widthMargin int
35 style *style.Styles
36 boxes []tea.Model
37 ref *plumbing.Reference
38}
39
40func NewBubble(repo types.Repo, styles *style.Styles, width, wm, height, hm int) *Bubble {
41 b := &Bubble{
42 repo: repo,
43 state: aboutPage,
44 width: width,
45 widthMargin: wm,
46 height: height,
47 heightMargin: hm,
48 style: styles,
49 boxes: make([]tea.Model, 4),
50 ref: repo.GetReference(),
51 }
52 heightMargin := hm + lipgloss.Height(b.headerView())
53 b.boxes[aboutPage] = about.NewBubble(repo, b.style, b.width, wm, b.height, heightMargin)
54 b.boxes[refsPage] = refs.NewBubble(repo, b.style, b.width, wm, b.height, heightMargin)
55 b.boxes[logPage] = log.NewBubble(repo, b.style, width, wm, height, heightMargin)
56 b.boxes[treePage] = tree.NewBubble(repo, b.style, width, wm, height, heightMargin)
57 return b
58}
59
60func (b *Bubble) Init() tea.Cmd {
61 return b.setupCmd
62}
63
64func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
65 cmds := make([]tea.Cmd, 0)
66 switch msg := msg.(type) {
67 case tea.KeyMsg:
68 if b.repo.GetName() != "config" {
69 switch msg.String() {
70 case "R":
71 b.state = aboutPage
72 case "B":
73 b.state = refsPage
74 case "C":
75 b.state = logPage
76 case "F":
77 b.state = treePage
78 }
79 }
80 case tea.WindowSizeMsg:
81 b.width = msg.Width
82 b.height = msg.Height
83 for i, bx := range b.boxes {
84 m, cmd := bx.Update(msg)
85 b.boxes[i] = m
86 if cmd != nil {
87 cmds = append(cmds, cmd)
88 }
89 }
90 case refs.RefMsg:
91 b.state = treePage
92 b.ref = msg
93 for i, bx := range b.boxes {
94 m, cmd := bx.Update(msg)
95 b.boxes[i] = m
96 if cmd != nil {
97 cmds = append(cmds, cmd)
98 }
99 }
100 }
101 m, cmd := b.boxes[b.state].Update(msg)
102 b.boxes[b.state] = m
103 if cmd != nil {
104 cmds = append(cmds, cmd)
105 }
106 return b, tea.Batch(cmds...)
107}
108
109func (b *Bubble) Help() []types.HelpEntry {
110 h := []types.HelpEntry{}
111 h = append(h, b.boxes[b.state].(types.BubbleHelper).Help()...)
112 if b.repo.GetName() != "config" {
113 h = append(h, types.HelpEntry{"R", "readme"})
114 h = append(h, types.HelpEntry{"F", "files"})
115 h = append(h, types.HelpEntry{"C", "commits"})
116 h = append(h, types.HelpEntry{"B", "branches"})
117 }
118 return h
119}
120
121func (b *Bubble) Reference() plumbing.ReferenceName {
122 return b.ref.Name()
123}
124
125func (b *Bubble) headerView() string {
126 // TODO better header, tabs?
127 return ""
128}
129
130func (b *Bubble) View() string {
131 header := b.headerView()
132 return header + b.boxes[b.state].View()
133}
134
135func (b *Bubble) setupCmd() tea.Msg {
136 cmds := make([]tea.Cmd, 0)
137 for _, bx := range b.boxes {
138 if bx != nil {
139 initCmd := bx.Init()
140 if initCmd != nil {
141 msg := initCmd()
142 switch msg := msg.(type) {
143 case types.ErrMsg:
144 return msg
145 }
146 }
147 cmds = append(cmds, initCmd)
148 }
149 }
150 return tea.Batch(cmds...)
151}