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 switch msg.String() {
67 case "A":
68 b.state = aboutPage
69 case "R":
70 b.state = refsPage
71 case "L":
72 b.state = logPage
73 case "T":
74 b.state = treePage
75 }
76 case tea.WindowSizeMsg:
77 b.width = msg.Width
78 b.height = msg.Height
79 for i, bx := range b.boxes {
80 m, cmd := bx.Update(msg)
81 b.boxes[i] = m
82 if cmd != nil {
83 cmds = append(cmds, cmd)
84 }
85 }
86 }
87 m, cmd := b.boxes[b.state].Update(msg)
88 b.boxes[b.state] = m
89 if cmd != nil {
90 cmds = append(cmds, cmd)
91 }
92
93 switch msg := msg.(type) {
94 case tea.KeyMsg:
95 switch msg.String() {
96 case "enter":
97 if b.state == refsPage {
98 b.state = treePage
99 cmds = append(cmds, b.boxes[b.state].Init())
100 }
101 }
102 }
103 return b, tea.Batch(cmds...)
104}
105
106func (b *Bubble) Help() []types.HelpEntry {
107 h := []types.HelpEntry{}
108 if b.state != treePage {
109 h = append(h, types.HelpEntry{"↑/↓", "navigate"})
110 }
111 h = append(h, b.boxes[b.state].(types.HelpableBubble).Help()...)
112 if b.state != aboutPage {
113 h = append(h, types.HelpEntry{"A", "about"})
114 }
115 if b.state != refsPage {
116 h = append(h, types.HelpEntry{"R", "refs"})
117 }
118 if b.state != logPage {
119 h = append(h, types.HelpEntry{"L", "log"})
120 }
121 if b.state != treePage {
122 h = append(h, types.HelpEntry{"T", "tree"})
123 }
124 return h
125}
126
127func (b *Bubble) Reference() plumbing.ReferenceName {
128 return b.repo.GetReference().Name()
129}
130
131func (b *Bubble) headerView() string {
132 // TODO better header, tabs?
133 return ""
134}
135
136func (b *Bubble) View() string {
137 header := b.headerView()
138 return header + b.boxes[b.state].View()
139}
140
141func (b *Bubble) setupCmd() tea.Msg {
142 cmds := make([]tea.Cmd, 0)
143 for _, bx := range b.boxes {
144 if bx != nil {
145 initCmd := bx.Init()
146 if initCmd != nil {
147 msg := initCmd()
148 switch msg := msg.(type) {
149 case types.ErrMsg:
150 return msg
151 }
152 }
153 cmds = append(cmds, initCmd)
154 }
155 }
156 return tea.Batch(cmds...)
157}