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