mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-01-20 05:19:24 +02:00
Enforce single-item selection in various actions
We want to show an error when the user tries to invoke an action that expects only a single item to be selected. We're using the GetDisabledReason field to enforce this (as well as DisabledReason on menu items). I've created a ListControllerTrait to store some shared convenience functions for this.
This commit is contained in:
parent
280b4d60f8
commit
51fb82d6bf
@ -114,10 +114,18 @@ func (self *ListCursor) CancelRangeSelect() {
|
||||
self.rangeSelectMode = RangeSelectModeNone
|
||||
}
|
||||
|
||||
// Returns true if we are in range select mode. Note that we may be in range select
|
||||
// mode and still only selecting a single item. See AreMultipleItemsSelected below.
|
||||
func (self *ListCursor) IsSelectingRange() bool {
|
||||
return self.rangeSelectMode != RangeSelectModeNone
|
||||
}
|
||||
|
||||
// Returns true if we are in range select mode and selecting multiple items
|
||||
func (self *ListCursor) AreMultipleItemsSelected() bool {
|
||||
startIdx, endIdx := self.GetSelectionRange()
|
||||
return startIdx != endIdx
|
||||
}
|
||||
|
||||
func (self *ListCursor) GetSelectionRange() (int, int) {
|
||||
if self.IsSelectingRange() {
|
||||
return utils.MinMax(self.selectedIdx, self.rangeStartIdx)
|
||||
|
@ -22,50 +22,61 @@ type ContainsCommits interface {
|
||||
|
||||
type BasicCommitsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Commit]
|
||||
c *ControllerCommon
|
||||
context ContainsCommits
|
||||
}
|
||||
|
||||
func NewBasicCommitsController(controllerCommon *ControllerCommon, context ContainsCommits) *BasicCommitsController {
|
||||
func NewBasicCommitsController(c *ControllerCommon, context ContainsCommits) *BasicCommitsController {
|
||||
return &BasicCommitsController{
|
||||
baseController: baseController{},
|
||||
c: controllerCommon,
|
||||
c: c,
|
||||
context: context,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Commit](
|
||||
c,
|
||||
context,
|
||||
context.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CheckoutCommit),
|
||||
Handler: self.checkSelected(self.checkout),
|
||||
Description: self.c.Tr.CheckoutCommit,
|
||||
Key: opts.GetKey(opts.Config.Commits.CheckoutCommit),
|
||||
Handler: self.withItem(self.checkout),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CheckoutCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard),
|
||||
Handler: self.checkSelected(self.copyCommitAttribute),
|
||||
Description: self.c.Tr.CopyCommitAttributeToClipboard,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard),
|
||||
Handler: self.withItem(self.copyCommitAttribute),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CopyCommitAttributeToClipboard,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.OpenInBrowser),
|
||||
Handler: self.checkSelected(self.openInBrowser),
|
||||
Description: self.c.Tr.OpenCommitInBrowser,
|
||||
Key: opts.GetKey(opts.Config.Commits.OpenInBrowser),
|
||||
Handler: self.withItem(self.openInBrowser),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenCommitInBrowser,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.checkSelected(self.newBranch),
|
||||
Description: self.c.Tr.CreateNewBranchFromCommit,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.withItem(self.newBranch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CreateNewBranchFromCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.checkSelected(self.createResetMenu),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.withItem(self.createResetMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CherryPickCopy),
|
||||
Handler: self.checkSelected(self.copyRange),
|
||||
Handler: self.withItem(self.copyRange),
|
||||
Description: self.c.Tr.CherryPickCopy,
|
||||
},
|
||||
{
|
||||
@ -74,30 +85,16 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
Description: self.c.Tr.ResetCherryPick,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.checkSelected(self.openDiffTool),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.withItem(self.openDiffTool),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
},
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
func (self *BasicCommitsController) checkSelected(callback func(*models.Commit) error) func() error {
|
||||
return func() error {
|
||||
commit := self.context.GetSelected()
|
||||
if commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BasicCommitsController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
||||
func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) error {
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard,
|
||||
|
@ -14,17 +14,23 @@ import (
|
||||
|
||||
type BisectController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Commit]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &BisectController{}
|
||||
|
||||
func NewBisectController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *BisectController {
|
||||
return &BisectController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Commit](
|
||||
c,
|
||||
c.Contexts().LocalCommits,
|
||||
c.Contexts().LocalCommits.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +38,7 @@ func (self *BisectController) GetKeybindings(opts types.KeybindingsOpts) []*type
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewBisectOptions),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.openMenu)),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.withItem(self.openMenu)),
|
||||
Description: self.c.Tr.ViewBisectOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
@ -70,9 +76,19 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
||||
// If we have a current sha already, then we always want to use that one. If
|
||||
// not, we're still picking the initial commits before we really start, so
|
||||
// use the selected commit in that case.
|
||||
shaToMark := lo.Ternary(info.GetCurrentSha() != "", info.GetCurrentSha(), commit.Sha)
|
||||
|
||||
bisecting := info.GetCurrentSha() != ""
|
||||
shaToMark := lo.Ternary(bisecting, info.GetCurrentSha(), commit.Sha)
|
||||
shortShaToMark := utils.ShortSha(shaToMark)
|
||||
|
||||
// For marking a commit as bad, when we're not already bisecting, we require
|
||||
// a single item selected, but once we are bisecting, it doesn't matter because
|
||||
// the action applies to the HEAD commit rather than the selected commit.
|
||||
var singleItemIfNotBisecting *types.DisabledReason
|
||||
if !bisecting {
|
||||
singleItemIfNotBisecting = self.require(self.singleItemSelected())()
|
||||
}
|
||||
|
||||
menuItems := []*types.MenuItem{
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortShaToMark, info.NewTerm()),
|
||||
@ -84,7 +100,8 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
||||
|
||||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
Key: 'b',
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 'b',
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortShaToMark, info.OldTerm()),
|
||||
@ -96,7 +113,8 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
||||
|
||||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
Key: 'g',
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 'g',
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortShaToMark),
|
||||
@ -108,7 +126,8 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
||||
|
||||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
Key: 's',
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 's',
|
||||
},
|
||||
}
|
||||
if info.GetCurrentSha() != "" && info.GetCurrentSha() != commit.Sha {
|
||||
@ -122,7 +141,8 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
||||
|
||||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
Key: 'S',
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'S',
|
||||
}))
|
||||
}
|
||||
menuItems = append(menuItems, lo.ToPtr(types.MenuItem{
|
||||
@ -157,7 +177,8 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
},
|
||||
Key: 'b',
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'b',
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.OldTerm()),
|
||||
@ -173,7 +194,8 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
},
|
||||
Key: 'g',
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'g',
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.Bisect.ChooseTerms,
|
||||
@ -273,21 +295,6 @@ func (self *BisectController) selectCurrentBisectCommit() {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BisectController) checkSelected(callback func(*models.Commit) error) func() error {
|
||||
return func() error {
|
||||
commit := self.context().GetSelected()
|
||||
if commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BisectController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *BisectController) context() *context.LocalCommitsContext {
|
||||
return self.c.Contexts().LocalCommits
|
||||
}
|
||||
|
@ -17,48 +17,61 @@ import (
|
||||
|
||||
type BranchesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Branch]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &BranchesController{}
|
||||
|
||||
func NewBranchesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *BranchesController {
|
||||
return &BranchesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Branch](
|
||||
c,
|
||||
c.Contexts().Branches,
|
||||
c.Contexts().Branches.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.press),
|
||||
GetDisabledReason: self.getDisabledReasonForPress,
|
||||
Description: self.c.Tr.Checkout,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.press),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(),
|
||||
self.notPulling,
|
||||
),
|
||||
Description: self.c.Tr.Checkout,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.checkSelected(self.newBranch),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.withItem(self.newBranch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.CreatePullRequest),
|
||||
Handler: self.checkSelected(self.handleCreatePullRequest),
|
||||
Description: self.c.Tr.CreatePullRequest,
|
||||
Key: opts.GetKey(opts.Config.Branches.CreatePullRequest),
|
||||
Handler: self.withItem(self.handleCreatePullRequest),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CreatePullRequest,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions),
|
||||
Handler: self.checkSelected(self.handleCreatePullRequestMenu),
|
||||
Description: self.c.Tr.CreatePullRequestOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions),
|
||||
Handler: self.withItem(self.handleCreatePullRequestMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CreatePullRequestOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL),
|
||||
Handler: self.copyPullRequestURL,
|
||||
Description: self.c.Tr.CopyPullRequestURL,
|
||||
Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL),
|
||||
Handler: self.copyPullRequestURL,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CopyPullRequestURL,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName),
|
||||
@ -66,60 +79,69 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
Description: self.c.Tr.CheckoutByName,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch),
|
||||
Handler: self.forceCheckout,
|
||||
Description: self.c.Tr.ForceCheckout,
|
||||
Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch),
|
||||
Handler: self.forceCheckout,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ForceCheckout,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelectedAndReal(self.delete),
|
||||
Description: self.c.Tr.ViewDeleteOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.delete),
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.branchIsReal)),
|
||||
Description: self.c.Tr.ViewDeleteOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.rebase),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
GetDisabledReason: self.getDisabledReasonForRebase,
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.rebase),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.notRebasingOntoSelf),
|
||||
),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.merge),
|
||||
Description: self.c.Tr.MergeIntoCurrentBranch,
|
||||
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.merge),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.MergeIntoCurrentBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.FastForward),
|
||||
Handler: self.checkSelectedAndReal(self.fastForward),
|
||||
Description: self.c.Tr.FastForward,
|
||||
Key: opts.GetKey(opts.Config.Branches.FastForward),
|
||||
Handler: self.withItem(self.fastForward),
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.branchIsReal)),
|
||||
Description: self.c.Tr.FastForward,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.CreateTag),
|
||||
Handler: self.checkSelected(self.createTag),
|
||||
Description: self.c.Tr.CreateTag,
|
||||
Key: opts.GetKey(opts.Config.Branches.CreateTag),
|
||||
Handler: self.withItem(self.createTag),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CreateTag,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SortOrder),
|
||||
Handler: self.createSortMenu,
|
||||
Description: self.c.Tr.SortOrder,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.checkSelected(self.createResetMenu),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.withItem(self.createResetMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RenameBranch),
|
||||
Handler: self.checkSelectedAndReal(self.rename),
|
||||
Description: self.c.Tr.RenameBranch,
|
||||
Key: opts.GetKey(opts.Config.Branches.RenameBranch),
|
||||
Handler: self.withItem(self.rename),
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.branchIsReal)),
|
||||
Description: self.c.Tr.RenameBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
||||
Handler: self.checkSelected(self.viewUpstreamOptions),
|
||||
Description: self.c.Tr.ViewBranchUpstreamOptions,
|
||||
Tooltip: self.c.Tr.ViewBranchUpstreamOptionsTooltip,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
||||
Handler: self.withItem(self.viewUpstreamOptions),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewBranchUpstreamOptions,
|
||||
Tooltip: self.c.Tr.ViewBranchUpstreamOptionsTooltip,
|
||||
OpensMenu: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -308,7 +330,7 @@ func (self *BranchesController) press(selectedBranch *models.Branch) error {
|
||||
return self.c.Helpers().Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{})
|
||||
}
|
||||
|
||||
func (self *BranchesController) getDisabledReasonForPress() *types.DisabledReason {
|
||||
func (self *BranchesController) notPulling() *types.DisabledReason {
|
||||
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
||||
if currentBranch != nil {
|
||||
op := self.c.State().GetItemOperation(currentBranch)
|
||||
@ -561,8 +583,8 @@ func (self *BranchesController) rebase() error {
|
||||
return self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranchName)
|
||||
}
|
||||
|
||||
func (self *BranchesController) getDisabledReasonForRebase() *types.DisabledReason {
|
||||
selectedBranchName := self.context().GetSelected().Name
|
||||
func (self *BranchesController) notRebasingOntoSelf(branch *models.Branch) *types.DisabledReason {
|
||||
selectedBranchName := branch.Name
|
||||
checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef().Name
|
||||
if selectedBranchName == checkedOutBranch {
|
||||
return &types.DisabledReason{Text: self.c.Tr.CantRebaseOntoSelf}
|
||||
@ -753,24 +775,10 @@ func (self *BranchesController) createPullRequest(from string, to string) error
|
||||
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) branchIsReal(branch *models.Branch) *types.DisabledReason {
|
||||
if !branch.IsRealBranch() {
|
||||
return &types.DisabledReason{Text: self.c.Tr.SelectedItemIsNotABranch}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ type CommandLogController struct {
|
||||
var _ types.IController = &CommandLogController{}
|
||||
|
||||
func NewCommandLogController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *CommandLogController {
|
||||
return &CommandLogController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,11 @@ type CommitDescriptionController struct {
|
||||
var _ types.IController = &CommitMessageController{}
|
||||
|
||||
func NewCommitDescriptionController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *CommitDescriptionController {
|
||||
return &CommitDescriptionController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@ type CommitMessageController struct {
|
||||
var _ types.IController = &CommitMessageController{}
|
||||
|
||||
func NewCommitMessageController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *CommitMessageController {
|
||||
return &CommitMessageController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,61 +12,74 @@ import (
|
||||
|
||||
type CommitFilesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*filetree.CommitFileNode]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &CommitFilesController{}
|
||||
|
||||
func NewCommitFilesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *CommitFilesController {
|
||||
return &CommitFilesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
ListControllerTrait: NewListControllerTrait[*filetree.CommitFileNode](
|
||||
c,
|
||||
c.Contexts().CommitFiles,
|
||||
c.Contexts().CommitFiles.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile),
|
||||
Handler: self.checkSelected(self.checkout),
|
||||
Description: self.c.Tr.CheckoutCommitFile,
|
||||
Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile),
|
||||
Handler: self.withItem(self.checkout),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CheckoutCommitFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.discard),
|
||||
Description: self.c.Tr.DiscardOldFileChange,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.discard),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.DiscardOldFileChange,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.checkSelected(self.open),
|
||||
Description: self.c.Tr.OpenFile,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.withItem(self.open),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.checkSelected(self.edit),
|
||||
Description: self.c.Tr.EditFile,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.withItem(self.edit),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EditFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.checkSelected(self.openDiffTool),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.withItem(self.openDiffTool),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.toggleForPatch),
|
||||
Description: self.c.Tr.ToggleAddToPatch,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.toggleForPatch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ToggleAddToPatch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ToggleStagedAll),
|
||||
Handler: self.checkSelected(self.toggleAllForPatch),
|
||||
Handler: self.withItem(self.toggleAllForPatch),
|
||||
Description: self.c.Tr.ToggleAllInPatch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.EnterFile,
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EnterFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ToggleTreeView),
|
||||
@ -89,21 +102,6 @@ func (self *CommitFilesController) GetMouseKeybindings(opts types.KeybindingsOpt
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) checkSelected(callback func(*filetree.CommitFileNode) error) func() error {
|
||||
return func() error {
|
||||
selected := self.context().GetSelected()
|
||||
if selected == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(selected)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) context() *context.CommitFilesContext {
|
||||
return self.c.Contexts().CommitFiles
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ type ConfirmationController struct {
|
||||
var _ types.IController = &ConfirmationController{}
|
||||
|
||||
func NewConfirmationController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *ConfirmationController {
|
||||
return &ConfirmationController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,11 @@ type ContextLinesController struct {
|
||||
var _ types.IController = &ContextLinesController{}
|
||||
|
||||
func NewContextLinesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *ContextLinesController {
|
||||
return &ContextLinesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,15 +62,22 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
||||
if self.c.CurrentContext().GetKey() == self.c.Contexts().LocalCommits.GetKey() {
|
||||
selectedCommit := self.c.Contexts().LocalCommits.GetSelected()
|
||||
if selectedCommit != nil && self.c.Git().Patch.PatchBuilder.To != selectedCommit.Sha {
|
||||
|
||||
var disabledReason *types.DisabledReason
|
||||
if self.c.Contexts().LocalCommits.AreMultipleItemsSelected() {
|
||||
disabledReason = &types.DisabledReason{Text: self.c.Tr.RangeSelectNotSupported}
|
||||
}
|
||||
|
||||
// adding this option to index 1
|
||||
menuItems = append(
|
||||
menuItems[:1],
|
||||
append(
|
||||
[]*types.MenuItem{
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Sha),
|
||||
OnPress: self.handleMovePatchToSelectedCommit,
|
||||
Key: 'm',
|
||||
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Sha),
|
||||
OnPress: self.handleMovePatchToSelectedCommit,
|
||||
Key: 'm',
|
||||
DisabledReason: disabledReason,
|
||||
},
|
||||
}, menuItems[1:]...,
|
||||
)...,
|
||||
|
@ -13,25 +13,32 @@ import (
|
||||
|
||||
type FilesController struct {
|
||||
baseController // nolint: unused
|
||||
c *ControllerCommon
|
||||
*ListControllerTrait[*filetree.FileNode]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &FilesController{}
|
||||
|
||||
func NewFilesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *FilesController {
|
||||
return &FilesController{
|
||||
c: common,
|
||||
c: c,
|
||||
ListControllerTrait: NewListControllerTrait[*filetree.FileNode](
|
||||
c,
|
||||
c.Contexts().Files,
|
||||
c.Contexts().Files.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelectedFileNode(self.press),
|
||||
Description: self.c.Tr.ToggleStaged,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.press),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ToggleStaged,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.OpenStatusFilter),
|
||||
@ -71,20 +78,23 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Tooltip: self.c.Tr.FindBaseCommitForFixupTooltip,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.checkSelectedFileNode(self.edit),
|
||||
Description: self.c.Tr.EditFile,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.withItem(self.edit),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EditFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.Open,
|
||||
Description: self.c.Tr.OpenFile,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.Open,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenFile,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.IgnoreFile),
|
||||
Handler: self.checkSelectedFileNode(self.ignoreOrExcludeMenu),
|
||||
Description: self.c.Tr.Actions.IgnoreExcludeFile,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Files.IgnoreFile),
|
||||
Handler: self.withItem(self.ignoreOrExcludeMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Actions.IgnoreExcludeFile,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.RefreshFiles),
|
||||
@ -108,9 +118,10 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Description: self.c.Tr.ToggleStagedAll,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.enter,
|
||||
Description: self.c.Tr.FileEnter,
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.enter,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.FileEnter,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
@ -130,9 +141,10 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Description: self.c.Tr.ToggleTreeView,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.checkSelectedFileNode(self.openDiffTool),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
Handler: self.withItem(self.openDiffTool),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenDiffTool,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
|
||||
@ -254,7 +266,7 @@ func (self *FilesController) GetOnRenderToMain() func() error {
|
||||
}
|
||||
|
||||
func (self *FilesController) GetOnClick() func() error {
|
||||
return self.checkSelectedFileNode(self.press)
|
||||
return self.withItemGraceful(self.press)
|
||||
}
|
||||
|
||||
// if we are dealing with a status for which there is no key in this map,
|
||||
@ -411,17 +423,6 @@ func (self *FilesController) press(node *filetree.FileNode) error {
|
||||
return self.context().HandleFocus(types.OnFocusOpts{})
|
||||
}
|
||||
|
||||
func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error {
|
||||
return func() error {
|
||||
node := self.context().GetSelected()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
@ -798,7 +799,8 @@ func (self *FilesController) openCopyMenu() error {
|
||||
self.c.Toast(self.c.Tr.FileNameCopiedToast)
|
||||
return nil
|
||||
},
|
||||
Key: 'n',
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'n',
|
||||
}
|
||||
copyPathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyFilePath,
|
||||
@ -809,7 +811,8 @@ func (self *FilesController) openCopyMenu() error {
|
||||
self.c.Toast(self.c.Tr.FilePathCopiedToast)
|
||||
return nil
|
||||
},
|
||||
Key: 'p',
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'p',
|
||||
}
|
||||
copyFileDiffItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopySelectedDiff,
|
||||
@ -827,6 +830,14 @@ func (self *FilesController) openCopyMenu() error {
|
||||
self.c.Toast(self.c.Tr.FileDiffCopiedToast)
|
||||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected(
|
||||
func(file *filetree.FileNode) *types.DisabledReason {
|
||||
if !node.GetHasStagedOrTrackedChanges() {
|
||||
return &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
))(),
|
||||
Key: 's',
|
||||
}
|
||||
copyAllDiff := &types.MenuItem{
|
||||
@ -844,21 +855,17 @@ func (self *FilesController) openCopyMenu() error {
|
||||
self.c.Toast(self.c.Tr.AllFilesDiffCopiedToast)
|
||||
return nil
|
||||
},
|
||||
DisabledReason: self.require(
|
||||
func() *types.DisabledReason {
|
||||
if !self.anyStagedOrTrackedFile() {
|
||||
return &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)(),
|
||||
Key: 'a',
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
copyNameItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
copyPathItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
copyFileDiffItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
}
|
||||
if node != nil && !node.GetHasStagedOrTrackedChanges() {
|
||||
copyFileDiffItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
}
|
||||
if !self.anyStagedOrTrackedFile() {
|
||||
copyAllDiff.DisabledReason = &types.DisabledReason{Text: self.c.Tr.NoContentToCopyError}
|
||||
}
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: self.c.Tr.CopyToClipboardMenu,
|
||||
Items: []*types.MenuItem{
|
||||
|
@ -3,7 +3,6 @@ package controllers
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
@ -13,27 +12,34 @@ import (
|
||||
|
||||
type FilesRemoveController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*filetree.FileNode]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &FilesRemoveController{}
|
||||
|
||||
func NewFilesRemoveController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *FilesRemoveController {
|
||||
return &FilesRemoveController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
ListControllerTrait: NewListControllerTrait[*filetree.FileNode](
|
||||
c,
|
||||
c.Contexts().Files,
|
||||
c.Contexts().Files.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesRemoveController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelectedFileNode(self.remove),
|
||||
Description: self.c.Tr.ViewDiscardOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.remove),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewDiscardOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -166,22 +172,3 @@ func (self *FilesRemoveController) ResetSubmodule(submodule *models.SubmoduleCon
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}})
|
||||
})
|
||||
}
|
||||
|
||||
func (self *FilesRemoveController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error {
|
||||
return func() error {
|
||||
node := self.context().GetSelected()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesRemoveController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *FilesRemoveController) context() *context.WorkingTreeContext {
|
||||
return self.c.Contexts().Files
|
||||
}
|
||||
|
@ -4,24 +4,29 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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 GitFlowController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Branch]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &GitFlowController{}
|
||||
|
||||
func NewGitFlowController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *GitFlowController {
|
||||
return &GitFlowController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Branch](
|
||||
c,
|
||||
c.Contexts().Branches,
|
||||
c.Contexts().Branches.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +34,7 @@ func (self *GitFlowController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.ViewGitFlowOptions),
|
||||
Handler: self.checkSelected(self.handleCreateGitFlowMenu),
|
||||
Handler: self.withItem(self.handleCreateGitFlowMenu),
|
||||
Description: self.c.Tr.GitFlowOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
@ -68,6 +73,7 @@ func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) er
|
||||
OnPress: func() error {
|
||||
return self.gitFlowFinishBranch(branch.Name)
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
},
|
||||
{
|
||||
Label: "start feature",
|
||||
@ -102,22 +108,3 @@ func (self *GitFlowController) gitFlowFinishBranch(branchName string) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.GitFlowFinish)
|
||||
return self.c.RunSubprocessAndRefresh(cmdObj)
|
||||
}
|
||||
|
||||
func (self *GitFlowController) checkSelected(callback func(*models.Branch) error) func() error {
|
||||
return func() error {
|
||||
node := self.context().GetSelected()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GitFlowController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *GitFlowController) context() *context.BranchesContext {
|
||||
return self.c.Contexts().Branches
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ type GlobalController struct {
|
||||
}
|
||||
|
||||
func NewGlobalController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *GlobalController {
|
||||
return &GlobalController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@ type JumpToSideWindowController struct {
|
||||
}
|
||||
|
||||
func NewJumpToSideWindowController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *JumpToSideWindowController {
|
||||
return &JumpToSideWindowController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
95
pkg/gui/controllers/list_controller_trait.go
Normal file
95
pkg/gui/controllers/list_controller_trait.go
Normal file
@ -0,0 +1,95 @@
|
||||
package controllers
|
||||
|
||||
import "github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
||||
// Embed this into your list controller to get some convenience methods for
|
||||
// ensuring a single item is selected, etc.
|
||||
|
||||
type ListControllerTrait[T comparable] struct {
|
||||
c *ControllerCommon
|
||||
context types.IListContext
|
||||
getSelected func() T
|
||||
}
|
||||
|
||||
func NewListControllerTrait[T comparable](
|
||||
c *ControllerCommon,
|
||||
context types.IListContext,
|
||||
getSelected func() T,
|
||||
) *ListControllerTrait[T] {
|
||||
return &ListControllerTrait[T]{
|
||||
c: c,
|
||||
context: context,
|
||||
getSelected: getSelected,
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience function for combining multiple disabledReason callbacks.
|
||||
// The first callback to return a disabled reason will be the one returned.
|
||||
func (self *ListControllerTrait[T]) require(callbacks ...func() *types.DisabledReason) func() *types.DisabledReason {
|
||||
return func() *types.DisabledReason {
|
||||
for _, callback := range callbacks {
|
||||
if disabledReason := callback(); disabledReason != nil {
|
||||
return disabledReason
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience function for enforcing that a single item is selected.
|
||||
// Also takes callbacks for additional disabled reasons, and passes the selected
|
||||
// item into each one.
|
||||
func (self *ListControllerTrait[T]) singleItemSelected(callbacks ...func(T) *types.DisabledReason) func() *types.DisabledReason {
|
||||
return func() *types.DisabledReason {
|
||||
if self.context.GetList().AreMultipleItemsSelected() {
|
||||
return &types.DisabledReason{Text: self.c.Tr.RangeSelectNotSupported}
|
||||
}
|
||||
|
||||
var zeroValue T
|
||||
item := self.getSelected()
|
||||
if item == zeroValue {
|
||||
return &types.DisabledReason{Text: self.c.Tr.NoItemSelected}
|
||||
}
|
||||
|
||||
for _, callback := range callbacks {
|
||||
if reason := callback(item); reason != nil {
|
||||
return reason
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Passes the selected item to the callback. Used for handler functions.
|
||||
func (self *ListControllerTrait[T]) withItem(callback func(T) error) func() error {
|
||||
return func() error {
|
||||
var zeroValue T
|
||||
commit := self.getSelected()
|
||||
if commit == zeroValue {
|
||||
return self.c.ErrorMsg(self.c.Tr.NoItemSelected)
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
// Like withItem, but doesn't show an error message if no item is selected.
|
||||
// Use this for click actions (it's a no-op to click empty space)
|
||||
func (self *ListControllerTrait[T]) withItemGraceful(callback func(T) error) func() error {
|
||||
return func() error {
|
||||
var zeroValue T
|
||||
commit := self.getSelected()
|
||||
if commit == zeroValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
// All controllers must implement this method so we're defining it here for convenience
|
||||
func (self *ListControllerTrait[T]) Context() types.Context {
|
||||
return self.context
|
||||
}
|
@ -25,6 +25,7 @@ type (
|
||||
|
||||
type LocalCommitsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Commit]
|
||||
c *ControllerCommon
|
||||
|
||||
pullFiles PullFilesFn
|
||||
@ -33,13 +34,18 @@ type LocalCommitsController struct {
|
||||
var _ types.IController = &LocalCommitsController{}
|
||||
|
||||
func NewLocalCommitsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
pullFiles PullFilesFn,
|
||||
) *LocalCommitsController {
|
||||
return &LocalCommitsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
pullFiles: pullFiles,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Commit](
|
||||
c,
|
||||
c.Contexts().LocalCommits,
|
||||
c.Contexts().LocalCommits.GetSelected,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,47 +54,59 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
|
||||
outsideFilterModeBindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.SquashDown),
|
||||
Handler: self.checkSelected(self.squashDown),
|
||||
GetDisabledReason: self.callGetDisabledReasonFuncWithSelectedCommit(self.getDisabledReasonForSquashDown),
|
||||
Description: self.c.Tr.SquashDown,
|
||||
Key: opts.GetKey(opts.Config.Commits.SquashDown),
|
||||
Handler: self.withItem(self.squashDown),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.getDisabledReasonForSquashDown),
|
||||
),
|
||||
Description: self.c.Tr.SquashDown,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup),
|
||||
Handler: self.checkSelected(self.fixup),
|
||||
GetDisabledReason: self.callGetDisabledReasonFuncWithSelectedCommit(self.getDisabledReasonForFixup),
|
||||
Description: self.c.Tr.FixupCommit,
|
||||
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup),
|
||||
Handler: self.withItem(self.fixup),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.getDisabledReasonForFixup),
|
||||
),
|
||||
Description: self.c.Tr.FixupCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommit),
|
||||
Handler: self.checkSelected(self.reword),
|
||||
GetDisabledReason: self.getDisabledReasonForRebaseCommandWithSelectedCommit(todo.Reword),
|
||||
Description: self.c.Tr.RewordCommit,
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommit),
|
||||
Handler: self.withItem(self.reword),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Reword)),
|
||||
),
|
||||
Description: self.c.Tr.RewordCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor),
|
||||
Handler: self.checkSelected(self.rewordEditor),
|
||||
GetDisabledReason: self.getDisabledReasonForRebaseCommandWithSelectedCommit(todo.Reword),
|
||||
Description: self.c.Tr.RenameCommitEditor,
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor),
|
||||
Handler: self.withItem(self.rewordEditor),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Reword)),
|
||||
),
|
||||
Description: self.c.Tr.RenameCommitEditor,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.drop),
|
||||
GetDisabledReason: self.getDisabledReasonForRebaseCommandWithSelectedCommit(todo.Drop),
|
||||
Description: self.c.Tr.DeleteCommit,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.drop),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Drop)),
|
||||
),
|
||||
Description: self.c.Tr.DeleteCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(editCommitKey),
|
||||
Handler: self.checkSelected(self.edit),
|
||||
GetDisabledReason: self.getDisabledReasonForRebaseCommandWithSelectedCommit(todo.Edit),
|
||||
Description: self.c.Tr.EditCommit,
|
||||
Key: opts.GetKey(editCommitKey),
|
||||
Handler: self.withItem(self.edit),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Edit)),
|
||||
),
|
||||
Description: self.c.Tr.EditCommit,
|
||||
},
|
||||
{
|
||||
// The user-facing description here is 'Start interactive rebase' but internally
|
||||
// we're calling it 'quick-start interactive rebase' to differentiate it from
|
||||
// when you manually select the base commit.
|
||||
Key: opts.GetKey(opts.Config.Commits.StartInteractiveRebase),
|
||||
Handler: self.checkSelected(self.quickStartInteractiveRebase),
|
||||
Handler: self.withItem(self.quickStartInteractiveRebase),
|
||||
GetDisabledReason: self.require(self.notMidRebase, self.canFindCommitForQuickStart),
|
||||
Description: self.c.Tr.QuickStartInteractiveRebase,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{
|
||||
@ -96,45 +114,50 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
}),
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.PickCommit),
|
||||
Handler: self.checkSelected(self.pick),
|
||||
GetDisabledReason: self.getDisabledReasonForRebaseCommandWithSelectedCommit(todo.Pick),
|
||||
Description: self.c.Tr.PickCommit,
|
||||
Key: opts.GetKey(opts.Config.Commits.PickCommit),
|
||||
Handler: self.withItem(self.pick),
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Pick)),
|
||||
),
|
||||
Description: self.c.Tr.PickCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CreateFixupCommit),
|
||||
Handler: self.checkSelected(self.createFixupCommit),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.createFixupCommit),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.CreateFixupCommitDescription,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits),
|
||||
Handler: self.checkSelected(self.squashAllAboveFixupCommits),
|
||||
GetDisabledReason: self.callGetDisabledReasonFuncWithSelectedCommit(self.getDisabledReasonForSquashAllAboveFixupCommits),
|
||||
Description: self.c.Tr.SquashAboveCommits,
|
||||
Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits),
|
||||
Handler: self.withItem(self.squashAllAboveFixupCommits),
|
||||
GetDisabledReason: self.require(
|
||||
self.notMidRebase,
|
||||
self.singleItemSelected(),
|
||||
),
|
||||
Description: self.c.Tr.SquashAboveCommits,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.MoveDownCommit),
|
||||
Handler: self.checkSelected(self.moveDown),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.moveDown),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.MoveDownCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.MoveUpCommit),
|
||||
Handler: self.checkSelected(self.moveUp),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.moveUp),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.MoveUpCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.PasteCommits),
|
||||
Handler: self.paste,
|
||||
GetDisabledReason: self.getDisabledReasonForPaste,
|
||||
GetDisabledReason: self.require(self.canPaste),
|
||||
Description: self.c.Tr.PasteCommits,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsBaseForRebase),
|
||||
Handler: self.checkSelected(self.markAsBaseCommit),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.markAsBaseCommit),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.MarkAsBaseCommit,
|
||||
Tooltip: self.c.Tr.MarkAsBaseCommitTooltip,
|
||||
},
|
||||
@ -161,27 +184,27 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
bindings := append(outsideFilterModeBindings, []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.AmendToCommit),
|
||||
Handler: self.checkSelected(self.amendTo),
|
||||
GetDisabledReason: self.callGetDisabledReasonFuncWithSelectedCommit(self.getDisabledReasonForAmendTo),
|
||||
Handler: self.withItem(self.amendTo),
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.canAmend)),
|
||||
Description: self.c.Tr.AmendToCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ResetCommitAuthor),
|
||||
Handler: self.checkSelected(self.amendAttribute),
|
||||
GetDisabledReason: self.callGetDisabledReasonFuncWithSelectedCommit(self.getDisabledReasonForAmendTo),
|
||||
Handler: self.withItem(self.amendAttribute),
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.canAmend)),
|
||||
Description: self.c.Tr.SetResetCommitAuthor,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.RevertCommit),
|
||||
Handler: self.checkSelected(self.revert),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.revert),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RevertCommit,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CreateTag),
|
||||
Handler: self.checkSelected(self.createTag),
|
||||
GetDisabledReason: self.disabledIfNoSelectedCommit(),
|
||||
Handler: self.withItem(self.createTag),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.TagCommit,
|
||||
},
|
||||
{
|
||||
@ -266,7 +289,7 @@ func (self *LocalCommitsController) getDisabledReasonForSquashDown(commit *model
|
||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
||||
}
|
||||
|
||||
return self.rebaseCommandEnabled(todo.Squash, commit)
|
||||
return self.rebaseCommandEnabled(todo.Squash)(commit)
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) fixup(commit *models.Commit) error {
|
||||
@ -295,7 +318,7 @@ func (self *LocalCommitsController) getDisabledReasonForFixup(commit *models.Com
|
||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
||||
}
|
||||
|
||||
return self.rebaseCommandEnabled(todo.Squash, commit)
|
||||
return self.rebaseCommandEnabled(todo.Squash)(commit)
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
||||
@ -528,36 +551,38 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action todo.TodoComma
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) rebaseCommandEnabled(action todo.TodoCommand, commit *models.Commit) *types.DisabledReason {
|
||||
if commit.Action == models.ActionConflict {
|
||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
||||
}
|
||||
func (self *LocalCommitsController) rebaseCommandEnabled(action todo.TodoCommand) func(*models.Commit) *types.DisabledReason {
|
||||
return func(commit *models.Commit) *types.DisabledReason {
|
||||
if commit.Action == models.ActionConflict {
|
||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
||||
}
|
||||
|
||||
if !commit.IsTODO() {
|
||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
||||
// If we are in a rebase, the only action that is allowed for
|
||||
// non-todo commits is rewording the current head commit
|
||||
if !(action == todo.Reword && self.isHeadCommit()) {
|
||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||
if !commit.IsTODO() {
|
||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
||||
// If we are in a rebase, the only action that is allowed for
|
||||
// non-todo commits is rewording the current head commit
|
||||
if !(action == todo.Reword && self.isHeadCommit()) {
|
||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// for now we do not support setting 'reword' because it requires an editor
|
||||
// and that means we either unconditionally wait around for the subprocess to ask for
|
||||
// our input or we set a lazygit client as the EDITOR env variable and have it
|
||||
// request us to edit the commit message when prompted.
|
||||
if action == todo.Reword {
|
||||
return &types.DisabledReason{Text: self.c.Tr.RewordNotSupported}
|
||||
}
|
||||
|
||||
if allowed := isChangeOfRebaseTodoAllowed(action); !allowed {
|
||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// for now we do not support setting 'reword' because it requires an editor
|
||||
// and that means we either unconditionally wait around for the subprocess to ask for
|
||||
// our input or we set a lazygit client as the EDITOR env variable and have it
|
||||
// request us to edit the commit message when prompted.
|
||||
if action == todo.Reword {
|
||||
return &types.DisabledReason{Text: self.c.Tr.RewordNotSupported}
|
||||
}
|
||||
|
||||
if allowed := isChangeOfRebaseTodoAllowed(action); !allowed {
|
||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) moveDown(commit *models.Commit) error {
|
||||
@ -687,7 +712,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) getDisabledReasonForAmendTo(commit *models.Commit) *types.DisabledReason {
|
||||
func (self *LocalCommitsController) canAmend(commit *models.Commit) *types.DisabledReason {
|
||||
if !self.isHeadCommit() && self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||
}
|
||||
@ -870,14 +895,6 @@ func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Co
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) getDisabledReasonForSquashAllAboveFixupCommits(commit *models.Commit) *types.DisabledReason {
|
||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// For getting disabled reason
|
||||
func (self *LocalCommitsController) notMidRebase() *types.DisabledReason {
|
||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
||||
@ -1016,39 +1033,6 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error {
|
||||
return func() error {
|
||||
commit := self.context().GetSelected()
|
||||
if commit == nil {
|
||||
// The enabled callback should have checked for this
|
||||
panic("no commit selected")
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) callGetDisabledReasonFuncWithSelectedCommit(callback func(*models.Commit) *types.DisabledReason) func() *types.DisabledReason {
|
||||
return func() *types.DisabledReason {
|
||||
commit := self.context().GetSelected()
|
||||
if commit == nil {
|
||||
return &types.DisabledReason{Text: self.c.Tr.NoCommitSelected}
|
||||
}
|
||||
|
||||
return callback(commit)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) disabledIfNoSelectedCommit() func() *types.DisabledReason {
|
||||
return self.callGetDisabledReasonFuncWithSelectedCommit(func(*models.Commit) *types.DisabledReason { return nil })
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) getDisabledReasonForRebaseCommandWithSelectedCommit(action todo.TodoCommand) func() *types.DisabledReason {
|
||||
return self.callGetDisabledReasonFuncWithSelectedCommit(func(commit *models.Commit) *types.DisabledReason {
|
||||
return self.rebaseCommandEnabled(action, commit)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
|
||||
return func(types.OnFocusOpts) error {
|
||||
context := self.context()
|
||||
@ -1065,10 +1049,6 @@ func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) context() *context.LocalCommitsContext {
|
||||
return self.c.Contexts().LocalCommits
|
||||
}
|
||||
@ -1077,7 +1057,7 @@ func (self *LocalCommitsController) paste() error {
|
||||
return self.c.Helpers().CherryPick.Paste()
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) getDisabledReasonForPaste() *types.DisabledReason {
|
||||
func (self *LocalCommitsController) canPaste() *types.DisabledReason {
|
||||
if !self.c.Helpers().CherryPick.CanPaste() {
|
||||
return &types.DisabledReason{Text: self.c.Tr.NoCopiedCommits}
|
||||
}
|
||||
@ -1099,19 +1079,6 @@ func (self *LocalCommitsController) isHeadCommit() bool {
|
||||
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
|
||||
}
|
||||
|
||||
// Convenience function for composing multiple disabled reason functions
|
||||
func (self *LocalCommitsController) require(callbacks ...func() *types.DisabledReason) func() *types.DisabledReason {
|
||||
return func() *types.DisabledReason {
|
||||
for _, callback := range callbacks {
|
||||
if disabledReason := callback(); disabledReason != nil {
|
||||
return disabledReason
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func isChangeOfRebaseTodoAllowed(action todo.TodoCommand) bool {
|
||||
allowedActions := []todo.TodoCommand{
|
||||
todo.Pick,
|
||||
|
@ -7,17 +7,23 @@ import (
|
||||
|
||||
type MenuController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*types.MenuItem]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &MenuController{}
|
||||
|
||||
func NewMenuController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *MenuController {
|
||||
return &MenuController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*types.MenuItem](
|
||||
c,
|
||||
c.Contexts().Menu,
|
||||
c.Contexts().Menu.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,14 +32,16 @@ func NewMenuController(
|
||||
func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.press,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.press),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: self.press,
|
||||
Description: self.c.Tr.Execute,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: self.withItem(self.press),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Execute,
|
||||
Display: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
@ -47,7 +55,7 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
}
|
||||
|
||||
func (self *MenuController) GetOnClick() func() error {
|
||||
return self.press
|
||||
return self.withItemGraceful(self.press)
|
||||
}
|
||||
|
||||
func (self *MenuController) GetOnFocus() func(types.OnFocusOpts) error {
|
||||
@ -60,8 +68,8 @@ func (self *MenuController) GetOnFocus() func(types.OnFocusOpts) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *MenuController) press() error {
|
||||
return self.context().OnMenuPress(self.context().GetSelected())
|
||||
func (self *MenuController) press(selectedItem *types.MenuItem) error {
|
||||
return self.context().OnMenuPress(selectedItem)
|
||||
}
|
||||
|
||||
func (self *MenuController) close() error {
|
||||
@ -73,10 +81,6 @@ func (self *MenuController) close() error {
|
||||
return self.c.PopContext()
|
||||
}
|
||||
|
||||
func (self *MenuController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *MenuController) context() *context.MenuContext {
|
||||
return self.c.Contexts().Menu
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ type MergeConflictsController struct {
|
||||
var _ types.IController = &MergeConflictsController{}
|
||||
|
||||
func NewMergeConflictsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *MergeConflictsController {
|
||||
return &MergeConflictsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@ type PatchBuildingController struct {
|
||||
var _ types.IController = &PatchBuildingController{}
|
||||
|
||||
func NewPatchBuildingController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *PatchBuildingController {
|
||||
return &PatchBuildingController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,30 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type ReflogCommitsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Commit]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &ReflogCommitsController{}
|
||||
|
||||
func NewReflogCommitsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *ReflogCommitsController {
|
||||
return &ReflogCommitsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Commit](
|
||||
c,
|
||||
c.Contexts().ReflogCommits,
|
||||
c.Contexts().ReflogCommits.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,17 +11,23 @@ import (
|
||||
|
||||
type RemoteBranchesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.RemoteBranch]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &RemoteBranchesController{}
|
||||
|
||||
func NewRemoteBranchesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *RemoteBranchesController {
|
||||
return &RemoteBranchesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.RemoteBranch](
|
||||
c,
|
||||
c.Contexts().RemoteBranches,
|
||||
c.Contexts().RemoteBranches.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,33 +36,39 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
// gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch
|
||||
Handler: self.checkSelected(self.newLocalBranch),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Handler: self.withItem(self.newLocalBranch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.checkSelected(self.newLocalBranch),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.withItem(self.newLocalBranch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.merge)),
|
||||
Description: self.c.Tr.MergeIntoCurrentBranch,
|
||||
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.withItem(self.merge)),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.MergeIntoCurrentBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.rebase)),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
Handler: opts.Guards.OutsideFilterMode(self.withItem(self.rebase)),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.delete),
|
||||
Description: self.c.Tr.DeleteRemoteTag,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.delete),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.DeleteRemoteTag,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
||||
Handler: self.checkSelected(self.setAsUpstream),
|
||||
Description: self.c.Tr.SetAsUpstream,
|
||||
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
||||
Handler: self.withItem(self.setAsUpstream),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.SetAsUpstream,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SortOrder),
|
||||
@ -65,10 +77,11 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.checkSelected(self.createResetMenu),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.withItem(self.createResetMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -96,25 +109,10 @@ func (self *RemoteBranchesController) GetOnRenderToMain() func() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) context() *context.RemoteBranchesContext {
|
||||
return self.c.Contexts().RemoteBranches
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) checkSelected(callback func(*models.RemoteBranch) error) func() error {
|
||||
return func() error {
|
||||
selectedItem := self.context().GetSelected()
|
||||
if selectedItem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(selectedItem)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error {
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(selectedBranch.RemoteName, selectedBranch.Name)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
type RemotesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Remote]
|
||||
c *ControllerCommon
|
||||
|
||||
setRemoteBranches func([]*models.RemoteBranch)
|
||||
@ -22,12 +23,17 @@ type RemotesController struct {
|
||||
var _ types.IController = &RemotesController{}
|
||||
|
||||
func NewRemotesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
setRemoteBranches func([]*models.RemoteBranch),
|
||||
) *RemotesController {
|
||||
return &RemotesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
baseController: baseController{},
|
||||
ListControllerTrait: NewListControllerTrait[*models.Remote](
|
||||
c,
|
||||
c.Contexts().Remotes,
|
||||
c.Contexts().Remotes.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
setRemoteBranches: setRemoteBranches,
|
||||
}
|
||||
}
|
||||
@ -35,13 +41,15 @@ func NewRemotesController(
|
||||
func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.FetchRemote),
|
||||
Handler: self.checkSelected(self.fetch),
|
||||
Description: self.c.Tr.FetchRemote,
|
||||
Key: opts.GetKey(opts.Config.Branches.FetchRemote),
|
||||
Handler: self.withItem(self.fetch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.FetchRemote,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
@ -49,24 +57,22 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
Description: self.c.Tr.AddNewRemote,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.remove),
|
||||
Description: self.c.Tr.RemoveRemote,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.remove),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RemoveRemote,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.checkSelected(self.edit),
|
||||
Description: self.c.Tr.EditRemote,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.withItem(self.edit),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EditRemote,
|
||||
},
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
func (self *RemotesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *RemotesController) context() *context.RemotesContext {
|
||||
return self.c.Contexts().Remotes
|
||||
}
|
||||
@ -94,7 +100,7 @@ func (self *RemotesController) GetOnRenderToMain() func() error {
|
||||
}
|
||||
|
||||
func (self *RemotesController) GetOnClick() func() error {
|
||||
return self.checkSelected(self.enter)
|
||||
return self.withItemGraceful(self.enter)
|
||||
}
|
||||
|
||||
func (self *RemotesController) enter(remote *models.Remote) error {
|
||||
@ -208,14 +214,3 @@ func (self *RemotesController) fetch(remote *models.Remote) error {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
})
|
||||
}
|
||||
|
||||
func (self *RemotesController) checkSelected(callback func(*models.Remote) error) func() error {
|
||||
return func() error {
|
||||
file := self.context().GetSelected()
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(file)
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ type SearchPromptController struct {
|
||||
var _ types.IController = &SearchPromptController{}
|
||||
|
||||
func NewSearchPromptController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *SearchPromptController {
|
||||
return &SearchPromptController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@ type SideWindowControllerFactory struct {
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
func NewSideWindowControllerFactory(common *ControllerCommon) *SideWindowControllerFactory {
|
||||
return &SideWindowControllerFactory{c: common}
|
||||
func NewSideWindowControllerFactory(c *ControllerCommon) *SideWindowControllerFactory {
|
||||
return &SideWindowControllerFactory{c: c}
|
||||
}
|
||||
|
||||
func (self *SideWindowControllerFactory) Create(context types.Context) types.IController {
|
||||
@ -24,12 +24,12 @@ type SideWindowController struct {
|
||||
}
|
||||
|
||||
func NewSideWindowController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
context types.Context,
|
||||
) *SideWindowController {
|
||||
return &SideWindowController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ type SnakeController struct {
|
||||
var _ types.IController = &SnakeController{}
|
||||
|
||||
func NewSnakeController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *SnakeController {
|
||||
return &SnakeController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,14 @@ type StagingController struct {
|
||||
var _ types.IController = &StagingController{}
|
||||
|
||||
func NewStagingController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
context types.IPatchExplorerContext,
|
||||
otherContext types.IPatchExplorerContext,
|
||||
staged bool,
|
||||
) *StagingController {
|
||||
return &StagingController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
context: context,
|
||||
otherContext: otherContext,
|
||||
staged: staged,
|
||||
|
@ -9,46 +9,57 @@ import (
|
||||
|
||||
type StashController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.StashEntry]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &StashController{}
|
||||
|
||||
func NewStashController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *StashController {
|
||||
return &StashController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.StashEntry](
|
||||
c,
|
||||
c.Contexts().Stash,
|
||||
c.Contexts().Stash.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.handleStashApply),
|
||||
Description: self.c.Tr.Apply,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.handleStashApply),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Apply,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Stash.PopStash),
|
||||
Handler: self.checkSelected(self.handleStashPop),
|
||||
Description: self.c.Tr.Pop,
|
||||
Key: opts.GetKey(opts.Config.Stash.PopStash),
|
||||
Handler: self.withItem(self.handleStashPop),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Pop,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.handleStashDrop),
|
||||
Description: self.c.Tr.Drop,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.handleStashDrop),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Drop,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.checkSelected(self.handleNewBranchOffStashEntry),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.withItem(self.handleNewBranchOffStashEntry),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Stash.RenameStash),
|
||||
Handler: self.checkSelected(self.handleRenameStashEntry),
|
||||
Description: self.c.Tr.RenameStash,
|
||||
Key: opts.GetKey(opts.Config.Stash.RenameStash),
|
||||
Handler: self.withItem(self.handleRenameStashEntry),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RenameStash,
|
||||
},
|
||||
}
|
||||
|
||||
@ -80,21 +91,6 @@ func (self *StashController) GetOnRenderToMain() func() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StashController) checkSelected(callback func(*models.StashEntry) error) func() error {
|
||||
return func() error {
|
||||
item := self.context().GetSelected()
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(item)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StashController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *StashController) context() *context.StashContext {
|
||||
return self.c.Contexts().Stash
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ type StatusController struct {
|
||||
var _ types.IController = &StatusController{}
|
||||
|
||||
func NewStatusController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *StatusController {
|
||||
return &StatusController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,23 +2,30 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type SubCommitsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Commit]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &SubCommitsController{}
|
||||
|
||||
func NewSubCommitsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *SubCommitsController {
|
||||
return &SubCommitsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Commit](
|
||||
c,
|
||||
c.Contexts().SubCommits,
|
||||
c.Contexts().SubCommits.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,41 +14,51 @@ import (
|
||||
|
||||
type SubmodulesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.SubmoduleConfig]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &SubmodulesController{}
|
||||
|
||||
func NewSubmodulesController(
|
||||
controllerCommon *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *SubmodulesController {
|
||||
return &SubmodulesController{
|
||||
baseController: baseController{},
|
||||
c: controllerCommon,
|
||||
ListControllerTrait: NewListControllerTrait[*models.SubmoduleConfig](
|
||||
c,
|
||||
c.Contexts().Submodules,
|
||||
c.Contexts().Submodules.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.EnterSubmodule,
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EnterSubmodule,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.EnterSubmodule,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EnterSubmodule,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.remove),
|
||||
Description: self.c.Tr.RemoveSubmodule,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.remove),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RemoveSubmodule,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Submodules.Update),
|
||||
Handler: self.checkSelected(self.update),
|
||||
Description: self.c.Tr.SubmoduleUpdate,
|
||||
Key: opts.GetKey(opts.Config.Submodules.Update),
|
||||
Handler: self.withItem(self.update),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.SubmoduleUpdate,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
@ -56,14 +66,16 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
Description: self.c.Tr.AddSubmodule,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.checkSelected(self.editURL),
|
||||
Description: self.c.Tr.EditSubmoduleUrl,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.withItem(self.editURL),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.EditSubmoduleUrl,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Submodules.Init),
|
||||
Handler: self.checkSelected(self.init),
|
||||
Description: self.c.Tr.InitSubmodule,
|
||||
Key: opts.GetKey(opts.Config.Submodules.Init),
|
||||
Handler: self.withItem(self.init),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.InitSubmodule,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Submodules.BulkMenu),
|
||||
@ -80,7 +92,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) GetOnClick() func() error {
|
||||
return self.checkSelected(self.enter)
|
||||
return self.withItemGraceful(self.enter)
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) GetOnRenderToMain() func() error {
|
||||
@ -265,21 +277,6 @@ func (self *SubmodulesController) easterEgg() error {
|
||||
return self.c.PushContext(self.c.Contexts().Snake)
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleConfig) error) func() error {
|
||||
return func() error {
|
||||
submodule := self.context().GetSelected()
|
||||
if submodule == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(submodule)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *SubmodulesController) context() *context.SubmodulesContext {
|
||||
return self.c.Contexts().Submodules
|
||||
}
|
||||
|
@ -7,25 +7,32 @@ import (
|
||||
|
||||
type SuggestionsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*types.Suggestion]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &SuggestionsController{}
|
||||
|
||||
func NewSuggestionsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *SuggestionsController {
|
||||
return &SuggestionsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*types.Suggestion](
|
||||
c,
|
||||
c.Contexts().Suggestions,
|
||||
c.Contexts().Suggestions.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
@ -47,10 +54,6 @@ func (self *SuggestionsController) GetOnFocusLost() func(types.OnFocusLostOpts)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SuggestionsController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *SuggestionsController) context() *context.SuggestionsContext {
|
||||
return self.c.Contexts().Suggestions
|
||||
}
|
||||
|
@ -10,13 +10,16 @@ import (
|
||||
var _ types.IController = &SwitchToDiffFilesController{}
|
||||
|
||||
type CanSwitchToDiffFiles interface {
|
||||
types.Context
|
||||
types.IListContext
|
||||
CanRebase() bool
|
||||
GetSelectedRef() types.Ref
|
||||
}
|
||||
|
||||
// Not using our ListControllerTrait because our 'selected' item is not a list item
|
||||
// but an attribute on it i.e. the ref of an item.
|
||||
type SwitchToDiffFilesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[types.Ref]
|
||||
c *ControllerCommon
|
||||
context CanSwitchToDiffFiles
|
||||
diffFilesContext *context.CommitFilesContext
|
||||
@ -28,7 +31,12 @@ func NewSwitchToDiffFilesController(
|
||||
diffFilesContext *context.CommitFilesContext,
|
||||
) *SwitchToDiffFilesController {
|
||||
return &SwitchToDiffFilesController{
|
||||
baseController: baseController{},
|
||||
baseController: baseController{},
|
||||
ListControllerTrait: NewListControllerTrait[types.Ref](
|
||||
c,
|
||||
context,
|
||||
context.GetSelectedRef,
|
||||
),
|
||||
c: c,
|
||||
context: context,
|
||||
diffFilesContext: diffFilesContext,
|
||||
@ -38,9 +46,10 @@ func NewSwitchToDiffFilesController(
|
||||
func (self *SwitchToDiffFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.ViewItemFiles,
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewItemFiles,
|
||||
},
|
||||
}
|
||||
|
||||
@ -48,18 +57,7 @@ func (self *SwitchToDiffFilesController) GetKeybindings(opts types.KeybindingsOp
|
||||
}
|
||||
|
||||
func (self *SwitchToDiffFilesController) GetOnClick() func() error {
|
||||
return self.checkSelected(self.enter)
|
||||
}
|
||||
|
||||
func (self *SwitchToDiffFilesController) checkSelected(callback func(types.Ref) error) func() error {
|
||||
return func() error {
|
||||
ref := self.context.GetSelectedRef()
|
||||
if ref == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(ref)
|
||||
}
|
||||
return self.withItemGraceful(self.enter)
|
||||
}
|
||||
|
||||
func (self *SwitchToDiffFilesController) enter(ref types.Ref) error {
|
||||
@ -70,10 +68,6 @@ func (self *SwitchToDiffFilesController) enter(ref types.Ref) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *SwitchToDiffFilesController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
||||
func (self *SwitchToDiffFilesController) viewFiles(opts SwitchToCommitFilesContextOpts) error {
|
||||
diffFilesContext := self.diffFilesContext
|
||||
|
||||
|
@ -8,34 +8,43 @@ import (
|
||||
var _ types.IController = &SwitchToSubCommitsController{}
|
||||
|
||||
type CanSwitchToSubCommits interface {
|
||||
types.Context
|
||||
types.IListContext
|
||||
GetSelectedRef() types.Ref
|
||||
ShowBranchHeadsInSubCommits() bool
|
||||
}
|
||||
|
||||
// Not using our ListControllerTrait because our 'selected' item is not a list item
|
||||
// but an attribute on it i.e. the ref of an item.
|
||||
type SwitchToSubCommitsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[types.Ref]
|
||||
c *ControllerCommon
|
||||
context CanSwitchToSubCommits
|
||||
}
|
||||
|
||||
func NewSwitchToSubCommitsController(
|
||||
controllerCommon *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
context CanSwitchToSubCommits,
|
||||
) *SwitchToSubCommitsController {
|
||||
return &SwitchToSubCommitsController{
|
||||
baseController: baseController{},
|
||||
c: controllerCommon,
|
||||
context: context,
|
||||
ListControllerTrait: NewListControllerTrait[types.Ref](
|
||||
c,
|
||||
context,
|
||||
context.GetSelectedRef,
|
||||
),
|
||||
c: c,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SwitchToSubCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Handler: self.viewCommits,
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Description: self.c.Tr.ViewCommits,
|
||||
Handler: self.viewCommits,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Key: opts.GetKey(opts.Config.Universal.GoInto),
|
||||
Description: self.c.Tr.ViewCommits,
|
||||
},
|
||||
}
|
||||
|
||||
@ -59,7 +68,3 @@ func (self *SwitchToSubCommitsController) viewCommits() error {
|
||||
ShowBranchHeads: self.context.ShowBranchHeadsInSubCommits(),
|
||||
})
|
||||
}
|
||||
|
||||
func (self *SwitchToSubCommitsController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
@ -10,37 +10,46 @@ import (
|
||||
|
||||
type TagsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Tag]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &TagsController{}
|
||||
|
||||
func NewTagsController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *TagsController {
|
||||
return &TagsController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Tag](
|
||||
c,
|
||||
c.Contexts().Tags,
|
||||
c.Contexts().Tags.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withSelectedTag(self.checkout),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.checkout),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withSelectedTag(self.delete),
|
||||
Description: self.c.Tr.ViewDeleteOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.delete),
|
||||
Description: self.c.Tr.ViewDeleteOptions,
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.PushTag),
|
||||
Handler: self.withSelectedTag(self.push),
|
||||
Description: self.c.Tr.PushTag,
|
||||
Key: opts.GetKey(opts.Config.Branches.PushTag),
|
||||
Handler: self.withItem(self.push),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.PushTag,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
@ -48,10 +57,11 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
Description: self.c.Tr.CreateTag,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.withSelectedTag(self.createResetMenu),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
Handler: self.withItem(self.createResetMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -215,21 +225,6 @@ func (self *TagsController) create() error {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error {
|
||||
return func() error {
|
||||
tag := self.context().GetSelected()
|
||||
if tag == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f(tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *TagsController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *TagsController) context() *context.TagsContext {
|
||||
return self.c.Contexts().Tags
|
||||
}
|
||||
|
@ -27,11 +27,11 @@ type UndoController struct {
|
||||
var _ types.IController = &UndoController{}
|
||||
|
||||
func NewUndoController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *UndoController {
|
||||
return &UndoController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,15 +14,21 @@ type CanViewWorktreeOptions interface {
|
||||
|
||||
type WorktreeOptionsController struct {
|
||||
baseController
|
||||
*ListControllerTrait[string]
|
||||
c *ControllerCommon
|
||||
context CanViewWorktreeOptions
|
||||
}
|
||||
|
||||
func NewWorktreeOptionsController(controllerCommon *ControllerCommon, context CanViewWorktreeOptions) *WorktreeOptionsController {
|
||||
func NewWorktreeOptionsController(c *ControllerCommon, context CanViewWorktreeOptions) *WorktreeOptionsController {
|
||||
return &WorktreeOptionsController{
|
||||
baseController: baseController{},
|
||||
c: controllerCommon,
|
||||
context: context,
|
||||
ListControllerTrait: NewListControllerTrait[string](
|
||||
c,
|
||||
context,
|
||||
context.GetSelectedItemId,
|
||||
),
|
||||
c: c,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +36,7 @@ func (self *WorktreeOptionsController) GetKeybindings(opts types.KeybindingsOpts
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Worktrees.ViewWorktreeOptions),
|
||||
Handler: self.checkSelected(self.viewWorktreeOptions),
|
||||
Handler: self.withItem(self.viewWorktreeOptions),
|
||||
Description: self.c.Tr.ViewWorktreeOptions,
|
||||
OpensMenu: true,
|
||||
},
|
||||
@ -39,21 +45,6 @@ func (self *WorktreeOptionsController) GetKeybindings(opts types.KeybindingsOpts
|
||||
return bindings
|
||||
}
|
||||
|
||||
func (self *WorktreeOptionsController) checkSelected(callback func(string) error) func() error {
|
||||
return func() error {
|
||||
ref := self.context.GetSelectedItemId()
|
||||
if ref == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(ref)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreeOptionsController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
||||
func (self *WorktreeOptionsController) viewWorktreeOptions(ref string) error {
|
||||
return self.c.Helpers().Worktree.ViewWorktreeOptions(self.context, ref)
|
||||
}
|
||||
|
@ -13,17 +13,23 @@ import (
|
||||
|
||||
type WorktreesController struct {
|
||||
baseController
|
||||
*ListControllerTrait[*models.Worktree]
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &WorktreesController{}
|
||||
|
||||
func NewWorktreesController(
|
||||
common *ControllerCommon,
|
||||
c *ControllerCommon,
|
||||
) *WorktreesController {
|
||||
return &WorktreesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
ListControllerTrait: NewListControllerTrait[*models.Worktree](
|
||||
c,
|
||||
c.Contexts().Worktrees,
|
||||
c.Contexts().Worktrees.GetSelected,
|
||||
),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,24 +41,28 @@ func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*t
|
||||
Description: self.c.Tr.CreateWorktree,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.SwitchToWorktree,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.SwitchToWorktree,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.SwitchToWorktree,
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.SwitchToWorktree,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.checkSelected(self.open),
|
||||
Description: self.c.Tr.OpenInEditor,
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
Handler: self.withItem(self.open),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.OpenInEditor,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.checkSelected(self.remove),
|
||||
Description: self.c.Tr.RemoveWorktree,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.withItem(self.remove),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RemoveWorktree,
|
||||
},
|
||||
}
|
||||
|
||||
@ -113,7 +123,7 @@ func (self *WorktreesController) remove(worktree *models.Worktree) error {
|
||||
}
|
||||
|
||||
func (self *WorktreesController) GetOnClick() func() error {
|
||||
return self.checkSelected(self.enter)
|
||||
return self.withItemGraceful(self.enter)
|
||||
}
|
||||
|
||||
func (self *WorktreesController) enter(worktree *models.Worktree) error {
|
||||
@ -124,21 +134,6 @@ func (self *WorktreesController) open(worktree *models.Worktree) error {
|
||||
return self.c.Helpers().Files.OpenDirInEditor(worktree.Path)
|
||||
}
|
||||
|
||||
func (self *WorktreesController) checkSelected(callback func(worktree *models.Worktree) error) func() error {
|
||||
return func() error {
|
||||
worktree := self.context().GetSelected()
|
||||
if worktree == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(worktree)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *WorktreesController) context() *context.WorktreesContext {
|
||||
return self.c.Contexts().Worktrees
|
||||
}
|
||||
|
@ -139,6 +139,28 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) getCopySelectedSideContextItemToClipboardDisabledReason() *types.DisabledReason {
|
||||
// important to note that this assumes we've selected an item in a side context
|
||||
currentSideContext := gui.c.CurrentSideContext()
|
||||
if currentSideContext == nil {
|
||||
// This should never happen but if it does we'll just ignore the keypress
|
||||
return nil
|
||||
}
|
||||
|
||||
listContext, ok := currentSideContext.(types.IListContext)
|
||||
if !ok {
|
||||
// This should never happen but if it does we'll just ignore the keypress
|
||||
return nil
|
||||
}
|
||||
|
||||
startIdx, endIdx := listContext.GetList().GetSelectionRange()
|
||||
if startIdx != endIdx {
|
||||
return &types.DisabledReason{Text: gui.Tr.RangeSelectNotSupported}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) setCaption(caption string) {
|
||||
gui.Views.Options.FgColor = gocui.ColorWhite
|
||||
gui.Views.Options.FgColor |= gocui.AttrBold
|
||||
|
@ -123,28 +123,32 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
|
||||
Handler: self.scrollDownMain,
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyFileNameToClipboard,
|
||||
ViewName: "files",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyFileNameToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "localBranches",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyBranchNameToClipboard,
|
||||
ViewName: "localBranches",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyBranchNameToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "remoteBranches",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyBranchNameToClipboard,
|
||||
ViewName: "remoteBranches",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyBranchNameToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
ViewName: "commits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
@ -153,16 +157,18 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
|
||||
Description: self.c.Tr.ResetCherryPick,
|
||||
},
|
||||
{
|
||||
ViewName: "reflogCommits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
ViewName: "reflogCommits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "subCommits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
ViewName: "subCommits",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyCommitShaToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "information",
|
||||
@ -171,10 +177,11 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
|
||||
Handler: self.handleInfoClick,
|
||||
},
|
||||
{
|
||||
ViewName: "commitFiles",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopyCommitFileNameToClipboard,
|
||||
ViewName: "commitFiles",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopyCommitFileNameToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
@ -240,10 +247,11 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
|
||||
Handler: self.scrollDownConfirmationPanel,
|
||||
},
|
||||
{
|
||||
ViewName: "submodules",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
Description: self.c.Tr.CopySubmoduleNameToClipboard,
|
||||
ViewName: "submodules",
|
||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||
Handler: self.handleCopySelectedSideContextItemToClipboard,
|
||||
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
|
||||
Description: self.c.Tr.CopySubmoduleNameToClipboard,
|
||||
},
|
||||
{
|
||||
ViewName: "extras",
|
||||
|
@ -231,6 +231,7 @@ type IListCursor interface {
|
||||
GetRangeStartIdx() (int, bool)
|
||||
GetSelectionRange() (int, int)
|
||||
IsSelectingRange() bool
|
||||
AreMultipleItemsSelected() bool
|
||||
ToggleStickyRange()
|
||||
ExpandNonStickyRange(int)
|
||||
}
|
||||
|
@ -644,7 +644,6 @@ type TranslationSet struct {
|
||||
MarkedCommitMarker string
|
||||
PleaseGoToURL string
|
||||
DisabledMenuItemPrefix string
|
||||
NoCommitSelected string
|
||||
NoCopiedCommits string
|
||||
QuickStartInteractiveRebase string
|
||||
QuickStartInteractiveRebaseTooltip string
|
||||
@ -652,6 +651,9 @@ type TranslationSet struct {
|
||||
ToggleRangeSelect string
|
||||
RangeSelectUp string
|
||||
RangeSelectDown string
|
||||
RangeSelectNotSupported string
|
||||
NoItemSelected string
|
||||
SelectedItemIsNotABranch string
|
||||
Actions Actions
|
||||
Bisect Bisect
|
||||
Log Log
|
||||
@ -1478,13 +1480,15 @@ func EnglishTranslationSet() TranslationSet {
|
||||
MarkedCommitMarker: "↑↑↑ Will rebase from here ↑↑↑",
|
||||
PleaseGoToURL: "Please go to {{.url}}",
|
||||
DisabledMenuItemPrefix: "Disabled: ",
|
||||
NoCommitSelected: "No commit selected",
|
||||
NoCopiedCommits: "No copied commits",
|
||||
QuickStartInteractiveRebase: "Start interactive rebase",
|
||||
QuickStartInteractiveRebaseTooltip: "Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.\nIf you would instead like to start an interactive rebase from the selected commit, press `{{.editKey}}`.",
|
||||
CannotQuickStartInteractiveRebase: "Cannot start interactive rebase: the HEAD commit is a merge commit or is present on the main branch, so there is no appropriate base commit to start the rebase from. You can start an interactive rebase from a specific commit by selecting the commit and pressing `{{.editKey}}`.",
|
||||
RangeSelectUp: "Range select up",
|
||||
RangeSelectDown: "Range select down",
|
||||
RangeSelectNotSupported: "Action does not support range selection, please select a single item",
|
||||
NoItemSelected: "No item selected",
|
||||
SelectedItemIsNotABranch: "Selected item is not a branch",
|
||||
Actions: Actions{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
|
@ -29,10 +29,10 @@ var CopyMenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Copy to clipboard")).
|
||||
Select(Contains("File name")).
|
||||
Tooltip(Equals("Disabled: Nothing to copy")).
|
||||
Tooltip(Equals("Disabled: No item selected")).
|
||||
Confirm().
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Disabled: Nothing to copy"))
|
||||
t.ExpectToast(Equals("Disabled: No item selected"))
|
||||
}).
|
||||
Cancel()
|
||||
})
|
||||
|
@ -22,7 +22,14 @@ var EmptyMenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// a string that filters everything out
|
||||
FilterOrSearch("ljasldkjaslkdjalskdjalsdjaslkd").
|
||||
IsEmpty().
|
||||
Press(keys.Universal.Select)
|
||||
Press(keys.Universal.Select).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Disabled: No item selected"))
|
||||
}).
|
||||
// escape the search
|
||||
PressEscape().
|
||||
// escape the view
|
||||
PressEscape()
|
||||
|
||||
// back in the files view, selecting the non-existing menu item was a no-op
|
||||
t.Views().Files().
|
||||
|
Loading…
x
Reference in New Issue
Block a user