mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-11-06 13:00:59 -04:00
Restore the terminal if a timer or errgroup function panics
time.AfterFunc and errgroup.Group.Go run the function they are given on a goroutine of their own, so a panic in it leaves the terminal in raw mode, like a panic in any other goroutine that doesn't use utils.Safe. Add utils.SafeFunc and utils.SafeFuncWithError, which return a copy of a function that runs through utils.Safe or utils.SafeWithError, and use them for the functions given to time.AfterFunc and errgroup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
73fac4a554
commit
7a9e4bee23
@@ -177,7 +177,7 @@ func (self *BranchLoader) checkForRewrittenUpstreams(branches []*models.Branch,
|
||||
continue
|
||||
}
|
||||
|
||||
errg.Go(func() error {
|
||||
errg.Go(utils.SafeFuncWithError(func() error {
|
||||
hasLocalOnlyCommits, err := self.hasLocalOnlyCommits(branch)
|
||||
if err != nil {
|
||||
// Not worth bothering the user about; it only means that we
|
||||
@@ -186,7 +186,7 @@ func (self *BranchLoader) checkForRewrittenUpstreams(branches []*models.Branch,
|
||||
}
|
||||
branch.UpstreamRewritten.Store(err == nil && !hasLocalOnlyCommits)
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
err := errg.Wait()
|
||||
@@ -220,7 +220,7 @@ func (self *BranchLoader) getBehindBaseBranchValuesLegacy(
|
||||
errg := errgroup.Group{}
|
||||
|
||||
for _, branch := range branches {
|
||||
errg.Go(func() error {
|
||||
errg.Go(utils.SafeFuncWithError(func() error {
|
||||
baseBranch, err := self.GetBaseBranch(branch, mainBranches)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -247,7 +247,7 @@ func (self *BranchLoader) getBehindBaseBranchValuesLegacy(
|
||||
}
|
||||
branch.BehindBaseBranch.Store(int32(behind))
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
err := errg.Wait()
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/cli/go-gh/v2/pkg/auth"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -233,14 +234,14 @@ func (self *GitHubCommands) FetchRecentPRs(branches []string, serviceInfo *hosti
|
||||
branchChunk := branches[i:end]
|
||||
|
||||
// Launch a goroutine for each chunk of branches
|
||||
g.Go(func() error {
|
||||
g.Go(utils.SafeFuncWithError(func() error {
|
||||
prs, err := self.fetchRecentPRsAux(endpoint, serviceInfo.Owner, serviceInfo.Repository, branchChunk, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results <- prs
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
// Wait for all goroutines, then close the channel so the range loop exits
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -91,12 +92,12 @@ func (self *DragAutoscroller) Cancel() {
|
||||
}
|
||||
|
||||
func (self *DragAutoscroller) schedule(generation uint64, delay time.Duration) {
|
||||
time.AfterFunc(delay, func() {
|
||||
time.AfterFunc(delay, utils.SafeFunc(func() {
|
||||
self.c.OnUIThreadBackground(func() error {
|
||||
self.tick(generation)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
func (self *DragAutoscroller) tick(generation uint64) {
|
||||
|
||||
@@ -267,7 +267,7 @@ func (self *FixupHelper) blameDeletedLines(deletedLineHunks []*hunk) ([]string,
|
||||
hashChan := make(chan string)
|
||||
|
||||
for _, h := range deletedLineHunks {
|
||||
errg.Go(func() error {
|
||||
errg.Go(utils.SafeFuncWithError(func() error {
|
||||
blameOutput, err := self.c.Git().Blame.BlameLineRange(h.filename, "HEAD", h.startLineIdx, h.numLines)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -277,7 +277,7 @@ func (self *FixupHelper) blameDeletedLines(deletedLineHunks []*hunk) ([]string,
|
||||
hashChan <- strings.Split(line, " ")[0]
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
go utils.Safe(func() {
|
||||
@@ -301,7 +301,7 @@ func (self *FixupHelper) blameAddedLines(commits []*models.Commit, addedLineHunk
|
||||
hashesChan := make(chan []string)
|
||||
|
||||
for _, h := range addedLineHunks {
|
||||
errg.Go(func() error {
|
||||
errg.Go(utils.SafeFuncWithError(func() error {
|
||||
result := make([]string, 0, 2)
|
||||
|
||||
appendBlamedLine := func(blameOutput string) {
|
||||
@@ -340,7 +340,7 @@ func (self *FixupHelper) blameAddedLines(commits []*models.Commit, addedLineHunk
|
||||
|
||||
hashesChan <- result
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
go utils.Safe(func() {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
@@ -629,14 +630,14 @@ func (self *MainViewController) editClickedLine(opts gocui.ViewMouseBindingOpts)
|
||||
self.c.GocuiGui().ForceFlushViewsContentOnly(self.c.GocuiGui().Views())
|
||||
})
|
||||
if flashGeneration != 0 {
|
||||
time.AfterFunc(editedLineFlashDuration, func() {
|
||||
time.AfterFunc(editedLineFlashDuration, utils.SafeFunc(func() {
|
||||
self.c.OnUIThreadContentOnlyBackground(func() error {
|
||||
if self.lineFlashGeneration == flashGeneration {
|
||||
self.context.GetView().ClearLineFlash()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -85,6 +85,18 @@ func SafeWithError(f func() error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// SafeFunc returns a function that runs f through Safe. Use it for functions
|
||||
// that something else runs on a goroutine of its own, such as time.AfterFunc.
|
||||
func SafeFunc(f func()) func() {
|
||||
return func() { Safe(f) }
|
||||
}
|
||||
|
||||
// SafeFuncWithError is like SafeFunc, for functions that return an error, such
|
||||
// as the ones passed to errgroup.Group.Go.
|
||||
func SafeFuncWithError(f func() error) func() error {
|
||||
return func() error { return SafeWithError(f) }
|
||||
}
|
||||
|
||||
func StackTrace() string {
|
||||
buf := make([]byte, 10000)
|
||||
n := runtime.Stack(buf, false)
|
||||
|
||||
Reference in New Issue
Block a user