Skip to content

Commit

Permalink
better locking of merge panel state
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseduffield committed Jan 27, 2022
1 parent 7f85bf5 commit 84a1992
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 36 deletions.
2 changes: 1 addition & 1 deletion pkg/gui/context_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (gui *Gui) contextTree() ContextTree {
Key: MAIN_PATCH_BUILDING_CONTEXT_KEY,
},
Merging: &BasicContext{
OnFocus: OnFocusWrapper(gui.renderConflictsWithFocus),
OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }),
Kind: MAIN_CONTEXT,
ViewName: "main",
Key: MAIN_MERGING_CONTEXT_KEY,
Expand Down
34 changes: 5 additions & 29 deletions pkg/gui/files_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,16 @@ func (gui *Gui) filesRenderToMain() error {
}

if node.File != nil && node.File.HasInlineMergeConflicts {
hasConflicts, err := gui.setMergeState(node.File.Name)
ok, err := gui.setConflictsAndRenderWithLock(node.GetPath(), false)
if err != nil {
return err
}

// if we don't have conflicts we'll fall through and show the diff
if hasConflicts {
return gui.renderConflicts(false)
if ok {
return nil
}
}

gui.resetMergeState()
gui.resetMergeStateWithLock()

cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.State.IgnoreWhitespaceInDiffView)

Expand Down Expand Up @@ -143,28 +141,6 @@ func (gui *Gui) refreshFilesAndSubmodules() error {
return nil
}

func (gui *Gui) refreshMergeState() error {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

if gui.currentContext().GetKey() != MAIN_MERGING_CONTEXT_KEY {
return nil
}

hasConflicts, err := gui.setMergeState(gui.State.Panels.Merging.GetPath())
if err != nil {
return gui.surfaceError(err)
}
if hasConflicts {
_ = gui.renderConflicts(true)
} else {
_ = gui.escapeMerge()
return nil
}

return nil
}

// specific functions

func (gui *Gui) stagedFiles() []*models.File {
Expand Down Expand Up @@ -959,7 +935,7 @@ func (gui *Gui) switchToMerge() error {
gui.takeOverMergeConflictScrolling()

if gui.State.Panels.Merging.GetPath() != file.Name {
hasConflicts, err := gui.setMergeState(file.Name)
hasConflicts, err := gui.setMergeStateWithLock(file.Name)
if err != nil {
return err
}
Expand Down
76 changes: 71 additions & 5 deletions pkg/gui/merge_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ func (gui *Gui) renderConflicts(hasFocus bool) error {
// TODO: find a way to not have to do this OnUIThread thing. Why doesn't it work
// without it given that we're calling the 'no scroll' variant below?
gui.OnUIThread(func() error {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

if !state.Active() {
return nil
}

gui.centerYPos(gui.Views.Main, state.GetConflictMiddle())
return nil
})
Expand All @@ -156,6 +163,12 @@ func (gui *Gui) renderConflictsWithFocus() error {
return gui.renderConflicts(true)
}

func (gui *Gui) renderConflictsWithLock(hasFocus bool) error {
return gui.withMergeConflictLock(func() error {
return gui.renderConflicts(hasFocus)
})
}

func (gui *Gui) centerYPos(view *gocui.View, y int) {
ox, _ := view.Origin()
_, height := view.Size()
Expand Down Expand Up @@ -205,15 +218,27 @@ func (gui *Gui) setMergeState(path string) (bool, error) {
return !gui.State.Panels.Merging.NoConflicts(), nil
}

func (gui *Gui) escapeMerge() error {
func (gui *Gui) setMergeStateWithLock(path string) (bool, error) {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

return gui.setMergeState(path)
}

func (gui *Gui) resetMergeStateWithLock() {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

gui.resetMergeState()
}

// it's possible this method won't be called from the merging view so we need to
// ensure we only 'return' focus if we already have it
func (gui *Gui) escapeMerge() error {
gui.resetMergeState()

if gui.currentContext().GetKey() == MAIN_MERGING_CONTEXT_KEY {
// doing this in separate UI thread so that we're not still holding the lock by the time refresh the file
gui.OnUIThread(func() error {
return gui.pushContext(gui.State.Contexts.Files)
}
})
return nil
}

Expand All @@ -236,3 +261,44 @@ func (gui *Gui) withMergeConflictLock(f func() error) error {
func (gui *Gui) takeOverMergeConflictScrolling() {
gui.State.Panels.Merging.UserVerticalScrolling = false
}

func (gui *Gui) setConflictsAndRender(path string, hasFocus bool) (bool, error) {
hasConflicts, err := gui.setMergeState(path)
if err != nil {
return false, err
}

// if we don't have conflicts we'll fall through and show the diff
if hasConflicts {
return true, gui.renderConflicts(hasFocus)
}

return false, nil
}

func (gui *Gui) setConflictsAndRenderWithLock(path string, hasFocus bool) (bool, error) {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

return gui.setConflictsAndRender(path, hasFocus)
}

func (gui *Gui) refreshMergeState() error {
gui.State.Panels.Merging.Lock()
defer gui.State.Panels.Merging.Unlock()

if gui.currentContext().GetKey() != MAIN_MERGING_CONTEXT_KEY {
return nil
}

hasConflicts, err := gui.setConflictsAndRender(gui.State.Panels.Merging.GetPath(), true)
if err != nil {
return gui.surfaceError(err)
}

if !hasConflicts {
return gui.escapeMerge()
}

return nil
}
8 changes: 7 additions & 1 deletion pkg/gui/mergeconflicts/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,13 @@ func (s *State) Active() bool {
}

func (s *State) GetConflictMiddle() int {
return s.currentConflict().target
currentConflict := s.currentConflict()

if currentConflict == nil {
return 0
}

return currentConflict.target
}

func (s *State) ContentAfterConflictResolve(selection Selection) (bool, string, error) {
Expand Down

0 comments on commit 84a1992

Please sign in to comment.