mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-03 00:57:52 +02:00
Refresh is one of those functions that shouldn't require error handling (similar to triggering a redraw of the UI, see https://github.com/jesseduffield/lazygit/issues/3887). As far as I see, the only reason why Refresh can currently return an error is that the Then function returns one. The actual refresh errors, e.g. from the git calls that are made to fetch data, are already logged and swallowed. Most of the Then functions do only UI stuff such as selecting a list item, and always return nil; there's only one that can return an error (updating the rebase todo file in LocalCommitsController.startInteractiveRebaseWithEdit); it's not a critical error if this fails, it is only used for setting rebase todo items to "edit" when you start an interactive rebase by pressing 'e' on a range selection of commits. We simply log this error instead of returning it.
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package gui
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/jesseduffield/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
type BackgroundRoutineMgr struct {
|
|
gui *Gui
|
|
|
|
// if we've suspended the gui (e.g. because we've switched to a subprocess)
|
|
// we typically want to pause some things that are running like background
|
|
// file refreshes
|
|
pauseBackgroundRefreshes bool
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) PauseBackgroundRefreshes(pause bool) {
|
|
self.pauseBackgroundRefreshes = pause
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) startBackgroundRoutines() {
|
|
userConfig := self.gui.UserConfig()
|
|
|
|
if userConfig.Git.AutoFetch {
|
|
fetchInterval := userConfig.Refresher.FetchInterval
|
|
if fetchInterval > 0 {
|
|
go utils.Safe(self.startBackgroundFetch)
|
|
} else {
|
|
self.gui.c.Log.Errorf(
|
|
"Value of config option 'refresher.fetchInterval' (%d) is invalid, disabling auto-fetch",
|
|
fetchInterval)
|
|
}
|
|
}
|
|
|
|
if userConfig.Git.AutoRefresh {
|
|
refreshInterval := userConfig.Refresher.RefreshInterval
|
|
if refreshInterval > 0 {
|
|
go utils.Safe(func() { self.startBackgroundFilesRefresh(refreshInterval) })
|
|
} else {
|
|
self.gui.c.Log.Errorf(
|
|
"Value of config option 'refresher.refreshInterval' (%d) is invalid, disabling auto-refresh",
|
|
refreshInterval)
|
|
}
|
|
}
|
|
|
|
if self.gui.Config.GetDebug() {
|
|
self.goEvery(time.Second*time.Duration(10), self.gui.stopChan, func() error {
|
|
formatBytes := func(b uint64) string {
|
|
const unit = 1000
|
|
if b < unit {
|
|
return fmt.Sprintf("%d B", b)
|
|
}
|
|
div, exp := uint64(unit), 0
|
|
for n := b / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
return fmt.Sprintf("%.1f %cB",
|
|
float64(b)/float64(div), "kMGTPE"[exp])
|
|
}
|
|
|
|
m := runtime.MemStats{}
|
|
runtime.ReadMemStats(&m)
|
|
self.gui.c.Log.Infof("Heap memory in use: %s", formatBytes(m.HeapAlloc))
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) startBackgroundFetch() {
|
|
self.gui.waitForIntro.Wait()
|
|
|
|
fetch := func() error {
|
|
return self.gui.helpers.AppStatus.WithWaitingStatusImpl(self.gui.Tr.FetchingStatus, func(gocui.Task) error {
|
|
return self.backgroundFetch()
|
|
}, nil)
|
|
}
|
|
|
|
// We want an immediate fetch at startup, and since goEvery starts by
|
|
// waiting for the interval, we need to trigger one manually first
|
|
_ = fetch()
|
|
|
|
userConfig := self.gui.UserConfig()
|
|
self.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), self.gui.stopChan, fetch)
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) startBackgroundFilesRefresh(refreshInterval int) {
|
|
self.gui.waitForIntro.Wait()
|
|
|
|
self.goEvery(time.Second*time.Duration(refreshInterval), self.gui.stopChan, func() error {
|
|
self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
|
|
done := make(chan struct{})
|
|
go utils.Safe(func() {
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
if self.pauseBackgroundRefreshes {
|
|
continue
|
|
}
|
|
self.gui.c.OnWorker(func(gocui.Task) error {
|
|
_ = function()
|
|
done <- struct{}{}
|
|
return nil
|
|
})
|
|
// waiting so that we don't bunch up refreshes if the refresh takes longer than the interval
|
|
<-done
|
|
case <-stop:
|
|
return
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func (self *BackgroundRoutineMgr) backgroundFetch() (err error) {
|
|
err = self.gui.git.Sync.FetchBackground()
|
|
|
|
self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.SYNC})
|
|
|
|
if err == nil {
|
|
err = self.gui.helpers.BranchesHelper.AutoForwardBranches()
|
|
}
|
|
|
|
return err
|
|
}
|