mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 15:46:26 -04:00
Repo-switch safety needs to answer, synchronously on the UI thread, "is any foreground work in flight right now?" so it can refuse a switch that would run against a repo about to be swapped out. gocui already tracks a task per OnWorker/Update for the test idle-listener; extend that. Tasks gain a background flag: background tasks (the ongoing routines like auto-fetch, and the refreshes they trigger) don't count towards busy, because their model writes are already guarded against a concurrent switch by the repo generation. Add OnWorkerBackground, UpdateBackground and UpdateContentOnlyBackground (plus the gui-layer OnUIThreadBackground / OnUIThreadContentOnlyBackground / OnWorkerBackground on IGuiCommon) so the few background call sites can opt in without touching the hundreds of foreground callers. TaskManager.hasBusyForegroundTaskExcept answers the query; Gui.Busy() wraps it, excluding the event currently being processed (recorded as currentTask) so a handler asking the question doesn't count itself. Nothing gates on Busy() yet; this is the mechanism only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package gocui
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestTaskManagerHasBusyForegroundTaskExcept(t *testing.T) {
|
|
t.Run("no tasks", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(nil))
|
|
})
|
|
|
|
t.Run("a busy foreground task counts", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
tm.NewTask(false)
|
|
assert.True(t, tm.hasBusyForegroundTaskExcept(nil))
|
|
})
|
|
|
|
t.Run("a busy background task does not count", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
tm.NewTask(true)
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(nil))
|
|
})
|
|
|
|
t.Run("a done foreground task does not count", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
task := tm.NewTask(false)
|
|
task.Done()
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(nil))
|
|
})
|
|
|
|
t.Run("a paused foreground task does not count", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
task := tm.NewTask(false)
|
|
task.Pause()
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(nil))
|
|
})
|
|
|
|
t.Run("the ignored task does not count", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
task := tm.NewTask(false)
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(task))
|
|
})
|
|
|
|
t.Run("another foreground task counts even when one is ignored", func(t *testing.T) {
|
|
tm := newTaskManager()
|
|
ignored := tm.NewTask(false)
|
|
tm.NewTask(false)
|
|
assert.True(t, tm.hasBusyForegroundTaskExcept(ignored))
|
|
})
|
|
|
|
t.Run("only a background task alongside the ignored current event", func(t *testing.T) {
|
|
// This is the repo-switch case: the switch is handled as the current
|
|
// event (ignored) while a background refresh is in flight; it must not
|
|
// be considered busy.
|
|
tm := newTaskManager()
|
|
current := tm.NewTask(false)
|
|
tm.NewTask(true)
|
|
assert.False(t, tm.hasBusyForegroundTaskExcept(current))
|
|
})
|
|
}
|