Skip to content

Commit 9f930ee

Browse files
authored
Trigger immediate background fetch when switching repos (#5047)
If background fetching is on (which it is by default), we usually run the first background fetch right after opening lazygit, which is nice because it immediately fetches all the stuff that's new. However, when switching to a different repo from within lazygit (either with the recent repos menu or by going into or out of a submodule) we didn't do that, and you'd have to wait for the next regular background fetch to come along. I'm finding myself pressing `f` in the Files panel to manually fetch after entering a submodule, and I shouldn't have to do that. This PR makes it so that when you switch repos, we trigger a background fetch immediately (unless the last one for this repo was less than the auto-fetch interval ago, in which case it's unnecessary).
2 parents ce76222 + 2af56de commit 9f930ee

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

pkg/config/user_config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ type RefresherConfig struct {
4949
FetchInterval int `yaml:"fetchInterval" jsonschema:"minimum=0"`
5050
}
5151

52+
func (c *RefresherConfig) RefreshIntervalDuration() time.Duration {
53+
return time.Second * time.Duration(c.RefreshInterval)
54+
}
55+
56+
func (c *RefresherConfig) FetchIntervalDuration() time.Duration {
57+
return time.Second * time.Duration(c.FetchInterval)
58+
}
59+
5260
type GuiConfig struct {
5361
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color
5462
AuthorColors map[string]string `yaml:"authorColors"`

pkg/gui/background.go

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ type BackgroundRoutineMgr struct {
1717
// we typically want to pause some things that are running like background
1818
// file refreshes
1919
pauseBackgroundRefreshes bool
20+
21+
// a channel to trigger an immediate background fetch; we use this when switching repos
22+
triggerFetch chan struct{}
2023
}
2124

2225
func (self *BackgroundRoutineMgr) PauseBackgroundRefreshes(pause bool) {
@@ -40,7 +43,7 @@ func (self *BackgroundRoutineMgr) startBackgroundRoutines() {
4043
if userConfig.Git.AutoRefresh {
4144
refreshInterval := userConfig.Refresher.RefreshInterval
4245
if refreshInterval > 0 {
43-
go utils.Safe(func() { self.startBackgroundFilesRefresh(refreshInterval) })
46+
go utils.Safe(self.startBackgroundFilesRefresh)
4447
} else {
4548
self.gui.c.Log.Errorf(
4649
"Value of config option 'refresher.refreshInterval' (%d) is invalid, disabling auto-refresh",
@@ -76,6 +79,16 @@ func (self *BackgroundRoutineMgr) startBackgroundFetch() {
7679
self.gui.waitForIntro.Wait()
7780

7881
fetch := func() error {
82+
// Do this on the UI thread so that we don't have to deal with synchronization around the
83+
// access of the repo state.
84+
self.gui.onUIThread(func() error {
85+
// There's a race here, where we might be recording the time stamp for a different repo
86+
// than where the fetch actually ran. It's not very likely though, and not harmful if it
87+
// does happen; guarding against it would be more effort than it's worth.
88+
self.gui.State.LastBackgroundFetchTime = time.Now()
89+
return nil
90+
})
91+
7992
return self.gui.helpers.AppStatus.WithWaitingStatusImpl(self.gui.Tr.FetchingStatus, func(gocui.Task) error {
8093
return self.backgroundFetch()
8194
}, nil)
@@ -86,41 +99,53 @@ func (self *BackgroundRoutineMgr) startBackgroundFetch() {
8699
_ = fetch()
87100

88101
userConfig := self.gui.UserConfig()
89-
self.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), self.gui.stopChan, fetch)
102+
self.triggerFetch = self.goEvery(userConfig.Refresher.FetchIntervalDuration(), self.gui.stopChan, fetch)
90103
}
91104

92-
func (self *BackgroundRoutineMgr) startBackgroundFilesRefresh(refreshInterval int) {
105+
func (self *BackgroundRoutineMgr) startBackgroundFilesRefresh() {
93106
self.gui.waitForIntro.Wait()
94107

95-
self.goEvery(time.Second*time.Duration(refreshInterval), self.gui.stopChan, func() error {
108+
userConfig := self.gui.UserConfig()
109+
self.goEvery(userConfig.Refresher.RefreshIntervalDuration(), self.gui.stopChan, func() error {
96110
self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
97111
return nil
98112
})
99113
}
100114

101-
func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
115+
// returns a channel that can be used to trigger the callback immediately
116+
func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan struct{}, function func() error) chan struct{} {
102117
done := make(chan struct{})
118+
retrigger := make(chan struct{})
103119
go utils.Safe(func() {
104120
ticker := time.NewTicker(interval)
105121
defer ticker.Stop()
122+
doit := func() {
123+
if self.pauseBackgroundRefreshes {
124+
return
125+
}
126+
self.gui.c.OnWorker(func(gocui.Task) error {
127+
_ = function()
128+
done <- struct{}{}
129+
return nil
130+
})
131+
// waiting so that we don't bunch up refreshes if the refresh takes longer than the
132+
// interval, or if a retrigger comes in while we're still processing a timer-based one
133+
// (or vice versa)
134+
<-done
135+
}
106136
for {
107137
select {
108138
case <-ticker.C:
109-
if self.pauseBackgroundRefreshes {
110-
continue
111-
}
112-
self.gui.c.OnWorker(func(gocui.Task) error {
113-
_ = function()
114-
done <- struct{}{}
115-
return nil
116-
})
117-
// waiting so that we don't bunch up refreshes if the refresh takes longer than the interval
118-
<-done
139+
doit()
140+
case <-retrigger:
141+
ticker.Reset(interval)
142+
doit()
119143
case <-stop:
120144
return
121145
}
122146
}
123147
})
148+
return retrigger
124149
}
125150

126151
func (self *BackgroundRoutineMgr) backgroundFetch() (err error) {
@@ -134,3 +159,9 @@ func (self *BackgroundRoutineMgr) backgroundFetch() (err error) {
134159

135160
return err
136161
}
162+
163+
func (self *BackgroundRoutineMgr) triggerImmediateFetch() {
164+
if self.triggerFetch != nil {
165+
self.triggerFetch <- struct{}{}
166+
}
167+
}

pkg/gui/controllers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (gui *Gui) resetHelpersAndControllers() {
2626

2727
helperCommon := gui.c
2828
recordDirectoryHelper := helpers.NewRecordDirectoryHelper(helperCommon)
29-
reposHelper := helpers.NewRecentReposHelper(helperCommon, recordDirectoryHelper, gui.onNewRepo)
29+
reposHelper := helpers.NewRecentReposHelper(helperCommon, recordDirectoryHelper, gui.onSwitchToNewRepo)
3030
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon)
3131
refsHelper := helpers.NewRefsHelper(helperCommon, rebaseHelper)
3232
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon)

pkg/gui/gui.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"sort"
1313
"strings"
1414
"sync"
15+
"time"
1516

1617
"github.com/jesseduffield/gocui"
1718
"github.com/jesseduffield/lazycore/pkg/boxlayout"
@@ -233,7 +234,6 @@ type GuiRepoState struct {
233234
Modes *types.Modes
234235

235236
SplitMainPanel bool
236-
LimitCommits bool
237237

238238
SearchState *types.SearchState
239239
StartupStage types.StartupStage // Allows us to not load everything at once
@@ -254,6 +254,8 @@ type GuiRepoState struct {
254254
ScreenMode types.ScreenMode
255255

256256
CurrentPopupOpts *types.CreatePopupPanelOpts
257+
258+
LastBackgroundFetchTime time.Time
257259
}
258260

259261
var _ types.IRepoStateAccessor = new(GuiRepoState)
@@ -306,6 +308,16 @@ func (self *GuiRepoState) GetSplitMainPanel() bool {
306308
return self.SplitMainPanel
307309
}
308310

311+
func (gui *Gui) onSwitchToNewRepo(startArgs appTypes.StartArgs, contextKey types.ContextKey) error {
312+
err := gui.onNewRepo(startArgs, contextKey)
313+
if err == nil && gui.UserConfig().Git.AutoFetch && gui.UserConfig().Refresher.FetchInterval > 0 {
314+
if time.Since(gui.State.LastBackgroundFetchTime) > gui.UserConfig().Refresher.FetchIntervalDuration() {
315+
gui.BackgroundRoutineMgr.triggerImmediateFetch()
316+
}
317+
}
318+
return err
319+
}
320+
309321
func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.ContextKey) error {
310322
var err error
311323
gui.git, err = commands.NewGitCommand(

0 commit comments

Comments
 (0)