bubble.go

  1package repo
  2
  3import (
  4	"bytes"
  5	"smoothie/git"
  6	"text/template"
  7
  8	"github.com/charmbracelet/bubbles/viewport"
  9	tea "github.com/charmbracelet/bubbletea"
 10	"github.com/charmbracelet/glamour"
 11)
 12
 13type ErrMsg struct {
 14	Error error
 15}
 16
 17type Bubble struct {
 18	templateObject interface{}
 19	repoSource     *git.RepoSource
 20	name           string
 21	repo           *git.Repo
 22	readmeViewport *ViewportBubble
 23	readme         string
 24	height         int
 25	heightMargin   int
 26	width          int
 27	widthMargin    int
 28}
 29
 30func NewBubble(rs *git.RepoSource, name string, width, wm, height, hm int, tmp interface{}) *Bubble {
 31	return &Bubble{
 32		templateObject: tmp,
 33		repoSource:     rs,
 34		name:           name,
 35		height:         height,
 36		width:          width,
 37		heightMargin:   hm,
 38		widthMargin:    wm,
 39		readmeViewport: &ViewportBubble{
 40			Viewport: &viewport.Model{
 41				Width:  width - wm,
 42				Height: height - hm,
 43			},
 44		},
 45	}
 46}
 47
 48func (b *Bubble) Init() tea.Cmd {
 49	return b.setupCmd
 50}
 51
 52func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 53	var cmds []tea.Cmd
 54	switch msg := msg.(type) {
 55	case tea.WindowSizeMsg:
 56		b.readmeViewport.Viewport.Width = msg.Width - b.widthMargin
 57		b.readmeViewport.Viewport.Height = msg.Height - b.heightMargin
 58		md, err := b.glamourize(b.readme)
 59		if err != nil {
 60			return b, nil
 61		}
 62		b.readmeViewport.Viewport.SetContent(md)
 63	}
 64	rv, cmd := b.readmeViewport.Update(msg)
 65	b.readmeViewport = rv.(*ViewportBubble)
 66	if cmd != nil {
 67		cmds = append(cmds, cmd)
 68	}
 69	return b, tea.Batch(cmds...)
 70}
 71
 72func (b *Bubble) GotoTop() {
 73	b.readmeViewport.Viewport.GotoTop()
 74}
 75
 76func (b *Bubble) View() string {
 77	return b.readmeViewport.View()
 78}
 79
 80func (b *Bubble) setupCmd() tea.Msg {
 81	r, err := b.repoSource.GetRepo(b.name)
 82	if err == git.ErrMissingRepo {
 83		return nil
 84	}
 85	if err != nil {
 86		return ErrMsg{err}
 87	}
 88	md := r.Readme
 89	if b.templateObject != nil {
 90		md, err = b.templatize(md)
 91		if err != nil {
 92			return ErrMsg{err}
 93		}
 94	}
 95	b.readme = md
 96	md, err = b.glamourize(md)
 97	if err != nil {
 98		return ErrMsg{err}
 99	}
100	b.readmeViewport.Viewport.SetContent(md)
101	b.GotoTop()
102	return nil
103}
104
105func (b *Bubble) templatize(mdt string) (string, error) {
106	t, err := template.New("readme").Parse(mdt)
107	if err != nil {
108		return "", err
109	}
110	buf := &bytes.Buffer{}
111	err = t.Execute(buf, b.templateObject)
112	if err != nil {
113		return "", err
114	}
115	return buf.String(), nil
116}
117
118func (b *Bubble) glamourize(md string) (string, error) {
119	tr, err := glamour.NewTermRenderer(
120		glamour.WithStandardStyle("dark"),
121		glamour.WithWordWrap(b.width-b.widthMargin),
122	)
123
124	if err != nil {
125		return "", err
126	}
127	mdt, err := tr.Render(md)
128	if err != nil {
129		return "", err
130	}
131	return mdt, nil
132}