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}
38
39func NewBubble(repo types.Repo, styles *style.Styles, width, wm, height, hm int) *Bubble {
40 b := &Bubble{
41 repo: repo,
42 state: aboutPage,
43 width: width,
44 widthMargin: wm,
45 height: height,
46 heightMargin: hm,
47 style: styles,
48 boxes: make([]tea.Model, 4),
49 }
50 heightMargin := hm + lipgloss.Height(b.headerView())
51 b.boxes[aboutPage] = about.NewBubble(repo, b.style, b.width, wm, b.height, heightMargin)
52 b.boxes[refsPage] = refs.NewBubble(repo, b.style, b.width, wm, b.height, heightMargin)
53 b.boxes[logPage] = log.NewBubble(repo, b.style, width, wm, height, heightMargin)
54 b.boxes[treePage] = tree.NewBubble(repo, b.style, width, wm, height, heightMargin)
55 return b
56}
57
58func (b *Bubble) Init() tea.Cmd {
59 return b.setupCmd
60}
61
62func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
63 cmds := make([]tea.Cmd, 0)
64 switch msg := msg.(type) {
65 case tea.KeyMsg:
66 if b.repo.Name() != "config" {
67 switch msg.String() {
68 case "r", "R":
69 b.state = aboutPage
70 case "b", "B":
71 b.state = refsPage
72 case "c", "C":
73 b.state = logPage
74 case "f", "F":
75 b.state = treePage
76 }
77 }
78 case tea.WindowSizeMsg:
79 b.width = msg.Width
80 b.height = msg.Height
81 for i, bx := range b.boxes {
82 m, cmd := bx.Update(msg)
83 b.boxes[i] = m
84 if cmd != nil {
85 cmds = append(cmds, cmd)
86 }
87 }
88 }
89 m, cmd := b.boxes[b.state].Update(msg)
90 b.boxes[b.state] = m
91 if cmd != nil {
92 cmds = append(cmds, cmd)
93 }
94
95 switch msg := msg.(type) {
96 case tea.KeyMsg:
97 switch msg.String() {
98 case "enter":
99 if b.state == refsPage {
100 b.state = treePage
101 cmds = append(cmds, b.boxes[b.state].Init())
102 }
103 }
104 }
105 return b, tea.Batch(cmds...)
106}
107
108func (b *Bubble) Help() []types.HelpEntry {
109 h := []types.HelpEntry{}
110 h = append(h, b.boxes[b.state].(types.HelpableBubble).Help()...)
111 if b.repo.Name() != "config" {
112 h = append(h, types.HelpEntry{"r", "readme"})
113 h = append(h, types.HelpEntry{"f", "files"})
114 h = append(h, types.HelpEntry{"c", "commits"})
115 h = append(h, types.HelpEntry{"b", "branches/tags"})
116 }
117 return h
118}
119
120func (b *Bubble) Reference() plumbing.ReferenceName {
121 return b.repo.GetReference().Name()
122}
123
124func (b *Bubble) headerView() string {
125 // TODO better header, tabs?
126 return ""
127}
128
129func (b *Bubble) View() string {
130 header := b.headerView()
131 return header + b.boxes[b.state].View()
132}
133
134func (b *Bubble) setupCmd() tea.Msg {
135 cmds := make([]tea.Cmd, 0)
136 for _, bx := range b.boxes {
137 if bx != nil {
138 initCmd := bx.Init()
139 if initCmd != nil {
140 msg := initCmd()
141 switch msg := msg.(type) {
142 case types.ErrMsg:
143 return msg
144 }
145 }
146 cmds = append(cmds, initCmd)
147 }
148 }
149 return tea.Batch(cmds...)
150}