Skip to content

Commit

Permalink
feat: show spinner when loading commits
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Apr 9, 2022
1 parent e256fed commit d3669af
Showing 1 changed file with 72 additions and 60 deletions.
132 changes: 72 additions & 60 deletions tui/log/bubble.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ var (
waitBeforeLoading = time.Millisecond * 300
)

type itemsMsg struct{}

type commitMsg *git.Commit

type countMsg int64

type sessionState int

const (
logState sessionState = iota
commitState
loadingState
errorState
)

Expand Down Expand Up @@ -98,6 +101,10 @@ type Bubble struct {
heightMargin int
error common.ErrMsg
spinner spinner.Model
loading bool
loadingStart time.Time
selectedCommit *git.Commit
nextPage int
}

func NewBubble(repo common.GitRepo, styles *style.Styles, width, widthMargin, height, heightMargin int) *Bubble {
Expand Down Expand Up @@ -132,49 +139,45 @@ func NewBubble(repo common.GitRepo, styles *style.Styles, width, widthMargin, he
return b
}

func (b *Bubble) reset() tea.Cmd {
errMsg := func(err error) tea.Cmd {
return func() tea.Msg { return common.ErrMsg{Err: err} }
}
func (b *Bubble) countCommits() tea.Msg {
if b.ref == nil {
ref, err := b.repo.HEAD()
if err != nil {
return errMsg(err)
return common.ErrMsg{Err: err}
}
b.ref = ref
}
count, err := b.repo.CountCommits(b.ref)
if err != nil {
return errMsg(err)
return common.ErrMsg{Err: err}
}
b.count = count
b.state = logState
b.list.Select(0)
cmd := b.updateItems()
return cmd
return countMsg(count)
}

func (b *Bubble) updateItems() tea.Cmd {
func (b *Bubble) updateItems() tea.Msg {
if b.count == 0 {
b.count = int64(b.countCommits().(countMsg))
}
count := b.count
items := make([]list.Item, count)
b.list.SetItems(items)
page := b.list.Paginator.Page
page := b.nextPage
limit := b.list.Paginator.PerPage
skip := page * limit
// CommitsByPage pages start at 1
cc, err := b.repo.CommitsByPage(b.ref, page+1, limit)
if err != nil {
return func() tea.Msg { return common.ErrMsg{Err: err} }
return common.ErrMsg{Err: err}
}
for i, c := range cc {
idx := i + skip
if idx >= int(count) {
if int64(idx) >= count {
break
}
items[idx] = item{c}
}
cmd := b.list.SetItems(items)
b.list.SetItems(items)
b.SetSize(b.width, b.height)
return cmd
return itemsMsg{}
}

func (b *Bubble) Help() []common.HelpEntry {
Expand Down Expand Up @@ -203,19 +206,32 @@ func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
b.SetSize(msg.Width, msg.Height)
cmds = append(cmds, b.updateItems())
cmds = append(cmds, b.updateItems)

case tea.KeyMsg:
switch msg.String() {
case "C":
return b, b.reset()
b.count = 0
b.loading = true
b.loadingStart = time.Now().Add(-waitBeforeLoading) // always show spinner
b.list.Select(0)
b.nextPage = 0
return b, tea.Batch(b.updateItems, b.spinner.Tick)
case "enter", "right", "l":
if b.state == logState {
cmds = append(cmds, b.loadCommit())
i := b.list.SelectedItem()
if i != nil {
c, ok := i.(item)
if ok {
b.selectedCommit = c.Commit
}
}
cmds = append(cmds, b.loadCommit, b.spinner.Tick)
}
case "esc", "left", "h":
if b.state != logState {
b.state = logState
b.selectedCommit = nil
}
}
switch b.state {
Expand All @@ -224,7 +240,11 @@ func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m, cmd := b.list.Update(msg)
b.list = m
if m.Paginator.Page != curPage {
cmds = append(cmds, b.updateItems())
b.loading = true
b.loadingStart = time.Now()
b.list.Paginator.Page = curPage
b.nextPage = m.Paginator.Page
cmds = append(cmds, b.updateItems, b.spinner.Tick)
}
cmds = append(cmds, cmd)
case commitState:
Expand All @@ -233,23 +253,28 @@ func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, cmd)
}
return b, tea.Batch(cmds...)
case itemsMsg:
b.loading = false
b.list.Paginator.Page = b.nextPage
if b.state != commitState {
b.state = logState
}
case countMsg:
b.count = int64(msg)
case common.ErrMsg:
b.error = msg
b.state = errorState
b.loading = false
return b, nil
case commitMsg:
if b.state == loadingState {
cmds = append(cmds, b.spinner.Tick)
}
b.loading = false
b.state = commitState
case refs.RefMsg:
b.ref = msg
count, err := b.repo.CountCommits(msg)
if err != nil {
b.error = common.ErrMsg{Err: err}
}
b.count = count
b.count = 0
cmds = append(cmds, b.countCommits)
case spinner.TickMsg:
if b.state == loadingState {
if b.loading {
s, cmd := b.spinner.Update(msg)
if cmd != nil {
cmds = append(cmds, cmd)
Expand Down Expand Up @@ -299,33 +324,14 @@ func (b *Bubble) loadPatch(c *git.Commit) error {
return nil
}

func (b *Bubble) loadCommit() tea.Cmd {
var err error
done := make(chan struct{}, 1)
i := b.list.SelectedItem()
if i == nil {
return nil
}
c, ok := i.(item)
if !ok {
return nil
}
go func() {
err = b.loadPatch(c.Commit)
done <- struct{}{}
b.state = commitState
}()
return func() tea.Msg {
select {
case <-done:
case <-time.After(waitBeforeLoading):
b.state = loadingState
}
if err != nil {
return common.ErrMsg{Err: err}
}
return commitMsg(c.Commit)
func (b *Bubble) loadCommit() tea.Msg {
b.loading = true
b.loadingStart = time.Now()
c := b.selectedCommit
if err := b.loadPatch(c); err != nil {
return common.ErrMsg{Err: err}
}
return commitMsg(c)
}

func (b *Bubble) renderCommit(c *git.Commit) string {
Expand Down Expand Up @@ -356,11 +362,17 @@ func (b *Bubble) renderDiff(diff *git.Diff) string {
}

func (b *Bubble) View() string {
if b.loading && b.loadingStart.Add(waitBeforeLoading).Before(time.Now()) {
msg := fmt.Sprintf("%s loading commit", b.spinner.View())
if b.selectedCommit == nil {
msg += "s"
}
msg += "…"
return msg
}
switch b.state {
case logState:
return b.list.View()
case loadingState:
return fmt.Sprintf("%s loading commit…", b.spinner.View())
case errorState:
return b.error.ViewWithPrefix(b.style, "Error")
case commitState:
Expand Down

0 comments on commit d3669af

Please sign in to comment.