diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 1457d5138..330329fd0 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -54,9 +54,6 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error { // gui.refreshStatus is called at the end of this because that's when we can // be sure there is a state.Branches array to pick the current branch from func (gui *Gui) refreshBranches() { - _ = gui.refreshRemotes() - _ = gui.refreshTags() - builder, err := commands.NewBranchListBuilder(gui.Log, gui.GitCommand, gui.State.ReflogCommits) if err != nil { _ = gui.createErrorPanel(gui.g, err.Error()) diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 622007967..01e006829 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -71,6 +71,13 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error { return nil } +// whenever we change commits, we should update branches because the upstream/downstream +// counts can change. Whenever we change branches we should probably also change commits +// e.g. in the case of switching branches. We also need the status to be refreshed whenever +// the working tree status changes or the branch upstream/downstream value changes. +// Given how fast the refreshStatus method is, we should really just call it every time +// we refresh, but I'm not sure how to do that asynchronously that prevents a race condition +// other than a mutex. func (gui *Gui) refreshCommits() error { wg := sync.WaitGroup{} wg.Add(2) @@ -78,6 +85,7 @@ func (gui *Gui) refreshCommits() error { go func() { gui.refreshReflogCommits() gui.refreshBranches() + gui.refreshStatus() wg.Done() }() @@ -91,8 +99,6 @@ func (gui *Gui) refreshCommits() error { wg.Wait() - gui.refreshStatus() - return nil } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 03a0be81a..bb8121a2d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -179,34 +179,35 @@ type searchingState struct { } type guiState struct { - Files []*commands.File - Branches []*commands.Branch - Commits []*commands.Commit - StashEntries []*commands.StashEntry - CommitFiles []*commands.CommitFile - ReflogCommits []*commands.Commit - DiffEntries []*commands.Commit - Remotes []*commands.Remote - RemoteBranches []*commands.RemoteBranch - Tags []*commands.Tag - MenuItemCount int // can't store the actual list because it's of interface{} type - PreviousView string - Platform commands.Platform - Updating bool - Panels *panelStates - MainContext string // used to keep the main and secondary views' contexts in sync - CherryPickedCommits []*commands.Commit - SplitMainPanel bool - RetainOriginalDir bool - IsRefreshingFiles bool - RefreshingFilesMutex sync.Mutex - Searching searchingState - ScreenMode int - SideView *gocui.View - Ptmx *os.File - PrevMainWidth int - PrevMainHeight int - OldInformation string + Files []*commands.File + Branches []*commands.Branch + Commits []*commands.Commit + StashEntries []*commands.StashEntry + CommitFiles []*commands.CommitFile + ReflogCommits []*commands.Commit + DiffEntries []*commands.Commit + Remotes []*commands.Remote + RemoteBranches []*commands.RemoteBranch + Tags []*commands.Tag + MenuItemCount int // can't store the actual list because it's of interface{} type + PreviousView string + Platform commands.Platform + Updating bool + Panels *panelStates + MainContext string // used to keep the main and secondary views' contexts in sync + CherryPickedCommits []*commands.Commit + SplitMainPanel bool + RetainOriginalDir bool + IsRefreshingFiles bool + RefreshingFilesMutex sync.Mutex + RefreshingStatusMutex sync.Mutex + Searching searchingState + ScreenMode int + SideView *gocui.View + Ptmx *os.File + PrevMainWidth int + PrevMainHeight int + OldInformation string } // for now the split view will always be on diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 69628e6f9..e5c91b810 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -99,7 +99,7 @@ func (gui *Gui) handleDeleteRemoteBranch(g *gocui.Gui, v *gocui.View) error { return err } - return gui.refreshRemotes() + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) }) }, nil) } diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index 149084869..699e4faa8 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -119,7 +119,7 @@ func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil { return err } - return gui.refreshRemotes() + return gui.refreshSidePanels(refreshOptions{scope: []int{REMOTES}}) }) }) } @@ -134,7 +134,7 @@ func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error { return err } - return gui.refreshRemotes() + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) }, nil) } @@ -174,7 +174,7 @@ func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { return gui.createErrorPanel(gui.g, err.Error()) } - return gui.refreshRemotes() + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) }) }) } @@ -190,6 +190,6 @@ func (gui *Gui) handleFetchRemote(g *gocui.Gui, v *gocui.View) error { return err } - return gui.refreshRemotes() + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) }) } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 6a952b580..207e493bb 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -12,8 +12,14 @@ import ( // never call this on its own, it should only be called from within refreshCommits() func (gui *Gui) refreshStatus() { + gui.State.RefreshingStatusMutex.Lock() + defer gui.State.RefreshingStatusMutex.Unlock() currentBranch := gui.currentBranch() + if currentBranch == nil { + // need to wait for branches to refresh + return + } status := "" if currentBranch.Pushables != "" && currentBranch.Pullables != "" { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 60d548bcb..50c40ede3 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -61,7 +61,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { scopeMap = intArrToMap(options.scope) } - if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] || scopeMap[TAGS] || scopeMap[REMOTES] { + if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] { wg.Add(1) func() { if options.mode == ASYNC { @@ -97,8 +97,34 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } + if scopeMap[TAGS] { + wg.Add(1) + func() { + if options.mode == ASYNC { + go gui.refreshTags() + } else { + gui.refreshTags() + } + wg.Done() + }() + } + + if scopeMap[REMOTES] { + wg.Add(1) + func() { + if options.mode == ASYNC { + go gui.refreshRemotes() + } else { + gui.refreshRemotes() + } + wg.Done() + }() + } + wg.Wait() + gui.refreshStatus() + if options.then != nil { options.then() }