bubble.go

  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}