mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-30 03:23:08 +03:00
Add explosion animation when nuking working tree
I've been thinking about this for a while: I think it looks really cool if nuking your working tree actually results in a nuke animation. So I've added an opt-out config for it
This commit is contained in:
@ -1,8 +1,13 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
@ -29,6 +34,10 @@ func (self *FilesController) createResetMenu() error {
|
||||
return self.c.Error(err)
|
||||
}
|
||||
|
||||
if self.c.UserConfig.Gui.AnimateExplosion {
|
||||
self.animateExplosion()
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
},
|
||||
Key: 'x',
|
||||
@ -135,3 +144,102 @@ func (self *FilesController) createResetMenu() error {
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{Title: "", Items: menuItems})
|
||||
}
|
||||
|
||||
func (self *FilesController) animateExplosion() {
|
||||
self.Explode(self.c.Views().Files, func() {
|
||||
err := self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
if err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Animates an explosion within the view by drawing a bunch of flamey characters
|
||||
func (self *FilesController) Explode(v *gocui.View, onDone func()) {
|
||||
width := v.InnerWidth()
|
||||
height := v.InnerHeight() + 1
|
||||
styles := []style.TextStyle{
|
||||
style.FgLightWhite.SetBold(),
|
||||
style.FgYellow.SetBold(),
|
||||
style.FgRed.SetBold(),
|
||||
style.FgBlue.SetBold(),
|
||||
style.FgBlack.SetBold(),
|
||||
}
|
||||
|
||||
self.c.OnWorker(func(_ gocui.Task) {
|
||||
max := 25
|
||||
for i := 0; i < max; i++ {
|
||||
image := getExplodeImage(width, height, i, max)
|
||||
style := styles[(i*len(styles)/max)%len(styles)]
|
||||
coloredImage := style.Sprint(image)
|
||||
self.c.OnUIThread(func() error {
|
||||
v.SetContent(coloredImage)
|
||||
return nil
|
||||
})
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
}
|
||||
self.c.OnUIThread(func() error {
|
||||
v.Clear()
|
||||
onDone()
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Render an explosion in the given bounds.
|
||||
func getExplodeImage(width int, height int, frame int, max int) string {
|
||||
// Predefine the explosion symbols
|
||||
explosionChars := []rune{'*', '.', '@', '#', '&', '+', '%'}
|
||||
|
||||
// Initialize a buffer to build our string
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Initialize RNG seed
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
// calculate the center of explosion
|
||||
centerX, centerY := width/2, height/2
|
||||
|
||||
// calculate the max radius (hypotenuse of the view)
|
||||
maxRadius := math.Hypot(float64(centerX), float64(centerY))
|
||||
|
||||
// calculate frame as a proportion of max, apply square root to create the non-linear effect
|
||||
progress := math.Sqrt(float64(frame) / float64(max))
|
||||
|
||||
// calculate radius of explosion according to frame and max
|
||||
radius := progress * maxRadius * 2
|
||||
|
||||
// introduce a new radius for the inner boundary of the explosion (the shockwave effect)
|
||||
var innerRadius float64
|
||||
if progress > 0.5 {
|
||||
innerRadius = (progress - 0.5) * 2 * maxRadius
|
||||
}
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
// calculate distance from center, scale x by 2 to compensate for character aspect ratio
|
||||
distance := math.Hypot(float64(x-centerX), float64(y-centerY)*2)
|
||||
|
||||
// if distance is less than radius and greater than innerRadius, draw explosion char
|
||||
if distance <= radius && distance >= innerRadius {
|
||||
// Make placement random and less likely as explosion progresses
|
||||
if rand.Float64() > progress {
|
||||
// Pick a random explosion char
|
||||
char := explosionChars[rand.Intn(len(explosionChars))]
|
||||
buf.WriteRune(char)
|
||||
} else {
|
||||
buf.WriteRune(' ')
|
||||
}
|
||||
} else {
|
||||
// If not explosion, then it's empty space
|
||||
buf.WriteRune(' ')
|
||||
}
|
||||
}
|
||||
// End of line
|
||||
if y < height-1 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
Reference in New Issue
Block a user