mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-12 11:15:00 +02:00
some more refactoring
This commit is contained in:
parent
e2f5fe1016
commit
0a8cff6ab6
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
@ -240,7 +239,7 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
|
|||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.Merge)
|
gui.c.LogAction(gui.c.Tr.Actions.Merge)
|
||||||
err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{})
|
err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{})
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -274,7 +273,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error {
|
|||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch)
|
gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch)
|
||||||
err := gui.git.Rebase.RebaseBranch(selectedBranchName)
|
err := gui.git.Rebase.RebaseBranch(selectedBranchName)
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -391,55 +390,6 @@ func (gui *Gui) handleRenameBranch() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleNewBranchOffCurrentItem() error {
|
|
||||||
ctx := gui.currentSideListContext()
|
|
||||||
|
|
||||||
item, ok := ctx.GetSelectedItem()
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
message := utils.ResolvePlaceholderString(
|
|
||||||
gui.c.Tr.NewBranchNameBranchOff,
|
|
||||||
map[string]string{
|
|
||||||
"branchName": item.Description(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
prefilledName := ""
|
|
||||||
if ctx.GetKey() == context.REMOTE_BRANCHES_CONTEXT_KEY {
|
|
||||||
// will set to the remote's branch name without the remote name
|
|
||||||
prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.c.Prompt(types.PromptOpts{
|
|
||||||
Title: message,
|
|
||||||
InitialContent: prefilledName,
|
|
||||||
HandleConfirm: func(response string) error {
|
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.CreateBranch)
|
|
||||||
if err := gui.git.Branch.New(sanitizedBranchName(response), item.ID()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're currently in the branch commits context then the selected commit
|
|
||||||
// is about to go to the top of the list
|
|
||||||
if ctx.GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY {
|
|
||||||
ctx.GetPanelState().SetSelectedLineIdx(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.GetKey() != gui.State.Contexts.Branches.GetKey() {
|
|
||||||
if err := gui.c.PushContext(gui.State.Contexts.Branches); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.State.Panels.Branches.SelectedLineIdx = 0
|
|
||||||
|
|
||||||
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanitizedBranchName will remove all spaces in favor of a dash "-" to meet
|
// sanitizedBranchName will remove all spaces in favor of a dash "-" to meet
|
||||||
// git's branch naming requirement.
|
// git's branch naming requirement.
|
||||||
func sanitizedBranchName(input string) string {
|
func sanitizedBranchName(input string) string {
|
||||||
@ -454,3 +404,12 @@ func (gui *Gui) handleEnterBranch() error {
|
|||||||
|
|
||||||
return gui.switchToSubCommitsContext(branch.RefName())
|
return gui.switchToSubCommitsContext(branch.RefName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleNewBranchOffBranch() error {
|
||||||
|
selectedBranch := gui.getSelectedBranch()
|
||||||
|
if selectedBranch == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "")
|
||||||
|
}
|
||||||
|
@ -1,187 +0,0 @@
|
|||||||
package gui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// you can only copy from one context at a time, because the order and position of commits matter
|
|
||||||
|
|
||||||
func (gui *Gui) resetCherryPickingIfNecessary(context types.Context) error {
|
|
||||||
oldContextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey)
|
|
||||||
|
|
||||||
if oldContextKey != context.GetKey() {
|
|
||||||
// need to reset the cherry picking mode
|
|
||||||
gui.State.Modes.CherryPicking.ContextKey = string(context.GetKey())
|
|
||||||
gui.State.Modes.CherryPicking.CherryPickedCommits = make([]*models.Commit, 0)
|
|
||||||
|
|
||||||
return gui.rerenderContextViewIfPresent(oldContextKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleCopyCommit() error {
|
|
||||||
// get currently selected commit, add the sha to state.
|
|
||||||
context := gui.currentSideListContext()
|
|
||||||
if context == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gui.resetCherryPickingIfNecessary(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
item, ok := context.GetSelectedItem()
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
commit, ok := item.(*models.Commit)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// we will un-copy it if it's already copied
|
|
||||||
for index, cherryPickedCommit := range gui.State.Modes.CherryPicking.CherryPickedCommits {
|
|
||||||
if commit.Sha == cherryPickedCommit.Sha {
|
|
||||||
gui.State.Modes.CherryPicking.CherryPickedCommits = append(gui.State.Modes.CherryPicking.CherryPickedCommits[0:index], gui.State.Modes.CherryPicking.CherryPickedCommits[index+1:]...)
|
|
||||||
return context.HandleRender()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.addCommitToCherryPickedCommits(context.GetPanelState().GetSelectedLineIdx())
|
|
||||||
return context.HandleRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) cherryPickedCommitShaMap() map[string]bool {
|
|
||||||
commitShaMap := map[string]bool{}
|
|
||||||
for _, commit := range gui.State.Modes.CherryPicking.CherryPickedCommits {
|
|
||||||
commitShaMap[commit.Sha] = true
|
|
||||||
}
|
|
||||||
return commitShaMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) commitsListForContext() []*models.Commit {
|
|
||||||
ctx := gui.currentSideListContext()
|
|
||||||
if ctx == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// using a switch statement, but we should use polymorphism
|
|
||||||
switch ctx.GetKey() {
|
|
||||||
case context.BRANCH_COMMITS_CONTEXT_KEY:
|
|
||||||
return gui.State.Commits
|
|
||||||
case context.REFLOG_COMMITS_CONTEXT_KEY:
|
|
||||||
return gui.State.FilteredReflogCommits
|
|
||||||
case context.SUB_COMMITS_CONTEXT_KEY:
|
|
||||||
return gui.State.SubCommits
|
|
||||||
default:
|
|
||||||
gui.c.Log.Errorf("no commit list for context %s", ctx.GetKey())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) addCommitToCherryPickedCommits(index int) {
|
|
||||||
commitShaMap := gui.cherryPickedCommitShaMap()
|
|
||||||
commitsList := gui.commitsListForContext()
|
|
||||||
commitShaMap[commitsList[index].Sha] = true
|
|
||||||
|
|
||||||
newCommits := []*models.Commit{}
|
|
||||||
for _, commit := range commitsList {
|
|
||||||
if commitShaMap[commit.Sha] {
|
|
||||||
// duplicating just the things we need to put in the rebase TODO list
|
|
||||||
newCommits = append(newCommits, &models.Commit{Name: commit.Name, Sha: commit.Sha})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.State.Modes.CherryPicking.CherryPickedCommits = newCommits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleCopyCommitRange() error {
|
|
||||||
// get currently selected commit, add the sha to state.
|
|
||||||
context := gui.currentSideListContext()
|
|
||||||
if context == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gui.resetCherryPickingIfNecessary(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
commitShaMap := gui.cherryPickedCommitShaMap()
|
|
||||||
commitsList := gui.commitsListForContext()
|
|
||||||
selectedLineIdx := context.GetPanelState().GetSelectedLineIdx()
|
|
||||||
|
|
||||||
if selectedLineIdx > len(commitsList)-1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the last commit that is copied that's above our position
|
|
||||||
// if there are none, startIndex = 0
|
|
||||||
startIndex := 0
|
|
||||||
for index, commit := range commitsList[0:selectedLineIdx] {
|
|
||||||
if commitShaMap[commit.Sha] {
|
|
||||||
startIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for index := startIndex; index <= selectedLineIdx; index++ {
|
|
||||||
gui.addCommitToCherryPickedCommits(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.HandleRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied
|
|
||||||
func (gui *Gui) HandlePasteCommits() error {
|
|
||||||
return gui.c.Ask(types.AskOpts{
|
|
||||||
Title: gui.c.Tr.CherryPick,
|
|
||||||
Prompt: gui.c.Tr.SureCherryPick,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return gui.c.WithWaitingStatus(gui.c.Tr.CherryPickingStatus, func() error {
|
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.CherryPick)
|
|
||||||
err := gui.git.Rebase.CherryPickCommits(gui.State.Modes.CherryPicking.CherryPickedCommits)
|
|
||||||
return gui.checkMergeOrRebase(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) exitCherryPickingMode() error {
|
|
||||||
contextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey)
|
|
||||||
|
|
||||||
gui.State.Modes.CherryPicking.ContextKey = ""
|
|
||||||
gui.State.Modes.CherryPicking.CherryPickedCommits = nil
|
|
||||||
|
|
||||||
if contextKey == "" {
|
|
||||||
gui.c.Log.Warn("context key blank when trying to exit cherry picking mode")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.rerenderContextViewIfPresent(contextKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) rerenderContextViewIfPresent(contextKey types.ContextKey) error {
|
|
||||||
if contextKey == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
context := gui.mustContextForContextKey(contextKey)
|
|
||||||
|
|
||||||
viewName := context.GetViewName()
|
|
||||||
|
|
||||||
view, err := gui.g.View(viewName)
|
|
||||||
if err != nil {
|
|
||||||
gui.c.Log.Error(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if types.ContextKey(view.Context) == contextKey {
|
|
||||||
if err := context.HandleRender(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -83,7 +83,7 @@ func (gui *Gui) handleDiscardOldFileChange() error {
|
|||||||
return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error {
|
return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error {
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange)
|
gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange)
|
||||||
if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil {
|
if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil {
|
||||||
if err := gui.checkMergeOrRebase(err); err != nil {
|
if err := gui.helpers.rebase.CheckMergeOrRebase(err); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,13 +464,7 @@ func (gui *Gui) getSideContextSelectedItemId() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
item, ok := currentSideContext.GetSelectedItem()
|
return currentSideContext.GetSelectedItemId()
|
||||||
|
|
||||||
if ok {
|
|
||||||
return item.ID()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently unused
|
// currently unused
|
||||||
|
@ -62,7 +62,11 @@ func NewCommitFilesContext(
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitFilesContext) GetSelectedItem() (types.ListItem, bool) {
|
func (self *CommitFilesContext) GetSelectedItemId() string {
|
||||||
item := self.CommitFileTreeViewModel.GetSelectedFileNode()
|
item := self.GetSelectedFileNode()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.ID()
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,15 @@ func NewTagsContext(
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *TagsContext) GetSelectedItemId() string {
|
||||||
|
item := self.GetSelectedTag()
|
||||||
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.ID()
|
||||||
|
}
|
||||||
|
|
||||||
type TagsViewModel struct {
|
type TagsViewModel struct {
|
||||||
*traits.ListCursor
|
*traits.ListCursor
|
||||||
getModel func() []*models.Tag
|
getModel func() []*models.Tag
|
||||||
@ -79,11 +88,6 @@ func (self *TagsViewModel) GetSelectedTag() *models.Tag {
|
|||||||
return self.getModel()[self.GetSelectedLineIdx()]
|
return self.getModel()[self.GetSelectedLineIdx()]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagsViewModel) GetSelectedItem() (types.ListItem, bool) {
|
|
||||||
item := self.GetSelectedTag()
|
|
||||||
return item, item != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel {
|
func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel {
|
||||||
self := &TagsViewModel{
|
self := &TagsViewModel{
|
||||||
getModel: getModel,
|
getModel: getModel,
|
||||||
|
@ -62,7 +62,11 @@ func NewWorkingTreeContext(
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeContext) GetSelectedItem() (types.ListItem, bool) {
|
func (self *WorkingTreeContext) GetSelectedItemId() string {
|
||||||
item := self.FileTreeViewModel.GetSelectedFileNode()
|
item := self.GetSelectedFileNode()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.ID()
|
||||||
}
|
}
|
||||||
|
156
pkg/gui/controllers/cherry_pick_helper.go
Normal file
156
pkg/gui/controllers/cherry_pick_helper.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CherryPickHelper struct {
|
||||||
|
c *types.ControllerCommon
|
||||||
|
|
||||||
|
git *commands.GitCommand
|
||||||
|
|
||||||
|
getContexts func() context.ContextTree
|
||||||
|
getData func() *cherrypicking.CherryPicking
|
||||||
|
|
||||||
|
rebaseHelper *RebaseHelper
|
||||||
|
}
|
||||||
|
|
||||||
|
// I'm using the analogy of copy+paste in the terminology here because it's intuitively what's going on,
|
||||||
|
// even if in truth we're running git cherry-pick
|
||||||
|
|
||||||
|
func NewCherryPickHelper(
|
||||||
|
c *types.ControllerCommon,
|
||||||
|
git *commands.GitCommand,
|
||||||
|
getContexts func() context.ContextTree,
|
||||||
|
getData func() *cherrypicking.CherryPicking,
|
||||||
|
rebaseHelper *RebaseHelper,
|
||||||
|
) *CherryPickHelper {
|
||||||
|
return &CherryPickHelper{
|
||||||
|
c: c,
|
||||||
|
git: git,
|
||||||
|
getContexts: getContexts,
|
||||||
|
getData: getData,
|
||||||
|
rebaseHelper: rebaseHelper,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) Copy(commit *models.Commit, commitsList []*models.Commit, context types.Context) error {
|
||||||
|
if err := self.resetIfNecessary(context); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// we will un-copy it if it's already copied
|
||||||
|
for index, cherryPickedCommit := range self.getData().CherryPickedCommits {
|
||||||
|
if commit.Sha == cherryPickedCommit.Sha {
|
||||||
|
self.getData().CherryPickedCommits = append(
|
||||||
|
self.getData().CherryPickedCommits[0:index],
|
||||||
|
self.getData().CherryPickedCommits[index+1:]...,
|
||||||
|
)
|
||||||
|
return self.rerender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add(commit, commitsList)
|
||||||
|
return self.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) CopyRange(selectedIndex int, commitsList []*models.Commit, context types.Context) error {
|
||||||
|
if err := self.resetIfNecessary(context); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
commitShaMap := self.CherryPickedCommitShaMap()
|
||||||
|
|
||||||
|
// find the last commit that is copied that's above our position
|
||||||
|
// if there are none, startIndex = 0
|
||||||
|
startIndex := 0
|
||||||
|
for index, commit := range commitsList[0:selectedIndex] {
|
||||||
|
if commitShaMap[commit.Sha] {
|
||||||
|
startIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := startIndex; index <= selectedIndex; index++ {
|
||||||
|
commit := commitsList[index]
|
||||||
|
self.add(commit, commitsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied.
|
||||||
|
// Only to be called from the branch commits controller
|
||||||
|
func (self *CherryPickHelper) Paste() error {
|
||||||
|
return self.c.Ask(types.AskOpts{
|
||||||
|
Title: self.c.Tr.CherryPick,
|
||||||
|
Prompt: self.c.Tr.SureCherryPick,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
return self.c.WithWaitingStatus(self.c.Tr.CherryPickingStatus, func() error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.CherryPick)
|
||||||
|
err := self.git.Rebase.CherryPickCommits(self.getData().CherryPickedCommits)
|
||||||
|
return self.rebaseHelper.CheckMergeOrRebase(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) Reset() error {
|
||||||
|
self.getData().ContextKey = ""
|
||||||
|
self.getData().CherryPickedCommits = nil
|
||||||
|
|
||||||
|
return self.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) CherryPickedCommitShaMap() map[string]bool {
|
||||||
|
commitShaMap := map[string]bool{}
|
||||||
|
for _, commit := range self.getData().CherryPickedCommits {
|
||||||
|
commitShaMap[commit.Sha] = true
|
||||||
|
}
|
||||||
|
return commitShaMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) add(selectedCommit *models.Commit, commitsList []*models.Commit) {
|
||||||
|
commitShaMap := self.CherryPickedCommitShaMap()
|
||||||
|
commitShaMap[selectedCommit.Sha] = true
|
||||||
|
|
||||||
|
newCommits := []*models.Commit{}
|
||||||
|
for _, commit := range commitsList {
|
||||||
|
if commitShaMap[commit.Sha] {
|
||||||
|
// duplicating just the things we need to put in the rebase TODO list
|
||||||
|
newCommits = append(newCommits, &models.Commit{Name: commit.Name, Sha: commit.Sha})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.getData().CherryPickedCommits = newCommits
|
||||||
|
}
|
||||||
|
|
||||||
|
// you can only copy from one context at a time, because the order and position of commits matter
|
||||||
|
func (self *CherryPickHelper) resetIfNecessary(context types.Context) error {
|
||||||
|
oldContextKey := types.ContextKey(self.getData().ContextKey)
|
||||||
|
|
||||||
|
if oldContextKey != context.GetKey() {
|
||||||
|
// need to reset the cherry picking mode
|
||||||
|
self.getData().ContextKey = string(context.GetKey())
|
||||||
|
self.getData().CherryPickedCommits = make([]*models.Commit, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CherryPickHelper) rerender() error {
|
||||||
|
for _, context := range []types.Context{
|
||||||
|
self.getContexts().BranchCommits,
|
||||||
|
self.getContexts().ReflogCommits,
|
||||||
|
self.getContexts().SubCommits,
|
||||||
|
} {
|
||||||
|
if err := self.c.PostRefreshUpdate(context); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -30,11 +30,13 @@ type LocalCommitsController struct {
|
|||||||
git *commands.GitCommand
|
git *commands.GitCommand
|
||||||
tagsHelper *TagsHelper
|
tagsHelper *TagsHelper
|
||||||
refsHelper IRefsHelper
|
refsHelper IRefsHelper
|
||||||
|
cherryPickHelper *CherryPickHelper
|
||||||
|
rebaseHelper *RebaseHelper
|
||||||
|
|
||||||
getSelectedLocalCommit func() *models.Commit
|
getSelectedLocalCommit func() *models.Commit
|
||||||
getCommits func() []*models.Commit
|
getCommits func() []*models.Commit
|
||||||
getSelectedLocalCommitIdx func() int
|
getSelectedLocalCommitIdx func() int
|
||||||
checkMergeOrRebase CheckMergeOrRebase
|
CheckMergeOrRebase CheckMergeOrRebase
|
||||||
pullFiles PullFilesFn
|
pullFiles PullFilesFn
|
||||||
getHostingServiceMgr GetHostingServiceMgrFn
|
getHostingServiceMgr GetHostingServiceMgrFn
|
||||||
switchToCommitFilesContext SwitchToCommitFilesContextFn
|
switchToCommitFilesContext SwitchToCommitFilesContextFn
|
||||||
@ -54,10 +56,12 @@ func NewLocalCommitsController(
|
|||||||
git *commands.GitCommand,
|
git *commands.GitCommand,
|
||||||
tagsHelper *TagsHelper,
|
tagsHelper *TagsHelper,
|
||||||
refsHelper IRefsHelper,
|
refsHelper IRefsHelper,
|
||||||
|
cherryPickHelper *CherryPickHelper,
|
||||||
|
rebaseHelper *RebaseHelper,
|
||||||
getSelectedLocalCommit func() *models.Commit,
|
getSelectedLocalCommit func() *models.Commit,
|
||||||
getCommits func() []*models.Commit,
|
getCommits func() []*models.Commit,
|
||||||
getSelectedLocalCommitIdx func() int,
|
getSelectedLocalCommitIdx func() int,
|
||||||
checkMergeOrRebase CheckMergeOrRebase,
|
CheckMergeOrRebase CheckMergeOrRebase,
|
||||||
pullFiles PullFilesFn,
|
pullFiles PullFilesFn,
|
||||||
getHostingServiceMgr GetHostingServiceMgrFn,
|
getHostingServiceMgr GetHostingServiceMgrFn,
|
||||||
switchToCommitFilesContext SwitchToCommitFilesContextFn,
|
switchToCommitFilesContext SwitchToCommitFilesContextFn,
|
||||||
@ -74,10 +78,12 @@ func NewLocalCommitsController(
|
|||||||
git: git,
|
git: git,
|
||||||
tagsHelper: tagsHelper,
|
tagsHelper: tagsHelper,
|
||||||
refsHelper: refsHelper,
|
refsHelper: refsHelper,
|
||||||
|
cherryPickHelper: cherryPickHelper,
|
||||||
|
rebaseHelper: rebaseHelper,
|
||||||
getSelectedLocalCommit: getSelectedLocalCommit,
|
getSelectedLocalCommit: getSelectedLocalCommit,
|
||||||
getCommits: getCommits,
|
getCommits: getCommits,
|
||||||
getSelectedLocalCommitIdx: getSelectedLocalCommitIdx,
|
getSelectedLocalCommitIdx: getSelectedLocalCommitIdx,
|
||||||
checkMergeOrRebase: checkMergeOrRebase,
|
CheckMergeOrRebase: CheckMergeOrRebase,
|
||||||
pullFiles: pullFiles,
|
pullFiles: pullFiles,
|
||||||
getHostingServiceMgr: getHostingServiceMgr,
|
getHostingServiceMgr: getHostingServiceMgr,
|
||||||
switchToCommitFilesContext: switchToCommitFilesContext,
|
switchToCommitFilesContext: switchToCommitFilesContext,
|
||||||
@ -160,6 +166,27 @@ func (self *LocalCommitsController) Keybindings(
|
|||||||
Handler: self.checkSelected(self.handleCommitRevert),
|
Handler: self.checkSelected(self.handleCommitRevert),
|
||||||
Description: self.c.Tr.LcRevertCommit,
|
Description: self.c.Tr.LcRevertCommit,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: getKey(config.Universal.New),
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: self.checkSelected(self.newBranch),
|
||||||
|
Description: self.c.Tr.LcCreateNewBranchFromCommit,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: getKey(config.Commits.CherryPickCopy),
|
||||||
|
Handler: self.checkSelected(self.copy),
|
||||||
|
Description: self.c.Tr.LcCherryPickCopy,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: getKey(config.Commits.CherryPickCopyRange),
|
||||||
|
Handler: self.checkSelected(self.copyRange),
|
||||||
|
Description: self.c.Tr.LcCherryPickCopyRange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: getKey(config.Commits.PasteCommits),
|
||||||
|
Handler: guards.OutsideFilterMode(self.paste),
|
||||||
|
Description: self.c.Tr.LcPasteCommits,
|
||||||
|
},
|
||||||
// overriding these navigation keybindings because we might need to load
|
// overriding these navigation keybindings because we might need to load
|
||||||
// more commits on demand
|
// more commits on demand
|
||||||
{
|
{
|
||||||
@ -380,7 +407,7 @@ func (self *LocalCommitsController) pick() error {
|
|||||||
|
|
||||||
func (self *LocalCommitsController) interactiveRebase(action string) error {
|
func (self *LocalCommitsController) interactiveRebase(action string) error {
|
||||||
err := self.git.Rebase.InteractiveRebase(self.getCommits(), self.getSelectedLocalCommitIdx(), action)
|
err := self.git.Rebase.InteractiveRebase(self.getCommits(), self.getSelectedLocalCommitIdx(), action)
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleMidRebaseCommand sees if the selected commit is in fact a rebasing
|
// handleMidRebaseCommand sees if the selected commit is in fact a rebasing
|
||||||
@ -448,7 +475,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error {
|
|||||||
// TODO: use MoveSelectedLine
|
// TODO: use MoveSelectedLine
|
||||||
_ = self.getContext().HandleNextLine()
|
_ = self.getContext().HandleNextLine()
|
||||||
}
|
}
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +510,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
_ = self.getContext().HandlePrevLine()
|
_ = self.getContext().HandlePrevLine()
|
||||||
}
|
}
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +522,7 @@ func (self *LocalCommitsController) handleCommitAmendTo() error {
|
|||||||
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error {
|
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
|
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
|
||||||
err := self.git.Rebase.AmendTo(self.getSelectedLocalCommit().Sha)
|
err := self.git.Rebase.AmendTo(self.getSelectedLocalCommit().Sha)
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -601,7 +628,7 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod
|
|||||||
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error {
|
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
|
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
|
||||||
err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha)
|
err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha)
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -781,3 +808,19 @@ func (self *LocalCommitsController) checkSelected(callback func(*models.Commit)
|
|||||||
func (self *LocalCommitsController) Context() types.Context {
|
func (self *LocalCommitsController) Context() types.Context {
|
||||||
return self.getContext()
|
return self.getContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) newBranch(commit *models.Commit) error {
|
||||||
|
return self.refsHelper.NewBranch(commit.RefName(), commit.Description(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) copy(commit *models.Commit) error {
|
||||||
|
return self.cherryPickHelper.Copy(commit, self.getCommits(), self.getContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) copyRange(*models.Commit) error {
|
||||||
|
return self.cherryPickHelper.CopyRange(self.getContext().GetPanelState().GetSelectedLineIdx(), self.getCommits(), self.getContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) paste() error {
|
||||||
|
return self.cherryPickHelper.Paste()
|
||||||
|
}
|
||||||
|
192
pkg/gui/controllers/rebase_helper.go
Normal file
192
pkg/gui/controllers/rebase_helper.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RebaseHelper struct {
|
||||||
|
c *types.ControllerCommon
|
||||||
|
getContexts func() context.ContextTree
|
||||||
|
git *commands.GitCommand
|
||||||
|
takeOverMergeConflictScrolling func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRebaseHelper(
|
||||||
|
c *types.ControllerCommon,
|
||||||
|
getContexts func() context.ContextTree,
|
||||||
|
git *commands.GitCommand,
|
||||||
|
takeOverMergeConflictScrolling func(),
|
||||||
|
) *RebaseHelper {
|
||||||
|
return &RebaseHelper{
|
||||||
|
c: c,
|
||||||
|
getContexts: getContexts,
|
||||||
|
git: git,
|
||||||
|
takeOverMergeConflictScrolling: takeOverMergeConflictScrolling,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RebaseOption string
|
||||||
|
|
||||||
|
const (
|
||||||
|
REBASE_OPTION_CONTINUE string = "continue"
|
||||||
|
REBASE_OPTION_ABORT string = "abort"
|
||||||
|
REBASE_OPTION_SKIP string = "skip"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (self *RebaseHelper) CreateRebaseOptionsMenu() error {
|
||||||
|
options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT}
|
||||||
|
|
||||||
|
if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
||||||
|
options = append(options, REBASE_OPTION_SKIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems := make([]*types.MenuItem, len(options))
|
||||||
|
for i, option := range options {
|
||||||
|
// note to self. Never, EVER, close over loop variables in a function
|
||||||
|
option := option
|
||||||
|
menuItems[i] = &types.MenuItem{
|
||||||
|
DisplayString: option,
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.genericMergeCommand(option)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var title string
|
||||||
|
if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING {
|
||||||
|
title = self.c.Tr.MergeOptionsTitle
|
||||||
|
} else {
|
||||||
|
title = self.c.Tr.RebaseOptionsTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseHelper) genericMergeCommand(command string) error {
|
||||||
|
status := self.git.Status.WorkingTreeState()
|
||||||
|
|
||||||
|
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
|
||||||
|
return self.c.ErrorMsg(self.c.Tr.NotMergingOrRebasing)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
||||||
|
|
||||||
|
commandType := ""
|
||||||
|
switch status {
|
||||||
|
case enums.REBASE_MODE_MERGING:
|
||||||
|
commandType = "merge"
|
||||||
|
case enums.REBASE_MODE_REBASING:
|
||||||
|
commandType = "rebase"
|
||||||
|
default:
|
||||||
|
// shouldn't be possible to land here
|
||||||
|
}
|
||||||
|
|
||||||
|
// we should end up with a command like 'git merge --continue'
|
||||||
|
|
||||||
|
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
||||||
|
if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig.Git.Merging.ManualCommit {
|
||||||
|
// TODO: see if we should be calling more of the code from self.Git.Rebase.GenericMergeOrRebaseAction
|
||||||
|
return self.c.RunSubprocessAndRefresh(
|
||||||
|
self.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
result := self.git.Rebase.GenericMergeOrRebaseAction(commandType, command)
|
||||||
|
if err := self.CheckMergeOrRebase(result); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var conflictStrings = []string{
|
||||||
|
"Failed to merge in the changes",
|
||||||
|
"When you have resolved this problem",
|
||||||
|
"fix conflicts",
|
||||||
|
"Resolve all conflicts manually",
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMergeConflictErr(errStr string) bool {
|
||||||
|
for _, str := range conflictStrings {
|
||||||
|
if strings.Contains(errStr, str) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseHelper) CheckMergeOrRebase(result error) error {
|
||||||
|
if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
return nil
|
||||||
|
} else if strings.Contains(result.Error(), "No changes - did you forget to use") {
|
||||||
|
return self.genericMergeCommand(REBASE_OPTION_SKIP)
|
||||||
|
} else if strings.Contains(result.Error(), "The previous cherry-pick is now empty") {
|
||||||
|
return self.genericMergeCommand(REBASE_OPTION_CONTINUE)
|
||||||
|
} else if strings.Contains(result.Error(), "No rebase in progress?") {
|
||||||
|
// assume in this case that we're already done
|
||||||
|
return nil
|
||||||
|
} else if isMergeConflictErr(result.Error()) {
|
||||||
|
return self.c.Ask(types.AskOpts{
|
||||||
|
Title: self.c.Tr.FoundConflictsTitle,
|
||||||
|
Prompt: self.c.Tr.FoundConflicts,
|
||||||
|
HandlersManageFocus: true,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
return self.c.PushContext(self.getContexts().Files)
|
||||||
|
},
|
||||||
|
HandleClose: func() error {
|
||||||
|
if err := self.c.PopContext(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.genericMergeCommand(REBASE_OPTION_ABORT)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return self.c.ErrorMsg(result.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error {
|
||||||
|
// prompt user to confirm that they want to abort, then do it
|
||||||
|
mode := self.workingTreeStateNoun()
|
||||||
|
return self.c.Ask(types.AskOpts{
|
||||||
|
Title: fmt.Sprintf(self.c.Tr.AbortTitle, mode),
|
||||||
|
Prompt: fmt.Sprintf(self.c.Tr.AbortPrompt, mode),
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
return self.genericMergeCommand(REBASE_OPTION_ABORT)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseHelper) workingTreeStateNoun() string {
|
||||||
|
workingTreeState := self.git.Status.WorkingTreeState()
|
||||||
|
switch workingTreeState {
|
||||||
|
case enums.REBASE_MODE_NONE:
|
||||||
|
return ""
|
||||||
|
case enums.REBASE_MODE_MERGING:
|
||||||
|
return "merge"
|
||||||
|
default:
|
||||||
|
return "rebase"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress
|
||||||
|
func (self *RebaseHelper) PromptToContinueRebase() error {
|
||||||
|
self.takeOverMergeConflictScrolling()
|
||||||
|
|
||||||
|
return self.c.Ask(types.AskOpts{
|
||||||
|
Title: "continue",
|
||||||
|
Prompt: self.c.Tr.ConflictsResolved,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
return self.genericMergeCommand(REBASE_OPTION_CONTINUE)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@ -22,7 +22,7 @@ type SyncController struct {
|
|||||||
getCheckedOutBranch func() *models.Branch
|
getCheckedOutBranch func() *models.Branch
|
||||||
suggestionsHelper ISuggestionsHelper
|
suggestionsHelper ISuggestionsHelper
|
||||||
getSuggestedRemote func() string
|
getSuggestedRemote func() string
|
||||||
checkMergeOrRebase func(error) error
|
CheckMergeOrRebase func(error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ types.IController = &SyncController{}
|
var _ types.IController = &SyncController{}
|
||||||
@ -33,7 +33,7 @@ func NewSyncController(
|
|||||||
getCheckedOutBranch func() *models.Branch,
|
getCheckedOutBranch func() *models.Branch,
|
||||||
suggestionsHelper ISuggestionsHelper,
|
suggestionsHelper ISuggestionsHelper,
|
||||||
getSuggestedRemote func() string,
|
getSuggestedRemote func() string,
|
||||||
checkMergeOrRebase func(error) error,
|
CheckMergeOrRebase func(error) error,
|
||||||
) *SyncController {
|
) *SyncController {
|
||||||
return &SyncController{
|
return &SyncController{
|
||||||
c: c,
|
c: c,
|
||||||
@ -42,7 +42,7 @@ func NewSyncController(
|
|||||||
getCheckedOutBranch: getCheckedOutBranch,
|
getCheckedOutBranch: getCheckedOutBranch,
|
||||||
suggestionsHelper: suggestionsHelper,
|
suggestionsHelper: suggestionsHelper,
|
||||||
getSuggestedRemote: getSuggestedRemote,
|
getSuggestedRemote: getSuggestedRemote,
|
||||||
checkMergeOrRebase: checkMergeOrRebase,
|
CheckMergeOrRebase: CheckMergeOrRebase,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ func (self *SyncController) pullWithLock(opts PullFilesOptions) error {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.checkMergeOrRebase(err)
|
return self.CheckMergeOrRebase(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type pushOpts struct {
|
type pushOpts struct {
|
||||||
|
@ -9,6 +9,7 @@ type IRefsHelper interface {
|
|||||||
CheckoutRef(ref string, options types.CheckoutRefOptions) error
|
CheckoutRef(ref string, options types.CheckoutRefOptions) error
|
||||||
CreateGitResetMenu(ref string) error
|
CreateGitResetMenu(ref string) error
|
||||||
ResetToRef(ref string, strength string, envVars []string) error
|
ResetToRef(ref string, strength string, envVars []string) error
|
||||||
|
NewBranch(from string, fromDescription string, suggestedBranchname string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ISuggestionsHelper interface {
|
type ISuggestionsHelper interface {
|
||||||
|
@ -53,15 +53,11 @@ func (gui *Gui) currentDiffTerminals() []string {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
context := gui.currentSideListContext()
|
itemId := gui.getSideContextSelectedItemId()
|
||||||
if context == nil {
|
if itemId == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
item, ok := context.GetSelectedItem()
|
return []string{itemId}
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []string{item.ID()}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// list panel functions
|
// list panel functions
|
||||||
@ -77,19 +76,6 @@ func (gui *Gui) filesRenderToMain() error {
|
|||||||
return gui.refreshMainViews(refreshOpts)
|
return gui.refreshMainViews(refreshOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// promptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress
|
|
||||||
func (gui *Gui) promptToContinueRebase() error {
|
|
||||||
gui.takeOverMergeConflictScrolling()
|
|
||||||
|
|
||||||
return gui.PopupHandler.Ask(types.AskOpts{
|
|
||||||
Title: "continue",
|
|
||||||
Prompt: gui.Tr.ConflictsResolved,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return gui.genericMergeCommand(REBASE_OPTION_CONTINUE)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) onFocusFile() error {
|
func (gui *Gui) onFocusFile() error {
|
||||||
gui.takeOverMergeConflictScrolling()
|
gui.takeOverMergeConflictScrolling()
|
||||||
return nil
|
return nil
|
||||||
|
@ -74,6 +74,8 @@ type Helpers struct {
|
|||||||
files *FilesHelper
|
files *FilesHelper
|
||||||
workingTree *WorkingTreeHelper
|
workingTree *WorkingTreeHelper
|
||||||
tags *controllers.TagsHelper
|
tags *controllers.TagsHelper
|
||||||
|
rebase *controllers.RebaseHelper
|
||||||
|
cherryPick *controllers.CherryPickHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
type Repo string
|
type Repo string
|
||||||
@ -373,7 +375,7 @@ const (
|
|||||||
|
|
||||||
type Modes struct {
|
type Modes struct {
|
||||||
Filtering filtering.Filtering
|
Filtering filtering.Filtering
|
||||||
CherryPicking cherrypicking.CherryPicking
|
CherryPicking *cherrypicking.CherryPicking
|
||||||
Diffing diffing.Diffing
|
Diffing diffing.Diffing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,10 +558,12 @@ func (gui *Gui) setControllers() {
|
|||||||
getState := func() *GuiRepoState { return gui.State }
|
getState := func() *GuiRepoState { return gui.State }
|
||||||
getContexts := func() context.ContextTree { return gui.State.Contexts }
|
getContexts := func() context.ContextTree { return gui.State.Contexts }
|
||||||
// TODO: have a getGit function too
|
// TODO: have a getGit function too
|
||||||
|
rebaseHelper := controllers.NewRebaseHelper(controllerCommon, getContexts, gui.git, gui.takeOverMergeConflictScrolling)
|
||||||
gui.helpers = &Helpers{
|
gui.helpers = &Helpers{
|
||||||
refs: NewRefsHelper(
|
refs: NewRefsHelper(
|
||||||
controllerCommon,
|
controllerCommon,
|
||||||
gui.git,
|
gui.git,
|
||||||
|
getContexts,
|
||||||
getState,
|
getState,
|
||||||
),
|
),
|
||||||
bisect: controllers.NewBisectHelper(controllerCommon, gui.git),
|
bisect: controllers.NewBisectHelper(controllerCommon, gui.git),
|
||||||
@ -567,6 +571,14 @@ func (gui *Gui) setControllers() {
|
|||||||
files: NewFilesHelper(controllerCommon, gui.git, osCommand),
|
files: NewFilesHelper(controllerCommon, gui.git, osCommand),
|
||||||
workingTree: NewWorkingTreeHelper(func() []*models.File { return gui.State.Files }),
|
workingTree: NewWorkingTreeHelper(func() []*models.File { return gui.State.Files }),
|
||||||
tags: controllers.NewTagsHelper(controllerCommon, gui.git),
|
tags: controllers.NewTagsHelper(controllerCommon, gui.git),
|
||||||
|
rebase: rebaseHelper,
|
||||||
|
cherryPick: controllers.NewCherryPickHelper(
|
||||||
|
controllerCommon,
|
||||||
|
gui.git,
|
||||||
|
getContexts,
|
||||||
|
func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking },
|
||||||
|
rebaseHelper,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
syncController := controllers.NewSyncController(
|
syncController := controllers.NewSyncController(
|
||||||
@ -575,7 +587,7 @@ func (gui *Gui) setControllers() {
|
|||||||
gui.getCheckedOutBranch,
|
gui.getCheckedOutBranch,
|
||||||
gui.helpers.suggestions,
|
gui.helpers.suggestions,
|
||||||
gui.getSuggestedRemote,
|
gui.getSuggestedRemote,
|
||||||
gui.checkMergeOrRebase,
|
gui.helpers.rebase.CheckMergeOrRebase,
|
||||||
)
|
)
|
||||||
|
|
||||||
gui.Controllers = Controllers{
|
gui.Controllers = Controllers{
|
||||||
@ -624,10 +636,12 @@ func (gui *Gui) setControllers() {
|
|||||||
gui.git,
|
gui.git,
|
||||||
gui.helpers.tags,
|
gui.helpers.tags,
|
||||||
gui.helpers.refs,
|
gui.helpers.refs,
|
||||||
|
gui.helpers.cherryPick,
|
||||||
|
gui.helpers.rebase,
|
||||||
gui.getSelectedLocalCommit,
|
gui.getSelectedLocalCommit,
|
||||||
func() []*models.Commit { return gui.State.Commits },
|
func() []*models.Commit { return gui.State.Commits },
|
||||||
func() int { return gui.State.Panels.Commits.SelectedLineIdx },
|
func() int { return gui.State.Panels.Commits.SelectedLineIdx },
|
||||||
gui.checkMergeOrRebase,
|
gui.helpers.rebase.CheckMergeOrRebase,
|
||||||
syncController.HandlePull,
|
syncController.HandlePull,
|
||||||
gui.getHostingServiceMgr,
|
gui.getHostingServiceMgr,
|
||||||
gui.SwitchToCommitFilesContext,
|
gui.SwitchToCommitFilesContext,
|
||||||
|
@ -276,7 +276,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
{
|
{
|
||||||
ViewName: "",
|
ViewName: "",
|
||||||
Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu),
|
Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu),
|
||||||
Handler: gui.handleCreateRebaseOptionsMenu,
|
Handler: gui.helpers.rebase.CreateRebaseOptionsMenu,
|
||||||
Description: gui.c.Tr.ViewMergeRebaseOptions,
|
Description: gui.c.Tr.ViewMergeRebaseOptions,
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
},
|
},
|
||||||
@ -423,7 +423,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
|
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Universal.New),
|
Key: gui.getKey(config.Universal.New),
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
Handler: gui.handleNewBranchOffBranch,
|
||||||
Description: gui.c.Tr.LcNewBranch,
|
Description: gui.c.Tr.LcNewBranch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -513,13 +513,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
Handler: gui.handleEnterRemoteBranch,
|
Handler: gui.handleEnterRemoteBranch,
|
||||||
Description: gui.c.Tr.LcViewCommits,
|
Description: gui.c.Tr.LcViewCommits,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
ViewName: "commits",
|
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopy),
|
|
||||||
Handler: gui.handleCopyCommit,
|
|
||||||
Description: gui.c.Tr.LcCherryPickCopy,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
||||||
@ -527,33 +520,11 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
Handler: gui.handleCopySelectedSideContextItemToClipboard,
|
Handler: gui.handleCopySelectedSideContextItemToClipboard,
|
||||||
Description: gui.c.Tr.LcCopyCommitShaToClipboard,
|
Description: gui.c.Tr.LcCopyCommitShaToClipboard,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
ViewName: "commits",
|
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopyRange),
|
|
||||||
Handler: gui.handleCopyCommitRange,
|
|
||||||
Description: gui.c.Tr.LcCherryPickCopyRange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ViewName: "commits",
|
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
|
||||||
Key: gui.getKey(config.Commits.PasteCommits),
|
|
||||||
Handler: guards.OutsideFilterMode(gui.HandlePasteCommits),
|
|
||||||
Description: gui.c.Tr.LcPasteCommits,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ViewName: "commits",
|
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
|
||||||
Key: gui.getKey(config.Universal.New),
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
|
||||||
Description: gui.c.Tr.LcCreateNewBranchFromCommit,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.ResetCherryPick),
|
Key: gui.getKey(config.Commits.ResetCherryPick),
|
||||||
Handler: gui.exitCherryPickingMode,
|
Handler: gui.helpers.cherryPick.Reset,
|
||||||
Description: gui.c.Tr.LcResetCherryPick,
|
Description: gui.c.Tr.LcResetCherryPick,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -582,21 +553,21 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopy),
|
Key: gui.getKey(config.Commits.CherryPickCopy),
|
||||||
Handler: guards.OutsideFilterMode(gui.handleCopyCommit),
|
Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommit),
|
||||||
Description: gui.c.Tr.LcCherryPickCopy,
|
Description: gui.c.Tr.LcCherryPickCopy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopyRange),
|
Key: gui.getKey(config.Commits.CherryPickCopyRange),
|
||||||
Handler: guards.OutsideFilterMode(gui.handleCopyCommitRange),
|
Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommitRange),
|
||||||
Description: gui.c.Tr.LcCherryPickCopyRange,
|
Description: gui.c.Tr.LcCherryPickCopyRange,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.ResetCherryPick),
|
Key: gui.getKey(config.Commits.ResetCherryPick),
|
||||||
Handler: gui.exitCherryPickingMode,
|
Handler: gui.helpers.cherryPick.Reset,
|
||||||
Description: gui.c.Tr.LcResetCherryPick,
|
Description: gui.c.Tr.LcResetCherryPick,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -632,28 +603,28 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Universal.New),
|
Key: gui.getKey(config.Universal.New),
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
Handler: gui.handleNewBranchOffSubCommit,
|
||||||
Description: gui.c.Tr.LcNewBranch,
|
Description: gui.c.Tr.LcNewBranch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopy),
|
Key: gui.getKey(config.Commits.CherryPickCopy),
|
||||||
Handler: gui.handleCopyCommit,
|
Handler: gui.handleCopySubCommit,
|
||||||
Description: gui.c.Tr.LcCherryPickCopy,
|
Description: gui.c.Tr.LcCherryPickCopy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.CherryPickCopyRange),
|
Key: gui.getKey(config.Commits.CherryPickCopyRange),
|
||||||
Handler: gui.handleCopyCommitRange,
|
Handler: gui.handleCopySubCommitRange,
|
||||||
Description: gui.c.Tr.LcCherryPickCopyRange,
|
Description: gui.c.Tr.LcCherryPickCopyRange,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Commits.ResetCherryPick),
|
Key: gui.getKey(config.Commits.ResetCherryPick),
|
||||||
Handler: gui.exitCherryPickingMode,
|
Handler: gui.helpers.cherryPick.Reset,
|
||||||
Description: gui.c.Tr.LcResetCherryPick,
|
Description: gui.c.Tr.LcResetCherryPick,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -690,7 +661,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
{
|
{
|
||||||
ViewName: "stash",
|
ViewName: "stash",
|
||||||
Key: gui.getKey(config.Universal.New),
|
Key: gui.getKey(config.Universal.New),
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
Handler: gui.handleNewBranchOffStashEntry,
|
||||||
Description: gui.c.Tr.LcNewBranch,
|
Description: gui.c.Tr.LcNewBranch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1220,14 +1191,14 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
|||||||
Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)},
|
Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Universal.Select),
|
Key: gui.getKey(config.Universal.Select),
|
||||||
// gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch
|
// gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
Handler: gui.handleNewBranchOffRemoteBranch,
|
||||||
Description: gui.c.Tr.LcCheckout,
|
Description: gui.c.Tr.LcCheckout,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "branches",
|
ViewName: "branches",
|
||||||
Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)},
|
Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)},
|
||||||
Key: gui.getKey(config.Universal.New),
|
Key: gui.getKey(config.Universal.New),
|
||||||
Handler: gui.handleNewBranchOffCurrentItem,
|
Handler: gui.handleNewBranchOffRemoteBranch,
|
||||||
Description: gui.c.Tr.LcNewBranch,
|
Description: gui.c.Tr.LcNewBranch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -16,8 +16,7 @@ type ListContext struct {
|
|||||||
OnRenderToMain func(...types.OnFocusOpts) error
|
OnRenderToMain func(...types.OnFocusOpts) error
|
||||||
OnFocusLost func() error
|
OnFocusLost func() error
|
||||||
|
|
||||||
// the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection)
|
OnGetSelectedItemId func() string
|
||||||
SelectedItem func() (types.ListItem, bool)
|
|
||||||
OnGetPanelState func() types.IListPanelState
|
OnGetPanelState func() types.IListPanelState
|
||||||
// if this is true, we'll call GetDisplayStrings for just the visible part of the
|
// if this is true, we'll call GetDisplayStrings for just the visible part of the
|
||||||
// view and re-render that. This is useful when you need to render different
|
// view and re-render that. This is useful when you need to render different
|
||||||
@ -56,8 +55,8 @@ func formatListFooter(selectedLineIdx int, length int) string {
|
|||||||
return fmt.Sprintf("%d of %d", selectedLineIdx+1, length)
|
return fmt.Sprintf("%d of %d", selectedLineIdx+1, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListContext) GetSelectedItem() (types.ListItem, bool) {
|
func (self *ListContext) GetSelectedItemId() string {
|
||||||
return self.SelectedItem()
|
return self.OnGetSelectedItemId()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
|
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
|
||||||
|
@ -63,9 +63,12 @@ func (gui *Gui) branchesListContext() types.IListContext {
|
|||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref)
|
return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedBranch()
|
item := gui.getSelectedBranch()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,9 +88,12 @@ func (gui *Gui) remotesListContext() types.IListContext {
|
|||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref)
|
return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedRemote()
|
item := gui.getSelectedRemote()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,9 +113,12 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext {
|
|||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref)
|
return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedRemoteBranch()
|
item := gui.getSelectedRemoteBranch()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +172,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext {
|
|||||||
return presentation.GetCommitListDisplayStrings(
|
return presentation.GetCommitListDisplayStrings(
|
||||||
gui.State.Commits,
|
gui.State.Commits,
|
||||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||||
gui.cherryPickedCommitShaMap(),
|
gui.helpers.cherryPick.CherryPickedCommitShaMap(),
|
||||||
gui.State.Modes.Diffing.Ref,
|
gui.State.Modes.Diffing.Ref,
|
||||||
parseEmoji,
|
parseEmoji,
|
||||||
selectedCommitSha,
|
selectedCommitSha,
|
||||||
@ -173,9 +182,12 @@ func (gui *Gui) branchCommitsListContext() types.IListContext {
|
|||||||
gui.State.BisectInfo,
|
gui.State.BisectInfo,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedLocalCommit()
|
item := gui.getSelectedLocalCommit()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
RenderSelection: true,
|
RenderSelection: true,
|
||||||
}
|
}
|
||||||
@ -205,7 +217,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext {
|
|||||||
return presentation.GetCommitListDisplayStrings(
|
return presentation.GetCommitListDisplayStrings(
|
||||||
gui.State.SubCommits,
|
gui.State.SubCommits,
|
||||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||||
gui.cherryPickedCommitShaMap(),
|
gui.helpers.cherryPick.CherryPickedCommitShaMap(),
|
||||||
gui.State.Modes.Diffing.Ref,
|
gui.State.Modes.Diffing.Ref,
|
||||||
parseEmoji,
|
parseEmoji,
|
||||||
selectedCommitSha,
|
selectedCommitSha,
|
||||||
@ -215,9 +227,12 @@ func (gui *Gui) subCommitsListContext() types.IListContext {
|
|||||||
git_commands.NewNullBisectInfo(),
|
git_commands.NewNullBisectInfo(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedSubCommit()
|
item := gui.getSelectedSubCommit()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
RenderSelection: true,
|
RenderSelection: true,
|
||||||
}
|
}
|
||||||
@ -259,14 +274,17 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext {
|
|||||||
return presentation.GetReflogCommitListDisplayStrings(
|
return presentation.GetReflogCommitListDisplayStrings(
|
||||||
gui.State.FilteredReflogCommits,
|
gui.State.FilteredReflogCommits,
|
||||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||||
gui.cherryPickedCommitShaMap(),
|
gui.helpers.cherryPick.CherryPickedCommitShaMap(),
|
||||||
gui.State.Modes.Diffing.Ref,
|
gui.State.Modes.Diffing.Ref,
|
||||||
parseEmoji,
|
parseEmoji,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedReflogCommit()
|
item := gui.getSelectedReflogCommit()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,9 +304,12 @@ func (gui *Gui) stashListContext() types.IListContext {
|
|||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref)
|
return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedStashEntry()
|
item := gui.getSelectedStashEntry()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,9 +353,12 @@ func (gui *Gui) submodulesListContext() types.IListContext {
|
|||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules)
|
return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (types.ListItem, bool) {
|
OnGetSelectedItemId: func() string {
|
||||||
item := gui.getSelectedSubmodule()
|
item := gui.getSelectedSubmodule()
|
||||||
return item, item != nil
|
if item == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return item.ID()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
|
|||||||
style.FgCyan,
|
style.FgCyan,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
reset: gui.exitCherryPickingMode,
|
reset: gui.helpers.cherryPick.Reset,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isActive: func() bool {
|
isActive: func() bool {
|
||||||
@ -73,7 +73,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
|
|||||||
formatWorkingTreeState(workingTreeState), style.FgYellow,
|
formatWorkingTreeState(workingTreeState), style.FgYellow,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
reset: gui.abortMergeOrRebaseWithConfirm,
|
reset: gui.helpers.rebase.AbortMergeOrRebaseWithConfirm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isActive: func() bool {
|
isActive: func() bool {
|
||||||
|
@ -11,8 +11,8 @@ type CherryPicking struct {
|
|||||||
ContextKey string
|
ContextKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() CherryPicking {
|
func New() *CherryPicking {
|
||||||
return CherryPicking{
|
return &CherryPicking{
|
||||||
CherryPickedCommits: make([]*models.Commit, 0),
|
CherryPickedCommits: make([]*models.Commit, 0),
|
||||||
ContextKey: "",
|
ContextKey: "",
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error {
|
|||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit)
|
gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit)
|
||||||
err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex)
|
err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex)
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error {
|
|||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit)
|
gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit)
|
||||||
err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx)
|
err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx)
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error {
|
|||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex)
|
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex)
|
||||||
err := gui.git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash)
|
err := gui.git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash)
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error {
|
|||||||
commitIndex := gui.getPatchCommitIndex()
|
commitIndex := gui.getPatchCommitIndex()
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit)
|
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit)
|
||||||
err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex)
|
err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex)
|
||||||
return gui.checkMergeOrRebase(err)
|
return gui.helpers.rebase.CheckMergeOrRebase(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,156 +0,0 @@
|
|||||||
package gui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RebaseOption string
|
|
||||||
|
|
||||||
const (
|
|
||||||
REBASE_OPTION_CONTINUE = "continue"
|
|
||||||
REBASE_OPTION_ABORT = "abort"
|
|
||||||
REBASE_OPTION_SKIP = "skip"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (gui *Gui) handleCreateRebaseOptionsMenu() error {
|
|
||||||
options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT}
|
|
||||||
|
|
||||||
if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
|
||||||
options = append(options, REBASE_OPTION_SKIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItems := make([]*types.MenuItem, len(options))
|
|
||||||
for i, option := range options {
|
|
||||||
// note to self. Never, EVER, close over loop variables in a function
|
|
||||||
option := option
|
|
||||||
menuItems[i] = &types.MenuItem{
|
|
||||||
DisplayString: option,
|
|
||||||
OnPress: func() error {
|
|
||||||
return gui.genericMergeCommand(option)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var title string
|
|
||||||
if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING {
|
|
||||||
title = gui.c.Tr.MergeOptionsTitle
|
|
||||||
} else {
|
|
||||||
title = gui.c.Tr.RebaseOptionsTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) genericMergeCommand(command string) error {
|
|
||||||
status := gui.git.Status.WorkingTreeState()
|
|
||||||
|
|
||||||
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
|
|
||||||
return gui.c.ErrorMsg(gui.c.Tr.NotMergingOrRebasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
|
||||||
|
|
||||||
commandType := ""
|
|
||||||
switch status {
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
commandType = "merge"
|
|
||||||
case enums.REBASE_MODE_REBASING:
|
|
||||||
commandType = "rebase"
|
|
||||||
default:
|
|
||||||
// shouldn't be possible to land here
|
|
||||||
}
|
|
||||||
|
|
||||||
// we should end up with a command like 'git merge --continue'
|
|
||||||
|
|
||||||
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
|
||||||
if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && gui.c.UserConfig.Git.Merging.ManualCommit {
|
|
||||||
// TODO: see if we should be calling more of the code from gui.Git.Rebase.GenericMergeOrRebaseAction
|
|
||||||
return gui.runSubprocessWithSuspenseAndRefresh(
|
|
||||||
gui.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
result := gui.git.Rebase.GenericMergeOrRebaseAction(commandType, command)
|
|
||||||
if err := gui.checkMergeOrRebase(result); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var conflictStrings = []string{
|
|
||||||
"Failed to merge in the changes",
|
|
||||||
"When you have resolved this problem",
|
|
||||||
"fix conflicts",
|
|
||||||
"Resolve all conflicts manually",
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMergeConflictErr(errStr string) bool {
|
|
||||||
for _, str := range conflictStrings {
|
|
||||||
if strings.Contains(errStr, str) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) checkMergeOrRebase(result error) error {
|
|
||||||
if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if result == nil {
|
|
||||||
return nil
|
|
||||||
} else if strings.Contains(result.Error(), "No changes - did you forget to use") {
|
|
||||||
return gui.genericMergeCommand(REBASE_OPTION_SKIP)
|
|
||||||
} else if strings.Contains(result.Error(), "The previous cherry-pick is now empty") {
|
|
||||||
return gui.genericMergeCommand(REBASE_OPTION_CONTINUE)
|
|
||||||
} else if strings.Contains(result.Error(), "No rebase in progress?") {
|
|
||||||
// assume in this case that we're already done
|
|
||||||
return nil
|
|
||||||
} else if isMergeConflictErr(result.Error()) {
|
|
||||||
return gui.c.Ask(types.AskOpts{
|
|
||||||
Title: gui.c.Tr.FoundConflictsTitle,
|
|
||||||
Prompt: gui.c.Tr.FoundConflicts,
|
|
||||||
HandlersManageFocus: true,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return gui.c.PushContext(gui.State.Contexts.Files)
|
|
||||||
},
|
|
||||||
HandleClose: func() error {
|
|
||||||
if err := gui.returnFromContext(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.genericMergeCommand(REBASE_OPTION_ABORT)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return gui.c.ErrorMsg(result.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) abortMergeOrRebaseWithConfirm() error {
|
|
||||||
// prompt user to confirm that they want to abort, then do it
|
|
||||||
mode := gui.workingTreeStateNoun()
|
|
||||||
return gui.c.Ask(types.AskOpts{
|
|
||||||
Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode),
|
|
||||||
Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode),
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return gui.genericMergeCommand(REBASE_OPTION_ABORT)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) workingTreeStateNoun() string {
|
|
||||||
workingTreeState := gui.git.Status.WorkingTreeState()
|
|
||||||
switch workingTreeState {
|
|
||||||
case enums.REBASE_MODE_NONE:
|
|
||||||
return ""
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
return "merge"
|
|
||||||
default:
|
|
||||||
return "rebase"
|
|
||||||
}
|
|
||||||
}
|
|
@ -79,3 +79,22 @@ func (gui *Gui) handleViewReflogCommitFiles() error {
|
|||||||
WindowName: "commits",
|
WindowName: "commits",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCopyReflogCommit() error {
|
||||||
|
commit := gui.getSelectedReflogCommit()
|
||||||
|
if commit == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.cherryPick.Copy(commit, gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCopyReflogCommitRange() error {
|
||||||
|
// just doing this to ensure something is selected
|
||||||
|
commit := gui.getSelectedReflogCommit()
|
||||||
|
if commit == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetPanelState().GetSelectedLineIdx(), gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits)
|
||||||
|
}
|
||||||
|
@ -408,7 +408,7 @@ func (gui *Gui) refreshStateFiles() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 {
|
if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 {
|
||||||
gui.OnUIThread(func() error { return gui.promptToContinueRebase() })
|
gui.OnUIThread(func() error { return gui.helpers.rebase.PromptToContinueRebase() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fileTreeViewModel.RWMutex.Lock()
|
fileTreeViewModel.RWMutex.Lock()
|
||||||
|
@ -6,14 +6,17 @@ import (
|
|||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RefsHelper struct {
|
type RefsHelper struct {
|
||||||
c *types.ControllerCommon
|
c *types.ControllerCommon
|
||||||
git *commands.GitCommand
|
git *commands.GitCommand
|
||||||
|
getContexts func() context.ContextTree
|
||||||
|
|
||||||
getState func() *GuiRepoState
|
getState func() *GuiRepoState
|
||||||
}
|
}
|
||||||
@ -21,11 +24,13 @@ type RefsHelper struct {
|
|||||||
func NewRefsHelper(
|
func NewRefsHelper(
|
||||||
c *types.ControllerCommon,
|
c *types.ControllerCommon,
|
||||||
git *commands.GitCommand,
|
git *commands.GitCommand,
|
||||||
|
getContexts func() context.ContextTree,
|
||||||
getState func() *GuiRepoState,
|
getState func() *GuiRepoState,
|
||||||
) *RefsHelper {
|
) *RefsHelper {
|
||||||
return &RefsHelper{
|
return &RefsHelper{
|
||||||
c: c,
|
c: c,
|
||||||
git: git,
|
git: git,
|
||||||
|
getContexts: getContexts,
|
||||||
getState: getState,
|
getState: getState,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,3 +139,34 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error {
|
|||||||
Items: menuItems,
|
Items: menuItems,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggestedBranchName string) error {
|
||||||
|
message := utils.ResolvePlaceholderString(
|
||||||
|
self.c.Tr.NewBranchNameBranchOff,
|
||||||
|
map[string]string{
|
||||||
|
"branchName": fromFormattedName,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.c.Prompt(types.PromptOpts{
|
||||||
|
Title: message,
|
||||||
|
InitialContent: suggestedBranchName,
|
||||||
|
HandleConfirm: func(response string) error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.CreateBranch)
|
||||||
|
if err := self.git.Branch.New(sanitizedBranchName(response), from); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.c.CurrentContext() != self.getContexts().Branches {
|
||||||
|
if err := self.c.PushContext(self.getContexts().Branches); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0)
|
||||||
|
self.getContexts().Branches.GetPanelState().SetSelectedLineIdx(0)
|
||||||
|
|
||||||
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@ -2,6 +2,7 @@ package gui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
@ -118,3 +119,15 @@ func (gui *Gui) handleEnterRemoteBranch() error {
|
|||||||
|
|
||||||
return gui.switchToSubCommitsContext(selectedBranch.RefName())
|
return gui.switchToSubCommitsContext(selectedBranch.RefName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleNewBranchOffRemoteBranch() error {
|
||||||
|
selectedBranch := gui.getSelectedRemoteBranch()
|
||||||
|
if selectedBranch == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// will set to the remote's branch name without the remote name
|
||||||
|
nameSuggestion := strings.SplitAfterN(selectedBranch.RefName(), "/", 2)[1]
|
||||||
|
|
||||||
|
return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion)
|
||||||
|
}
|
||||||
|
@ -136,3 +136,12 @@ func (gui *Gui) handleViewStashFiles() error {
|
|||||||
WindowName: "stash",
|
WindowName: "stash",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleNewBranchOffStashEntry() error {
|
||||||
|
stashEntry := gui.getSelectedStashEntry()
|
||||||
|
if stashEntry == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "")
|
||||||
|
}
|
||||||
|
@ -48,7 +48,7 @@ func (gui *Gui) handleStatusClick() error {
|
|||||||
case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING:
|
case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING:
|
||||||
workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState))
|
workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState))
|
||||||
if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) {
|
if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) {
|
||||||
return gui.handleCreateRebaseOptionsMenu()
|
return gui.helpers.rebase.CreateRebaseOptionsMenu()
|
||||||
}
|
}
|
||||||
if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
|
if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
|
||||||
return gui.handleCreateRecentReposMenu()
|
return gui.handleCreateRecentReposMenu()
|
||||||
|
@ -102,3 +102,31 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error {
|
|||||||
|
|
||||||
return gui.c.PushContext(gui.State.Contexts.SubCommits)
|
return gui.c.PushContext(gui.State.Contexts.SubCommits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleNewBranchOffSubCommit() error {
|
||||||
|
commit := gui.getSelectedSubCommit()
|
||||||
|
if commit == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.refs.NewBranch(commit.RefName(), commit.Description(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCopySubCommit() error {
|
||||||
|
commit := gui.getSelectedSubCommit()
|
||||||
|
if commit == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.cherryPick.Copy(commit, gui.State.SubCommits, gui.State.Contexts.SubCommits)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCopySubCommitRange() error {
|
||||||
|
// just doing this to ensure something is selected
|
||||||
|
commit := gui.getSelectedSubCommit()
|
||||||
|
if commit == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.SubCommits.GetPanelState().GetSelectedLineIdx(), gui.State.SubCommits, gui.State.Contexts.SubCommits)
|
||||||
|
}
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// if Go let me do private struct embedding of structs with public fields (which it should)
|
|
||||||
// I would just do that. But alas.
|
|
||||||
type ControllerCommon struct {
|
type ControllerCommon struct {
|
||||||
*common.Common
|
*common.Common
|
||||||
IGuiCommon
|
IGuiCommon
|
||||||
|
@ -61,8 +61,8 @@ type IController interface {
|
|||||||
|
|
||||||
type IListContext interface {
|
type IListContext interface {
|
||||||
HasKeybindings
|
HasKeybindings
|
||||||
GetSelectedItem() (ListItem, bool)
|
|
||||||
|
|
||||||
|
GetSelectedItemId() string
|
||||||
HandlePrevLine() error
|
HandlePrevLine() error
|
||||||
HandleNextLine() error
|
HandleNextLine() error
|
||||||
HandleScrollLeft() error
|
HandleScrollLeft() error
|
||||||
|
Loading…
Reference in New Issue
Block a user