1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-01 13:17:53 +02:00

refactor controllers

This commit is contained in:
Jesse Duffield 2022-02-06 15:54:26 +11:00
parent b93b8cc00a
commit 722410aded
56 changed files with 1406 additions and 1553 deletions

View File

@ -1,18 +1,5 @@
package gui
import (
"errors"
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
// list panel functions
func (gui *Gui) branchesRenderToMain() error {
var task updateTask
branch := gui.State.Contexts.Branches.GetSelected()
@ -31,368 +18,3 @@ func (gui *Gui) branchesRenderToMain() error {
},
})
}
// specific functions
func (gui *Gui) handleBranchPress() error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil {
return nil
}
if branch == gui.getCheckedOutBranch() {
return gui.c.ErrorMsg(gui.c.Tr.AlreadyCheckedOutBranch)
}
gui.c.LogAction(gui.c.Tr.Actions.CheckoutBranch)
return gui.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{})
}
func (gui *Gui) handleCreatePullRequestPress() error {
branch := gui.State.Contexts.Branches.GetSelected()
return gui.createPullRequest(branch.Name, "")
}
func (gui *Gui) handleCreatePullRequestMenu() error {
selectedBranch := gui.State.Contexts.Branches.GetSelected()
if selectedBranch == nil {
return nil
}
checkedOutBranch := gui.getCheckedOutBranch()
return gui.createPullRequestMenu(selectedBranch, checkedOutBranch)
}
func (gui *Gui) handleCopyPullRequestURLPress() error {
hostingServiceMgr := gui.getHostingServiceMgr()
branch := gui.State.Contexts.Branches.GetSelected()
branchExistsOnRemote := gui.git.Remote.CheckRemoteBranchExists(branch.Name)
if !branchExistsOnRemote {
return gui.c.Error(errors.New(gui.c.Tr.NoBranchOnRemote))
}
url, err := hostingServiceMgr.GetPullRequestURL(branch.Name, "")
if err != nil {
return gui.c.Error(err)
}
gui.c.LogAction(gui.c.Tr.Actions.CopyPullRequestURL)
if err := gui.os.CopyToClipboard(url); err != nil {
return gui.c.Error(err)
}
gui.c.Toast(gui.c.Tr.PullRequestURLCopiedToClipboard)
return nil
}
func (gui *Gui) handleGitFetch() error {
return gui.c.WithLoaderPanel(gui.c.Tr.FetchWait, func() error {
if err := gui.fetch(); err != nil {
_ = gui.c.Error(err)
}
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
})
}
func (gui *Gui) handleForceCheckout() error {
branch := gui.State.Contexts.Branches.GetSelected()
message := gui.c.Tr.SureForceCheckout
title := gui.c.Tr.ForceCheckoutBranch
return gui.c.Ask(types.AskOpts{
Title: title,
Prompt: message,
HandleConfirm: func() error {
gui.c.LogAction(gui.c.Tr.Actions.ForceCheckoutBranch)
if err := gui.git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil {
_ = gui.c.Error(err)
}
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
},
})
}
func (gui *Gui) handleCheckoutByName() error {
return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.BranchName + ":",
FindSuggestionsFunc: gui.helpers.Suggestions.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error {
gui.c.LogAction("Checkout branch")
return gui.helpers.Refs.CheckoutRef(response, types.CheckoutRefOptions{
OnRefNotFound: func(ref string) error {
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.BranchNotFoundTitle,
Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"),
HandleConfirm: func() error {
return gui.createNewBranchWithName(ref)
},
})
},
})
}},
)
}
func (gui *Gui) getCheckedOutBranch() *models.Branch {
if len(gui.State.Model.Branches) == 0 {
return nil
}
return gui.State.Model.Branches[0]
}
func (gui *Gui) createNewBranchWithName(newBranchName string) error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil {
return nil
}
if err := gui.git.Branch.New(newBranchName, branch.Name); err != nil {
return gui.c.Error(err)
}
gui.State.Contexts.Branches.SetSelectedLineIdx(0)
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}
func (gui *Gui) handleDeleteBranch() error {
return gui.deleteBranch(false)
}
func (gui *Gui) deleteBranch(force bool) error {
selectedBranch := gui.State.Contexts.Branches.GetSelected()
if selectedBranch == nil {
return nil
}
checkedOutBranch := gui.getCheckedOutBranch()
if checkedOutBranch.Name == selectedBranch.Name {
return gui.c.ErrorMsg(gui.c.Tr.CantDeleteCheckOutBranch)
}
return gui.deleteNamedBranch(selectedBranch, force)
}
func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) error {
title := gui.c.Tr.DeleteBranch
var templateStr string
if force {
templateStr = gui.c.Tr.ForceDeleteBranchMessage
} else {
templateStr = gui.c.Tr.DeleteBranchMessage
}
message := utils.ResolvePlaceholderString(
templateStr,
map[string]string{
"selectedBranchName": selectedBranch.Name,
},
)
return gui.c.Ask(types.AskOpts{
Title: title,
Prompt: message,
HandleConfirm: func() error {
gui.c.LogAction(gui.c.Tr.Actions.DeleteBranch)
if err := gui.git.Branch.Delete(selectedBranch.Name, force); err != nil {
errMessage := err.Error()
if !force && strings.Contains(errMessage, "git branch -D ") {
return gui.deleteNamedBranch(selectedBranch, true)
}
return gui.c.ErrorMsg(errMessage)
}
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
},
})
}
func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
if gui.git.Branch.IsHeadDetached() {
return gui.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on")
}
checkedOutBranchName := gui.getCheckedOutBranch().Name
if checkedOutBranchName == branchName {
return gui.c.ErrorMsg(gui.c.Tr.CantMergeBranchIntoItself)
}
prompt := utils.ResolvePlaceholderString(
gui.c.Tr.ConfirmMerge,
map[string]string{
"checkedOutBranch": checkedOutBranchName,
"selectedBranch": branchName,
},
)
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.MergingTitle,
Prompt: prompt,
HandleConfirm: func() error {
gui.c.LogAction(gui.c.Tr.Actions.Merge)
err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{})
return gui.helpers.Rebase.CheckMergeOrRebase(err)
},
})
}
func (gui *Gui) handleMerge() error {
selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name
return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName)
}
func (gui *Gui) handleRebaseOntoLocalBranch() error {
selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name
return gui.handleRebaseOntoBranch(selectedBranchName)
}
func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error {
checkedOutBranch := gui.getCheckedOutBranch().Name
if selectedBranchName == checkedOutBranch {
return gui.c.ErrorMsg(gui.c.Tr.CantRebaseOntoSelf)
}
prompt := utils.ResolvePlaceholderString(
gui.c.Tr.ConfirmRebase,
map[string]string{
"checkedOutBranch": checkedOutBranch,
"selectedBranch": selectedBranchName,
},
)
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.RebasingTitle,
Prompt: prompt,
HandleConfirm: func() error {
gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch)
err := gui.git.Rebase.RebaseBranch(selectedBranchName)
return gui.helpers.Rebase.CheckMergeOrRebase(err)
},
})
}
func (gui *Gui) handleFastForward() error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil || !branch.IsRealBranch() {
return nil
}
if !branch.IsTrackingRemote() {
return gui.c.ErrorMsg(gui.c.Tr.FwdNoUpstream)
}
if !branch.RemoteBranchStoredLocally() {
return gui.c.ErrorMsg(gui.c.Tr.FwdNoLocalUpstream)
}
if branch.HasCommitsToPush() {
return gui.c.ErrorMsg(gui.c.Tr.FwdCommitsToPush)
}
action := gui.c.Tr.Actions.FastForwardBranch
message := utils.ResolvePlaceholderString(
gui.c.Tr.Fetching,
map[string]string{
"from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch),
"to": branch.Name,
},
)
return gui.c.WithLoaderPanel(message, func() error {
if branch == gui.getCheckedOutBranch() {
gui.c.LogAction(action)
err := gui.git.Sync.Pull(
git_commands.PullOptions{
RemoteName: branch.UpstreamRemote,
BranchName: branch.Name,
FastForwardOnly: true,
},
)
if err != nil {
_ = gui.c.Error(err)
}
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
} else {
gui.c.LogAction(action)
err := gui.git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch)
if err != nil {
_ = gui.c.Error(err)
}
_ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
}
return nil
})
}
func (gui *Gui) handleCreateResetToBranchMenu() error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil {
return nil
}
return gui.helpers.Refs.CreateGitResetMenu(branch.Name)
}
func (gui *Gui) handleRenameBranch() error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil || !branch.IsRealBranch() {
return nil
}
promptForNewName := func() error {
return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":",
InitialContent: branch.Name,
HandleConfirm: func(newBranchName string) error {
gui.c.LogAction(gui.c.Tr.Actions.RenameBranch)
if err := gui.git.Branch.Rename(branch.Name, newBranchName); err != nil {
return gui.c.Error(err)
}
// need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch
gui.refreshBranches()
// now that we've got our stuff again we need to find that branch and reselect it.
for i, newBranch := range gui.State.Model.Branches {
if newBranch.Name == newBranchName {
gui.State.Contexts.Branches.SetSelectedLineIdx(i)
if err := gui.State.Contexts.Branches.HandleRender(); err != nil {
return err
}
}
}
return nil
},
})
}
// I could do an explicit check here for whether the branch is tracking a remote branch
// but if we've selected it we'll already know that via Pullables and Pullables.
// Bit of a hack but I'm lazy.
if !branch.IsTrackingRemote() {
return promptForNewName()
}
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.LcRenameBranch,
Prompt: gui.c.Tr.RenameBranchWarning,
HandleConfirm: promptForNewName,
})
}
func (gui *Gui) handleEnterBranch() error {
branch := gui.State.Contexts.Branches.GetSelected()
if branch == nil {
return nil
}
return gui.switchToSubCommitsContext(branch.RefName())
}
func (gui *Gui) handleNewBranchOffBranch() error {
selectedBranch := gui.State.Contexts.Branches.GetSelected()
if selectedBranch == nil {
return nil
}
return gui.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "")
}

View File

@ -85,7 +85,7 @@ func (gui *Gui) handleDiscardOldFileChange() error {
return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error {
gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange)
if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.BranchCommits.GetSelectedLineIdx(), fileName); err != nil {
if err := gui.helpers.Rebase.CheckMergeOrRebase(err); err != nil {
if err := gui.helpers.MergeAndRebase.CheckMergeOrRebase(err); err != nil {
return err
}
}
@ -265,7 +265,7 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC
gui.State.Contexts.CommitFiles.SetRefName(opts.RefName)
gui.State.Contexts.CommitFiles.SetCanRebase(opts.CanRebase)
gui.State.Contexts.CommitFiles.SetParentContext(opts.Context)
gui.State.Contexts.CommitFiles.SetWindowName(opts.WindowName)
gui.State.Contexts.CommitFiles.SetWindowName(opts.Context.GetWindowName())
if err := gui.refreshCommitFilesView(); err != nil {
return err

View File

@ -23,7 +23,7 @@ func NewBranchesContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *BranchesContext {
viewModel := NewBranchesViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewCommitFilesContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *CommitFilesContext {
viewModel := filetree.NewCommitFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree)

View File

@ -10,7 +10,7 @@ import (
type ListContextTrait struct {
types.Context
c *types.ControllerCommon
c *types.HelperCommon
list types.IList
viewTrait *ViewTrait
getDisplayStrings func(startIdx int, length int) [][]string

View File

@ -23,7 +23,7 @@ func NewLocalCommitsContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *LocalCommitsContext {
viewModel := NewLocalCommitsViewModel(getModel)
@ -61,8 +61,14 @@ func (self *LocalCommitsContext) GetSelectedItemId() string {
type LocalCommitsViewModel struct {
*traits.ListCursor
getModel func() []*models.Commit
// If this is true we limit the amount of commits we load, for the sake of keeping things fast.
// If the user attempts to scroll past the end of the list, we will load more commits.
limitCommits bool
getModel func() []*models.Commit
// If this is true we'll use git log --all when fetching the commits.
showWholeGitGraph bool
}
func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsViewModel {
@ -95,3 +101,11 @@ func (self *LocalCommitsViewModel) SetLimitCommits(value bool) {
func (self *LocalCommitsViewModel) GetLimitCommits() bool {
return self.limitCommits
}
func (self *LocalCommitsViewModel) SetShowWholeGitGraph(value bool) {
self.showWholeGitGraph = value
}
func (self *LocalCommitsViewModel) GetShowWholeGitGraph() bool {
return self.showWholeGitGraph
}

View File

@ -21,7 +21,7 @@ func NewMenuContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
getOptionsMap func() map[string]string,
) *MenuContext {
viewModel := NewMenuViewModel()

View File

@ -23,7 +23,7 @@ func NewReflogCommitsContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *ReflogCommitsContext {
viewModel := NewReflogCommitsViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewRemoteBranchesContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *RemoteBranchesContext {
viewModel := NewRemoteBranchesViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewRemotesContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *RemotesContext {
viewModel := NewRemotesViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewStashContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *StashContext {
viewModel := NewStashViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewSubCommitsContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *SubCommitsContext {
viewModel := NewSubCommitsViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewSubmodulesContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *SubmodulesContext {
viewModel := NewSubmodulesViewModel(getModel)

View File

@ -22,7 +22,7 @@ func NewSuggestionsContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *SuggestionsContext {
viewModel := NewSuggestionsViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewTagsContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *TagsContext {
viewModel := NewTagsViewModel(getModel)

View File

@ -23,7 +23,7 @@ func NewWorkingTreeContext(
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
c *types.HelperCommon,
) *WorkingTreeContext {
viewModel := filetree.NewFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree)

View File

@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
@ -13,33 +12,17 @@ import (
type BisectController struct {
baseController
c *types.ControllerCommon
context *context.LocalCommitsContext
git *commands.GitCommand
bisectHelper *BisectHelper
getCommits func() []*models.Commit
*controllerCommon
}
var _ types.IController = &BisectController{}
func NewBisectController(
c *types.ControllerCommon,
context *context.LocalCommitsContext,
git *commands.GitCommand,
bisectHelper *BisectHelper,
getCommits func() []*models.Commit,
common *controllerCommon,
) *BisectController {
return &BisectController{
baseController: baseController{},
c: c,
context: context,
git: git,
bisectHelper: bisectHelper,
getCommits: getCommits,
baseController: baseController{},
controllerCommon: common,
}
}
@ -119,7 +102,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
{
DisplayString: self.c.Tr.Bisect.ResetOption,
OnPress: func() error {
return self.bisectHelper.Reset()
return self.helpers.Bisect.Reset()
},
},
}
@ -146,7 +129,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
return self.c.Error(err)
}
return self.bisectHelper.PostBisectCommandRefresh()
return self.helpers.Bisect.PostBisectCommandRefresh()
},
},
{
@ -161,7 +144,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
return self.c.Error(err)
}
return self.bisectHelper.PostBisectCommandRefresh()
return self.helpers.Bisect.PostBisectCommandRefresh()
},
},
},
@ -188,7 +171,7 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string)
return self.c.Error(err)
}
return self.bisectHelper.PostBisectCommandRefresh()
return self.helpers.Bisect.PostBisectCommandRefresh()
},
})
}
@ -222,7 +205,7 @@ func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToR
} else {
selectFn()
return self.bisectHelper.PostBisectCommandRefresh()
return self.helpers.Bisect.PostBisectCommandRefresh()
}
}
@ -230,10 +213,10 @@ func (self *BisectController) selectCurrentBisectCommit() {
info := self.git.Bisect.GetInfo()
if info.GetCurrentSha() != "" {
// find index of commit with that sha, move cursor to that.
for i, commit := range self.getCommits() {
for i, commit := range self.model.Commits {
if commit.Sha == info.GetCurrentSha() {
self.context.SetSelectedLineIdx(i)
_ = self.context.HandleFocus()
self.context().SetSelectedLineIdx(i)
_ = self.context().HandleFocus()
break
}
}
@ -242,7 +225,7 @@ func (self *BisectController) selectCurrentBisectCommit() {
func (self *BisectController) checkSelected(callback func(*models.Commit) error) func() error {
return func() error {
commit := self.context.GetSelected()
commit := self.context().GetSelected()
if commit == nil {
return nil
}
@ -252,5 +235,9 @@ func (self *BisectController) checkSelected(callback func(*models.Commit) error)
}
func (self *BisectController) Context() types.Context {
return self.context
return self.context()
}
func (self *BisectController) context() *context.LocalCommitsContext {
return self.contexts.BranchCommits
}

View File

@ -0,0 +1,475 @@
package controllers
import (
"errors"
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"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/utils"
)
type BranchesController struct {
baseController
*controllerCommon
}
var _ types.IController = &BranchesController{}
func NewBranchesController(
common *controllerCommon,
) *BranchesController {
return &BranchesController{
baseController: baseController{},
controllerCommon: common,
}
}
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Universal.Select),
Handler: self.handleBranchPress,
Description: self.c.Tr.LcCheckout,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.CreatePullRequest),
Handler: self.handleCreatePullRequestPress,
Description: self.c.Tr.LcCreatePullRequest,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions),
Handler: self.checkSelected(self.handleCreatePullRequestMenu),
Description: self.c.Tr.LcCreatePullRequestOptions,
OpensMenu: true,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL),
Handler: self.handleCopyPullRequestURLPress,
Description: self.c.Tr.LcCopyPullRequestURL,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName),
Handler: self.handleCheckoutByName,
Description: self.c.Tr.LcCheckoutByName,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch),
Handler: self.handleForceCheckout,
Description: self.c.Tr.LcForceCheckout,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Universal.New),
Handler: self.checkSelected(self.handleNewBranchOffBranch),
Description: self.c.Tr.LcNewBranch,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.checkSelectedAndReal(self.handleDeleteBranch),
Description: self.c.Tr.LcDeleteBranch,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
Handler: opts.Guards.OutsideFilterMode(self.handleRebaseOntoLocalBranch),
Description: self.c.Tr.LcRebaseBranch,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
Handler: opts.Guards.OutsideFilterMode(self.handleMerge),
Description: self.c.Tr.LcMergeIntoCurrentBranch,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.FastForward),
Handler: self.checkSelectedAndReal(self.handleFastForward),
Description: self.c.Tr.FastForward,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
Handler: self.checkSelected(self.handleCreateResetToBranchMenu),
Description: self.c.Tr.LcViewResetOptions,
OpensMenu: true,
},
{
ViewName: "branches",
Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Branches.RenameBranch),
Handler: self.checkSelectedAndReal(self.handleRenameBranch),
Description: self.c.Tr.LcRenameBranch,
},
}
}
func (self *BranchesController) Context() types.Context {
return self.context()
}
func (self *BranchesController) context() *context.BranchesContext {
return self.contexts.Branches
}
func (self *BranchesController) handleBranchPress() error {
branch := self.context().GetSelected()
if branch == nil {
return nil
}
if branch == self.helpers.Refs.GetCheckedOutRef() {
return self.c.ErrorMsg(self.c.Tr.AlreadyCheckedOutBranch)
}
self.c.LogAction(self.c.Tr.Actions.CheckoutBranch)
return self.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{})
}
func (self *BranchesController) handleCreatePullRequestPress() error {
branch := self.context().GetSelected()
return self.createPullRequest(branch.Name, "")
}
func (self *BranchesController) handleCreatePullRequestMenu(selectedBranch *models.Branch) error {
checkedOutBranch := self.helpers.Refs.GetCheckedOutRef()
return self.createPullRequestMenu(selectedBranch, checkedOutBranch)
}
func (self *BranchesController) handleCopyPullRequestURLPress() error {
branch := self.context().GetSelected()
branchExistsOnRemote := self.git.Remote.CheckRemoteBranchExists(branch.Name)
if !branchExistsOnRemote {
return self.c.Error(errors.New(self.c.Tr.NoBranchOnRemote))
}
url, err := self.helpers.Host.GetPullRequestURL(branch.Name, "")
if err != nil {
return self.c.Error(err)
}
self.c.LogAction(self.c.Tr.Actions.CopyPullRequestURL)
if err := self.os.CopyToClipboard(url); err != nil {
return self.c.Error(err)
}
self.c.Toast(self.c.Tr.PullRequestURLCopiedToClipboard)
return nil
}
func (self *BranchesController) handleForceCheckout() error {
branch := self.context().GetSelected()
message := self.c.Tr.SureForceCheckout
title := self.c.Tr.ForceCheckoutBranch
return self.c.Ask(types.AskOpts{
Title: title,
Prompt: message,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.ForceCheckoutBranch)
if err := self.git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
},
})
}
func (self *BranchesController) handleCheckoutByName() error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.BranchName + ":",
FindSuggestionsFunc: self.helpers.Suggestions.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error {
self.c.LogAction("Checkout branch")
return self.helpers.Refs.CheckoutRef(response, types.CheckoutRefOptions{
OnRefNotFound: func(ref string) error {
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.BranchNotFoundTitle,
Prompt: fmt.Sprintf("%s %s%s", self.c.Tr.BranchNotFoundPrompt, ref, "?"),
HandleConfirm: func() error {
return self.createNewBranchWithName(ref)
},
})
},
})
}},
)
}
func (self *BranchesController) createNewBranchWithName(newBranchName string) error {
branch := self.context().GetSelected()
if branch == nil {
return nil
}
if err := self.git.Branch.New(newBranchName, branch.Name); err != nil {
return self.c.Error(err)
}
self.context().SetSelectedLineIdx(0)
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}
func (self *BranchesController) handleDeleteBranch(branch *models.Branch) error {
return self.deleteBranch(branch, false)
}
func (self *BranchesController) deleteBranch(branch *models.Branch, force bool) error {
checkedOutBranch := self.helpers.Refs.GetCheckedOutRef()
if checkedOutBranch.Name == branch.Name {
return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch)
}
return self.deleteNamedBranch(branch, force)
}
func (self *BranchesController) deleteNamedBranch(selectedBranch *models.Branch, force bool) error {
title := self.c.Tr.DeleteBranch
var templateStr string
if force {
templateStr = self.c.Tr.ForceDeleteBranchMessage
} else {
templateStr = self.c.Tr.DeleteBranchMessage
}
message := utils.ResolvePlaceholderString(
templateStr,
map[string]string{
"selectedBranchName": selectedBranch.Name,
},
)
return self.c.Ask(types.AskOpts{
Title: title,
Prompt: message,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.DeleteBranch)
if err := self.git.Branch.Delete(selectedBranch.Name, force); err != nil {
errMessage := err.Error()
if !force && strings.Contains(errMessage, "git branch -D ") {
return self.deleteNamedBranch(selectedBranch, true)
}
return self.c.ErrorMsg(errMessage)
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
},
})
}
func (self *BranchesController) handleMerge() error {
selectedBranchName := self.context().GetSelected().Name
return self.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)
}
func (self *BranchesController) handleRebaseOntoLocalBranch() error {
selectedBranchName := self.context().GetSelected().Name
return self.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName)
}
func (self *BranchesController) handleFastForward(branch *models.Branch) error {
if !branch.IsTrackingRemote() {
return self.c.ErrorMsg(self.c.Tr.FwdNoUpstream)
}
if !branch.RemoteBranchStoredLocally() {
return self.c.ErrorMsg(self.c.Tr.FwdNoLocalUpstream)
}
if branch.HasCommitsToPush() {
return self.c.ErrorMsg(self.c.Tr.FwdCommitsToPush)
}
action := self.c.Tr.Actions.FastForwardBranch
message := utils.ResolvePlaceholderString(
self.c.Tr.Fetching,
map[string]string{
"from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch),
"to": branch.Name,
},
)
return self.c.WithLoaderPanel(message, func() error {
if branch == self.helpers.Refs.GetCheckedOutRef() {
self.c.LogAction(action)
err := self.git.Sync.Pull(
git_commands.PullOptions{
RemoteName: branch.UpstreamRemote,
BranchName: branch.Name,
FastForwardOnly: true,
},
)
if err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
} else {
self.c.LogAction(action)
err := self.git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch)
if err != nil {
_ = self.c.Error(err)
}
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
}
return nil
})
}
func (self *BranchesController) handleCreateResetToBranchMenu(selectedBranch *models.Branch) error {
return self.helpers.Refs.CreateGitResetMenu(selectedBranch.Name)
}
func (self *BranchesController) handleRenameBranch(branch *models.Branch) error {
promptForNewName := func() error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":",
InitialContent: branch.Name,
HandleConfirm: func(newBranchName string) error {
self.c.LogAction(self.c.Tr.Actions.RenameBranch)
if err := self.git.Branch.Rename(branch.Name, newBranchName); err != nil {
return self.c.Error(err)
}
// need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch
_ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.BRANCHES}})
// now that we've got our stuff again we need to find that branch and reselect it.
for i, newBranch := range self.model.Branches {
if newBranch.Name == newBranchName {
self.context().SetSelectedLineIdx(i)
if err := self.context().HandleRender(); err != nil {
return err
}
}
}
return nil
},
})
}
// I could do an explicit check here for whether the branch is tracking a remote branch
// but if we've selected it we'll already know that via Pullables and Pullables.
// Bit of a hack but I'm lazy.
if !branch.IsTrackingRemote() {
return promptForNewName()
}
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.LcRenameBranch,
Prompt: self.c.Tr.RenameBranchWarning,
HandleConfirm: promptForNewName,
})
}
func (self *BranchesController) handleNewBranchOffBranch(selectedBranch *models.Branch) error {
return self.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "")
}
func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
menuItems := make([]*types.MenuItem, 0, 4)
fromToDisplayStrings := func(from string, to string) []string {
return []string{fmt.Sprintf("%s → %s", from, to)}
}
menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem {
return []*types.MenuItem{
{
DisplayStrings: fromToDisplayStrings(branch.Name, self.c.Tr.LcDefaultBranch),
OnPress: func() error {
return self.createPullRequest(branch.Name, "")
},
},
{
DisplayStrings: fromToDisplayStrings(branch.Name, self.c.Tr.LcSelectBranch),
OnPress: func() error {
return self.c.Prompt(types.PromptOpts{
Title: branch.Name + " →",
FindSuggestionsFunc: self.helpers.Suggestions.GetBranchNameSuggestionsFunc(),
HandleConfirm: func(targetBranchName string) error {
return self.createPullRequest(branch.Name, targetBranchName)
}},
)
},
},
}
}
if selectedBranch != checkedOutBranch {
menuItems = append(menuItems,
&types.MenuItem{
DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name),
OnPress: func() error {
return self.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
},
},
)
menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...)
}
menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
return self.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(self.c.Tr.CreatePullRequestOptions), Items: menuItems})
}
func (self *BranchesController) createPullRequest(from string, to string) error {
url, err := self.helpers.Host.GetPullRequestURL(from, to)
if err != nil {
return self.c.Error(err)
}
self.c.LogAction(self.c.Tr.Actions.OpenPullRequest)
if err := self.os.OpenLink(url); err != nil {
return self.c.Error(err)
}
return nil
}
func (self *BranchesController) checkSelected(callback func(*models.Branch) error) func() error {
return func() error {
selectedItem := self.context().GetSelected()
if selectedItem == nil {
return nil
}
return callback(selectedItem)
}
}
func (self *BranchesController) checkSelectedAndReal(callback func(*models.Branch) error) func() error {
return func() error {
selectedItem := self.context().GetSelected()
if selectedItem == nil || !selectedItem.IsRealBranch() {
return nil
}
return callback(selectedItem)
}
}

View File

@ -0,0 +1,39 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type controllerCommon struct {
c *types.HelperCommon
os *oscommands.OSCommand
git *commands.GitCommand
helpers *helpers.Helpers
model *types.Model
contexts *context.ContextTree
modes *types.Modes
}
func NewControllerCommon(
c *types.HelperCommon,
os *oscommands.OSCommand,
git *commands.GitCommand,
helpers *helpers.Helpers,
model *types.Model,
contexts *context.ContextTree,
modes *types.Modes,
) *controllerCommon {
return &controllerCommon{
c: c,
os: os,
git: git,
helpers: helpers,
model: model,
contexts: contexts,
modes: modes,
}
}

View File

@ -6,7 +6,7 @@ import (
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/config"
@ -17,73 +17,33 @@ import (
)
type FilesController struct {
// I've said publicly that I'm against single-letter variable names but in this
// case I would actually prefer a _zero_ letter variable name in the form of
// struct embedding, but Go does not allow hiding public fields in an embedded struct
// to the client
c *types.ControllerCommon
context *context.WorkingTreeContext
model *types.Model
git *commands.GitCommand
os *oscommands.OSCommand
baseController
*controllerCommon
getSelectedFileNode func() *filetree.FileNode
contexts *context.ContextTree
enterSubmodule func(submodule *models.SubmoduleConfig) error
getSubmodules func() []*models.SubmoduleConfig
setCommitMessage func(message string)
getCheckedOutBranch func() *models.Branch
withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error
getFailedCommitMessage func() string
getSelectedPath func() string
switchToMergeFn func(path string) error
suggestionsHelper ISuggestionsHelper
refsHelper IRefsHelper
filesHelper IFilesHelper
workingTreeHelper IWorkingTreeHelper
}
var _ types.IController = &FilesController{}
func NewFilesController(
c *types.ControllerCommon,
context *context.WorkingTreeContext,
model *types.Model,
git *commands.GitCommand,
os *oscommands.OSCommand,
getSelectedFileNode func() *filetree.FileNode,
allContexts *context.ContextTree,
common *controllerCommon,
enterSubmodule func(submodule *models.SubmoduleConfig) error,
getSubmodules func() []*models.SubmoduleConfig,
setCommitMessage func(message string),
withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error,
getFailedCommitMessage func() string,
getSelectedPath func() string,
switchToMergeFn func(path string) error,
suggestionsHelper ISuggestionsHelper,
refsHelper IRefsHelper,
filesHelper IFilesHelper,
workingTreeHelper IWorkingTreeHelper,
) *FilesController {
return &FilesController{
c: c,
context: context,
model: model,
git: git,
os: os,
getSelectedFileNode: getSelectedFileNode,
contexts: allContexts,
controllerCommon: common,
enterSubmodule: enterSubmodule,
getSubmodules: getSubmodules,
setCommitMessage: setCommitMessage,
withGpgHandling: withGpgHandling,
getFailedCommitMessage: getFailedCommitMessage,
getSelectedPath: getSelectedPath,
switchToMergeFn: switchToMergeFn,
suggestionsHelper: suggestionsHelper,
refsHelper: refsHelper,
filesHelper: filesHelper,
workingTreeHelper: workingTreeHelper,
}
}
@ -96,7 +56,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
},
// {
// Key: gocui.MouseLeft,
// Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) },
// Handler: func() error { return self.context().HandleClick(self.checkSelectedFileNode(self.press)) },
// },
{
Key: opts.GetKey("<c-b>"), // TODO: softcode
@ -187,6 +147,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
Handler: self.OpenMergeTool,
Description: self.c.Tr.LcOpenMergeTool,
},
{
Key: opts.GetKey(opts.Config.Files.Fetch),
Handler: self.fetch,
Description: self.c.Tr.LcFetch,
},
}
}
@ -249,12 +214,12 @@ func (self *FilesController) press(node *filetree.FileNode) error {
return err
}
return self.context.HandleFocus()
return self.context().HandleFocus()
}
func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error {
return func() error {
node := self.getSelectedFileNode()
node := self.context().GetSelectedFileNode()
if node == nil {
return nil
}
@ -264,11 +229,15 @@ func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileN
}
func (self *FilesController) Context() types.Context {
return self.context
return self.context()
}
func (self *FilesController) context() *context.WorkingTreeContext {
return self.contexts.Files
}
func (self *FilesController) getSelectedFile() *models.File {
node := self.getSelectedFileNode()
node := self.context().GetSelectedFileNode()
if node == nil {
return nil
}
@ -280,7 +249,7 @@ func (self *FilesController) enter() error {
}
func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
node := self.getSelectedFileNode()
node := self.context().GetSelectedFileNode()
if node == nil {
return nil
}
@ -291,7 +260,7 @@ func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
file := node.File
submoduleConfigs := self.getSubmodules()
submoduleConfigs := self.model.Submodules
if file.IsSubmodule(submoduleConfigs) {
submoduleConfig := file.SubmoduleConfig(submoduleConfigs)
return self.enterSubmodule(submoduleConfig)
@ -410,7 +379,7 @@ func (self *FilesController) commitPrefixConfigForRepo() *config.CommitPrefixCon
}
func (self *FilesController) prepareFilesForCommit() error {
noStagedFiles := !self.workingTreeHelper.AnyStagedFiles()
noStagedFiles := !self.helpers.WorkingTree.AnyStagedFiles()
if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning {
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
err := self.git.WorkingTree.StageAll()
@ -442,7 +411,7 @@ func (self *FilesController) HandleCommitPress() error {
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
}
if !self.workingTreeHelper.AnyStagedFiles() {
if !self.helpers.WorkingTree.AnyStagedFiles() {
return self.promptToStageAllAndRetry(self.HandleCommitPress)
}
@ -458,7 +427,7 @@ func (self *FilesController) HandleCommitPress() error {
if err != nil {
return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.LcCommitPrefixPatternError, err.Error()))
}
prefix := rgx.ReplaceAllString(self.getCheckedOutBranch().Name, prefixReplace)
prefix := rgx.ReplaceAllString(self.helpers.Refs.GetCheckedOutRef().Name, prefixReplace)
self.setCommitMessage(prefix)
}
}
@ -493,7 +462,7 @@ func (self *FilesController) handleAmendCommitPress() error {
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
}
if !self.workingTreeHelper.AnyStagedFiles() {
if !self.helpers.WorkingTree.AnyStagedFiles() {
return self.promptToStageAllAndRetry(self.handleAmendCommitPress)
}
@ -519,7 +488,7 @@ func (self *FilesController) HandleCommitEditorPress() error {
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
}
if !self.workingTreeHelper.AnyStagedFiles() {
if !self.helpers.WorkingTree.AnyStagedFiles() {
return self.promptToStageAllAndRetry(self.HandleCommitEditorPress)
}
@ -556,8 +525,8 @@ func (self *FilesController) handleStatusFilterPressed() error {
}
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
self.context.FileTreeViewModel.SetFilter(filter)
return self.c.PostRefreshUpdate(self.context)
self.context().FileTreeViewModel.SetFilter(filter)
return self.c.PostRefreshUpdate(self.context())
}
func (self *FilesController) edit(node *filetree.FileNode) error {
@ -565,16 +534,16 @@ func (self *FilesController) edit(node *filetree.FileNode) error {
return self.c.ErrorMsg(self.c.Tr.ErrCannotEditDirectory)
}
return self.filesHelper.EditFile(node.GetPath())
return self.helpers.Files.EditFile(node.GetPath())
}
func (self *FilesController) Open() error {
node := self.getSelectedFileNode()
node := self.context().GetSelectedFileNode()
if node == nil {
return nil
}
return self.filesHelper.OpenFile(node.GetPath())
return self.helpers.Files.OpenFile(node.GetPath())
}
func (self *FilesController) switchToMerge() error {
@ -613,16 +582,16 @@ func (self *FilesController) stash() error {
}
func (self *FilesController) createResetMenu() error {
return self.refsHelper.CreateGitResetMenu("@{upstream}")
return self.helpers.Refs.CreateGitResetMenu("@{upstream}")
}
func (self *FilesController) handleToggleDirCollapsed() error {
node := self.getSelectedFileNode()
node := self.context().GetSelectedFileNode()
if node == nil {
return nil
}
self.context.FileTreeViewModel.ToggleCollapsed(node.GetPath())
self.context().FileTreeViewModel.ToggleCollapsed(node.GetPath())
if err := self.c.PostRefreshUpdate(self.contexts.Files); err != nil {
self.c.Log.Error(err)
@ -632,9 +601,9 @@ func (self *FilesController) handleToggleDirCollapsed() error {
}
func (self *FilesController) toggleTreeView() error {
self.context.FileTreeViewModel.ToggleShowTree()
self.context().FileTreeViewModel.ToggleShowTree()
return self.c.PostRefreshUpdate(self.context)
return self.c.PostRefreshUpdate(self.context())
}
func (self *FilesController) OpenMergeTool() error {
@ -654,7 +623,7 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e
return self.c.WithWaitingStatus(self.c.Tr.LcResettingSubmoduleStatus, func() error {
self.c.LogAction(self.c.Tr.Actions.ResetSubmodule)
file := self.workingTreeHelper.FileForSubmodule(submodule)
file := self.helpers.WorkingTree.FileForSubmodule(submodule)
if file != nil {
if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
return self.c.Error(err)
@ -673,7 +642,7 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e
}
func (self *FilesController) handleStashSave(stashFunc func(message string) error) error {
if !self.workingTreeHelper.IsWorkingTreeDirty() {
if !self.helpers.WorkingTree.IsWorkingTreeDirty() {
return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash)
}
@ -697,3 +666,25 @@ func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) e
clickedViewLineIdx := opts.Cy + opts.Oy
return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: clickedViewLineIdx})
}
func (self *FilesController) fetch() error {
return self.c.WithLoaderPanel(self.c.Tr.FetchWait, func() error {
if err := self.fetchAux(); err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
})
}
func (self *FilesController) fetchAux() (err error) {
self.c.LogAction("Fetch")
err = self.git.Sync.Fetch(git_commands.FetchOptions{})
if err != nil && strings.Contains(err.Error(), "exit status 128") {
_ = self.c.ErrorMsg(self.c.Tr.PassUnameWrong)
}
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC})
return err
}

View File

@ -39,7 +39,7 @@ func (self *FilesController) remove(node *filetree.FileNode) error {
} else {
file := node.File
submodules := self.getSubmodules()
submodules := self.model.Submodules
if file.IsSubmodule(submodules) {
submodule := file.SubmoduleConfig(submodules)

View File

@ -1,26 +1,22 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type GlobalController struct {
baseController
c *types.ControllerCommon
os *oscommands.OSCommand
*controllerCommon
}
func NewGlobalController(
c *types.ControllerCommon,
os *oscommands.OSCommand,
common *controllerCommon,
) *GlobalController {
return &GlobalController{
baseController: baseController{},
c: c,
os: os,
baseController: baseController{},
controllerCommon: common,
}
}
@ -63,7 +59,7 @@ func (self *GlobalController) GetCustomCommandsHistorySuggestionsFunc() func(str
// reversing so that we display the latest command first
history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory)
return FuzzySearchFunc(history)
return helpers.FuzzySearchFunc(history)
}
func (self *GlobalController) Context() types.Context {

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
@ -6,12 +6,12 @@ import (
)
type BisectHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
git *commands.GitCommand
}
func NewBisectHelper(
c *types.ControllerCommon,
c *types.HelperCommon,
git *commands.GitCommand,
) *BisectHelper {
return &BisectHelper{

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
@ -9,25 +9,25 @@ import (
)
type CherryPickHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
git *commands.GitCommand
contexts *context.ContextTree
getData func() *cherrypicking.CherryPicking
rebaseHelper *RebaseHelper
rebaseHelper *MergeAndRebaseHelper
}
// 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,
c *types.HelperCommon,
git *commands.GitCommand,
contexts *context.ContextTree,
getData func() *cherrypicking.CherryPicking,
rebaseHelper *RebaseHelper,
rebaseHelper *MergeAndRebaseHelper,
) *CherryPickHelper {
return &CherryPickHelper{
c: c,

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
@ -14,13 +14,13 @@ type IFilesHelper interface {
}
type FilesHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
git *commands.GitCommand
os *oscommands.OSCommand
}
func NewFilesHelper(
c *types.ControllerCommon,
c *types.HelperCommon,
git *commands.GitCommand,
os *oscommands.OSCommand,
) *FilesHelper {

View File

@ -0,0 +1,13 @@
package helpers
type Helpers struct {
Refs *RefsHelper
Bisect *BisectHelper
Suggestions *SuggestionsHelper
Files *FilesHelper
WorkingTree *WorkingTreeHelper
Tags *TagsHelper
MergeAndRebase *MergeAndRebaseHelper
CherryPick *CherryPickHelper
Host *HostHelper
}

View File

@ -0,0 +1,46 @@
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
// this helper just wraps our hosting_service package
type IHostHelper interface {
GetPullRequestURL(from string, to string) (string, error)
GetCommitURL(commitSha string) (string, error)
}
type HostHelper struct {
c *types.HelperCommon
git *commands.GitCommand
}
func NewHostHelper(
c *types.HelperCommon,
git *commands.GitCommand,
) *HostHelper {
return &HostHelper{
c: c,
git: git,
}
}
func (self *HostHelper) GetPullRequestURL(from string, to string) (string, error) {
return self.getHostingServiceMgr().GetPullRequestURL(from, to)
}
func (self *HostHelper) GetCommitURL(commitSha string) (string, error) {
return self.getHostingServiceMgr().GetCommitURL(commitSha)
}
// getting this on every request rather than storing it in state in case our remoteURL changes
// from one invocation to the next. Note however that we're currently caching config
// results so we might want to invalidate the cache here if it becomes a problem.
func (self *HostHelper) getHostingServiceMgr() *hosting_service.HostingServiceMgr {
remoteUrl := self.git.Config.GetRemoteURL()
configServices := self.c.UserConfig.Services
return hosting_service.NewHostingServiceMgr(self.c.Log, self.c.Tr, remoteUrl, configServices)
}

View File

@ -1,33 +1,38 @@
package controllers
package helpers
import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type RebaseHelper struct {
c *types.ControllerCommon
type MergeAndRebaseHelper struct {
c *types.HelperCommon
contexts *context.ContextTree
git *commands.GitCommand
takeOverMergeConflictScrolling func()
refsHelper *RefsHelper
}
func NewRebaseHelper(
c *types.ControllerCommon,
func NewMergeAndRebaseHelper(
c *types.HelperCommon,
contexts *context.ContextTree,
git *commands.GitCommand,
takeOverMergeConflictScrolling func(),
) *RebaseHelper {
return &RebaseHelper{
refsHelper *RefsHelper,
) *MergeAndRebaseHelper {
return &MergeAndRebaseHelper{
c: c,
contexts: contexts,
git: git,
takeOverMergeConflictScrolling: takeOverMergeConflictScrolling,
refsHelper: refsHelper,
}
}
@ -39,7 +44,7 @@ const (
REBASE_OPTION_SKIP string = "skip"
)
func (self *RebaseHelper) CreateRebaseOptionsMenu() error {
func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT}
if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
@ -68,7 +73,7 @@ func (self *RebaseHelper) CreateRebaseOptionsMenu() error {
return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
}
func (self *RebaseHelper) genericMergeCommand(command string) error {
func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
status := self.git.Status.WorkingTreeState()
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
@ -120,7 +125,7 @@ func isMergeConflictErr(errStr string) bool {
return false
}
func (self *RebaseHelper) CheckMergeOrRebase(result error) error {
func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error {
if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
return err
}
@ -154,7 +159,7 @@ func (self *RebaseHelper) CheckMergeOrRebase(result error) error {
}
}
func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error {
func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
// prompt user to confirm that they want to abort, then do it
mode := self.workingTreeStateNoun()
return self.c.Ask(types.AskOpts{
@ -166,7 +171,7 @@ func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error {
})
}
func (self *RebaseHelper) workingTreeStateNoun() string {
func (self *MergeAndRebaseHelper) workingTreeStateNoun() string {
workingTreeState := self.git.Status.WorkingTreeState()
switch workingTreeState {
case enums.REBASE_MODE_NONE:
@ -179,7 +184,7 @@ func (self *RebaseHelper) workingTreeStateNoun() string {
}
// PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress
func (self *RebaseHelper) PromptToContinueRebase() error {
func (self *MergeAndRebaseHelper) PromptToContinueRebase() error {
self.takeOverMergeConflictScrolling()
return self.c.Ask(types.AskOpts{
@ -190,3 +195,54 @@ func (self *RebaseHelper) PromptToContinueRebase() error {
},
})
}
func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
checkedOutBranch := self.refsHelper.GetCheckedOutRef().Name
if ref == checkedOutBranch {
return self.c.ErrorMsg(self.c.Tr.CantRebaseOntoSelf)
}
prompt := utils.ResolvePlaceholderString(
self.c.Tr.ConfirmRebase,
map[string]string{
"checkedOutBranch": checkedOutBranch,
"selectedBranch": ref,
},
)
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.RebasingTitle,
Prompt: prompt,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
err := self.git.Rebase.RebaseBranch(ref)
return self.CheckMergeOrRebase(err)
},
})
}
func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) error {
if self.git.Branch.IsHeadDetached() {
return self.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on")
}
checkedOutBranchName := self.refsHelper.GetCheckedOutRef().Name
if checkedOutBranchName == refName {
return self.c.ErrorMsg(self.c.Tr.CantMergeBranchIntoItself)
}
prompt := utils.ResolvePlaceholderString(
self.c.Tr.ConfirmMerge,
map[string]string{
"checkedOutBranch": checkedOutBranchName,
"selectedBranch": refName,
},
)
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.MergingTitle,
Prompt: prompt,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Merge)
err := self.git.Branch.Merge(refName, git_commands.MergeOpts{})
return self.CheckMergeOrRebase(err)
},
})
}

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"fmt"
@ -6,6 +6,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@ -14,26 +15,30 @@ import (
type IRefsHelper interface {
CheckoutRef(ref string, options types.CheckoutRefOptions) error
GetCheckedOutRef() *models.Branch
CreateGitResetMenu(ref string) error
ResetToRef(ref string, strength string, envVars []string) error
NewBranch(from string, fromDescription string, suggestedBranchname string) error
}
type RefsHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
git *commands.GitCommand
contexts *context.ContextTree
model *types.Model
}
func NewRefsHelper(
c *types.ControllerCommon,
c *types.HelperCommon,
git *commands.GitCommand,
contexts *context.ContextTree,
model *types.Model,
) *RefsHelper {
return &RefsHelper{
c: c,
git: git,
contexts: contexts,
model: model,
}
}
@ -99,6 +104,14 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
})
}
func (self *RefsHelper) GetCheckedOutRef() *models.Branch {
if len(self.model.Branches) == 0 {
return nil
}
return self.model.Branches[0]
}
func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string) error {
if err := self.git.Commit.ResetToCommit(ref, strength, envVars); err != nil {
return self.c.Error(err)

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"fmt"
@ -30,7 +30,7 @@ type ISuggestionsHelper interface {
}
type SuggestionsHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
model *types.Model
refreshSuggestionsFn func()
@ -39,7 +39,7 @@ type SuggestionsHelper struct {
var _ ISuggestionsHelper = &SuggestionsHelper{}
func NewSuggestionsHelper(
c *types.ControllerCommon,
c *types.HelperCommon,
model *types.Model,
refreshSuggestionsFn func(),
) *SuggestionsHelper {

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
@ -10,11 +10,11 @@ import (
// and the commits context.
type TagsHelper struct {
c *types.ControllerCommon
c *types.HelperCommon
git *commands.GitCommand
}
func NewTagsHelper(c *types.ControllerCommon, git *commands.GitCommand) *TagsHelper {
func NewTagsHelper(c *types.HelperCommon, git *commands.GitCommand) *TagsHelper {
return &TagsHelper{
c: c,
git: git,

View File

@ -1,4 +1,4 @@
package controllers
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands/models"

View File

@ -6,10 +6,10 @@ import (
)
type ListControllerFactory struct {
c *types.ControllerCommon
c *types.HelperCommon
}
func NewListControllerFactory(c *types.ControllerCommon) *ListControllerFactory {
func NewListControllerFactory(c *types.HelperCommon) *ListControllerFactory {
return &ListControllerFactory{
c: c,
}
@ -25,7 +25,7 @@ func (self *ListControllerFactory) Create(context types.IListContext) *ListContr
type ListController struct {
baseController
c *types.ControllerCommon
c *types.HelperCommon
context types.IListContext
}

View File

@ -4,80 +4,37 @@ import (
"fmt"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type (
CheckoutRefFn func(refName string, opts types.CheckoutRefOptions) error
CreateGitResetMenuFn func(refName string) error
SwitchToCommitFilesContextFn func(SwitchToCommitFilesContextOpts) error
GetHostingServiceMgrFn func() *hosting_service.HostingServiceMgr
PullFilesFn func() error
CheckMergeOrRebase func(error) error
)
type LocalCommitsController struct {
baseController
c *types.ControllerCommon
context *context.LocalCommitsContext
os *oscommands.OSCommand
git *commands.GitCommand
tagsHelper *TagsHelper
refsHelper IRefsHelper
cherryPickHelper *CherryPickHelper
rebaseHelper *RebaseHelper
*controllerCommon
model *types.Model
CheckMergeOrRebase CheckMergeOrRebase
pullFiles PullFilesFn
getHostingServiceMgr GetHostingServiceMgrFn
switchToCommitFilesContext SwitchToCommitFilesContextFn
getShowWholeGitGraph func() bool
setShowWholeGitGraph func(bool)
}
var _ types.IController = &LocalCommitsController{}
func NewLocalCommitsController(
c *types.ControllerCommon,
context *context.LocalCommitsContext,
os *oscommands.OSCommand,
git *commands.GitCommand,
tagsHelper *TagsHelper,
refsHelper IRefsHelper,
cherryPickHelper *CherryPickHelper,
rebaseHelper *RebaseHelper,
model *types.Model,
CheckMergeOrRebase CheckMergeOrRebase,
common *controllerCommon,
pullFiles PullFilesFn,
getHostingServiceMgr GetHostingServiceMgrFn,
switchToCommitFilesContext SwitchToCommitFilesContextFn,
getShowWholeGitGraph func() bool,
setShowWholeGitGraph func(bool),
) *LocalCommitsController {
return &LocalCommitsController{
baseController: baseController{},
c: c,
context: context,
os: os,
git: git,
tagsHelper: tagsHelper,
refsHelper: refsHelper,
cherryPickHelper: cherryPickHelper,
rebaseHelper: rebaseHelper,
model: model,
CheckMergeOrRebase: CheckMergeOrRebase,
controllerCommon: common,
pullFiles: pullFiles,
getHostingServiceMgr: getHostingServiceMgr,
switchToCommitFilesContext: switchToCommitFilesContext,
getShowWholeGitGraph: getShowWholeGitGraph,
setShowWholeGitGraph: setShowWholeGitGraph,
}
}
@ -185,7 +142,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
},
// {
// Key: gocui.MouseLeft,
// Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) },
// Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) },
// },
}
@ -305,7 +262,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
InitialContent: message,
HandleConfirm: func(response string) error {
self.c.LogAction(self.c.Tr.Actions.RewordCommit)
if err := self.git.Rebase.RewordCommit(self.model.Commits, self.context.GetSelectedLineIdx(), response); err != nil {
if err := self.git.Rebase.RewordCommit(self.model.Commits, self.context().GetSelectedLineIdx(), response); err != nil {
return self.c.Error(err)
}
@ -325,7 +282,7 @@ func (self *LocalCommitsController) rewordEditor() error {
self.c.LogAction(self.c.Tr.Actions.RewordCommit)
subProcess, err := self.git.Rebase.RewordCommitInEditor(
self.model.Commits, self.context.GetSelectedLineIdx(),
self.model.Commits, self.context().GetSelectedLineIdx(),
)
if err != nil {
return self.c.Error(err)
@ -388,15 +345,15 @@ func (self *LocalCommitsController) pick() error {
}
func (self *LocalCommitsController) interactiveRebase(action string) error {
err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.context.GetSelectedLineIdx(), action)
return self.CheckMergeOrRebase(err)
err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.context().GetSelectedLineIdx(), action)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
}
// handleMidRebaseCommand sees if the selected commit is in fact a rebasing
// commit meaning you are trying to edit the todo file rather than actually
// begin a rebase. It then updates the todo file with that action
func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, error) {
selectedCommit := self.context.GetSelected()
selectedCommit := self.context().GetSelected()
if selectedCommit.Status != "rebasing" {
return false, nil
}
@ -416,7 +373,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool,
)
if err := self.git.Rebase.EditRebaseTodo(
self.context.GetSelectedLineIdx(), action,
self.context().GetSelectedLineIdx(), action,
); err != nil {
return false, self.c.Error(err)
}
@ -427,7 +384,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool,
}
func (self *LocalCommitsController) handleCommitMoveDown() error {
index := self.context.GetSelectedLineIdx()
index := self.context().GetSelectedLineIdx()
commits := self.model.Commits
selectedCommit := self.model.Commits[index]
if selectedCommit.Status == "rebasing" {
@ -443,7 +400,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error {
if err := self.git.Rebase.MoveTodoDown(index); err != nil {
return self.c.Error(err)
}
self.context.MoveSelectedLine(1)
self.context().MoveSelectedLine(1)
return self.c.Refresh(types.RefreshOptions{
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
})
@ -453,14 +410,14 @@ func (self *LocalCommitsController) handleCommitMoveDown() error {
self.c.LogAction(self.c.Tr.Actions.MoveCommitDown)
err := self.git.Rebase.MoveCommitDown(self.model.Commits, index)
if err == nil {
self.context.MoveSelectedLine(1)
self.context().MoveSelectedLine(1)
}
return self.CheckMergeOrRebase(err)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}
func (self *LocalCommitsController) handleCommitMoveUp() error {
index := self.context.GetSelectedLineIdx()
index := self.context().GetSelectedLineIdx()
if index == 0 {
return nil
}
@ -478,7 +435,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error {
if err := self.git.Rebase.MoveTodoDown(index - 1); err != nil {
return self.c.Error(err)
}
self.context.MoveSelectedLine(-1)
self.context().MoveSelectedLine(-1)
return self.c.Refresh(types.RefreshOptions{
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
})
@ -488,9 +445,9 @@ func (self *LocalCommitsController) handleCommitMoveUp() error {
self.c.LogAction(self.c.Tr.Actions.MoveCommitUp)
err := self.git.Rebase.MoveCommitDown(self.model.Commits, index-1)
if err == nil {
self.context.MoveSelectedLine(-1)
self.context().MoveSelectedLine(-1)
}
return self.CheckMergeOrRebase(err)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}
@ -501,8 +458,8 @@ func (self *LocalCommitsController) handleCommitAmendTo() error {
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error {
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
err := self.git.Rebase.AmendTo(self.context.GetSelected().Sha)
return self.CheckMergeOrRebase(err)
err := self.git.Rebase.AmendTo(self.context().GetSelected().Sha)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
},
})
@ -556,7 +513,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C
}
func (self *LocalCommitsController) afterRevertCommit() error {
self.context.MoveSelectedLine(1)
self.context().MoveSelectedLine(1)
return self.c.Refresh(types.RefreshOptions{
Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES},
})
@ -564,10 +521,9 @@ func (self *LocalCommitsController) afterRevertCommit() error {
func (self *LocalCommitsController) enter(commit *models.Commit) error {
return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{
RefName: commit.Sha,
CanRebase: true,
Context: self.context,
WindowName: "commits",
RefName: commit.Sha,
CanRebase: true,
Context: self.context(),
})
}
@ -608,14 +564,14 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha)
return self.CheckMergeOrRebase(err)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
},
})
}
func (self *LocalCommitsController) handleTagCommit(commit *models.Commit) error {
return self.tagsHelper.CreateTagMenu(commit.Sha, func() {})
return self.helpers.Tags.CreateTagMenu(commit.Sha, func() {})
}
func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error {
@ -624,19 +580,19 @@ func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit)
Prompt: self.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.CheckoutCommit)
return self.refsHelper.CheckoutRef(commit.Sha, types.CheckoutRefOptions{})
return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{})
},
})
}
func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.Commit) error {
return self.refsHelper.CreateGitResetMenu(commit.Sha)
return self.helpers.Refs.CreateGitResetMenu(commit.Sha)
}
func (self *LocalCommitsController) openSearch() error {
// we usually lazyload these commits but now that we're searching we need to load them now
if self.context.GetLimitCommits() {
self.context.SetLimitCommits(false)
if self.context().GetLimitCommits() {
self.context().SetLimitCommits(false)
if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil {
return err
}
@ -649,14 +605,14 @@ func (self *LocalCommitsController) openSearch() error {
func (self *LocalCommitsController) gotoBottom() error {
// we usually lazyload these commits but now that we're jumping to the bottom we need to load them now
if self.context.GetLimitCommits() {
self.context.SetLimitCommits(false)
if self.context().GetLimitCommits() {
self.context().SetLimitCommits(false)
if err := self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil {
return err
}
}
self.context.SetSelectedLineIdx(self.context.GetItemsLength() - 1)
self.context().SetSelectedLineIdx(self.context().GetItemsLength() - 1)
return nil
}
@ -684,10 +640,10 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
{
DisplayString: self.c.Tr.ToggleShowGitGraphAll,
OnPress: func() error {
self.setShowWholeGitGraph(!self.getShowWholeGitGraph())
self.context().SetShowWholeGitGraph(!self.context().GetShowWholeGitGraph())
if self.getShowWholeGitGraph() {
self.context.SetLimitCommits(false)
if self.context().GetShowWholeGitGraph() {
self.context().SetLimitCommits(false)
}
return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error {
@ -761,9 +717,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
}
func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Commit) error {
hostingServiceMgr := self.getHostingServiceMgr()
url, err := hostingServiceMgr.GetCommitURL(commit.Sha)
url, err := self.helpers.Host.GetCommitURL(commit.Sha)
if err != nil {
return self.c.Error(err)
}
@ -778,7 +732,7 @@ func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Com
func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error {
return func() error {
commit := self.context.GetSelected()
commit := self.context().GetSelected()
if commit == nil {
return nil
}
@ -788,21 +742,25 @@ func (self *LocalCommitsController) checkSelected(callback func(*models.Commit)
}
func (self *LocalCommitsController) Context() types.Context {
return self.context
return self.context()
}
func (self *LocalCommitsController) context() *context.LocalCommitsContext {
return self.contexts.BranchCommits
}
func (self *LocalCommitsController) newBranch(commit *models.Commit) error {
return self.refsHelper.NewBranch(commit.RefName(), commit.Description(), "")
return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "")
}
func (self *LocalCommitsController) copy(commit *models.Commit) error {
return self.cherryPickHelper.Copy(commit, self.model.Commits, self.context)
return self.helpers.CherryPick.Copy(commit, self.model.Commits, self.context())
}
func (self *LocalCommitsController) copyRange(*models.Commit) error {
return self.cherryPickHelper.CopyRange(self.context.GetSelectedLineIdx(), self.model.Commits, self.context)
return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.Commits, self.context())
}
func (self *LocalCommitsController) paste() error {
return self.cherryPickHelper.Paste()
return self.helpers.CherryPick.Paste()
}

View File

@ -7,22 +7,17 @@ import (
type MenuController struct {
baseController
c *types.ControllerCommon
context *context.MenuContext
*controllerCommon
}
var _ types.IController = &MenuController{}
func NewMenuController(
c *types.ControllerCommon,
context *context.MenuContext,
common *controllerCommon,
) *MenuController {
return &MenuController{
baseController: baseController{},
c: c,
context: context,
baseController: baseController{},
controllerCommon: common,
}
}
@ -50,7 +45,7 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.
}
func (self *MenuController) press() error {
selectedItem := self.context.GetSelected()
selectedItem := self.context().GetSelected()
if err := self.c.PopContext(); err != nil {
return err
@ -64,5 +59,9 @@ func (self *MenuController) press() error {
}
func (self *MenuController) Context() types.Context {
return self.context
return self.context()
}
func (self *MenuController) context() *context.MenuContext {
return self.contexts.Menu
}

View File

@ -1,7 +1,6 @@
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/types"
@ -10,30 +9,22 @@ import (
type RemotesController struct {
baseController
c *types.ControllerCommon
*controllerCommon
context *context.RemotesContext
git *commands.GitCommand
setRemoteBranches func([]*models.RemoteBranch)
contexts *context.ContextTree
}
var _ types.IController = &RemotesController{}
func NewRemotesController(
c *types.ControllerCommon,
context *context.RemotesContext,
git *commands.GitCommand,
contexts *context.ContextTree,
common *controllerCommon,
setRemoteBranches func([]*models.RemoteBranch),
) *RemotesController {
return &RemotesController{
baseController: baseController{},
c: c,
git: git,
contexts: contexts,
context: context,
controllerCommon: common,
context: common.contexts.Remotes,
setRemoteBranches: setRemoteBranches,
}
}

View File

@ -1,19 +1,14 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type SubCommitsSwitchControllerFactory struct {
c *types.ControllerCommon
subCommitsContext *context.SubCommitsContext
git *commands.GitCommand
modes *types.Modes
setSubCommits func([]*models.Commit)
controllerCommon *controllerCommon
setSubCommits func([]*models.Commit)
}
var _ types.IController = &SubCommitsSwitchController{}
@ -25,40 +20,28 @@ type ContextWithRefName interface {
type SubCommitsSwitchController struct {
baseController
*controllerCommon
context ContextWithRefName
c *types.ControllerCommon
context ContextWithRefName
subCommitsContext *context.SubCommitsContext
git *commands.GitCommand
modes *types.Modes
setSubCommits func([]*models.Commit)
setSubCommits func([]*models.Commit)
}
func NewSubCommitsSwitchControllerFactory(
c *types.ControllerCommon,
subCommitsContext *context.SubCommitsContext,
git *commands.GitCommand,
modes *types.Modes,
common *controllerCommon,
setSubCommits func([]*models.Commit),
) *SubCommitsSwitchControllerFactory {
return &SubCommitsSwitchControllerFactory{
c: c,
subCommitsContext: subCommitsContext,
git: git,
modes: modes,
setSubCommits: setSubCommits,
controllerCommon: common,
setSubCommits: setSubCommits,
}
}
func (self *SubCommitsSwitchControllerFactory) Create(context ContextWithRefName) *SubCommitsSwitchController {
return &SubCommitsSwitchController{
baseController: baseController{},
c: self.c,
context: context,
subCommitsContext: self.subCommitsContext,
git: self.git,
modes: self.modes,
setSubCommits: self.setSubCommits,
baseController: baseController{},
controllerCommon: self.controllerCommon,
context: context,
setSubCommits: self.setSubCommits,
}
}
@ -94,10 +77,10 @@ func (self *SubCommitsSwitchController) viewCommits() error {
}
self.setSubCommits(commits)
self.subCommitsContext.SetSelectedLineIdx(0)
self.subCommitsContext.SetParentContext(self.context)
self.contexts.SubCommits.SetSelectedLineIdx(0)
self.contexts.SubCommits.SetParentContext(self.context)
return self.c.PushContext(self.subCommitsContext)
return self.c.PushContext(self.contexts.SubCommits)
}
func (self *SubCommitsSwitchController) Context() types.Context {

View File

@ -5,7 +5,6 @@ import (
"path/filepath"
"strings"
"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/style"
@ -14,10 +13,7 @@ import (
type SubmodulesController struct {
baseController
c *types.ControllerCommon
context *context.SubmodulesContext
git *commands.GitCommand
*controllerCommon
enterSubmodule func(submodule *models.SubmoduleConfig) error
}
@ -25,17 +21,13 @@ type SubmodulesController struct {
var _ types.IController = &SubmodulesController{}
func NewSubmodulesController(
c *types.ControllerCommon,
context *context.SubmodulesContext,
git *commands.GitCommand,
controllerCommon *controllerCommon,
enterSubmodule func(submodule *models.SubmoduleConfig) error,
) *SubmodulesController {
return &SubmodulesController{
baseController: baseController{},
c: c,
context: context,
git: git,
enterSubmodule: enterSubmodule,
baseController: baseController{},
controllerCommon: controllerCommon,
enterSubmodule: enterSubmodule,
}
}
@ -79,7 +71,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
},
// {
// Key: gocui.MouseLeft,
// Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) },
// Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) },
// },
}
}
@ -227,7 +219,7 @@ func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) erro
func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleConfig) error) func() error {
return func() error {
submodule := self.context.GetSelected()
submodule := self.context().GetSelected()
if submodule == nil {
return nil
}
@ -237,5 +229,9 @@ func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleC
}
func (self *SubmodulesController) Context() types.Context {
return self.context
return self.context()
}
func (self *SubmodulesController) context() *context.SubmodulesContext {
return self.contexts.Submodules
}

View File

@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@ -12,35 +11,22 @@ import (
type SyncController struct {
baseController
*controllerCommon
c *types.ControllerCommon
git *commands.GitCommand
getCheckedOutBranch func() *models.Branch
suggestionsHelper ISuggestionsHelper
getSuggestedRemote func() string
CheckMergeOrRebase func(error) error
getSuggestedRemote func() string
}
var _ types.IController = &SyncController{}
func NewSyncController(
c *types.ControllerCommon,
git *commands.GitCommand,
getCheckedOutBranch func() *models.Branch,
suggestionsHelper ISuggestionsHelper,
common *controllerCommon,
getSuggestedRemote func() string,
CheckMergeOrRebase func(error) error,
) *SyncController {
return &SyncController{
baseController: baseController{},
c: c,
git: git,
baseController: baseController{},
controllerCommon: common,
getCheckedOutBranch: getCheckedOutBranch,
suggestionsHelper: suggestionsHelper,
getSuggestedRemote: getSuggestedRemote,
CheckMergeOrRebase: CheckMergeOrRebase,
getSuggestedRemote: getSuggestedRemote,
}
}
@ -75,7 +61,7 @@ func (self *SyncController) HandlePull() error {
func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error {
return func() error {
currentBranch := self.getCheckedOutBranch()
currentBranch := self.helpers.Refs.GetCheckedOutRef()
if currentBranch == nil {
// need to wait for branches to refresh
return nil
@ -160,7 +146,7 @@ func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onCo
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.EnterUpstream,
InitialContent: suggestedRemote + " " + currentBranch.Name,
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "),
FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteBranchesSuggestionsFunc(" "),
HandleConfirm: onConfirm,
})
}
@ -189,7 +175,7 @@ func (self *SyncController) pullWithLock(opts PullFilesOptions) error {
},
)
return self.CheckMergeOrRebase(err)
return self.helpers.MergeAndRebase.CheckMergeOrRebase(err)
}
type pushOpts struct {

View File

@ -1,7 +1,6 @@
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/types"
@ -10,43 +9,17 @@ import (
type TagsController struct {
baseController
c *types.ControllerCommon
context *context.TagsContext
git *commands.GitCommand
contexts *context.ContextTree
tagsHelper *TagsHelper
refsHelper IRefsHelper
suggestionsHelper ISuggestionsHelper
switchToSubCommitsContext func(string) error
*controllerCommon
}
var _ types.IController = &TagsController{}
func NewTagsController(
c *types.ControllerCommon,
context *context.TagsContext,
git *commands.GitCommand,
contexts *context.ContextTree,
tagsHelper *TagsHelper,
refsHelper IRefsHelper,
suggestionsHelper ISuggestionsHelper,
switchToSubCommitsContext func(string) error,
common *controllerCommon,
) *TagsController {
return &TagsController{
baseController: baseController{},
c: c,
context: context,
git: git,
contexts: contexts,
tagsHelper: tagsHelper,
refsHelper: refsHelper,
suggestionsHelper: suggestionsHelper,
switchToSubCommitsContext: switchToSubCommitsContext,
baseController: baseController{},
controllerCommon: common,
}
}
@ -85,7 +58,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
func (self *TagsController) checkout(tag *models.Tag) error {
self.c.LogAction(self.c.Tr.Actions.CheckoutTag)
if err := self.refsHelper.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil {
if err := self.helpers.Refs.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil {
return err
}
return self.c.PushContext(self.contexts.Branches)
@ -123,7 +96,7 @@ func (self *TagsController) push(tag *models.Tag) error {
return self.c.Prompt(types.PromptOpts{
Title: title,
InitialContent: "origin",
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(),
FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteSuggestionsFunc(),
HandleConfirm: func(response string) error {
return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func() error {
self.c.LogAction(self.c.Tr.Actions.PushTag)
@ -139,17 +112,17 @@ func (self *TagsController) push(tag *models.Tag) error {
}
func (self *TagsController) createResetMenu(tag *models.Tag) error {
return self.refsHelper.CreateGitResetMenu(tag.Name)
return self.helpers.Refs.CreateGitResetMenu(tag.Name)
}
func (self *TagsController) create() error {
// leaving commit SHA blank so that we're just creating the tag for the current commit
return self.tagsHelper.CreateTagMenu("", func() { self.context.SetSelectedLineIdx(0) })
return self.helpers.Tags.CreateTagMenu("", func() { self.context().SetSelectedLineIdx(0) })
}
func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error {
return func() error {
tag := self.context.GetSelected()
tag := self.context().GetSelected()
if tag == nil {
return nil
}
@ -159,5 +132,9 @@ func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func(
}
func (self *TagsController) Context() types.Context {
return self.context
return self.context()
}
func (self *TagsController) context() *context.TagsContext {
return self.contexts.Tags
}

View File

@ -6,8 +6,7 @@ import (
// all fields mandatory (except `CanRebase` because it's boolean)
type SwitchToCommitFilesContextOpts struct {
RefName string
CanRebase bool
Context types.Context
WindowName string
RefName string
CanRebase bool
Context types.Context
}

View File

@ -1,8 +1,6 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
@ -20,34 +18,17 @@ import (
type UndoController struct {
baseController
c *types.ControllerCommon
git *commands.GitCommand
refsHelper IRefsHelper
workingTreeHelper IWorkingTreeHelper
getFilteredReflogCommits func() []*models.Commit
*controllerCommon
}
var _ types.IController = &UndoController{}
func NewUndoController(
c *types.ControllerCommon,
git *commands.GitCommand,
refsHelper IRefsHelper,
workingTreeHelper IWorkingTreeHelper,
getFilteredReflogCommits func() []*models.Commit,
common *controllerCommon,
) *UndoController {
return &UndoController{
baseController: baseController{},
c: c,
git: git,
refsHelper: refsHelper,
workingTreeHelper: workingTreeHelper,
getFilteredReflogCommits: getFilteredReflogCommits,
baseController: baseController{},
controllerCommon: common,
}
}
@ -109,7 +90,7 @@ func (self *UndoController) reflogUndo() error {
})
case CHECKOUT:
self.c.LogAction(self.c.Tr.Actions.Undo)
return true, self.refsHelper.CheckoutRef(action.from, types.CheckoutRefOptions{
return true, self.helpers.Refs.CheckoutRef(action.from, types.CheckoutRefOptions{
EnvVars: undoEnvVars,
WaitingStatus: undoingStatus,
})
@ -147,7 +128,7 @@ func (self *UndoController) reflogRedo() error {
})
case CHECKOUT:
self.c.LogAction(self.c.Tr.Actions.Redo)
return true, self.refsHelper.CheckoutRef(action.to, types.CheckoutRefOptions{
return true, self.helpers.Refs.CheckoutRef(action.to, types.CheckoutRefOptions{
EnvVars: redoEnvVars,
WaitingStatus: redoingStatus,
})
@ -168,7 +149,7 @@ func (self *UndoController) reflogRedo() error {
// Though we might support this later, hence the use of the CURRENT_REBASE action kind.
func (self *UndoController) parseReflogForActions(onUserAction func(counter int, action reflogAction) (bool, error)) error {
counter := 0
reflogCommits := self.getFilteredReflogCommits()
reflogCommits := self.model.FilteredReflogCommits
rebaseFinishCommitSha := ""
var action *reflogAction
for reflogCommitIdx, reflogCommit := range reflogCommits {
@ -222,14 +203,14 @@ type hardResetOptions struct {
// only to be used in the undo flow for now (does an autostash)
func (self *UndoController) hardResetWithAutoStash(commitSha string, options hardResetOptions) error {
reset := func() error {
if err := self.refsHelper.ResetToRef(commitSha, "hard", options.EnvVars); err != nil {
if err := self.helpers.Refs.ResetToRef(commitSha, "hard", options.EnvVars); err != nil {
return self.c.Error(err)
}
return nil
}
// if we have any modified tracked files we need to ask the user if they want us to stash for them
dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty()
dirtyWorkingTree := self.helpers.WorkingTree.IsWorkingTreeDirty()
if dirtyWorkingTree {
// offer to autostash changes
return self.c.Ask(types.AskOpts{

View File

@ -54,7 +54,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
SelectedCommitFile: gui.getSelectedCommitFile(),
SelectedCommitFilePath: gui.getSelectedCommitFilePath(),
SelectedSubCommit: gui.State.Contexts.SubCommits.GetSelected(),
CheckedOutBranch: gui.getCheckedOutBranch(),
CheckedOutBranch: gui.helpers.Refs.GetCheckedOutRef(),
PromptResponses: promptResponses,
}

View File

@ -189,19 +189,6 @@ func (gui *Gui) handleMouseDownMain() error {
return nil
}
func (gui *Gui) fetch() (err error) {
gui.c.LogAction("Fetch")
err = gui.git.Sync.Fetch(git_commands.FetchOptions{})
if err != nil && strings.Contains(err.Error(), "exit status 128") {
_ = gui.c.ErrorMsg(gui.c.Tr.PassUnameWrong)
}
_ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC})
return err
}
func (gui *Gui) backgroundFetch() (err error) {
err = gui.git.Sync.Fetch(git_commands.FetchOptions{Background: true})

View File

@ -20,6 +20,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/lbl"
"github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts"
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
@ -67,17 +68,6 @@ func NewContextManager(initialContext types.Context) ContextManager {
}
}
type Helpers struct {
Refs *controllers.RefsHelper
Bisect *controllers.BisectHelper
Suggestions *controllers.SuggestionsHelper
Files *controllers.FilesHelper
WorkingTree *controllers.WorkingTreeHelper
Tags *controllers.TagsHelper
Rebase *controllers.RebaseHelper
CherryPick *controllers.CherryPickHelper
}
type Repo string
// Gui wraps the gocui Gui object which handles rendering and events
@ -144,9 +134,6 @@ type Gui struct {
// flag as to whether or not the diff view should ignore whitespace
IgnoreWhitespaceInDiffView bool
// if this is true, we'll load our commits using `git log --all`
ShowWholeGitGraph bool
// we use this to decide whether we'll return to the original directory that
// lazygit was opened in, or if we'll retain the one we're currently in.
RetainOriginalDir bool
@ -161,8 +148,8 @@ type Gui struct {
// process
InitialDir string
c *types.ControllerCommon
helpers *Helpers
c *types.HelperCommon
helpers *helpers.Helpers
}
// we keep track of some stuff from one render to the next to see if certain
@ -488,11 +475,11 @@ func NewGui(
)
guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler}
controllerCommon := &types.ControllerCommon{IGuiCommon: guiCommon, Common: cmn}
helperCommon := &types.HelperCommon{IGuiCommon: guiCommon, Common: cmn}
// storing this stuff on the gui for now to ease refactoring
// TODO: reset these controllers upon changing repos due to state changing
gui.c = controllerCommon
gui.c = helperCommon
authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors)
presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors)
@ -503,21 +490,23 @@ func NewGui(
func (gui *Gui) resetControllers() {
controllerCommon := gui.c
osCommand := gui.os
rebaseHelper := controllers.NewRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling)
model := gui.State.Model
gui.helpers = &Helpers{
Refs: controllers.NewRefsHelper(
controllerCommon,
gui.git,
gui.State.Contexts,
),
Bisect: controllers.NewBisectHelper(controllerCommon, gui.git),
Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions),
Files: controllers.NewFilesHelper(controllerCommon, gui.git, osCommand),
WorkingTree: controllers.NewWorkingTreeHelper(model),
Tags: controllers.NewTagsHelper(controllerCommon, gui.git),
Rebase: rebaseHelper,
CherryPick: controllers.NewCherryPickHelper(
refsHelper := helpers.NewRefsHelper(
controllerCommon,
gui.git,
gui.State.Contexts,
model,
)
rebaseHelper := helpers.NewMergeAndRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper)
gui.helpers = &helpers.Helpers{
Refs: refsHelper,
Bisect: helpers.NewBisectHelper(controllerCommon, gui.git),
Suggestions: helpers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions),
Files: helpers.NewFilesHelper(controllerCommon, gui.git, osCommand),
WorkingTree: helpers.NewWorkingTreeHelper(model),
Tags: helpers.NewTagsHelper(controllerCommon, gui.git),
MergeAndRebase: rebaseHelper,
CherryPick: helpers.NewCherryPickHelper(
controllerCommon,
gui.git,
gui.State.Contexts,
@ -526,109 +515,58 @@ func (gui *Gui) resetControllers() {
),
}
syncController := controllers.NewSyncController(
common := controllers.NewControllerCommon(
controllerCommon,
osCommand,
gui.git,
gui.getCheckedOutBranch,
gui.helpers.Suggestions,
gui.helpers,
model,
gui.State.Contexts,
gui.State.Modes,
)
syncController := controllers.NewSyncController(
common,
gui.getSuggestedRemote,
gui.helpers.Rebase.CheckMergeOrRebase,
)
submodulesController := controllers.NewSubmodulesController(
controllerCommon,
gui.State.Contexts.Submodules,
gui.git,
common,
gui.enterSubmodule,
)
bisectController := controllers.NewBisectController(
controllerCommon,
gui.State.Contexts.BranchCommits,
gui.git,
gui.helpers.Bisect,
func() []*models.Commit { return gui.State.Model.Commits },
)
bisectController := controllers.NewBisectController(common)
gui.Controllers = Controllers{
Submodules: submodulesController,
Global: controllers.NewGlobalController(
controllerCommon,
osCommand,
),
Global: controllers.NewGlobalController(common),
Files: controllers.NewFilesController(
controllerCommon,
gui.State.Contexts.Files,
model,
gui.git,
osCommand,
gui.getSelectedFileNode,
gui.State.Contexts,
common,
gui.enterSubmodule,
func() []*models.SubmoduleConfig { return gui.State.Model.Submodules },
gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }),
gui.withGpgHandling,
func() string { return gui.State.failedCommitMessage },
gui.getSelectedPath,
gui.switchToMerge,
gui.helpers.Suggestions,
gui.helpers.Refs,
gui.helpers.Files,
gui.helpers.WorkingTree,
),
Tags: controllers.NewTagsController(
controllerCommon,
gui.State.Contexts.Tags,
gui.git,
gui.State.Contexts,
gui.helpers.Tags,
gui.helpers.Refs,
gui.helpers.Suggestions,
gui.switchToSubCommitsContext,
),
Tags: controllers.NewTagsController(common),
LocalCommits: controllers.NewLocalCommitsController(
controllerCommon,
gui.State.Contexts.BranchCommits,
osCommand,
gui.git,
gui.helpers.Tags,
gui.helpers.Refs,
gui.helpers.CherryPick,
gui.helpers.Rebase,
model,
gui.helpers.Rebase.CheckMergeOrRebase,
common,
syncController.HandlePull,
gui.getHostingServiceMgr,
gui.SwitchToCommitFilesContext,
func() bool { return gui.ShowWholeGitGraph },
func(value bool) { gui.ShowWholeGitGraph = value },
),
Remotes: controllers.NewRemotesController(
controllerCommon,
gui.State.Contexts.Remotes,
gui.git,
gui.State.Contexts,
common,
func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches },
),
Menu: controllers.NewMenuController(
controllerCommon,
gui.State.Contexts.Menu,
),
Undo: controllers.NewUndoController(
controllerCommon,
gui.git,
gui.helpers.Refs,
gui.helpers.WorkingTree,
func() []*models.Commit { return gui.State.Model.FilteredReflogCommits },
),
Menu: controllers.NewMenuController(common),
Undo: controllers.NewUndoController(common),
Sync: syncController,
}
branchesController := controllers.NewBranchesController(common)
switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory(
controllerCommon,
gui.State.Contexts.SubCommits,
gui.git,
gui.State.Modes,
common,
func(commits []*models.Commit) { gui.State.Model.SubCommits = commits },
)
@ -640,6 +578,7 @@ func (gui *Gui) resetControllers() {
controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context))
}
controllers.AttachControllers(gui.State.Contexts.Branches, branchesController)
controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files)
controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags)
controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules)

File diff suppressed because it is too large Load Diff

View File

@ -73,7 +73,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
formatWorkingTreeState(workingTreeState), style.FgYellow,
)
},
reset: gui.helpers.Rebase.AbortMergeOrRebaseWithConfirm,
reset: gui.helpers.MergeAndRebase.AbortMergeOrRebaseWithConfirm,
},
{
isActive: func() bool {

View File

@ -102,7 +102,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error {
commitIndex := gui.getPatchCommitIndex()
gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit)
err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Model.Commits, commitIndex)
return gui.helpers.Rebase.CheckMergeOrRebase(err)
return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}
@ -119,7 +119,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error {
commitIndex := gui.getPatchCommitIndex()
gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit)
err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Contexts.BranchCommits.GetSelectedLineIdx())
return gui.helpers.Rebase.CheckMergeOrRebase(err)
return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}
@ -137,7 +137,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error {
commitIndex := gui.getPatchCommitIndex()
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex)
err := gui.git.Patch.MovePatchIntoIndex(gui.State.Model.Commits, commitIndex, stash)
return gui.helpers.Rebase.CheckMergeOrRebase(err)
return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}
@ -167,7 +167,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error {
commitIndex := gui.getPatchCommitIndex()
gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit)
err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Model.Commits, commitIndex)
return gui.helpers.Rebase.CheckMergeOrRebase(err)
return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err)
})
}

View File

@ -1,78 +0,0 @@
package gui
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
menuItems := make([]*types.MenuItem, 0, 4)
fromToDisplayStrings := func(from string, to string) []string {
return []string{fmt.Sprintf("%s → %s", from, to)}
}
menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem {
return []*types.MenuItem{
{
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch),
OnPress: func() error {
return gui.createPullRequest(branch.Name, "")
},
},
{
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch),
OnPress: func() error {
return gui.c.Prompt(types.PromptOpts{
Title: branch.Name + " →",
FindSuggestionsFunc: gui.helpers.Suggestions.GetBranchNameSuggestionsFunc(),
HandleConfirm: func(targetBranchName string) error {
return gui.createPullRequest(branch.Name, targetBranchName)
}},
)
},
},
}
}
if selectedBranch != checkedOutBranch {
menuItems = append(menuItems,
&types.MenuItem{
DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name),
OnPress: func() error {
return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
},
},
)
menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...)
}
menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
return gui.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(gui.c.Tr.CreatePullRequestOptions), Items: menuItems})
}
func (gui *Gui) createPullRequest(from string, to string) error {
hostingServiceMgr := gui.getHostingServiceMgr()
url, err := hostingServiceMgr.GetPullRequestURL(from, to)
if err != nil {
return gui.c.Error(err)
}
gui.c.LogAction(gui.c.Tr.Actions.OpenPullRequest)
if err := gui.os.OpenLink(url); err != nil {
return gui.c.Error(err)
}
return nil
}
func (gui *Gui) getHostingServiceMgr() *hosting_service.HostingServiceMgr {
remoteUrl := gui.git.Config.GetRemoteURL()
configServices := gui.c.UserConfig.Services
return hosting_service.NewHostingServiceMgr(gui.Log, gui.Tr, remoteUrl, configServices)
}

View File

@ -65,10 +65,9 @@ func (gui *Gui) handleViewReflogCommitFiles() error {
}
return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{
RefName: commit.Sha,
CanRebase: false,
Context: gui.State.Contexts.ReflogCommits,
WindowName: "commits",
RefName: commit.Sha,
CanRebase: false,
Context: gui.State.Contexts.ReflogCommits,
})
}

View File

@ -215,7 +215,7 @@ func (gui *Gui) refreshCommitsWithLimit() error {
FilterPath: gui.State.Modes.Filtering.GetPath(),
IncludeRebaseCommits: true,
RefName: gui.refForLog(),
All: gui.ShowWholeGitGraph,
All: gui.State.Contexts.BranchCommits.GetShowWholeGitGraph(),
},
)
if err != nil {
@ -408,7 +408,7 @@ func (gui *Gui) refreshStateFiles() error {
}
if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 {
gui.OnUIThread(func() error { return gui.helpers.Rebase.PromptToContinueRebase() })
gui.OnUIThread(func() error { return gui.helpers.MergeAndRebase.PromptToContinueRebase() })
}
fileTreeViewModel.RWMutex.Lock()
@ -526,7 +526,7 @@ func (gui *Gui) refreshStatus() {
gui.Mutexes.RefreshingStatusMutex.Lock()
defer gui.Mutexes.RefreshingStatusMutex.Unlock()
currentBranch := gui.getCheckedOutBranch()
currentBranch := gui.helpers.Refs.GetCheckedOutRef()
if currentBranch == nil {
// need to wait for branches to refresh
return

View File

@ -34,7 +34,7 @@ func (gui *Gui) handleRemoteBranchesEscape() error {
func (gui *Gui) handleMergeRemoteBranch() error {
selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName()
return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName)
return gui.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)
}
func (gui *Gui) handleDeleteRemoteBranch() error {
@ -63,12 +63,12 @@ func (gui *Gui) handleDeleteRemoteBranch() error {
func (gui *Gui) handleRebaseOntoRemoteBranch() error {
selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName()
return gui.handleRebaseOntoBranch(selectedBranchName)
return gui.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName)
}
func (gui *Gui) handleSetBranchUpstream() error {
selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected()
checkedOutBranch := gui.getCheckedOutBranch()
checkedOutBranch := gui.helpers.Refs.GetCheckedOutRef()
message := utils.ResolvePlaceholderString(
gui.c.Tr.SetUpstreamMessage,
@ -101,15 +101,6 @@ func (gui *Gui) handleCreateResetToRemoteBranchMenu() error {
return gui.helpers.Refs.CreateGitResetMenu(selectedBranch.FullName())
}
func (gui *Gui) handleEnterRemoteBranch() error {
selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected()
if selectedBranch == nil {
return nil
}
return gui.switchToSubCommitsContext(selectedBranch.RefName())
}
func (gui *Gui) handleNewBranchOffRemoteBranch() error {
selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected()
if selectedBranch == nil {

View File

@ -37,8 +37,6 @@ func (gui *Gui) handleStashApply() error {
return nil
}
skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning
apply := func() error {
gui.c.LogAction(gui.c.Tr.Actions.Stash)
err := gui.git.Stash.Apply(stashEntry.Index)
@ -49,7 +47,7 @@ func (gui *Gui) handleStashApply() error {
return nil
}
if skipStashWarning {
if gui.c.UserConfig.Gui.SkipStashWarning {
return apply()
}
@ -68,8 +66,6 @@ func (gui *Gui) handleStashPop() error {
return nil
}
skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning
pop := func() error {
gui.c.LogAction(gui.c.Tr.Actions.Stash)
err := gui.git.Stash.Pop(stashEntry.Index)
@ -80,7 +76,7 @@ func (gui *Gui) handleStashPop() error {
return nil
}
if skipStashWarning {
if gui.c.UserConfig.Gui.SkipStashWarning {
return pop()
}
@ -125,10 +121,9 @@ func (gui *Gui) handleViewStashFiles() error {
}
return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{
RefName: stashEntry.RefName(),
CanRebase: false,
Context: gui.State.Contexts.Stash,
WindowName: "stash",
RefName: stashEntry.RefName(),
CanRebase: false,
Context: gui.State.Contexts.Stash,
})
}

View File

@ -30,7 +30,7 @@ func (gui *Gui) handleCheckForUpdate() error {
func (gui *Gui) handleStatusClick() error {
// TODO: move into some abstraction (status is currently not a listViewContext where a lot of this code lives)
currentBranch := gui.getCheckedOutBranch()
currentBranch := gui.helpers.Refs.GetCheckedOutRef()
if currentBranch == nil {
// need to wait for branches to refresh
return nil
@ -48,7 +48,7 @@ func (gui *Gui) handleStatusClick() error {
case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING:
workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState))
if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) {
return gui.helpers.Rebase.CreateRebaseOptionsMenu()
return gui.helpers.MergeAndRebase.CreateRebaseOptionsMenu()
}
if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
return gui.handleCreateRecentReposMenu()
@ -74,7 +74,6 @@ func formatWorkingTreeState(rebaseMode enums.RebaseMode) string {
}
func (gui *Gui) statusRenderToMain() error {
// TODO: move into some abstraction (status is currently not a listViewContext where a lot of this code lives)
dashboardString := strings.Join(
[]string{
lazygitTitle(),
@ -114,9 +113,8 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error {
}
}
return gui.c.Menu(types.CreateMenuOptions{
Title: gui.c.Tr.SelectConfigFile,
Items: menuItems,
HideCancel: true,
Title: gui.c.Tr.SelectConfigFile,
Items: menuItems,
})
}
}

View File

@ -63,10 +63,9 @@ func (gui *Gui) handleViewSubCommitFiles() error {
}
return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{
RefName: commit.Sha,
CanRebase: false,
Context: gui.State.Contexts.SubCommits,
WindowName: "branches",
RefName: commit.Sha,
CanRebase: false,
Context: gui.State.Contexts.SubCommits,
})
}

View File

@ -9,7 +9,7 @@ import (
"gopkg.in/ozeidan/fuzzy-patricia.v3/patricia"
)
type ControllerCommon struct {
type HelperCommon struct {
*common.Common
IGuiCommon
}