1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-25 12:24:47 +02:00

bump gocui to support loader animations on views

This commit is contained in:
Jesse Duffield 2019-02-15 20:54:03 +11:00
parent c101993405
commit 306ac41fd8
4 changed files with 71 additions and 15 deletions

4
Gopkg.lock generated
View File

@ -197,11 +197,11 @@
[[projects]]
branch = "master"
digest = "1:a783e08c25b01d2b1b447469bc6e80a666ddac91087fb286864a81c34d9da99d"
digest = "1:b44cde97053119000e1295929118f935a59787e41c1b4b7db8e7bfdb11db5be1"
name = "github.com/jesseduffield/gocui"
packages = ["."]
pruneopts = "NUT"
revision = "985c2f8d59e55de7e78b1ecf72277041df7dd44d"
revision = "e70eea43593b15d0f70e802771b871c08dacd5ee"
[[projects]]
branch = "master"

2
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/heroku/rollrus v0.0.0-20180515183152-fc0cef2ff331
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63
github.com/jesseduffield/gocui v0.0.0-20190211105959-985c2f8d59e5
github.com/jesseduffield/gocui v0.0.0-20190215095146-e70eea43593b
github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406
github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8

View File

@ -5,6 +5,9 @@
package gocui
import (
standardErrors "errors"
"time"
"github.com/go-errors/errors"
"github.com/jesseduffield/termbox-go"
@ -12,10 +15,10 @@ import (
var (
// ErrQuit is used to decide if the MainLoop finished successfully.
ErrQuit = errors.New("quit")
ErrQuit = standardErrors.New("quit")
// ErrUnknownView allows to assert if a View must be initialized.
ErrUnknownView = errors.New("unknown view")
ErrUnknownView = standardErrors.New("unknown view")
)
// OutputMode represents the terminal's output mode (8 or 256 colors).
@ -163,7 +166,7 @@ func (g *Gui) SetView(name string, x0, y0, x1, y1 int, overlaps byte) (*View, er
v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor
v.Overlaps = overlaps
g.views = append(g.views, v)
return v, ErrUnknownView
return v, errors.Wrap(ErrUnknownView, 0)
}
// SetViewOnTop sets the given view on top of the existing ones.
@ -175,7 +178,7 @@ func (g *Gui) SetViewOnTop(name string) (*View, error) {
return v, nil
}
}
return nil, ErrUnknownView
return nil, errors.Wrap(ErrUnknownView, 0)
}
// SetViewOnBottom sets the given view on bottom of the existing ones.
@ -187,7 +190,7 @@ func (g *Gui) SetViewOnBottom(name string) (*View, error) {
return v, nil
}
}
return nil, ErrUnknownView
return nil, errors.Wrap(ErrUnknownView, 0)
}
// Views returns all the views in the GUI.
@ -203,7 +206,7 @@ func (g *Gui) View(name string) (*View, error) {
return v, nil
}
}
return nil, ErrUnknownView
return nil, errors.Wrap(ErrUnknownView, 0)
}
// ViewByPosition returns a pointer to a view matching the given position, or
@ -216,7 +219,7 @@ func (g *Gui) ViewByPosition(x, y int) (*View, error) {
return v, nil
}
}
return nil, ErrUnknownView
return nil, errors.Wrap(ErrUnknownView, 0)
}
// ViewPosition returns the coordinates of the view with the given name, or
@ -227,7 +230,7 @@ func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {
return v.x0, v.y0, v.x1, v.y1, nil
}
}
return 0, 0, 0, 0, ErrUnknownView
return 0, 0, 0, 0, errors.Wrap(ErrUnknownView, 0)
}
// DeleteView deletes a view by name.
@ -238,7 +241,7 @@ func (g *Gui) DeleteView(name string) error {
return nil
}
}
return ErrUnknownView
return errors.Wrap(ErrUnknownView, 0)
}
// SetCurrentView gives the focus to a given view.
@ -249,7 +252,7 @@ func (g *Gui) SetCurrentView(name string) (*View, error) {
return v, nil
}
}
return nil, ErrUnknownView
return nil, errors.Wrap(ErrUnknownView, 0)
}
// CurrentView returns the currently focused view, or nil if no view
@ -364,6 +367,7 @@ func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
// MainLoop runs the main loop until an error is returned. A successful
// finish should return ErrQuit.
func (g *Gui) MainLoop() error {
g.loaderTick()
if err := g.flush(); err != nil {
return err
}
@ -705,3 +709,16 @@ func (g *Gui) execKeybinding(v *View, kb *keybinding) (bool, error) {
}
return true, nil
}
func (g *Gui) loaderTick() {
go func() {
for range time.Tick(time.Millisecond) {
for _, view := range g.Views() {
if view.HasLoader {
g.userEvents <- userEvent{func(g *Gui) error { return nil }}
break
}
}
}
}()
}

View File

@ -8,6 +8,7 @@ import (
"bytes"
"io"
"strings"
"time"
"github.com/go-errors/errors"
@ -87,6 +88,9 @@ type View struct {
// Overlaps describes which edges are overlapping with another view's edges
Overlaps byte
// If HasLoader is true, the message will be appended with a spinning loader animation
HasLoader bool
}
type viewLine struct {
@ -322,7 +326,11 @@ func (v *View) draw() error {
}
if v.tainted {
v.viewLines = nil
for i, line := range v.lines {
lines := v.lines
if v.HasLoader {
lines = v.loaderLines()
}
for i, line := range lines {
wrap := 0
if v.Wrap {
wrap = maxX
@ -334,7 +342,9 @@ func (v *View) draw() error {
v.viewLines = append(v.viewLines, vline)
}
}
v.tainted = false
if !v.HasLoader {
v.tainted = false
}
}
if v.Autoscroll && len(v.viewLines) > maxY {
@ -564,3 +574,32 @@ func linesToString(lines [][]cell) string {
return strings.Join(str, "\n")
}
func (v *View) loaderLines() [][]cell {
duplicate := make([][]cell, len(v.lines))
for i := range v.lines {
if i < len(v.lines)-1 {
duplicate[i] = make([]cell, len(v.lines[i]))
copy(duplicate[i], v.lines[i])
} else {
duplicate[i] = make([]cell, len(v.lines[i])+2)
copy(duplicate[i], v.lines[i])
duplicate[i][len(duplicate[i])-2] = cell{chr: ' '}
duplicate[i][len(duplicate[i])-1] = Loader()
}
}
return duplicate
}
func Loader() cell {
characters := "|/-\\"
now := time.Now()
nanos := now.UnixNano()
index := nanos / 50000000 % int64(len(characters))
str := characters[index : index+1]
chr := []rune(str)[0]
return cell{
chr: chr,
}
}