1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +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/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d 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/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e 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/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 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/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.20230710004407-9bbfd873713b h1:8FmmdaYHes1m3oNyNdS+VIgkgkFpNZAWuwTnvp0tG14=
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/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 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= 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= 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() 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"). cmdArgs := NewGitCmd("push").
Arg(remoteName, "--delete", branchName). Arg(remoteName, "--delete", branchName).
ToArgv() ToArgv()

View File

@ -24,7 +24,7 @@ type PushOpts struct {
SetUpstream bool 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 == "" { if opts.UpstreamBranch != "" && opts.UpstreamRemote == "" {
return nil, errors.New(self.Tr.MustSpecifyOriginError) return nil, errors.New(self.Tr.MustSpecifyOriginError)
} }
@ -40,7 +40,7 @@ func (self *SyncCommands) PushCmdObj(task *gocui.Task, opts PushOpts) (oscommand
return cmdObj, nil 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) cmdObj, err := self.PushCmdObj(task, opts)
if err != nil { if err != nil {
return err return err
@ -49,24 +49,33 @@ func (self *SyncCommands) Push(task *gocui.Task, opts PushOpts) error {
return cmdObj.Run() return cmdObj.Run()
} }
func (self *SyncCommands) Fetch(task *gocui.Task) error { func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
cmdArgs := NewGitCmd("fetch"). cmdArgs := NewGitCmd("fetch").
ArgIf(self.UserConfig.Git.FetchAll, "--all"). ArgIf(self.UserConfig.Git.FetchAll, "--all").
ToArgv() ToArgv()
cmdObj := self.cmd.New(cmdArgs) cmdObj := self.cmd.New(cmdArgs)
cmdObj.PromptOnCredentialRequest(task) 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"). cmdArgs := NewGitCmd("fetch").
ArgIf(self.UserConfig.Git.FetchAll, "--all"). ArgIf(self.UserConfig.Git.FetchAll, "--all").
ToArgv() ToArgv()
cmdObj := self.cmd.New(cmdArgs) cmdObj := self.cmd.New(cmdArgs)
cmdObj.DontLog().FailOnCredentialRequest() 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 { type PullOptions struct {
@ -75,7 +84,7 @@ type PullOptions struct {
FastForwardOnly bool 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"). cmdArgs := NewGitCmd("pull").
Arg("--no-edit"). Arg("--no-edit").
ArgIf(opts.FastForwardOnly, "--ff-only"). 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() 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"). cmdArgs := NewGitCmd("fetch").
Arg(remoteName). Arg(remoteName).
Arg(remoteBranchName + ":" + branchName). 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() 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"). cmdArgs := NewGitCmd("fetch").
Arg(remoteName). Arg(remoteName).
ToArgv() ToArgv()

View File

@ -3,6 +3,7 @@ package git_commands
import ( import (
"testing" "testing"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -88,7 +89,8 @@ func TestSyncPush(t *testing.T) {
s := s s := s
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
instance := buildSyncCommands(commonDeps{}) 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) { func TestSyncFetch(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
opts FetchOptions
fetchAllConfig bool fetchAllConfig bool
test func(oscommands.ICmdObj) test func(oscommands.ICmdObj)
} }
@ -104,7 +105,6 @@ func TestSyncFetch(t *testing.T) {
scenarios := []scenario{ scenarios := []scenario{
{ {
testName: "Fetch in foreground (all=false)", testName: "Fetch in foreground (all=false)",
opts: FetchOptions{Background: false},
fetchAllConfig: false, fetchAllConfig: false,
test: func(cmdObj oscommands.ICmdObj) { test: func(cmdObj oscommands.ICmdObj) {
assert.True(t, cmdObj.ShouldLog()) assert.True(t, cmdObj.ShouldLog())
@ -114,7 +114,6 @@ func TestSyncFetch(t *testing.T) {
}, },
{ {
testName: "Fetch in foreground (all=true)", testName: "Fetch in foreground (all=true)",
opts: FetchOptions{Background: false},
fetchAllConfig: true, fetchAllConfig: true,
test: func(cmdObj oscommands.ICmdObj) { test: func(cmdObj oscommands.ICmdObj) {
assert.True(t, cmdObj.ShouldLog()) assert.True(t, cmdObj.ShouldLog())
@ -122,9 +121,29 @@ func TestSyncFetch(t *testing.T) {
assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--all"}) 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)", testName: "Fetch in background (all=false)",
opts: FetchOptions{Background: true},
fetchAllConfig: false, fetchAllConfig: false,
test: func(cmdObj oscommands.ICmdObj) { test: func(cmdObj oscommands.ICmdObj) {
assert.False(t, cmdObj.ShouldLog()) assert.False(t, cmdObj.ShouldLog())
@ -134,7 +153,6 @@ func TestSyncFetch(t *testing.T) {
}, },
{ {
testName: "Fetch in background (all=true)", testName: "Fetch in background (all=true)",
opts: FetchOptions{Background: true},
fetchAllConfig: true, fetchAllConfig: true,
test: func(cmdObj oscommands.ICmdObj) { test: func(cmdObj oscommands.ICmdObj) {
assert.False(t, cmdObj.ShouldLog()) assert.False(t, cmdObj.ShouldLog())
@ -149,7 +167,7 @@ func TestSyncFetch(t *testing.T) {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
instance := buildSyncCommands(commonDeps{}) instance := buildSyncCommands(commonDeps{})
instance.UserConfig.Git.FetchAll = s.fetchAllConfig 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() 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). cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
ToArgv() ToArgv()

View File

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

View File

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

View File

@ -4,6 +4,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -111,7 +112,8 @@ func TestProcessOutput(t *testing.T) {
reader := strings.NewReader(scenario.output) reader := strings.NewReader(scenario.output)
writer := &strings.Builder{} 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 { if writer.String() != scenario.expectedToWrite {
t.Errorf("expected to write '%s' but got '%s'", scenario.expectedToWrite, writer.String()) 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 { if self.pauseBackgroundRefreshes {
continue continue
} }
self.gui.c.OnWorker(func(*gocui.Task) { _ = function() }) self.gui.c.OnWorker(func(gocui.Task) { _ = function() })
case <-stop: case <-stop:
return 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() { if branch == self.c.Helpers().Refs.GetCheckedOutRef() {
self.c.LogAction(action) self.c.LogAction(action)

View File

@ -177,7 +177,7 @@ func (self *CommitFilesController) discard(node *filetree.CommitFileNode) error
Title: self.c.Tr.DiscardFileChangesTitle, Title: self.c.Tr.DiscardFileChangesTitle,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { 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) 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.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 { 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 { func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) error {
toggle := func() 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 !self.c.Git().Patch.PatchBuilder.Active() {
if err := self.startPatchBuilder(); err != nil { if err := self.startPatchBuilder(); err != nil {
return err return err

View File

@ -117,7 +117,7 @@ func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
return err 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() commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit) self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
err := self.c.Git().Patch.DeletePatchesFromCommit(self.c.Model().Commits, commitIndex) err := self.c.Git().Patch.DeletePatchesFromCommit(self.c.Model().Commits, commitIndex)
@ -134,7 +134,7 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() erro
return err 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() commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchToSelectedCommit) self.c.LogAction(self.c.Tr.Actions.MovePatchToSelectedCommit)
err := self.c.Git().Patch.MovePatchToSelectedCommit(self.c.Model().Commits, commitIndex, self.c.Contexts().LocalCommits.GetSelectedLineIdx()) 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 { 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() commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex) self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, stash) err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, stash)
@ -182,7 +182,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
return err 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() commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit) self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
err := self.c.Git().Patch.PullPatchIntoNewCommit(self.c.Model().Commits, commitIndex) 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 { 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 { if err := self.fetchAux(task); err != nil {
_ = self.c.Error(err) _ = 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") self.c.LogAction("Fetch")
err = self.c.Git().Sync.Fetch(task) 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 { 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) self.c.LogAction(self.c.Tr.Actions.ResetSubmodule)
file := self.c.Helpers().WorkingTree.FileForSubmodule(submodule) 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 // 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) { func (self *AppStatusHelper) WithWaitingStatus(message string, f func(gocui.Task) error) {
self.c.OnWorker(func(task *gocui.Task) { self.c.OnWorker(func(task gocui.Task) {
self.statusMgr().WithWaitingStatus(message, func() { self.statusMgr().WithWaitingStatus(message, func() {
self.renderAppStatus() self.renderAppStatus()
@ -50,7 +50,7 @@ func (self *AppStatusHelper) GetStatusString() string {
} }
func (self *AppStatusHelper) renderAppStatus() { func (self *AppStatusHelper) renderAppStatus() {
self.c.OnWorker(func(_ *gocui.Task) { self.c.OnWorker(func(_ gocui.Task) {
ticker := time.NewTicker(time.Millisecond * 50) ticker := time.NewTicker(time.Millisecond * 50)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C { for range ticker.C {

View File

@ -76,7 +76,7 @@ func (self *CherryPickHelper) Paste() error {
Title: self.c.Tr.CherryPick, Title: self.c.Tr.CherryPick,
Prompt: self.c.Tr.SureCherryPick, Prompt: self.c.Tr.SureCherryPick,
HandleConfirm: func() error { 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) self.c.LogAction(self.c.Tr.Actions.CherryPick)
err := self.c.Git().Rebase.CherryPickCommits(self.getData().CherryPickedCommits) err := self.c.Git().Rebase.CherryPickCommits(self.getData().CherryPickedCommits)
return self.rebaseHelper.CheckMergeOrRebase(err) 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 { 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 { if err := cmdObj.StreamOutput().Run(); err != nil {
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
return self.c.Error( return self.c.Error(

View File

@ -87,7 +87,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
refresh := func(f func()) { refresh := func(f func()) {
if options.Mode == types.ASYNC { if options.Mode == types.ASYNC {
self.c.OnWorker(func(t *gocui.Task) { self.c.OnWorker(func(t gocui.Task) {
f() f()
}) })
} else { } else {
@ -201,7 +201,7 @@ func getModeName(mode types.RefreshMode) string {
func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() { func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
switch self.c.State().GetRepoState().GetStartupStage() { switch self.c.State().GetRepoState().GetStartupStage() {
case types.INITIAL: case types.INITIAL:
self.c.OnWorker(func(_ *gocui.Task) { self.c.OnWorker(func(_ gocui.Task) {
_ = self.refreshReflogCommits() _ = self.refreshReflogCommits()
self.refreshBranches() self.refreshBranches()
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE) 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) 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 { 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 // 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 // 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 // if nothing has been typed because there'll be too much to display efficiently
func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*types.Suggestion { 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() trie := patricia.NewTrie()
// load every non-gitignored file in the repo // load every non-gitignored file in the repo
ignore, err := gitignore.FromGit() ignore, err := gitignore.FromGit()

View File

@ -38,7 +38,7 @@ func (self *UpdateHelper) CheckForUpdateInBackground() {
} }
func (self *UpdateHelper) CheckForUpdateInForeground() error { 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 { self.updater.CheckForNewUpdate(func(newVersion string, err error) error {
if err != nil { if err != nil {
return self.c.Error(err) return self.c.Error(err)
@ -54,7 +54,7 @@ func (self *UpdateHelper) CheckForUpdateInForeground() error {
} }
func (self *UpdateHelper) startUpdating(newVersion string) { 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) self.c.State().SetUpdating(true)
err := self.updater.Update(newVersion) err := self.updater.Update(newVersion)
return self.onUpdateFinish(err) return self.onUpdateFinish(err)

View File

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

View File

@ -118,7 +118,7 @@ func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch
Title: self.c.Tr.DeleteRemoteBranch, Title: self.c.Tr.DeleteRemoteBranch,
Prompt: message, Prompt: message,
HandleConfirm: func() error { 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) self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
err := self.c.Git().Remote.DeleteRemoteBranch(task, selectedBranch.RemoteName, selectedBranch.Name) err := self.c.Git().Remote.DeleteRemoteBranch(task, selectedBranch.RemoteName, selectedBranch.Name)
if err != nil { 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 { 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) err := self.c.Git().Sync.FetchRemote(task, remote.Name)
if err != nil { if err != nil {
_ = self.c.Error(err) _ = self.c.Error(err)

View File

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

View File

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

View File

@ -139,12 +139,12 @@ type PullFilesOptions struct {
} }
func (self *SyncController) PullAux(opts PullFilesOptions) error { 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) 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) self.c.LogAction(opts.Action)
err := self.c.Git().Sync.Pull( err := self.c.Git().Sync.Pull(
@ -167,7 +167,7 @@ type pushOpts struct {
} }
func (self *SyncController) pushAux(opts pushOpts) error { 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) self.c.LogAction(self.c.Tr.Actions.Push)
err := self.c.Git().Sync.Push( err := self.c.Git().Sync.Push(
task, task,

View File

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

View File

@ -248,7 +248,7 @@ func (self *UndoController) hardResetWithAutoStash(commitSha string, options har
Title: self.c.Tr.AutoStashTitle, Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt, Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error { 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 { if err := self.c.Git().Stash.Save(self.c.Tr.StashPrefix + commitSha); err != nil {
return self.c.Error(err) 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() return reset()
}) })
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -265,7 +265,7 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
loadingText = self.c.Tr.RunningCustomCommandStatus 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) self.c.LogAction(self.c.Tr.Actions.CustomCommand)
if customCommand.Stream { if customCommand.Stream {

View File

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

View File

@ -79,7 +79,7 @@ type IGuiCommon interface {
OnUIThread(f func() error) 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 // 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 // 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 // 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 // this struct and instead want to use another method above
@ -121,8 +121,8 @@ type IPopupHandler interface {
Confirm(opts ConfirmOpts) error Confirm(opts ConfirmOpts) error
// Shows a popup prompting the user for input. // Shows a popup prompting the user for input.
Prompt(opts PromptOpts) error Prompt(opts PromptOpts) error
WithLoaderPanel(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 WithWaitingStatus(message string, f func(gocui.Task) error) error
Menu(opts CreateMenuOptions) error Menu(opts CreateMenuOptions) error
Toast(message string) Toast(message string)
GetPromptInput() string GetPromptInput() string

View File

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

View File

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

View File

@ -50,7 +50,10 @@ type ViewBufferManager struct {
onEndOfInput func() onEndOfInput func()
// see docs/dev/Busy.md // 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 // if the user flicks through a heap of items, with each one
// spawning a process to render something to the main view, // spawning a process to render something to the main view,
@ -80,7 +83,7 @@ func NewViewBufferManager(
refreshView func(), refreshView func(),
onEndOfInput func(), onEndOfInput func(),
onNewKey func(), onNewKey func(),
newTask func() *gocui.Task, newGocuiTask func() gocui.Task,
) *ViewBufferManager { ) *ViewBufferManager {
return &ViewBufferManager{ return &ViewBufferManager{
Log: log, Log: log,
@ -90,7 +93,7 @@ func NewViewBufferManager(
onEndOfInput: onEndOfInput, onEndOfInput: onEndOfInput,
readLines: make(chan LinesToRead, 1024), readLines: make(chan LinesToRead, 1024),
onNewKey: onNewKey, onNewKey: onNewKey,
newTask: newTask, newGocuiTask: newGocuiTask,
} }
} }
@ -296,7 +299,7 @@ type TaskOpts struct {
} }
func (self *ViewBufferManager) NewTask(f func(TaskOpts) error, key string) error { func (self *ViewBufferManager) NewTask(f func(TaskOpts) error, key string) error {
task := self.newTask() task := self.newGocuiTask()
var completeTaskOnce sync.Once var completeTaskOnce sync.Once

View File

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

View File

@ -177,87 +177,6 @@ type Gui struct {
taskManager *TaskManager 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. // 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) { func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless bool, runeReplacements map[rune]string) (*Gui, error) {
g := &Gui{} g := &Gui{}
@ -314,7 +233,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless
return g, nil return g, nil
} }
func (g *Gui) NewTask() *Task { func (g *Gui) NewTask() *TaskImpl {
return g.taskManager.NewTask() 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 // integration tests which can wait for the program to be idle before taking
// the next step in the test. // the next step in the test.
func (g *Gui) AddIdleListener(c chan struct{}) { 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 // 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. // userEvent represents an event triggered by the user.
type userEvent struct { type userEvent struct {
f func(*Gui) error f func(*Gui) error
task *Task task Task
} }
// Update executes the passed function. This method can be called safely from a // 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) 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} 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 // 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 // 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) // (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() task := g.NewTask()
go func() { go func() {
g.onWorkerAux(f, task) 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 panicking := true
defer func() { defer func() {
if panicking && Screen != nil { 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/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder 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 ## explicit; go 1.12
github.com/jesseduffield/gocui github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10