summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-07-09 11:32:27 +1000
committerJesse Duffield <jessedduffield@gmail.com>2023-07-09 21:30:19 +1000
commit14ecc15e71f648a95dab297ce9360d0badb6669a (patch)
tree8a60cc5a3e9836688e6e1943266541a76628b141
parent9e79ee5fe36dc849479ce8f3b05e7cca56c7c216 (diff)
Use first class task objects instead of global counter
The global counter approach is easy to understand but it's brittle and depends on implicit behaviour that is not very discoverable. With a global counter, if any goroutine accidentally decrements the counter twice, we'll think lazygit is idle when it's actually busy. Likewise if a goroutine accidentally increments the counter twice we'll think lazygit is busy when it's actually idle. With the new approach we have a map of tasks where each task can either be busy or not. We create a new task and add it to the map when we spawn a worker goroutine (among other things) and we remove it once the task is done. The task can also be paused and continued for situations where we switch back and forth between running a program and asking for user input. In order for this to work with `git push` (and other commands that require credentials) we need to obtain the task from gocui when we create the worker goroutine, and then pass it along to the commands package to pause/continue the task as required. This is MUCH more discoverable than the old approach which just decremented and incremented the global counter from within the commands package, but it's at the cost of expanding some function signatures (arguably a good thing). Likewise, whenever you want to call WithWaitingStatus or WithLoaderPanel the callback will now have access to the task for pausing/ continuing. We only need to actually make use of this functionality in a couple of places so it's a high price to pay, but I don't know if I want to introduce a WithWaitingStatusTask and WithLoaderPanelTask function (open to suggestions).
-rw-r--r--docs/dev/Busy.md38
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--pkg/commands/git_commands/remote.go6
-rw-r--r--pkg/commands/git_commands/sync.go47
-rw-r--r--pkg/commands/git_commands/tag.go6
-rw-r--r--pkg/commands/oscommands/cmd_obj.go12
-rw-r--r--pkg/commands/oscommands/cmd_obj_runner.go12
-rw-r--r--pkg/commands/oscommands/gui_io.go9
-rw-r--r--pkg/gui/background.go6
-rw-r--r--pkg/gui/controllers/branches_controller.go6
-rw-r--r--pkg/gui/controllers/commits_files_controller.go4
-rw-r--r--pkg/gui/controllers/custom_patch_options_menu_action.go9
-rw-r--r--pkg/gui/controllers/files_controller.go9
-rw-r--r--pkg/gui/controllers/files_remove_controller.go3
-rw-r--r--pkg/gui/controllers/helpers/app_status_helper.go9
-rw-r--r--pkg/gui/controllers/helpers/cherry_pick_helper.go3
-rw-r--r--pkg/gui/controllers/helpers/gpg_helper.go3
-rw-r--r--pkg/gui/controllers/helpers/refresh_helper.go7
-rw-r--r--pkg/gui/controllers/helpers/refs_helper.go3
-rw-r--r--pkg/gui/controllers/helpers/suggestions_helper.go3
-rw-r--r--pkg/gui/controllers/helpers/update_helper.go5
-rw-r--r--pkg/gui/controllers/local_commits_controller.go27
-rw-r--r--pkg/gui/controllers/remote_branches_controller.go5
-rw-r--r--pkg/gui/controllers/remotes_controller.go5
-rw-r--r--pkg/gui/controllers/sub_commits_controller.go3
-rw-r--r--pkg/gui/controllers/submodules_controller.go15
-rw-r--r--pkg/gui/controllers/sync_controller.go24
-rw-r--r--pkg/gui/controllers/tags_controller.go5
-rw-r--r--pkg/gui/controllers/undo_controller.go5
-rw-r--r--pkg/gui/gui.go14
-rw-r--r--pkg/gui/gui_common.go2
-rw-r--r--pkg/gui/popup/fake_popup_handler.go13
-rw-r--r--pkg/gui/popup/popup_handler.go16
-rw-r--r--pkg/gui/services/custom_commands/handler_creator.go3
-rw-r--r--pkg/gui/tasks_adapter.go5
-rw-r--r--pkg/gui/types/common.go6
-rw-r--r--pkg/tasks/async_handler.go7
-rw-r--r--pkg/tasks/async_handler_test.go5
-rw-r--r--pkg/tasks/tasks.go38
-rw-r--r--pkg/tasks/tasks_test.go11
-rw-r--r--vendor/github.com/jesseduffield/gocui/gui.go150
-rw-r--r--vendor/modules.txt2
43 files changed, 320 insertions, 247 deletions
diff --git a/docs/dev/Busy.md b/docs/dev/Busy.md
index ce7a08e13..309f2d25d 100644
--- a/docs/dev/Busy.md
+++ b/docs/dev/Busy.md
@@ -25,27 +25,27 @@ First, it's important to distinguish three different types of goroutines:
The point of distinguishing worker goroutines from background goroutines is that when any worker goroutine is running, we consider Lazygit to be 'busy', whereas this is not the case with background goroutines. It would be pointless to have background goroutines be considered 'busy' because then Lazygit would be considered busy for the entire duration of the program!
-Lazygit is considered to be 'busy' so long as the counter remains greater than zero, and as soon as it hits zero, Lazygit is considered 'idle' and the integration test is notified. So it's important that we play by the rules below to ensure that after the user does anything, all the processing that follows happens in a contiguous block of busy-ness with no gaps.
+In gocui, the underlying package we use for managing the UI and events, we keep track of how many busy goroutines there are using the `Task` type. A task represents some work being done by lazygit. The gocui Gui struct holds a map of tasks and allows creating a new task (which adds it to the map), pausing/continuing a task, and marking a task as done (which removes it from the map). Lazygit is considered to be busy so long as there is at least one busy task in the map; otherwise it's considered idle. When Lazygit goes from busy to idle, it notifies the integration test.
-In gocui, the underlying package we use for managing the UI and events, we keep track of how many busy goroutines there are with a `busyCount` counter.
+It's important that we play by the rules below to ensure that after the user does anything, all the processing that follows happens in a contiguous block of busy-ness with no gaps.
### Spawning a worker goroutine
-Here's the basic implementation of `OnWorker`:
+Here's the basic implementation of `OnWorker` (using the same flow as `WaitGroup`s):
```go
-func (g *Gui) OnWorker(f func()) {
- g.IncrementBusyCount()
+func (g *Gui) OnWorker(f func(*Task)) {
+ task := g.NewTask()
go func() {
- f()
- g.DecrementBusyCount()
+ f(task)
+ task.Done()
}()
}
```
-The crucial thing here is that we increment the busy count _before_ spawning the goroutine, because it means that our counter never goes to zero while there's still work being done. If we incremented the busy count within the goroutine, the current function could exit and decrement the counter to zero before the goroutine starts.
+The crucial thing here is that we create the task _before_ spawning the goroutine, because it means that we'll have at least one busy task in the map until the completion of the goroutine. If we created the task within the goroutine, the current function could exit and Lazygit would be considered idle before the goroutine starts, leading to our integration test prematurely progressing.
-You typically invoke this with `self.c.OnWorker(f)`
+You typically invoke this with `self.c.OnWorker(f)`. Note that the callback function receives the task. This allows the callback to pause/continue the task (see below).
### Spawning a background goroutine
@@ -59,30 +59,20 @@ Where `utils.Safe` is a helper function that ensures we clean up the gui if the
### Programmatically enqueing a UI event
-This is invoked with `self.c.OnUIThread(f)`. Internally, it increments the counter before enqueuing the function as an event and once that event is processed by the event queue (and any other pending events are processed) the counter is decremented again.
+This is invoked with `self.c.OnUIThread(f)`. Internally, it creates a task before enqueuing the function as an event (including the task in the event struct) and once that event is processed by the event queue (and any other pending events are processed) the task is removed from the map by calling `task.Done()`.
### Pressing a key
-If the user presses a key, an event will be enqueued automatically and the counter will be incremented before (and decremented after) the event is processed.
+If the user presses a key, an event will be enqueued automatically and a task will be created before (and `Done`'d after) the event is processed.
## Special cases
-There are a couple of special cases where we manually increment/decrement the counter in the code. These are subject to change but for the sake of completeness:
+There are a couple of special cases where we manually pause/continue the task directly in the client code. These are subject to change but for the sake of completeness:
### Writing to the main view(s)
-If the user focuses a file in the files panel, we run a `git diff` command for that file and write the output to the main view. But we only read enough of the command's output to fill the view's viewport: further loading only happens if the user scrolls. Given that we have a background goroutine for running the command and writing more output upon scrolling, we manually increment the busy count within that goroutine and then decrement it once the viewport is filled.
+If the user focuses a file in the files panel, we run a `git diff` command for that file and write the output to the main view. But we only read enough of the command's output to fill the view's viewport: further loading only happens if the user scrolls. Given that we have a background goroutine for running the command and writing more output upon scrolling, we create our own task and call `Done` on it as soon as the viewport is filled.
### Requesting credentials from a git command
-Some git commands (e.g. git push) may request credentials. This is the same deal as above; we use a background goroutine and manually increment/decrement the counter as we go from waiting on the git command to waiting on user input.
-
-## Future improvements
-
-### Better API
-
-The current approach is fairly simple in terms of the API which, except for the special cases above, encapsulates the incrementing/decrementing of the busy counter. But the counter is a form of global state and in future we may switch to an API where we have objects representing a task in progress, and those objects have `Start()`, `Finish()`, and `Pause()` methods. This would better defend against bugs caused by a random goroutine accidentally decrementing twice, for example.
-
-### More applications
-
-We could use the concept of idle/busy to show a loader whenever Lazygit is busy. But our current situation is pretty good: we have the `WithWaitingStatus()` method for running a function on a worker goroutine along with a message to show within the loader e.g. 'Refreshing branches'. If we find a situation where we're a function is taking a while and a loader isn't appearing, that's because we're running the code on the UI goroutine and we should just wrap the code in `WithWaitingStatus()`.
+Some git commands (e.g. git push) may request credentials. This is the same deal as above; we use a worker goroutine and manually pause continue its task as we go from waiting on the git command to waiting on user input. This requires passing the task through to the `Push` method so that it can be paused/continued.
diff --git a/go.mod b/go.mod
index 044b85718..abb696dad 100644
--- a/go.mod
+++ b/go.mod
@@ -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.20230708122437-f7e1c7c16828
+ github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52
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
diff --git a/go.sum b/go.sum
index 431555a65..5d283df8b 100644
--- a/go.sum
+++ b/go.sum
@@ -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.20230708122437-f7e1c7c16828 h1:1Eos/Z+6/JhXZ9qsniKpKqLsf/z7dSoP2EBfK7T2Mic=
-github.com/jesseduffield/gocui v0.3.1-0.20230708122437-f7e1c7c16828/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
+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/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=
diff --git a/pkg/commands/git_commands/remote.go b/pkg/commands/git_commands/remote.go
index b594db28c..4366ba539 100644
--- a/pkg/commands/git_commands/remote.go
+++ b/pkg/commands/git_commands/remote.go
@@ -2,6 +2,8 @@ package git_commands
import (
"fmt"
+
+ "github.com/jesseduffield/gocui"
)
type RemoteCommands struct {
@@ -46,12 +48,12 @@ func (self *RemoteCommands) UpdateRemoteUrl(remoteName string, updatedUrl string
return self.cmd.New(cmdArgs).Run()
}
-func (self *RemoteCommands) DeleteRemoteBranch(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()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
// CheckRemoteBranchExists Returns remote branch
diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go
index dc0a0c68c..901133c4d 100644
--- a/pkg/commands/git_commands/sync.go
+++ b/pkg/commands/git_commands/sync.go
@@ -2,6 +2,7 @@ package git_commands
import (
"github.com/go-errors/errors"
+ "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
)
@@ -23,7 +24,7 @@ type PushOpts struct {
SetUpstream bool
}
-func (self *SyncCommands) PushCmdObj(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)
}
@@ -35,12 +36,12 @@ func (self *SyncCommands) PushCmdObj(opts PushOpts) (oscommands.ICmdObj, error)
ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
ToArgv()
- cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest().WithMutex(self.syncMutex)
+ cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex)
return cmdObj, nil
}
-func (self *SyncCommands) Push(opts PushOpts) error {
- cmdObj, err := self.PushCmdObj(opts)
+func (self *SyncCommands) Push(task *gocui.Task, opts PushOpts) error {
+ cmdObj, err := self.PushCmdObj(task, opts)
if err != nil {
return err
}
@@ -48,28 +49,24 @@ func (self *SyncCommands) Push(opts PushOpts) error {
return cmdObj.Run()
}
-type FetchOptions struct {
- Background bool
-}
-
-// Fetch fetch git repo
-func (self *SyncCommands) FetchCmdObj(opts FetchOptions) oscommands.ICmdObj {
+func (self *SyncCommands) Fetch(task *gocui.Task) error {
cmdArgs := NewGitCmd("fetch").
ArgIf(self.UserConfig.Git.FetchAll, "--all").
ToArgv()
cmdObj := self.cmd.New(cmdArgs)
- if opts.Background {
- cmdObj.DontLog().FailOnCredentialRequest()
- } else {
- cmdObj.PromptOnCredentialRequest()
- }
- return cmdObj.WithMutex(self.syncMutex)
+ cmdObj.PromptOnCredentialRequest(task)
+ return cmdObj.WithMutex(self.syncMutex).Run()
}
-func (self *SyncCommands) Fetch(opts FetchOptions) error {
- cmdObj := self.FetchCmdObj(opts)
- return cmdObj.Run()
+func (self *SyncCommands) FetchBackground() error {
+ cmdArgs := NewGitCmd("fetch").
+ ArgIf(self.UserConfig.Git.FetchAll, "--all").
+ ToArgv()
+
+ cmdObj := self.cmd.New(cmdArgs)
+ cmdObj.DontLog().FailOnCredentialRequest()
+ return cmdObj.WithMutex(self.syncMutex).Run()
}
type PullOptions struct {
@@ -78,7 +75,7 @@ type PullOptions struct {
FastForwardOnly bool
}
-func (self *SyncCommands) Pull(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,22 +85,22 @@ func (self *SyncCommands) Pull(opts PullOptions) error {
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
// has 'pull.rebase = interactive' configured.
- return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest().WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
-func (self *SyncCommands) FastForward(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).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
-func (self *SyncCommands) FetchRemote(remoteName string) error {
+func (self *SyncCommands) FetchRemote(task *gocui.Task, remoteName string) error {
cmdArgs := NewGitCmd("fetch").
Arg(remoteName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
diff --git a/pkg/commands/git_commands/tag.go b/pkg/commands/git_commands/tag.go
index f399a578a..e58e81d07 100644
--- a/pkg/commands/git_commands/tag.go
+++ b/pkg/commands/git_commands/tag.go
@@ -1,5 +1,7 @@
package git_commands
+import "github.com/jesseduffield/gocui"
+
type TagCommands struct {
*GitCommon
}
@@ -34,9 +36,9 @@ func (self *TagCommands) Delete(tagName string) error {
return self.cmd.New(cmdArgs).Run()
}
-func (self *TagCommands) Push(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()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
}
diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go
index b1223ea00..a46fe9699 100644
--- a/pkg/commands/oscommands/cmd_obj.go
+++ b/pkg/commands/oscommands/cmd_obj.go
@@ -4,6 +4,7 @@ import (
"os/exec"
"strings"
+ "github.com/jesseduffield/gocui"
"github.com/samber/lo"
"github.com/sasha-s/go-deadlock"
)
@@ -56,13 +57,14 @@ type ICmdObj interface {
// returns true if IgnoreEmptyError() was called
ShouldIgnoreEmptyError() bool
- PromptOnCredentialRequest() ICmdObj
+ PromptOnCredentialRequest(task *gocui.Task) ICmdObj
FailOnCredentialRequest() ICmdObj
WithMutex(mutex *deadlock.Mutex) ICmdObj
Mutex() *deadlock.Mutex
GetCredentialStrategy() CredentialStrategy
+ GetTask() *gocui.Task
}
type CmdObj struct {
@@ -85,6 +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
// can be set so that we don't run certain commands simultaneously
mutex *deadlock.Mutex
@@ -192,8 +195,9 @@ func (self *CmdObj) RunAndProcessLines(onLine func(line string) (bool, error)) e
return self.runner.RunAndProcessLines(self, onLine)
}
-func (self *CmdObj) PromptOnCredentialRequest() ICmdObj {
+func (self *CmdObj) PromptOnCredentialRequest(task *gocui.Task) ICmdObj {
self.credentialStrategy = PROMPT
+ self.task = task
return self
}
@@ -207,3 +211,7 @@ func (self *CmdObj) FailOnCredentialRequest() ICmdObj {
func (self *CmdObj) GetCredentialStrategy() CredentialStrategy {
return self.credentialStrategy
}
+
+func (self *CmdObj) GetTask() *gocui.Task {
+ return self.task
+}
diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go
index 55cf1e1ce..fc1c55f05 100644
--- a/pkg/commands/oscommands/cmd_obj_runner.go
+++ b/pkg/commands/oscommands/cmd_obj_runner.go
@@ -8,6 +8,7 @@ import (
"strings"
"github.com/go-errors/errors"
+ "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/sirupsen/logrus"
)
@@ -308,7 +309,7 @@ func (self *cmdObjRunner) runAndDetectCredentialRequest(
tr := io.TeeReader(handler.stdoutPipe, cmdWriter)
go utils.Safe(func() {
- self.processOutput(tr, handler.stdinPipe, promptUserForCredential)
+ self.processOutput(tr, handler.stdinPipe, promptUserForCredential, cmdObj.GetTask())
})
})
}
@@ -317,6 +318,7 @@ func (self *cmdObjRunner) processOutput(
reader io.Reader,
writer io.Writer,
promptUserForCredential func(CredentialType) <-chan string,
+ task *gocui.Task,
) {
checkForCredentialRequest := self.getCheckForCredentialRequestFunc()
@@ -327,13 +329,9 @@ func (self *cmdObjRunner) processOutput(
askFor, ok := checkForCredentialRequest(newBytes)
if ok {
responseChan := promptUserForCredential(askFor)
- // We assume that the busy count is greater than zero here because we're
- // in the middle of a command. We decrement it so that The user can be prompted
- // without lazygit thinking it's still doing its own processing. This helps
- // integration tests know how long to wait before typing in a response.
- self.guiIO.DecrementBusyCount()
+ task.Pause()
toInput := <-responseChan
- self.guiIO.IncrementBusyCount()
+ task.Continue()
// If the return data is empty we don't write anything to stdin
if toInput != "" {
_, _ = writer.Write([]byte(toInput))
diff --git a/pkg/commands/oscommands/gui_io.go b/pkg/commands/oscommands/gui_io.go
index 1ff090052..6a6198310 100644
--- a/pkg/commands/oscommands/gui_io.go
+++ b/pkg/commands/oscommands/gui_io.go
@@ -27,9 +27,6 @@ type guiIO struct {
// that a command requests it.
// the 'credential' arg is something like 'username' or 'password'
promptForCredentialFn func(credential CredentialType) <-chan string
-
- IncrementBusyCount func()
- DecrementBusyCount func()
}
func NewGuiIO(
@@ -37,16 +34,12 @@ func NewGuiIO(
logCommandFn func(string, bool),
newCmdWriterFn func() io.Writer,
promptForCredentialFn func(CredentialType) <-chan string,
- IncrementBusyCount func(),
- DecrementBusyCount func(),
) *guiIO {
return &guiIO{
log: log,
logCommandFn: logCommandFn,
newCmdWriterFn: newCmdWriterFn,
promptForCredentialFn: promptForCredentialFn,
- IncrementBusyCount: IncrementBusyCount,
- DecrementBusyCount: DecrementBusyCount,
}
}
@@ -58,7 +51,5 @@ func NewNullGuiIO(log *logrus.Entry) *guiIO {
logCommandFn: func(string, bool) {},
newCmdWriterFn: func() io.Writer { return io.Discard },
promptForCredentialFn: failPromptFn,
- IncrementBusyCount: func() {},
- DecrementBusyCount: func() {},
}
}
diff --git a/pkg/gui/background.go b/pkg/gui/background.go
index d789f1790..3417d67bf 100644
--- a/pkg/gui/background.go
+++ b/pkg/gui/background.go
@@ -4,7 +4,7 @@ import (
"strings"
"time"
- "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
+ "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@@ -86,7 +86,7 @@ func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan stru
if self.pauseBackgroundRefreshes {
continue
}
- self.gui.c.OnWorker(func() { _ = function() })
+ self.gui.c.OnWorker(func(*gocui.Task) { _ = function() })
case <-stop:
return
}
@@ -95,7 +95,7 @@ func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan stru
}
func (self *BackgroundRoutineMgr) backgroundFetch() (err error) {
- err = self.gui.git.Sync.Fetch(git_commands.FetchOptions{Background: true})
+ err = self.gui.git.Sync.FetchBackground()
_ = self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC})
diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go
index 972ea6090..d0ef6ee69 100644
--- a/pkg/gui/controllers/branches_controller.go
+++ b/pkg/gui/controllers/branches_controller.go
@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
+ "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
@@ -363,11 +364,12 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
},
)
- return self.c.WithLoaderPanel(message, func() error {
+ return self.c.WithLoaderPanel(message, func(task *gocui.Task) error {
if branch == self.c.Helpers().Refs.GetCheckedOutRef() {
self.c.LogAction(action)
err := self.c.Git().Sync.Pull(
+ task,
git_commands.PullOptions{
RemoteName: branch.UpstreamRemote,
BranchName: branch.UpstreamBranch,
@@ -381,7 +383,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
} else {
self.c.LogAction(action)
- err := self.c.Git().Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch)
+ err := self.c.Git().Sync.FastForward(task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch)
if err != nil {
_ = self.c.Error(err)
}
diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go
index 745186df0..f7208012e 100644
--- a/pkg/gui/controllers/commits_files_controller.go
+++ b/pkg/gui/controllers/commits_files_controller.go