diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2023-07-09 21:09:52 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2023-07-10 17:12:21 +1000 |
commit | 6b9390409eb533fe87648be55e9db7d36b1d9ee3 (patch) | |
tree | 43e35b86a17dbee8aac245cc93c2645727b61148 /vendor | |
parent | 8964cedf27cbdb81f59e2400cfc89684d7458605 (diff) |
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
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/gui.go | 93 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/task.go | 94 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/task_manager.go | 67 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
4 files changed, 168 insertions, 88 deletions
diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 006761293..47590f959 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -177,87 +177,6 @@ type Gui struct { taskManager *TaskManager } -type TaskManager struct { - // Tracks whether the program is busy (i.e. either something is happening on - // the main goroutine or a worker goroutine). Used by integration tests - // to wait until the program is idle before progressing. - idleListeners []chan struct{} - tasks map[int]*Task - newTaskId int - tasksMutex sync.Mutex -} - -func newTaskManager() *TaskManager { - return &TaskManager{ - tasks: make(map[int]*Task), - idleListeners: []chan struct{}{}, - } -} - -func (self *TaskManager) NewTask() *Task { - self.tasksMutex.Lock() - defer self.tasksMutex.Unlock() - - self.newTaskId++ - taskId := self.newTaskId - - withMutex := func(f func()) { - self.tasksMutex.Lock() - defer self.tasksMutex.Unlock() - - f() - - // Check if all tasks are done - for _, task := range self.tasks { - if task.isBusy { - return - } - } - - // If we get here, all tasks are done, so - // notify listeners that the program is idle - for _, listener := range self.idleListeners { - listener <- struct{}{} - } - } - onDone := func() { - withMutex(func() { - delete(self.tasks, taskId) - }) - } - task := &Task{id: taskId, isBusy: true, onDone: onDone, withMutex: withMutex} - self.tasks[taskId] = task - - return task -} - -func (self *TaskManager) AddIdleListener(c chan struct{}) { - self.idleListeners = append(self.idleListeners, c) -} - -type Task struct { - id int - isBusy bool - onDone func() - withMutex func(func()) -} - -func (self *Task) Done() { - self.onDone() -} - -func (self *Task) Pause() { - self.withMutex(func() { - self.isBusy = false - }) -} - -func (self *Task) Continue() { - self.withMutex(func() { - self.isBusy = true - }) -} - // NewGui returns a new Gui object with a given output mode. func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless bool, runeReplacements map[rune]string) (*Gui, error) { g := &Gui{} @@ -314,7 +233,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless return g, nil } -func (g *Gui) NewTask() *Task { +func (g *Gui) NewTask() *TaskImpl { return g.taskManager.NewTask() } @@ -322,7 +241,7 @@ func (g *Gui) NewTask() *Task { // integration tests which can wait for the program to be idle before taking // the next step in the test. func (g *Gui) AddIdleListener(c chan struct{}) { - g.taskManager.AddIdleListener(c) + g.taskManager.addIdleListener(c) } // Close finalizes the library. It should be called after a successful @@ -689,7 +608,7 @@ func getKey(key interface{}) (Key, rune, error) { // userEvent represents an event triggered by the user. type userEvent struct { f func(*Gui) error - task *Task + task Task } // Update executes the passed function. This method can be called safely from a @@ -712,7 +631,7 @@ func (g *Gui) UpdateAsync(f func(*Gui) error) { g.updateAsyncAux(f, task) } -func (g *Gui) updateAsyncAux(f func(*Gui) error, task *Task) { +func (g *Gui) updateAsyncAux(f func(*Gui) error, task Task) { g.userEvents <- userEvent{f: f, task: task} } @@ -722,7 +641,7 @@ func (g *Gui) updateAsyncAux(f func(*Gui) error, task *Task) { // consider itself 'busy` as it runs the code. Don't use for long-running // background goroutines where you wouldn't want lazygit to be considered busy // (i.e. when you wouldn't want a loader to be shown to the user) -func (g *Gui) OnWorker(f func(*Task)) { +func (g *Gui) OnWorker(f func(Task)) { task := g.NewTask() go func() { g.onWorkerAux(f, task) @@ -730,7 +649,7 @@ func (g *Gui) OnWorker(f func(*Task)) { }() } -func (g *Gui) onWorkerAux(f func(*Task), task *Task) { +func (g *Gui) onWorkerAux(f func(Task), task Task) { panicking := true defer func() { if panicking && Screen != nil { diff --git a/vendor/github.com/jesseduffield/gocui/task.go b/vendor/github.com/jesseduffield/gocui/task.go new file mode 100644 index 000000000..ace72f4a8 --- /dev/null +++ b/vendor/github.com/jesseduffield/gocui/task.go @@ -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" +} diff --git a/vendor/github.com/jesseduffield/gocui/task_manager.go b/vendor/github.com/jesseduffield/gocui/task_manager.go new file mode 100644 index 000000000..e3c82b4d4 --- /dev/null +++ b/vendor/github.com/jesseduffield/gocui/task_manager.go @@ -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) + }) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4c89cd64e..88f05f458 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20230709105400-44d9f78b4b52 +# github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b ## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 |