2022-08-06 10:50:52 +02:00
|
|
|
package helpers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type MergeConflictsHelper struct {
|
2023-03-23 03:53:18 +02:00
|
|
|
c *HelperCommon
|
2022-08-06 10:50:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewMergeConflictsHelper(
|
2023-03-23 03:35:07 +02:00
|
|
|
c *HelperCommon,
|
2022-08-06 10:50:52 +02:00
|
|
|
) *MergeConflictsHelper {
|
|
|
|
return &MergeConflictsHelper{
|
2023-03-23 03:53:18 +02:00
|
|
|
c: c,
|
2022-08-06 10:50:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) SetMergeState(path string) (bool, error) {
|
|
|
|
self.context().GetMutex().Lock()
|
|
|
|
defer self.context().GetMutex().Unlock()
|
|
|
|
|
|
|
|
return self.setMergeStateWithoutLock(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) setMergeStateWithoutLock(path string) (bool, error) {
|
2023-03-23 03:53:18 +02:00
|
|
|
content, err := self.c.Git().File.Cat(path)
|
2022-08-06 10:50:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if path != self.context().GetState().GetPath() {
|
|
|
|
self.context().SetUserScrolling(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
self.context().GetState().SetContent(content, path)
|
|
|
|
|
|
|
|
return !self.context().GetState().NoConflicts(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) ResetMergeState() {
|
|
|
|
self.context().GetMutex().Lock()
|
|
|
|
defer self.context().GetMutex().Unlock()
|
|
|
|
|
|
|
|
self.resetMergeState()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) resetMergeState() {
|
|
|
|
self.context().SetUserScrolling(false)
|
|
|
|
self.context().GetState().Reset()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) EscapeMerge() error {
|
|
|
|
self.resetMergeState()
|
|
|
|
|
|
|
|
// doing this in separate UI thread so that we're not still holding the lock by the time refresh the file
|
|
|
|
self.c.OnUIThread(func() error {
|
2023-05-16 12:45:43 +02:00
|
|
|
// There is a race condition here: refreshing the files scope can trigger the
|
|
|
|
// confirmation context to be pushed if all conflicts are resolved (prompting
|
|
|
|
// to continue the merge/rebase. In that case, we don't want to then push the
|
|
|
|
// files context over it.
|
|
|
|
// So long as both places call OnUIThread, we're fine.
|
|
|
|
if self.c.IsCurrentContext(self.c.Contexts().MergeConflicts) {
|
|
|
|
return self.c.PushContext(self.c.Contexts().Files)
|
|
|
|
}
|
|
|
|
return nil
|
2022-08-06 10:50:52 +02:00
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) SetConflictsAndRender(path string, isFocused bool) (bool, error) {
|
|
|
|
hasConflicts, err := self.setMergeStateWithoutLock(path)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if hasConflicts {
|
|
|
|
return true, self.context().Render(isFocused)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) SwitchToMerge(path string) error {
|
|
|
|
if self.context().GetState().GetPath() != path {
|
|
|
|
hasConflicts, err := self.SetMergeState(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !hasConflicts {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-23 03:53:18 +02:00
|
|
|
return self.c.PushContext(self.c.Contexts().MergeConflicts)
|
2022-08-06 10:50:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) context() *context.MergeConflictsContext {
|
2023-03-23 03:53:18 +02:00
|
|
|
return self.c.Contexts().MergeConflicts
|
2022-08-06 10:50:52 +02:00
|
|
|
}
|
2022-12-30 14:24:24 +02:00
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) Render(isFocused bool) error {
|
|
|
|
content := self.context().GetContentToRender(isFocused)
|
|
|
|
|
|
|
|
var task types.UpdateTask
|
|
|
|
if self.context().IsUserScrolling() {
|
|
|
|
task = types.NewRenderStringWithoutScrollTask(content)
|
|
|
|
} else {
|
|
|
|
originY := self.context().GetOriginY()
|
|
|
|
task = types.NewRenderStringWithScrollTask(content, 0, originY)
|
|
|
|
}
|
|
|
|
|
|
|
|
return self.c.RenderToMainViews(types.RefreshMainOpts{
|
|
|
|
Pair: self.c.MainViewPairs().MergeConflicts,
|
|
|
|
Main: &types.ViewUpdateOpts{
|
|
|
|
Task: task,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *MergeConflictsHelper) RefreshMergeState() error {
|
2023-03-23 03:53:18 +02:00
|
|
|
self.c.Contexts().MergeConflicts.GetMutex().Lock()
|
|
|
|
defer self.c.Contexts().MergeConflicts.GetMutex().Unlock()
|
2022-12-30 14:24:24 +02:00
|
|
|
|
|
|
|
if self.c.CurrentContext().GetKey() != context.MERGE_CONFLICTS_CONTEXT_KEY {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-23 03:53:18 +02:00
|
|
|
hasConflicts, err := self.SetConflictsAndRender(self.c.Contexts().MergeConflicts.GetState().GetPath(), true)
|
2022-12-30 14:24:24 +02:00
|
|
|
if err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !hasConflicts {
|
|
|
|
return self.EscapeMerge()
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|