1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-09 13:47:11 +02:00

Use an interface for tasks instead of a concrete struct

By using an interface for tasks we can use a fake implementation in tests with extra methods
This commit is contained in:
Jesse Duffield 2023-07-09 21:09:52 +10:00
parent 8964cedf27
commit 6b9390409e
45 changed files with 333 additions and 222 deletions

2
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e

4
go.sum
View File

@ -72,8 +72,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52 h1:rrKgkOAVJD5rgC6aoX3zWTSiSiHkuQBA2JW/r+v1eKE=
github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b h1:8FmmdaYHes1m3oNyNdS+VIgkgkFpNZAWuwTnvp0tG14=
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=

View File

@ -48,7 +48,7 @@ func (self *RemoteCommands) UpdateRemoteUrl(remoteName string, updatedUrl string
return self.cmd.New(cmdArgs).Run()
}
func (self *RemoteCommands) DeleteRemoteBranch(task *gocui.Task, remoteName string, branchName string) error {
func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName string, branchName string) error {
cmdArgs := NewGitCmd("push").
Arg(remoteName, "--delete", branchName).
ToArgv()

View File

@ -24,7 +24,7 @@ type PushOpts struct {
SetUpstream bool
}
func (self *SyncCommands) PushCmdObj(task *gocui.Task, opts PushOpts) (oscommands.ICmdObj, error) {
func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands.ICmdObj, error) {
if opts.UpstreamBranch != "" && opts.UpstreamRemote == "" {
return nil, errors.New(self.Tr.MustSpecifyOriginError)
}
@ -40,7 +40,7 @@ func (self *SyncCommands) PushCmdObj(task *gocui.Task, opts PushOpts) (oscommand
return cmdObj, nil
}
func (self *SyncCommands) Push(task *gocui.Task, opts PushOpts) error {
func (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error {
cmdObj, err := self.PushCmdObj(task, opts)
if err != nil {
return err
@ -49,24 +49,33 @@ func (self *SyncCommands) Push(task *gocui.Task, opts PushOpts) error {
return cmdObj.Run()
}
func (self *SyncCommands) Fetch(task *gocui.Task) error {
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
cmdArgs := NewGitCmd("fetch").
ArgIf(self.UserConfig.Git.FetchAll, "--all").
ToArgv()
cmdObj := self.cmd.New(cmdArgs)
cmdObj.PromptOnCredentialRequest(task)
return cmdObj.WithMutex(self.syncMutex).Run()
return cmdObj
}
func (self *SyncCommands) FetchBackground() error {
func (self *SyncCommands) Fetch(task gocui.Task) error {
return self.FetchCmdObj(task).Run()
}
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
cmdArgs := NewGitCmd("fetch").
ArgIf(self.UserConfig.Git.FetchAll, "--all").
ToArgv()
cmdObj := self.cmd.New(cmdArgs)
cmdObj.DontLog().FailOnCredentialRequest()
return cmdObj.WithMutex(self.syncMutex).Run()
cmdObj.WithMutex(self.syncMutex)
return cmdObj
}
func (self *SyncCommands) FetchBackground() error {
return self.FetchBackgroundCmdObj().Run()
}
type PullOptions struct {
@ -75,7 +84,7 @@ type PullOptions struct {
FastForwardOnly bool
}
func (self *SyncCommands) Pull(task *gocui.Task, opts PullOptions) error {
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
cmdArgs := NewGitCmd("pull").
Arg("--no-edit").
ArgIf(opts.FastForwardOnly, "--ff-only").
@ -88,7 +97,7 @@ func (self *SyncCommands) Pull(task *gocui.Task, opts PullOptions) error {
return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
func (self *SyncCommands) FastForward(task *gocui.Task, branchName string, remoteName string, remoteBranchName string) error {
func (self *SyncCommands) FastForward(task gocui.Task, branchName string, remoteName string, remoteBranchName string) error {
cmdArgs := NewGitCmd("fetch").
Arg(remoteName).
Arg(remoteBranchName + ":" + branchName).
@ -97,7 +106,7 @@ func (self *SyncCommands) FastForward(task *gocui.Task, branchName string, remot
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
func (self *SyncCommands) FetchRemote(task *gocui.Task, remoteName string) error {
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
cmdArgs := NewGitCmd("fetch").
Arg(remoteName).
ToArgv()

View File

@ -3,6 +3,7 @@ package git_commands
import (
"testing"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/stretchr/testify/assert"
)
@ -88,7 +89,8 @@ func TestSyncPush(t *testing.T) {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildSyncCommands(commonDeps{})
s.test(instance.PushCmdObj(s.opts))
task := gocui.NewFakeTask()
s.test(instance.PushCmdObj(task, s.opts))
})
}
}
@ -96,7 +98,6 @@ func TestSyncPush(t *testing.T) {
func TestSyncFetch(t *testing.T) {
type scenario struct {
testName string
opts FetchOptions
fetchAllConfig bool
test func(oscommands.ICmdObj)
}
@ -104,7 +105,6 @@ func TestSyncFetch(t *testing.T) {
scenarios := []scenario{
{
testName: "Fetch in foreground (all=false)",
opts: FetchOptions{Background: false},
fetchAllConfig: false,
test: func(cmdObj oscommands.ICmdObj) {
assert.True(t, cmdObj.ShouldLog())
@ -114,7 +114,6 @@ func TestSyncFetch(t *testing.T) {
},
{
testName: "Fetch in foreground (all=true)",
opts: FetchOptions{Background: false},
fetchAllConfig: true,
test: func(cmdObj oscommands.ICmdObj) {
assert.True(t, cmdObj.ShouldLog())
@ -122,9 +121,29 @@ func TestSyncFetch(t *testing.T) {
assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--all"})
},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildSyncCommands(commonDeps{})
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
task := gocui.NewFakeTask()
s.test(instance.FetchCmdObj(task))
})
}
}
func TestSyncFetchBackground(t *testing.T) {
type scenario struct {
testName string
fetchAllConfig bool
test func(oscommands.ICmdObj)
}
scenarios := []scenario{
{
testName: "Fetch in background (all=false)",
opts: FetchOptions{Background: true},
fetchAllConfig: false,
test: func(cmdObj oscommands.ICmdObj) {
assert.False(t, cmdObj.ShouldLog())
@ -134,7 +153,6 @@ func TestSyncFetch(t *testing.T) {
},
{
testName: "Fetch in background (all=true)",
opts: FetchOptions{Background: true},
fetchAllConfig: true,
test: func(cmdObj oscommands.ICmdObj) {
assert.False(t, cmdObj.ShouldLog())
@ -149,7 +167,7 @@ func TestSyncFetch(t *testing.T) {
t.Run(s.testName, func(t *testing.T) {
instance := buildSyncCommands(commonDeps{})
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
s.test(instance.FetchCmdObj(s.opts))
s.test(instance.FetchBackgroundCmdObj())
})
}
}

View File

@ -36,7 +36,7 @@ func (self *TagCommands) Delete(tagName string) error {
return self.cmd.New(cmdArgs).Run()
}
func (self *TagCommands) Push(task *gocui.Task, remoteName string, tagName string) error {
func (self *TagCommands) Push(task gocui.Task, remoteName string, tagName string) error {
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
ToArgv()

View File

@ -57,14 +57,14 @@ type ICmdObj interface {
// returns true if IgnoreEmptyError() was called
ShouldIgnoreEmptyError() bool
PromptOnCredentialRequest(task *gocui.Task) ICmdObj
PromptOnCredentialRequest(task gocui.Task) ICmdObj
FailOnCredentialRequest() ICmdObj
WithMutex(mutex *deadlock.Mutex) ICmdObj
Mutex() *deadlock.Mutex
GetCredentialStrategy() CredentialStrategy
GetTask() *gocui.Task
GetTask() gocui.Task
}
type CmdObj struct {
@ -87,7 +87,7 @@ type CmdObj struct {
// if set to true, it means we might be asked to enter a username/password by this command.
credentialStrategy CredentialStrategy
task *gocui.Task
task gocui.Task
// can be set so that we don't run certain commands simultaneously
mutex *deadlock.Mutex
@ -195,7 +195,7 @@ func (self *CmdObj) RunAndProcessLines(onLine func(line string) (bool, error)) e
return self.runner.RunAndProcessLines(self, onLine)
}
func (self *CmdObj) PromptOnCredentialRequest(task *gocui.Task) ICmdObj {
func (self *CmdObj) PromptOnCredentialRequest(task gocui.Task) ICmdObj {
self.credentialStrategy = PROMPT
self.task = task
@ -212,6 +212,6 @@ func (self *CmdObj) GetCredentialStrategy() CredentialStrategy {
return self.credentialStrategy
}
func (self *CmdObj) GetTask() *gocui.Task {
func (self *CmdObj) GetTask() gocui.Task {
return self.task
}

View File

@ -318,7 +318,7 @@ func (self *cmdObjRunner) processOutput(
reader io.Reader,
writer io.Writer,
promptUserForCredential func(CredentialType) <-chan string,
task *gocui.Task,
task gocui.Task,
) {
checkForCredentialRequest := self.getCheckForCredentialRequestFunc()

View File

@ -4,6 +4,7 @@ import (
"strings"
"testing"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@ -111,7 +112,8 @@ func TestProcessOutput(t *testing.T) {
reader := strings.NewReader(scenario.output)
writer := &strings.Builder{}
runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential))
task := gocui.NewFakeTask()
runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential), task)
if writer.String() != scenario.expectedToWrite {
t.Errorf("expected to write '%s' but got '%s'", scenario.expectedToWrite, writer.String())

View File

@ -86,7 +86,7 @@ func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan stru
if self.pauseBackgroundRefreshes {
continue
}
self.gui.c.OnWorker(func(*gocui.Task) { _ = function() })
self.gui.c.OnWorker(func(gocui.Task) { _ = function() })
case <-stop:
return
}

View File

@ -364,7 +364,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
},
)
return self.c.WithLoaderPanel(message, func(task *gocui.Task) error {
return self.c.WithLoaderPanel(message, func(task gocui.Task) error {
if branch == self.c.Helpers().Refs.GetCheckedOutRef() {
self.c.LogAction(action)

View File

@ -177,7 +177,7 @@ func (self *CommitFilesController) discard(node *filetree.CommitFileNode) error
Title: self.c.Tr.DiscardFileChangesTitle,
Prompt: prompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DiscardOldFileChange)
if err := self.c.Git().Rebase.DiscardOldFileChanges(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), node.GetPath()); err != nil {
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
@ -205,7 +205,7 @@ func (self *CommitFilesController) edit(node *filetree.CommitFileNode) error {
func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) error {
toggle := func() error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingPatch, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingPatch, func(gocui.Task) error {
if !self.c.Git().Patch.PatchBuilder.Active() {
if err := self.startPatchBuilder(); err != nil {
return err

View File

@ -117,7 +117,7 @@ func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
return err
}
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
err := self.c.Git().Patch.DeletePatchesFromCommit(self.c.Model().Commits, commitIndex)
@ -134,7 +134,7 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() erro
return err
}
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchToSelectedCommit)
err := self.c.Git().Patch.MovePatchToSelectedCommit(self.c.Model().Commits, commitIndex, self.c.Contexts().LocalCommits.GetSelectedLineIdx())
@ -152,7 +152,7 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error
}
pull := func(stash bool) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, stash)
@ -182,7 +182,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
return err
}
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
err := self.c.Git().Patch.PullPatchIntoNewCommit(self.c.Model().Commits, commitIndex)

View File

@ -800,7 +800,7 @@ func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) e
}
func (self *FilesController) fetch() error {
return self.c.WithLoaderPanel(self.c.Tr.FetchWait, func(task *gocui.Task) error {
return self.c.WithLoaderPanel(self.c.Tr.FetchWait, func(task gocui.Task) error {
if err := self.fetchAux(task); err != nil {
_ = self.c.Error(err)
}
@ -808,7 +808,7 @@ func (self *FilesController) fetch() error {
})
}
func (self *FilesController) fetchAux(task *gocui.Task) (err error) {
func (self *FilesController) fetchAux(task gocui.Task) (err error) {
self.c.LogAction("Fetch")
err = self.c.Git().Sync.Fetch(task)

View File

@ -146,7 +146,7 @@ func (self *FilesRemoveController) remove(node *filetree.FileNode) error {
}
func (self *FilesRemoveController) ResetSubmodule(submodule *models.SubmoduleConfig) error {
return self.c.WithWaitingStatus(self.c.Tr.ResettingSubmoduleStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.ResettingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.ResetSubmodule)
file := self.c.Helpers().WorkingTree.FileForSubmodule(submodule)

View File

@ -27,8 +27,8 @@ func (self *AppStatusHelper) Toast(message string) {
}
// withWaitingStatus wraps a function and shows a waiting status while the function is still executing
func (self *AppStatusHelper) WithWaitingStatus(message string, f func(*gocui.Task) error) {
self.c.OnWorker(func(task *gocui.Task) {
func (self *AppStatusHelper) WithWaitingStatus(message string, f func(gocui.Task) error) {
self.c.OnWorker(func(task gocui.Task) {
self.statusMgr().WithWaitingStatus(message, func() {
self.renderAppStatus()
@ -50,7 +50,7 @@ func (self *AppStatusHelper) GetStatusString() string {
}
func (self *AppStatusHelper) renderAppStatus() {
self.c.OnWorker(func(_ *gocui.Task) {
self.c.OnWorker(func(_ gocui.Task) {
ticker := time.NewTicker(time.Millisecond * 50)
defer ticker.Stop()
for range ticker.C {

View File

@ -76,7 +76,7 @@ func (self *CherryPickHelper) Paste() error {
Title: self.c.Tr.CherryPick,
Prompt: self.c.Tr.SureCherryPick,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.CherryPickingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.CherryPickingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.CherryPick)
err := self.c.Git().Rebase.CherryPickCommits(self.getData().CherryPickedCommits)
return self.rebaseHelper.CheckMergeOrRebase(err)

View File

@ -42,7 +42,7 @@ func (self *GpgHelper) WithGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus
}
func (self *GpgHelper) runAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error {
return self.c.WithWaitingStatus(waitingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(waitingStatus, func(gocui.Task) error {
if err := cmdObj.StreamOutput().Run(); err != nil {
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
return self.c.Error(

View File

@ -87,7 +87,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
refresh := func(f func()) {
if options.Mode == types.ASYNC {
self.c.OnWorker(func(t *gocui.Task) {
self.c.OnWorker(func(t gocui.Task) {
f()
})
} else {
@ -201,7 +201,7 @@ func getModeName(mode types.RefreshMode) string {
func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
switch self.c.State().GetRepoState().GetStartupStage() {
case types.INITIAL:
self.c.OnWorker(func(_ *gocui.Task) {
self.c.OnWorker(func(_ gocui.Task) {
_ = self.refreshReflogCommits()
self.refreshBranches()
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)

View File

@ -51,7 +51,7 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
self.c.Contexts().LocalCommits.SetLimitCommits(true)
}
return self.c.WithWaitingStatus(waitingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(waitingStatus, func(gocui.Task) error {
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
// note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option

View File

@ -101,7 +101,7 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty
// Notably, unlike other suggestion functions we're not showing all the options
// if nothing has been typed because there'll be too much to display efficiently
func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*types.Suggestion {
_ = self.c.WithWaitingStatus(self.c.Tr.LoadingFileSuggestions, func(*gocui.Task) error {
_ = self.c.WithWaitingStatus(self.c.Tr.LoadingFileSuggestions, func(gocui.Task) error {
trie := patricia.NewTrie()
// load every non-gitignored file in the repo
ignore, err := gitignore.FromGit()

View File

@ -38,7 +38,7 @@ func (self *UpdateHelper) CheckForUpdateInBackground() {
}
func (self *UpdateHelper) CheckForUpdateInForeground() error {
return self.c.WithWaitingStatus(self.c.Tr.CheckingForUpdates, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.CheckingForUpdates, func(gocui.Task) error {
self.updater.CheckForNewUpdate(func(newVersion string, err error) error {
if err != nil {
return self.c.Error(err)
@ -54,7 +54,7 @@ func (self *UpdateHelper) CheckForUpdateInForeground() error {
}
func (self *UpdateHelper) startUpdating(newVersion string) {
_ = self.c.WithWaitingStatus(self.c.Tr.UpdateInProgressWaitingStatus, func(*gocui.Task) error {
_ = self.c.WithWaitingStatus(self.c.Tr.UpdateInProgressWaitingStatus, func(gocui.Task) error {
self.c.State().SetUpdating(true)
err := self.updater.Update(newVersion)
return self.onUpdateFinish(err)

View File

@ -218,7 +218,7 @@ func (self *LocalCommitsController) squashDown(commit *models.Commit) error {
Title: self.c.Tr.Squash,
Prompt: self.c.Tr.SureSquashThisCommit,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashCommitDown)
return self.interactiveRebase(todo.Squash)
})
@ -243,7 +243,7 @@ func (self *LocalCommitsController) fixup(commit *models.Commit) error {
Title: self.c.Tr.Fixup,
Prompt: self.c.Tr.SureFixupThisCommit,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.FixupCommit)
return self.interactiveRebase(todo.Fixup)
})
@ -339,7 +339,7 @@ func (self *LocalCommitsController) drop(commit *models.Commit) error {
Title: self.c.Tr.DeleteCommitTitle,
Prompt: self.c.Tr.DeleteCommitPrompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DropCommit)
return self.interactiveRebase(todo.Drop)
})
@ -356,7 +356,7 @@ func (self *LocalCommitsController) edit(commit *models.Commit) error {
return nil
}
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.EditCommit)
err := self.c.Git().Rebase.EditRebase(commit.Sha)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
@ -461,7 +461,7 @@ func (self *LocalCommitsController) moveDown(commit *models.Commit) error {
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
}
return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.MoveCommitDown)
err := self.c.Git().Rebase.MoveCommitDown(self.c.Model().Commits, index)
if err == nil {
@ -499,7 +499,7 @@ func (self *LocalCommitsController) moveUp(commit *models.Commit) error {
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
}
return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.MoveCommitUp)
err := self.c.Git().Rebase.MoveCommitUp(self.c.Model().Commits, index)
if err == nil {
@ -525,7 +525,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitPrompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
err := self.c.Git().Rebase.AmendTo(self.c.Model().Commits, self.context().GetView().SelectedLineIdx())
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
@ -559,7 +559,7 @@ func (self *LocalCommitsController) amendAttribute(commit *models.Commit) error
}
func (self *LocalCommitsController) resetAuthor() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.ResetCommitAuthor)
if err := self.c.Git().Rebase.ResetCommitAuthor(self.c.Model().Commits, self.context().GetSelectedLineIdx()); err != nil {
return self.c.Error(err)
@ -574,7 +574,7 @@ func (self *LocalCommitsController) setAuthor() error {
Title: self.c.Tr.SetAuthorPromptTitle,
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
HandleConfirm: func(value string) error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SetCommitAuthor)
if err := self.c.Git().Rebase.SetCommitAuthor(self.c.Model().Commits, self.context().GetSelectedLineIdx(), value); err != nil {
return self.c.Error(err)
@ -672,7 +672,7 @@ func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Co
Title: self.c.Tr.SquashAboveCommits,
Prompt: prompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
@ -724,7 +724,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
self.context().SetLimitCommits(false)
}
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(gocui.Task) error {
return self.c.Refresh(
types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}},
)
@ -767,7 +767,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
onPress := func(value string) func() error {
return func() error {
self.c.UserConfig.Git.Log.Order = value
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(gocui.Task) error {
return self.c.Refresh(
types.RefreshOptions{
Mode: types.SYNC,
@ -817,7 +817,7 @@ func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
context := self.context()
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)
self.c.OnWorker(func(_ *gocui.Task) {
self.c.OnWorker(func(_ gocui.Task) {
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}); err != nil {
_ = self.c.Error(err)
}

View File

@ -118,7 +118,7 @@ func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch
Title: self.c.Tr.DeleteRemoteBranch,
Prompt: message,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task *gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
err := self.c.Git().Remote.DeleteRemoteBranch(task, selectedBranch.RemoteName, selectedBranch.Name)
if err != nil {

View File

@ -198,7 +198,7 @@ func (self *RemotesController) edit(remote *models.Remote) error {
}
func (self *RemotesController) fetch(remote *models.Remote) error {
return self.c.WithWaitingStatus(self.c.Tr.FetchingRemoteStatus, func(task *gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.FetchingRemoteStatus, func(task gocui.Task) error {
err := self.c.Git().Sync.FetchRemote(task, remote.Name)
if err != nil {
_ = self.c.Error(err)

View File

@ -60,7 +60,7 @@ func (self *SubCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
context := self.context()
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)
self.c.OnWorker(func(_ *gocui.Task) {
self.c.OnWorker(func(_ gocui.Task) {
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUB_COMMITS}}); err != nil {
_ = self.c.Error(err)
}

View File

@ -131,7 +131,7 @@ func (self *SubmodulesController) add() error {
Title: self.c.Tr.NewSubmodulePath,
InitialContent: submoduleName,
HandleConfirm: func(submodulePath string) error {
return self.c.WithWaitingStatus(self.c.Tr.AddingSubmoduleStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.AddingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AddSubmodule)
err := self.c.Git().Submodule.Add(submoduleName, submodulePath, submoduleUrl)
if err != nil {
@ -153,7 +153,7 @@ func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) err
Title: fmt.Sprintf(self.c.Tr.UpdateSubmoduleUrl, submodule.Name),
InitialContent: submodule.Url,
HandleConfirm: func(newUrl string) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleUrlStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleUrlStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.UpdateSubmoduleUrl)
err := self.c.Git().Submodule.UpdateUrl(submodule.Name, submodule.Path, newUrl)
if err != nil {
@ -167,7 +167,7 @@ func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) err
}
func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error {
return self.c.WithWaitingStatus(self.c.Tr.InitializingSubmoduleStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.InitializingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.InitialiseSubmodule)
err := self.c.Git().Submodule.Init(submodule.Path)
if err != nil {
@ -185,7 +185,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
{
LabelColumns: []string{self.c.Tr.BulkInitSubmodules, style.FgGreen.Sprint(self.c.Git().Submodule.BulkInitCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkInitialiseSubmodules)
err := self.c.Git().Submodule.BulkInitCmdObj().Run()
if err != nil {
@ -200,7 +200,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
{
LabelColumns: []string{self.c.Tr.BulkUpdateSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkUpdateSubmodules)
if err := self.c.Git().Submodule.BulkUpdateCmdObj().Run(); err != nil {
return self.c.Error(err)
@ -214,7 +214,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
{
LabelColumns: []string{self.c.Tr.BulkDeinitSubmodules, style.FgRed.Sprint(self.c.Git().Submodule.BulkDeinitCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkDeinitialiseSubmodules)
if err := self.c.Git().Submodule.BulkDeinitCmdObj().Run(); err != nil {
return self.c.Error(err)
@ -230,7 +230,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
}
func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.UpdateSubmodule)
err := self.c.Git().Submodule.Update(submodule.Path)
if err != nil {

View File

@ -139,12 +139,12 @@ type PullFilesOptions struct {
}
func (self *SyncController) PullAux(opts PullFilesOptions) error {
return self.c.WithLoaderPanel(self.c.Tr.PullWait, func(task *gocui.Task) error {
return self.c.WithLoaderPanel(self.c.Tr.PullWait, func(task gocui.Task) error {
return self.pullWithLock(task, opts)
})
}
func (self *SyncController) pullWithLock(task *gocui.Task, opts PullFilesOptions) error {
func (self *SyncController) pullWithLock(task gocui.Task, opts PullFilesOptions) error {
self.c.LogAction(opts.Action)
err := self.c.Git().Sync.Pull(
@ -167,7 +167,7 @@ type pushOpts struct {
}
func (self *SyncController) pushAux(opts pushOpts) error {
return self.c.WithLoaderPanel(self.c.Tr.PushWait, func(task *gocui.Task) error {
return self.c.WithLoaderPanel(self.c.Tr.PushWait, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.Push)
err := self.c.Git().Sync.Push(
task,

View File

@ -122,7 +122,7 @@ func (self *TagsController) push(tag *models.Tag) error {
InitialContent: "origin",
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
HandleConfirm: func(response string) error {
return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func(task *gocui.Task) error {
return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.PushTag)
err := self.c.Git().Tag.Push(task, response, tag.Name)
if err != nil {

View File

@ -248,7 +248,7 @@ func (self *UndoController) hardResetWithAutoStash(commitSha string, options har
Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(options.WaitingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
if err := self.c.Git().Stash.Save(self.c.Tr.StashPrefix + commitSha); err != nil {
return self.c.Error(err)
}
@ -269,7 +269,7 @@ func (self *UndoController) hardResetWithAutoStash(commitSha string, options har
})
}
return self.c.WithWaitingStatus(options.WaitingStatus, func(*gocui.Task) error {
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
return reset()
})
}

View File

@ -472,10 +472,10 @@ func NewGui(
func() error { return gui.State.ContextMgr.Pop() },
func() types.Context { return gui.State.ContextMgr.Current() },
gui.createMenu,
func(message string, f func(*gocui.Task) error) { gui.helpers.AppStatus.WithWaitingStatus(message, f) },
func(message string, f func(gocui.Task) error) { gui.helpers.AppStatus.WithWaitingStatus(message, f) },
func(message string) { gui.helpers.AppStatus.Toast(message) },
func() string { return gui.Views.Confirmation.TextArea.GetContent() },
func(f func(*gocui.Task)) { gui.c.OnWorker(f) },
func(f func(gocui.Task)) { gui.c.OnWorker(f) },
)
guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler}
@ -780,19 +780,19 @@ func (gui *Gui) loadNewRepo() error {
return nil
}
func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) {
gui.waitForIntro.Add(len(tasks))
func (gui *Gui) showInitialPopups(popupTasks []func(chan struct{}) error) {
gui.waitForIntro.Add(len(popupTasks))
done := make(chan struct{})
gui.c.OnWorker(func(gocuiTask *gocui.Task) {
for _, task := range tasks {
if err := task(done); err != nil {
gui.c.OnWorker(func(task gocui.Task) {
for _, popupTask := range popupTasks {
if err := popupTask(done); err != nil {
_ = gui.c.Error(err)
}
gocuiTask.Pause()
task.Pause()
<-done
gocuiTask.Continue()
task.Continue()
gui.waitForIntro.Done()
}
})
@ -833,7 +833,7 @@ func (gui *Gui) onUIThread(f func() error) {
})
}
func (gui *Gui) onWorker(f func(*gocui.Task)) {
func (gui *Gui) onWorker(f func(gocui.Task)) {
gui.g.OnWorker(f)
}

View File

@ -136,7 +136,7 @@ func (self *guiCommon) OnUIThread(f func() error) {
self.gui.onUIThread(f)
}
func (self *guiCommon) OnWorker(f func(*gocui.Task)) {
func (self *guiCommon) OnWorker(f func(gocui.Task)) {
self.gui.onWorker(f)
}

View File

@ -33,12 +33,12 @@ func (self *FakePopupHandler) Prompt(opts types.PromptOpts) error {
return self.OnPrompt(opts)
}
func (self *FakePopupHandler) WithLoaderPanel(message string, f func(*gocui.Task) error) error {
return f(&gocui.Task{})
func (self *FakePopupHandler) WithLoaderPanel(message string, f func(gocui.Task) error) error {
return f(gocui.NewFakeTask())
}
func (self *FakePopupHandler) WithWaitingStatus(message string, f func(*gocui.Task) error) error {
return f(&gocui.Task{})
func (self *FakePopupHandler) WithWaitingStatus(message string, f func(gocui.Task) error) error {
return f(gocui.NewFakeTask())
}
func (self *FakePopupHandler) Menu(opts types.CreateMenuOptions) error {

View File

@ -21,10 +21,10 @@ type PopupHandler struct {
popContextFn func() error
currentContextFn func() types.Context
createMenuFn func(types.CreateMenuOptions) error
withWaitingStatusFn func(message string, f func(*gocui.Task) error)
withWaitingStatusFn func(message string, f func(gocui.Task) error)
toastFn func(message string)
getPromptInputFn func() string
onWorker func(func(*gocui.Task))
onWorker func(func(gocui.Task))
}
var _ types.IPopupHandler = &PopupHandler{}
@ -36,10 +36,10 @@ func NewPopupHandler(
popContextFn func() error,
currentContextFn func() types.Context,
createMenuFn func(types.CreateMenuOptions) error,
withWaitingStatusFn func(message string, f func(*gocui.Task) error),
withWaitingStatusFn func(message string, f func(gocui.Task) error),
toastFn func(message string),
getPromptInputFn func() string,
onWorker func(func(*gocui.Task)),
onWorker func(func(gocui.Task)),
) *PopupHandler {
return &PopupHandler{
Common: common,
@ -64,7 +64,7 @@ func (self *PopupHandler) Toast(message string) {
self.toastFn(message)
}
func (self *PopupHandler) WithWaitingStatus(message string, f func(*gocui.Task) error) error {
func (self *PopupHandler) WithWaitingStatus(message string, f func(gocui.Task) error) error {
self.withWaitingStatusFn(message, f)
return nil
}
@ -124,7 +124,7 @@ func (self *PopupHandler) Prompt(opts types.PromptOpts) error {
})
}
func (self *PopupHandler) WithLoaderPanel(message string, f func(*gocui.Task) error) error {
func (self *PopupHandler) WithLoaderPanel(message string, f func(gocui.Task) error) error {
index := 0
self.Lock()
self.index++
@ -143,7 +143,7 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func(*gocui.Task) er
return nil
}
self.onWorker(func(task *gocui.Task) {
self.onWorker(func(task gocui.Task) {
if err := f(task); err != nil {
self.Log.Error(err)
}

View File

@ -265,7 +265,7 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
loadingText = self.c.Tr.RunningCustomCommandStatus
}
return self.c.WithWaitingStatus(loadingText, func(*gocui.Task) error {
return self.c.WithWaitingStatus(loadingText, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.CustomCommand)
if customCommand.Stream {

View File

@ -130,7 +130,7 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
func() {
_ = view.SetOrigin(0, 0)
},
func() *gocui.Task {
func() gocui.Task {
return gui.c.GocuiGui().NewTask()
},
)

View File

@ -79,7 +79,7 @@ type IGuiCommon interface {
OnUIThread(f func() error)
// Runs a function in a goroutine. Use this whenever you want to run a goroutine and keep track of the fact
// that lazygit is still busy. See docs/dev/Busy.md
OnWorker(f func(*gocui.Task))
OnWorker(f func(gocui.Task))
// returns the gocui Gui struct. There is a good chance you don't actually want to use
// this struct and instead want to use another method above
@ -121,8 +121,8 @@ type IPopupHandler interface {
Confirm(opts ConfirmOpts) error
// Shows a popup prompting the user for input.
Prompt(opts PromptOpts) error
WithLoaderPanel(message string, f func(*gocui.Task) error) error
WithWaitingStatus(message string, f func(*gocui.Task) error) error
WithLoaderPanel(message string, f func(gocui.Task) error) error
WithWaitingStatus(message string, f func(gocui.Task) error) error
Menu(opts CreateMenuOptions) error
Toast(message string)
GetPromptInput() string

View File

@ -18,10 +18,10 @@ type AsyncHandler struct {
lastId int
mutex deadlock.Mutex
onReject func()
onWorker func(func(*gocui.Task))
onWorker func(func(gocui.Task))
}
func NewAsyncHandler(onWorker func(func(*gocui.Task))) *AsyncHandler {
func NewAsyncHandler(onWorker func(func(gocui.Task))) *AsyncHandler {
return &AsyncHandler{
mutex: deadlock.Mutex{},
onWorker: onWorker,
@ -34,7 +34,7 @@ func (self *AsyncHandler) Do(f func() func()) {
id := self.currentId
self.mutex.Unlock()
self.onWorker(func(*gocui.Task) {
self.onWorker(func(gocui.Task) {
after := f()
self.handle(after, id)
})

View File

@ -13,8 +13,8 @@ func TestAsyncHandler(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(2)
onWorker := func(f func(*gocui.Task)) {
go f(&gocui.Task{})
onWorker := func(f func(gocui.Task)) {
go f(gocui.NewFakeTask())
}
handler := NewAsyncHandler(onWorker)
handler.onReject = func() {

View File

@ -50,7 +50,10 @@ type ViewBufferManager struct {
onEndOfInput func()
// see docs/dev/Busy.md
newTask func() *gocui.Task
// A gocui task is not the same thing as the tasks defined in this file.
// A gocui task simply represents the fact that lazygit is busy doing something,
// whereas the tasks in this file are about rendering content to a view.
newGocuiTask func() gocui.Task
// if the user flicks through a heap of items, with each one
// spawning a process to render something to the main view,
@ -80,7 +83,7 @@ func NewViewBufferManager(
refreshView func(),
onEndOfInput func(),
onNewKey func(),
newTask func() *gocui.Task,
newGocuiTask func() gocui.Task,
) *ViewBufferManager {
return &ViewBufferManager{
Log: log,
@ -90,7 +93,7 @@ func NewViewBufferManager(
onEndOfInput: onEndOfInput,
readLines: make(chan LinesToRead, 1024),
onNewKey: onNewKey,
newTask: newTask,
newGocuiTask: newGocuiTask,
}
}
@ -296,7 +299,7 @@ type TaskOpts struct {
}
func (self *ViewBufferManager) NewTask(f func(TaskOpts) error, key string) error {
task := self.newTask()
task := self.newGocuiTask()
var completeTaskOnce sync.Once

View File

@ -20,11 +20,6 @@ func getCounter() (func(), func() int) {
return func() { counter++ }, func() int { return counter }
}
func getIncDecCounter(initialValue int) (func(), func(), func() int) {
counter := initialValue
return func() { counter++ }, func() { counter-- }, func() int { return counter }
}
func TestNewCmdTaskInstantStop(t *testing.T) {
writer := bytes.NewBuffer(nil)
beforeStart, getBeforeStartCallCount := getCounter()
@ -32,8 +27,8 @@ func TestNewCmdTaskInstantStop(t *testing.T) {
onEndOfInput, getOnEndOfInputCallCount := getCounter()
onNewKey, getOnNewKeyCallCount := getCounter()
onDone, getOnDoneCallCount := getCounter()
task := &gocui.Task{}
newTask := func() *gocui.Task {
task := gocui.NewFakeTask()
newTask := func() gocui.Task {
return task
}
@ -79,8 +74,8 @@ func TestNewCmdTaskInstantStop(t *testing.T) {
}
}
if getBusyCount() != 0 {
t.Errorf("expected busy count to be 0, got %d", getBusyCount())
if task.Status() != gocui.TaskStatusDone {
t.Errorf("expected task status to be 'done', got '%s'", task.FormatStatus())
}
expectedContent := ""
@ -97,7 +92,10 @@ func TestNewCmdTask(t *testing.T) {
onEndOfInput, getOnEndOfInputCallCount := getCounter()
onNewKey, getOnNewKeyCallCount := getCounter()
onDone, getOnDoneCallCount := getCounter()
incBusyCount, decBusyCount, getBusyCount := getIncDecCounter(1)
task := gocui.NewFakeTask()
newTask := func() gocui.Task {
return task
}
manager := NewViewBufferManager(
utils.NewDummyLog(),
@ -106,8 +104,7 @@ func TestNewCmdTask(t *testing.T) {
refreshView,
onEndOfInput,
onNewKey,
incBusyCount,
decBusyCount,
newTask,
)
stop := make(chan struct{})
@ -127,7 +124,7 @@ func TestNewCmdTask(t *testing.T) {
close(stop)
wg.Done()
}()
_ = fn(TaskOpts{Stop: stop, InitialContentLoaded: decBusyCount})
_ = fn(TaskOpts{Stop: stop, InitialContentLoaded: func() { task.Done() }})
wg.Wait()
@ -148,8 +145,8 @@ func TestNewCmdTask(t *testing.T) {
}
}
if getBusyCount() != 0 {
t.Errorf("expected busy count to be 0, got %d", getBusyCount())
if task.Status() != gocui.TaskStatusDone {
t.Errorf("expected task status to be 'done', got '%s'", task.FormatStatus())
}
expectedContent := "prefix\ntest\n"
@ -230,7 +227,10 @@ func TestNewCmdTaskRefresh(t *testing.T) {
lineCountsOnRefresh = append(lineCountsOnRefresh, strings.Count(writer.String(), "\n"))
}
decBusyCount := func() {}
task := gocui.NewFakeTask()
newTask := func() gocui.Task {
return task
}
manager := NewViewBufferManager(
utils.NewDummyLog(),
@ -239,8 +239,7 @@ func TestNewCmdTaskRefresh(t *testing.T) {
refreshView,
func() {},
func() {},
func() {},
decBusyCount,
newTask,
)
stop := make(chan struct{})
@ -260,7 +259,7 @@ func TestNewCmdTaskRefresh(t *testing.T) {
close(stop)
wg.Done()
}()
_ = fn(TaskOpts{Stop: stop, InitialContentLoaded: decBusyCount})
_ = fn(TaskOpts{Stop: stop, InitialContentLoaded: func() { task.Done() }})
wg.Wait()

View File

@ -177,87 +177,6 @@ type Gui struct {
taskManager *TaskManager
}
type TaskManager struct {
// Tracks whether the program is busy (i.e. either something is happening on
// the main goroutine or a worker goroutine). Used by integration tests
// to wait until the program is idle before progressing.
idleListeners []chan struct{}
tasks map[int]*Task
newTaskId int
tasksMutex sync.Mutex
}
func newTaskManager() *TaskManager {
return &TaskManager{
tasks: make(map[int]*Task),
idleListeners: []chan struct{}{},
}
}
func (self *TaskManager) NewTask() *Task {
self.tasksMutex.Lock()
defer self.tasksMutex.Unlock()
self.newTaskId++
taskId := self.newTaskId
withMutex := func(f func()) {
self.tasksMutex.Lock()
defer self.tasksMutex.Unlock()
f()
// Check if all tasks are done
for _, task := range self.tasks {
if task.isBusy {
return
}
}
// If we get here, all tasks are done, so
// notify listeners that the program is idle
for _, listener := range self.idleListeners {
listener <- struct{}{}
}
}
onDone := func() {
withMutex(func() {
delete(self.tasks, taskId)
})
}
task := &Task{id: taskId, isBusy: true, onDone: onDone, withMutex: withMutex}
self.tasks[taskId] = task
return task
}
func (self *TaskManager) AddIdleListener(c chan struct{}) {
self.idleListeners = append(self.idleListeners, c)
}
type Task struct {
id int
isBusy bool
onDone func()
withMutex func(func())
}
func (self *Task) Done() {
self.onDone()
}
func (self *Task) Pause() {
self.withMutex(func() {
self.isBusy = false
})
}
func (self *Task) Continue() {
self.withMutex(func() {
self.isBusy = true
})
}
// NewGui returns a new Gui object with a given output mode.
func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless bool, runeReplacements map[rune]string) (*Gui, error) {
g := &Gui{}
@ -314,7 +233,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless
return g, nil
}
func (g *Gui) NewTask() *Task {
func (g *Gui) NewTask() *TaskImpl {
return g.taskManager.NewTask()
}
@ -322,7 +241,7 @@ func (g *Gui) NewTask() *Task {
// integration tests which can wait for the program to be idle before taking
// the next step in the test.
func (g *Gui) AddIdleListener(c chan struct{}) {
g.taskManager.AddIdleListener(c)
g.taskManager.addIdleListener(c)
}
// Close finalizes the library. It should be called after a successful
@ -689,7 +608,7 @@ func getKey(key interface{}) (Key, rune, error) {
// userEvent represents an event triggered by the user.
type userEvent struct {
f func(*Gui) error
task *Task
task Task
}
// Update executes the passed function. This method can be called safely from a
@ -712,7 +631,7 @@ func (g *Gui) UpdateAsync(f func(*Gui) error) {
g.updateAsyncAux(f, task)
}
func (g *Gui) updateAsyncAux(f func(*Gui) error, task *Task) {
func (g *Gui) updateAsyncAux(f func(*Gui) error, task Task) {
g.userEvents <- userEvent{f: f, task: task}
}
@ -722,7 +641,7 @@ func (g *Gui) updateAsyncAux(f func(*Gui) error, task *Task) {
// consider itself 'busy` as it runs the code. Don't use for long-running
// background goroutines where you wouldn't want lazygit to be considered busy
// (i.e. when you wouldn't want a loader to be shown to the user)
func (g *Gui) OnWorker(f func(*Task)) {
func (g *Gui) OnWorker(f func(Task)) {
task := g.NewTask()
go func() {
g.onWorkerAux(f, task)
@ -730,7 +649,7 @@ func (g *Gui) OnWorker(f func(*Task)) {
}()
}
func (g *Gui) onWorkerAux(f func(*Task), task *Task) {
func (g *Gui) onWorkerAux(f func(Task), task Task) {
panicking := true
defer func() {
if panicking && Screen != nil {

94
vendor/github.com/jesseduffield/gocui/task.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
package gocui
// A task represents the fact that the program is busy doing something, which
// is useful for integration tests which only want to proceed when the program
// is idle.
type Task interface {
Done()
Pause()
Continue()
// not exporting because we don't need to
isBusy() bool
}
type TaskImpl struct {
id int
busy bool
onDone func()
withMutex func(func())
}
func (self *TaskImpl) Done() {
self.onDone()
}
func (self *TaskImpl) Pause() {
self.withMutex(func() {
self.busy = false
})
}
func (self *TaskImpl) Continue() {
self.withMutex(func() {
self.busy = true
})
}
func (self *TaskImpl) isBusy() bool {
return self.busy
}
type TaskStatus int
const (
TaskStatusBusy TaskStatus = iota
TaskStatusPaused
TaskStatusDone
)
type FakeTask struct {
status TaskStatus
}
func NewFakeTask() *FakeTask {
return &FakeTask{
status: TaskStatusBusy,
}
}
func (self *FakeTask) Done() {
self.status = TaskStatusDone
}
func (self *FakeTask) Pause() {
self.status = TaskStatusPaused
}
func (self *FakeTask) Continue() {
self.status = TaskStatusBusy
}
func (self *FakeTask) isBusy() bool {
return self.status == TaskStatusBusy
}
func (self *FakeTask) Status() TaskStatus {
return self.status
}
func (self *FakeTask) FormatStatus() string {
return formatTaskStatus(self.status)
}
func formatTaskStatus(status TaskStatus) string {
switch status {
case TaskStatusBusy:
return "busy"
case TaskStatusPaused:
return "paused"
case TaskStatusDone:
return "done"
}
return "unknown"
}

67
vendor/github.com/jesseduffield/gocui/task_manager.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
package gocui
import "sync"
// Tracks whether the program is busy (i.e. either something is happening on
// the main goroutine or a worker goroutine). Used by integration tests
// to wait until the program is idle before progressing.
type TaskManager struct {
// each of these listeners will be notified when the program goes from busy to idle
idleListeners []chan struct{}
tasks map[int]Task
// auto-incrementing id for new tasks
nextId int
mutex sync.Mutex
}
func newTaskManager() *TaskManager {
return &TaskManager{
tasks: make(map[int]Task),
idleListeners: []chan struct{}{},
}
}
func (self *TaskManager) NewTask() *TaskImpl {
self.mutex.Lock()
defer self.mutex.Unlock()
self.nextId++
taskId := self.nextId
onDone := func() { self.delete(taskId) }
task := &TaskImpl{id: taskId, busy: true, onDone: onDone, withMutex: self.withMutex}
self.tasks[taskId] = task
return task
}
func (self *TaskManager) addIdleListener(c chan struct{}) {
self.idleListeners = append(self.idleListeners, c)
}
func (self *TaskManager) withMutex(f func()) {
self.mutex.Lock()
defer self.mutex.Unlock()
f()
// Check if all tasks are done
for _, task := range self.tasks {
if task.isBusy() {
return
}
}
// If we get here, all tasks are done, so
// notify listeners that the program is idle
for _, listener := range self.idleListeners {
listener <- struct{}{}
}
}
func (self *TaskManager) delete(taskId int) {
self.withMutex(func() {
delete(self.tasks, taskId)
})
}

2
vendor/modules.txt vendored
View File

@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
# github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52
# github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b
## explicit; go 1.12
github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10