diff options
Diffstat (limited to 'pkg/tasks')
-rw-r--r-- | pkg/tasks/async_handler.go | 56 | ||||
-rw-r--r-- | pkg/tasks/async_handler_test.go | 44 |
2 files changed, 100 insertions, 0 deletions
diff --git a/pkg/tasks/async_handler.go b/pkg/tasks/async_handler.go new file mode 100644 index 000000000..897efb0e2 --- /dev/null +++ b/pkg/tasks/async_handler.go @@ -0,0 +1,56 @@ +package tasks + +import ( + "sync" + + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// the purpose of an AsyncHandler is to ensure that if we have multiple long-running +// requests, we only handle the result of the latest one. For example, if I am +// searching for 'abc' and I have to type 'a' then 'b' then 'c' and each keypress +// dispatches a request to search for things with the string so-far, we'll be searching +// for 'a', 'ab', and 'abc', and it may be that 'abc' comes back first, then 'ab', +// then 'a' and we don't want to display the result for 'a' just because it came +// back last. AsyncHandler keeps track of the order in which things were dispatched +// so that we can ignore anything that comes back late. +type AsyncHandler struct { + currentId int + lastId int + mutex sync.Mutex + onReject func() +} + +func NewAsyncHandler() *AsyncHandler { + return &AsyncHandler{ + mutex: sync.Mutex{}, + } +} + +func (self *AsyncHandler) Do(f func() func()) { + self.mutex.Lock() + self.currentId++ + id := self.currentId + self.mutex.Unlock() + + go utils.Safe(func() { + after := f() + self.handle(after, id) + }) +} + +// f here is expected to be a function that doesn't take long to run +func (self *AsyncHandler) handle(f func(), id int) { + self.mutex.Lock() + defer self.mutex.Unlock() + + if id < self.lastId { + if self.onReject != nil { + self.onReject() + } + return + } + + self.lastId = id + f() +} diff --git a/pkg/tasks/async_handler_test.go b/pkg/tasks/async_handler_test.go new file mode 100644 index 000000000..b6edbec20 --- /dev/null +++ b/pkg/tasks/async_handler_test.go @@ -0,0 +1,44 @@ +package tasks + +import ( + "fmt" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAsyncHandler(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(2) + + handler := NewAsyncHandler() + handler.onReject = func() { + wg.Done() + } + + result := 0 + + wg2 := sync.WaitGroup{} + wg2.Add(1) + + handler.Do(func() func() { + wg2.Wait() + return func() { + fmt.Println("setting to 1") + result = 1 + } + }) + handler.Do(func() func() { + return func() { + fmt.Println("setting to 2") + result = 2 + wg.Done() + wg2.Done() + } + }) + + wg.Wait() + + assert.EqualValues(t, 2, result) +} |