mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-23 12:18:51 +02:00
This is how we do it for confirmation with suggestions too, so be consistent. It will make things easier later in this branch if we only have one context per "panel" on the stack, even if the panel consists of two views. Concretely this means: - only push the message context onto the stack when opening the panel (this requires making the description view visible manually; we do the same for suggestions) - when switching between message and description, use ReplaceContext rather than PushContext
258 lines
7.9 KiB
Go
258 lines
7.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/jesseduffield/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
)
|
|
|
|
type CustomPatchOptionsMenuAction struct {
|
|
c *ControllerCommon
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) Call() error {
|
|
if !self.c.Git().Patch.PatchBuilder.Active() {
|
|
return errors.New(self.c.Tr.NoPatchError)
|
|
}
|
|
|
|
if self.c.Git().Patch.PatchBuilder.IsEmpty() {
|
|
return errors.New(self.c.Tr.EmptyPatchError)
|
|
}
|
|
|
|
menuItems := []*types.MenuItem{
|
|
{
|
|
Label: self.c.Tr.ResetPatch,
|
|
Tooltip: self.c.Tr.ResetPatchTooltip,
|
|
OnPress: self.c.Helpers().PatchBuilding.Reset,
|
|
Key: 'c',
|
|
},
|
|
{
|
|
Label: self.c.Tr.ApplyPatch,
|
|
Tooltip: self.c.Tr.ApplyPatchTooltip,
|
|
OnPress: func() error { return self.handleApplyPatch(false) },
|
|
Key: 'a',
|
|
},
|
|
{
|
|
Label: self.c.Tr.ApplyPatchInReverse,
|
|
Tooltip: self.c.Tr.ApplyPatchInReverseTooltip,
|
|
OnPress: func() error { return self.handleApplyPatch(true) },
|
|
Key: 'r',
|
|
},
|
|
}
|
|
|
|
if self.c.Git().Patch.PatchBuilder.CanRebase && self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_NONE {
|
|
menuItems = append(menuItems, []*types.MenuItem{
|
|
{
|
|
Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, self.c.Git().Patch.PatchBuilder.To),
|
|
Tooltip: self.c.Tr.RemovePatchFromOriginalCommitTooltip,
|
|
OnPress: self.handleDeletePatchFromCommit,
|
|
Key: 'd',
|
|
},
|
|
{
|
|
Label: self.c.Tr.MovePatchOutIntoIndex,
|
|
Tooltip: self.c.Tr.MovePatchOutIntoIndexTooltip,
|
|
OnPress: self.handleMovePatchIntoWorkingTree,
|
|
Key: 'i',
|
|
},
|
|
{
|
|
Label: self.c.Tr.MovePatchIntoNewCommit,
|
|
Tooltip: self.c.Tr.MovePatchIntoNewCommitTooltip,
|
|
OnPress: self.handlePullPatchIntoNewCommit,
|
|
Key: 'n',
|
|
},
|
|
}...)
|
|
|
|
if self.c.CurrentContext().GetKey() == self.c.Contexts().LocalCommits.GetKey() {
|
|
selectedCommit := self.c.Contexts().LocalCommits.GetSelected()
|
|
if selectedCommit != nil && self.c.Git().Patch.PatchBuilder.To != selectedCommit.Hash {
|
|
|
|
var disabledReason *types.DisabledReason
|
|
if self.c.Contexts().LocalCommits.AreMultipleItemsSelected() {
|
|
disabledReason = &types.DisabledReason{Text: self.c.Tr.RangeSelectNotSupported}
|
|
}
|
|
|
|
// adding this option to index 1
|
|
menuItems = append(
|
|
menuItems[:1],
|
|
append(
|
|
[]*types.MenuItem{
|
|
{
|
|
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Hash),
|
|
Tooltip: self.c.Tr.MovePatchToSelectedCommitTooltip,
|
|
OnPress: self.handleMovePatchToSelectedCommit,
|
|
Key: 'm',
|
|
DisabledReason: disabledReason,
|
|
},
|
|
}, menuItems[1:]...,
|
|
)...,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
menuItems = append(menuItems, []*types.MenuItem{
|
|
{
|
|
Label: self.c.Tr.CopyPatchToClipboard,
|
|
OnPress: func() error { return self.copyPatchToClipboard() },
|
|
Key: 'y',
|
|
},
|
|
}...)
|
|
|
|
return self.c.Menu(types.CreateMenuOptions{Title: self.c.Tr.PatchOptionsTitle, Items: menuItems})
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
|
|
for index, commit := range self.c.Model().Commits {
|
|
if commit.Hash == self.c.Git().Patch.PatchBuilder.To {
|
|
return index
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) validateNormalWorkingTreeState() (bool, error) {
|
|
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
|
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) returnFocusFromPatchExplorerIfNecessary() error {
|
|
if self.c.CurrentContext().GetKey() == self.c.Contexts().CustomPatchBuilder.GetKey() {
|
|
return self.c.Helpers().PatchBuilding.Escape()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
|
|
if ok, err := self.validateNormalWorkingTreeState(); !ok {
|
|
return err
|
|
}
|
|
|
|
if err := self.returnFocusFromPatchExplorerIfNecessary(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
|
commitIndex := self.getPatchCommitIndex()
|
|
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
|
|
err := self.c.Git().Patch.DeletePatchesFromCommit(self.c.Model().Commits, commitIndex)
|
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
|
})
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() error {
|
|
if ok, err := self.validateNormalWorkingTreeState(); !ok {
|
|
return err
|
|
}
|
|
|
|
if err := self.returnFocusFromPatchExplorerIfNecessary(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
|
commitIndex := self.getPatchCommitIndex()
|
|
self.c.LogAction(self.c.Tr.Actions.MovePatchToSelectedCommit)
|
|
err := self.c.Git().Patch.MovePatchToSelectedCommit(self.c.Model().Commits, commitIndex, self.c.Contexts().LocalCommits.GetSelectedLineIdx())
|
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
|
})
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error {
|
|
if ok, err := self.validateNormalWorkingTreeState(); !ok {
|
|
return err
|
|
}
|
|
|
|
if err := self.returnFocusFromPatchExplorerIfNecessary(); err != nil {
|
|
return err
|
|
}
|
|
|
|
pull := func(stash bool) error {
|
|
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
|
commitIndex := self.getPatchCommitIndex()
|
|
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
|
|
err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, stash)
|
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
|
})
|
|
}
|
|
|
|
if self.c.Helpers().WorkingTree.IsWorkingTreeDirty() {
|
|
return self.c.Confirm(types.ConfirmOpts{
|
|
Title: self.c.Tr.MustStashTitle,
|
|
Prompt: self.c.Tr.MustStashWarning,
|
|
HandleConfirm: func() error {
|
|
return pull(true)
|
|
},
|
|
})
|
|
} else {
|
|
return pull(false)
|
|
}
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
|
if ok, err := self.validateNormalWorkingTreeState(); !ok {
|
|
return err
|
|
}
|
|
|
|
if err := self.returnFocusFromPatchExplorerIfNecessary(); err != nil {
|
|
return err
|
|
}
|
|
|
|
commitIndex := self.getPatchCommitIndex()
|
|
return self.c.Helpers().Commits.OpenCommitMessagePanel(
|
|
&helpers.OpenCommitMessagePanelOpts{
|
|
// Pass a commit index of one less than the moved-from commit, so that
|
|
// you can press up arrow once to recall the original commit message:
|
|
CommitIndex: commitIndex - 1,
|
|
InitialMessage: "",
|
|
SummaryTitle: self.c.Tr.CommitSummaryTitle,
|
|
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
|
|
PreserveMessage: false,
|
|
OnConfirm: func(summary string, description string) error {
|
|
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
|
_ = self.c.Helpers().Commits.CloseCommitMessagePanel()
|
|
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
|
|
err := self.c.Git().Patch.PullPatchIntoNewCommit(self.c.Model().Commits, commitIndex, summary, description)
|
|
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
|
|
return err
|
|
}
|
|
return self.c.PushContext(self.c.Contexts().LocalCommits)
|
|
})
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error {
|
|
if err := self.returnFocusFromPatchExplorerIfNecessary(); err != nil {
|
|
return err
|
|
}
|
|
|
|
action := self.c.Tr.Actions.ApplyPatch
|
|
if reverse {
|
|
action = "Apply patch in reverse"
|
|
}
|
|
self.c.LogAction(action)
|
|
if err := self.c.Git().Patch.ApplyCustomPatch(reverse, true); err != nil {
|
|
return err
|
|
}
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
}
|
|
|
|
func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
|
|
patch := self.c.Git().Patch.PatchBuilder.RenderAggregatedPatch(true)
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.CopyPatchToClipboard)
|
|
if err := self.c.OS().CopyToClipboard(patch); err != nil {
|
|
return err
|
|
}
|
|
|
|
self.c.Toast(self.c.Tr.PatchCopiedToClipboard)
|
|
|
|
return nil
|
|
}
|