diff --git a/pkg/gocui/gui.go b/pkg/gocui/gui.go index ff113a2dd..a13744997 100644 --- a/pkg/gocui/gui.go +++ b/pkg/gocui/gui.go @@ -282,6 +282,13 @@ func (g *Gui) NewTask() *TaskImpl { return g.taskManager.NewTask(false) } +// NewBackgroundTask creates a task that is tracked for idle detection but does +// not count towards the program being busy for repo-switch safety. See +// TaskImpl.background. +func (g *Gui) NewBackgroundTask() *TaskImpl { + return g.taskManager.NewTask(true) +} + // Busy reports whether any foreground work is in flight, ignoring the event // currently being processed on the main goroutine (see currentTask). Background // routines (auto-fetch etc.) don't count. It's used to decide whether it's safe diff --git a/pkg/gocui/task.go b/pkg/gocui/task.go index 377781a4f..08a77463f 100644 --- a/pkg/gocui/task.go +++ b/pkg/gocui/task.go @@ -20,10 +20,14 @@ type TaskImpl struct { withMutex func(func()) // Background tasks don't count towards the program being "busy" for the // purpose of deciding whether a repo switch is safe (see - // TaskManager.hasBusyForegroundTaskExcept). They're the ongoing background - // routines (auto-fetch, files refresh, external-change detection) and the - // refreshes they trigger, whose model writes are already guarded against a - // concurrent repo switch by the repo generation. + // TaskManager.hasBusyForegroundTaskExcept). Two kinds of work are tagged + // this way: the ongoing background routines (auto-fetch, files refresh, + // external-change detection) and the refreshes they trigger, whose model + // writes are already guarded against a concurrent repo switch by the repo + // generation; and view-buffer content rendering, which only paints a view + // and so is harmless to leave running across a switch. What stays + // foreground is lazygit driving a git operation and applying its results + // to the model — exactly the work a repo switch must not run underneath. background bool } diff --git a/pkg/gui/tasks_adapter.go b/pkg/gui/tasks_adapter.go index 09edd2d36..dd7999107 100644 --- a/pkg/gui/tasks_adapter.go +++ b/pkg/gui/tasks_adapter.go @@ -136,7 +136,14 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager { view.SetOrigin(0, 0) }, func() gocui.Task { - return gui.c.GocuiGui().NewTask() + // A background task: rendering content into a view is display + // work, not lazygit driving a git operation, so it must not + // count towards being busy and block a repo switch. These + // renders fire on nearly every focus/selection change, including + // the context activation that happens right before a menu/prompt + // handler runs (e.g. confirming worktree creation), which would + // otherwise make the switch that handler triggers refuse itself. + return gui.c.GocuiGui().NewBackgroundTask() }, ) gui.viewBufferManagerMap[view.Name()] = manager