mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-03 13:21:56 +02:00
Show better keybinding suggestions (#3203)
- **PR Description** This PR's goal is to improve discoverability of keybindings in lazygit. I've have a couple people in real life mention to me that it wasn't obvious what key to press for viewing rebase options, for example. This PR: * shows more keybindings in the options view * shows certain keybindings prominently in certain modes e.g. 'view rebase options: m' when mid-rebase. Before: ![image](https://github.com/jesseduffield/lazygit/assets/8456633/483477ef-93e1-4fd1-af86-3ffa84167f62) After: ![image](https://github.com/jesseduffield/lazygit/assets/8456633/4c93dd19-f072-45ec-afa6-810727211f66) - **Please check if the PR fulfills these requirements** * [x] Cheatsheets are up-to-date (run `go generate ./...`) * [x] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting)) * [x] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide) * [x] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation)) * [x] Docs (specifically `docs/Config.md`) have been updated if necessary * [x] You've read through your own file changes for silly mistakes etc <!-- Be sure to name your PR with an imperative e.g. 'Add worktrees view' see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for examples -->
This commit is contained in:
commit
cf5d4d4f8e
@ -12,3 +12,11 @@ const (
|
||||
REBASE_MODE_REBASING
|
||||
REBASE_MODE_MERGING
|
||||
)
|
||||
|
||||
func (self RebaseMode) IsMerging() bool {
|
||||
return self == REBASE_MODE_MERGING
|
||||
}
|
||||
|
||||
func (self RebaseMode) IsRebasing() bool {
|
||||
return self == REBASE_MODE_INTERACTIVE || self == REBASE_MODE_NORMAL || self == REBASE_MODE_REBASING
|
||||
}
|
||||
|
@ -245,8 +245,6 @@ func (self *ContextMgr) ActivateContext(c types.Context, opts types.OnFocusOpts)
|
||||
|
||||
self.gui.c.GocuiGui().Cursor = v.Editable
|
||||
|
||||
self.gui.renderContextOptionsMap(c)
|
||||
|
||||
if err := c.HandleFocus(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,15 +20,11 @@ func NewListViewModel[T HasID](getModel func() []T) *ListViewModel[T] {
|
||||
getModel: getModel,
|
||||
}
|
||||
|
||||
self.ListCursor = traits.NewListCursor(self)
|
||||
self.ListCursor = traits.NewListCursor(func() int { return len(getModel()) })
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) Len() int {
|
||||
return len(self.getModel())
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) GetSelected() T {
|
||||
if self.Len() == 0 {
|
||||
return Zero[T]()
|
||||
|
@ -5,10 +5,6 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
type HasLength interface {
|
||||
Len() int
|
||||
}
|
||||
|
||||
type RangeSelectMode int
|
||||
|
||||
const (
|
||||
@ -27,15 +23,17 @@ type ListCursor struct {
|
||||
rangeSelectMode RangeSelectMode
|
||||
// value is ignored when rangeSelectMode is RangeSelectModeNone
|
||||
rangeStartIdx int
|
||||
list HasLength
|
||||
// Get the length of the list. We use this to clamp the selection so that
|
||||
// the selected index is always valid
|
||||
getLength func() int
|
||||
}
|
||||
|
||||
func NewListCursor(list HasLength) *ListCursor {
|
||||
func NewListCursor(getLength func() int) *ListCursor {
|
||||
return &ListCursor{
|
||||
selectedIdx: 0,
|
||||
rangeStartIdx: 0,
|
||||
rangeSelectMode: RangeSelectModeNone,
|
||||
list: list,
|
||||
getLength: getLength,
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +79,9 @@ func (self *ListCursor) GetSelectionRangeAndMode() (int, int, RangeSelectMode) {
|
||||
|
||||
func (self *ListCursor) clampValue(value int) int {
|
||||
clampedValue := -1
|
||||
if self.list.Len() > 0 {
|
||||
clampedValue = utils.Clamp(value, 0, self.list.Len()-1)
|
||||
length := self.getLength()
|
||||
if length > 0 {
|
||||
clampedValue = utils.Clamp(value, 0, length-1)
|
||||
}
|
||||
|
||||
return clampedValue
|
||||
@ -114,7 +113,12 @@ func (self *ListCursor) ClampSelection() {
|
||||
}
|
||||
|
||||
func (self *ListCursor) Len() int {
|
||||
return self.list.Len()
|
||||
// The length of the model slice can change at any time, so the selection may
|
||||
// become out of bounds. To reduce the likelihood of this, we clamp the selection
|
||||
// whenever we obtain the length of the model.
|
||||
self.ClampSelection()
|
||||
|
||||
return self.getLength()
|
||||
}
|
||||
|
||||
func (self *ListCursor) GetRangeStartIdx() (int, bool) {
|
||||
|
@ -52,6 +52,7 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.CheckoutCommitTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard),
|
||||
@ -80,6 +81,7 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
Tooltip: self.c.Tr.ResetTooltip,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CherryPickCopy),
|
||||
@ -91,6 +93,7 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
"escape": keybindings.Label(opts.Config.Universal.Return),
|
||||
},
|
||||
),
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ResetCherryPick),
|
||||
|
@ -47,14 +47,16 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
self.singleItemSelected(),
|
||||
self.notPulling,
|
||||
),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.CheckoutTooltip,
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.CheckoutTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.withItem(self.newBranch),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.NewBranch,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.CreatePullRequest),
|
||||
@ -95,6 +97,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
Description: self.c.Tr.Delete,
|
||||
Tooltip: self.c.Tr.BranchDeleteTooltip,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
@ -102,8 +105,9 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.notRebasingOntoSelf),
|
||||
),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
Tooltip: self.c.Tr.RebaseBranchTooltip,
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
Tooltip: self.c.Tr.RebaseBranchTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
||||
@ -111,6 +115,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Merge,
|
||||
Tooltip: self.c.Tr.MergeBranchTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.FastForward),
|
||||
@ -136,6 +141,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewResetOptions,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RenameBranch),
|
||||
@ -151,6 +157,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
|
||||
Tooltip: self.c.Tr.ViewBranchUpstreamOptionsTooltip,
|
||||
ShortDescription: self.c.Tr.Upstream,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.CheckoutCommitFileTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
@ -50,6 +51,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Remove,
|
||||
Tooltip: self.c.Tr.DiscardOldFileChangeTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
@ -64,6 +66,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Edit,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenDiffTool),
|
||||
@ -79,6 +82,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.ToggleAddToPatchTooltip,
|
||||
map[string]string{"doc": constants.Links.Docs.CustomPatchDemo},
|
||||
),
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ToggleStagedAll),
|
||||
|
@ -24,16 +24,16 @@ func NewConfirmationController(
|
||||
func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Description: self.c.Tr.Confirm,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: func() error { return self.context().State.OnClose() },
|
||||
Description: self.c.Tr.CloseCancel,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: func() error { return self.context().State.OnClose() },
|
||||
Description: self.c.Tr.CloseCancel,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
|
@ -43,6 +43,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
GetDisabledReason: self.require(self.itemsSelected()),
|
||||
Description: self.c.Tr.Stage,
|
||||
Tooltip: self.c.Tr.StageTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.OpenStatusFilter),
|
||||
@ -56,10 +57,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.CommitChanges),
|
||||
Handler: self.c.Helpers().WorkingTree.HandleCommitPress,
|
||||
Description: self.c.Tr.Commit,
|
||||
Tooltip: self.c.Tr.CommitTooltip,
|
||||
Key: opts.GetKey(opts.Config.Files.CommitChanges),
|
||||
Handler: self.c.Helpers().WorkingTree.HandleCommitPress,
|
||||
Description: self.c.Tr.Commit,
|
||||
Tooltip: self.c.Tr.CommitTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook),
|
||||
@ -88,6 +90,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Edit,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
@ -109,10 +112,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Description: self.c.Tr.RefreshFiles,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.StashAllChanges),
|
||||
Handler: self.stash,
|
||||
Description: self.c.Tr.Stash,
|
||||
Tooltip: self.c.Tr.StashTooltip,
|
||||
Key: opts.GetKey(opts.Config.Files.StashAllChanges),
|
||||
Handler: self.stash,
|
||||
Description: self.c.Tr.Stash,
|
||||
Tooltip: self.c.Tr.StashTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ViewStashOptions),
|
||||
@ -141,6 +145,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Description: self.c.Tr.Discard,
|
||||
Tooltip: self.c.Tr.DiscardFileChangesTooltip,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
@ -149,11 +154,12 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ViewResetOptions),
|
||||
Handler: self.createResetMenu,
|
||||
Description: self.c.Tr.Reset,
|
||||
Tooltip: self.c.Tr.FileResetOptionsTooltip,
|
||||
OpensMenu: true,
|
||||
Key: opts.GetKey(opts.Config.Files.ViewResetOptions),
|
||||
Handler: self.createResetMenu,
|
||||
Description: self.c.Tr.Reset,
|
||||
Tooltip: self.c.Tr.FileResetOptionsTooltip,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.ToggleTreeView),
|
||||
|
@ -72,6 +72,7 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type
|
||||
Description: self.c.Tr.OpenKeybindingsMenu,
|
||||
Handler: self.createOptionsMenu,
|
||||
ShortDescription: self.c.Tr.Keybindings,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
@ -112,10 +113,11 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type
|
||||
Handler: self.quitWithoutChangingDirectory,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: self.escape,
|
||||
Description: self.c.Tr.Cancel,
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: self.escape,
|
||||
Description: self.c.Tr.Cancel,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.ToggleWhitespaceInDiffView),
|
||||
|
@ -64,8 +64,9 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
self.canSquashOrFixup,
|
||||
),
|
||||
),
|
||||
Description: self.c.Tr.Squash,
|
||||
Tooltip: self.c.Tr.SquashTooltip,
|
||||
Description: self.c.Tr.Squash,
|
||||
Tooltip: self.c.Tr.SquashTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup),
|
||||
@ -76,8 +77,9 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
self.canSquashOrFixup,
|
||||
),
|
||||
),
|
||||
Description: self.c.Tr.Fixup,
|
||||
Tooltip: self.c.Tr.FixupTooltip,
|
||||
Description: self.c.Tr.Fixup,
|
||||
Tooltip: self.c.Tr.FixupTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommit),
|
||||
@ -85,9 +87,10 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
GetDisabledReason: self.require(
|
||||
self.singleItemSelected(self.rewordEnabled),
|
||||
),
|
||||
Description: self.c.Tr.Reword,
|
||||
Tooltip: self.c.Tr.CommitRewordTooltip,
|
||||
OpensMenu: true,
|
||||
Description: self.c.Tr.Reword,
|
||||
Tooltip: self.c.Tr.CommitRewordTooltip,
|
||||
DisplayOnScreen: true,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor),
|
||||
@ -105,8 +108,9 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
self.midRebaseCommandEnabled,
|
||||
),
|
||||
),
|
||||
Description: self.c.Tr.DropCommit,
|
||||
Tooltip: self.c.Tr.DropCommitTooltip,
|
||||
Description: self.c.Tr.DropCommit,
|
||||
Tooltip: self.c.Tr.DropCommitTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(editCommitKey),
|
||||
@ -118,6 +122,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
Description: self.c.Tr.EditCommit,
|
||||
ShortDescription: self.c.Tr.Edit,
|
||||
Tooltip: self.c.Tr.EditCommitTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
// The user-facing description here is 'Start interactive rebase' but internally
|
||||
@ -139,6 +144,14 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
),
|
||||
Description: self.c.Tr.Pick,
|
||||
Tooltip: self.c.Tr.PickCommitTooltip,
|
||||
// Not displaying this because we only want to display it when a TODO commit
|
||||
// is selected. A keybinding is displayed in the options view if Display is true,
|
||||
// and if it's not disabled, but if we disable it whenever a non-TODO commit is
|
||||
// selected, we'll be preventing pulls from happening within the commits view
|
||||
// (given they both use the 'p' key). Some approaches that come to mind:
|
||||
// * Allow a disabled keybinding to conditionally fallback to a global keybinding
|
||||
// * Allow a separate way of deciding whether a keybinding is displayed in the options view
|
||||
DisplayOnScreen: false,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.CreateFixupCommit),
|
||||
@ -221,6 +234,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
GetDisabledReason: self.require(self.singleItemSelected(self.canAmend)),
|
||||
Description: self.c.Tr.Amend,
|
||||
Tooltip: self.c.Tr.AmendCommitTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ResetCommitAuthor),
|
||||
|
@ -42,13 +42,13 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
Handler: self.withItem(self.press),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Execute,
|
||||
Display: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: self.close,
|
||||
Description: self.c.Tr.Close,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: self.close,
|
||||
Description: self.c.Tr.Close,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -28,50 +28,54 @@ func NewMergeConflictsController(
|
||||
func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withRenderAndFocus(self.HandlePickHunk),
|
||||
Description: self.c.Tr.PickHunk,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.withRenderAndFocus(self.HandlePickHunk),
|
||||
Description: self.c.Tr.PickHunk,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Main.PickBothHunks),
|
||||
Handler: self.withRenderAndFocus(self.HandlePickAllHunks),
|
||||
Description: self.c.Tr.PickAllHunks,
|
||||
Key: opts.GetKey(opts.Config.Main.PickBothHunks),
|
||||
Handler: self.withRenderAndFocus(self.HandlePickAllHunks),
|
||||
Description: self.c.Tr.PickAllHunks,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.PrevItem),
|
||||
Handler: self.withRenderAndFocus(self.PrevConflictHunk),
|
||||
Description: self.c.Tr.SelectPrevHunk,
|
||||
Key: opts.GetKey(opts.Config.Universal.PrevItem),
|
||||
Handler: self.withRenderAndFocus(self.PrevConflictHunk),
|
||||
Description: self.c.Tr.SelectPrevHunk,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.NextItem),
|
||||
Handler: self.withRenderAndFocus(self.NextConflictHunk),
|
||||
Description: self.c.Tr.SelectNextHunk,
|
||||
Key: opts.GetKey(opts.Config.Universal.NextItem),
|
||||
Handler: self.withRenderAndFocus(self.NextConflictHunk),
|
||||
Description: self.c.Tr.SelectNextHunk,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.PrevBlock),
|
||||
Handler: self.withRenderAndFocus(self.PrevConflict),
|
||||
Description: self.c.Tr.PrevConflict,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.PrevBlock),
|
||||
Handler: self.withRenderAndFocus(self.PrevConflict),
|
||||
Description: self.c.Tr.PrevConflict,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.NextBlock),
|
||||
Handler: self.withRenderAndFocus(self.NextConflict),
|
||||
Description: self.c.Tr.NextConflict,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.NextBlock),
|
||||
Handler: self.withRenderAndFocus(self.NextConflict),
|
||||
Description: self.c.Tr.NextConflict,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Undo),
|
||||
Handler: self.withRenderAndFocus(self.HandleUndo),
|
||||
Description: self.c.Tr.Undo,
|
||||
Tooltip: self.c.Tr.UndoMergeResolveTooltip,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Undo),
|
||||
Handler: self.withRenderAndFocus(self.HandleUndo),
|
||||
Description: self.c.Tr.Undo,
|
||||
Tooltip: self.c.Tr.UndoMergeResolveTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.HandleEditFile,
|
||||
Description: self.c.Tr.EditFile,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.HandleEditFile,
|
||||
Description: self.c.Tr.EditFile,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
@ -108,11 +112,11 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
Tag: "navigation",
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
|
||||
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
|
||||
Description: self.c.Tr.OpenMergeTool,
|
||||
Tooltip: self.c.Tr.OpenMergeToolTooltip,
|
||||
Display: true,
|
||||
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
|
||||
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
|
||||
Description: self.c.Tr.OpenMergeTool,
|
||||
Tooltip: self.c.Tr.OpenMergeToolTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
|
@ -37,9 +37,10 @@ func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.ToggleSelectionAndRefresh,
|
||||
Description: self.c.Tr.ToggleSelectionForPatch,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.ToggleSelectionAndRefresh,
|
||||
Description: self.c.Tr.ToggleSelectionForPatch,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
|
@ -92,10 +92,11 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
Description: self.c.Tr.ToggleRangeSelect,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk),
|
||||
Handler: self.withRenderAndFocus(self.HandleToggleSelectHunk),
|
||||
Description: self.c.Tr.ToggleSelectHunk,
|
||||
Tooltip: self.c.Tr.ToggleSelectHunkTooltip,
|
||||
Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk),
|
||||
Handler: self.withRenderAndFocus(self.HandleToggleSelectHunk),
|
||||
Description: self.c.Tr.ToggleSelectHunk,
|
||||
Tooltip: self.c.Tr.ToggleSelectHunkTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Tag: "navigation",
|
||||
|
@ -41,6 +41,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.RemoteBranchCheckoutTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
@ -54,6 +55,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Merge,
|
||||
Tooltip: self.c.Tr.MergeBranchTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
||||
@ -61,6 +63,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.RebaseBranch,
|
||||
Tooltip: self.c.Tr.RebaseBranchTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
@ -68,6 +71,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Delete,
|
||||
Tooltip: self.c.Tr.DeleteRemoteBranchTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
||||
@ -75,6 +79,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.SetAsUpstream,
|
||||
Tooltip: self.c.Tr.SetAsUpstreamTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.SortOrder),
|
||||
|
@ -46,11 +46,13 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
Handler: self.withItem(self.enter),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.ViewBranches,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewRemote,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewRemote,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
@ -58,6 +60,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Remove,
|
||||
Tooltip: self.c.Tr.RemoveRemoteTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
@ -65,6 +68,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Edit,
|
||||
Tooltip: self.c.Tr.EditRemoteTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.FetchRemote),
|
||||
@ -72,6 +76,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Fetch,
|
||||
Tooltip: self.c.Tr.FetchRemoteTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -40,16 +40,18 @@ func NewStagingController(
|
||||
func (self *StagingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.ToggleStaged,
|
||||
Description: self.c.Tr.Stage,
|
||||
Tooltip: self.c.Tr.StageSelectionTooltip,
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.ToggleStaged,
|
||||
Description: self.c.Tr.Stage,
|
||||
Tooltip: self.c.Tr.StageSelectionTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.DiscardSelection,
|
||||
Description: self.c.Tr.DiscardSelection,
|
||||
Tooltip: self.c.Tr.DiscardSelectionTooltip,
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
Handler: self.DiscardSelection,
|
||||
Description: self.c.Tr.DiscardSelection,
|
||||
Tooltip: self.c.Tr.DiscardSelectionTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.OpenFile),
|
||||
@ -69,10 +71,11 @@ func (self *StagingController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
||||
Description: self.c.Tr.ReturnToFilesPanel,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
Handler: self.TogglePanel,
|
||||
Description: self.c.Tr.ToggleStagingView,
|
||||
Tooltip: self.c.Tr.ToggleStagingViewTooltip,
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
Handler: self.TogglePanel,
|
||||
Description: self.c.Tr.ToggleStagingView,
|
||||
Tooltip: self.c.Tr.ToggleStagingViewTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Main.EditSelectHunk),
|
||||
|
@ -38,6 +38,7 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Apply,
|
||||
Tooltip: self.c.Tr.StashApplyTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Stash.PopStash),
|
||||
@ -45,6 +46,7 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Pop,
|
||||
Tooltip: self.c.Tr.StashPopTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
@ -52,6 +54,7 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Drop,
|
||||
Tooltip: self.c.Tr.StashDropTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
|
@ -39,20 +39,23 @@ func (self *StatusController) GetKeybindings(opts types.KeybindingsOpts) []*type
|
||||
Tooltip: self.c.Tr.OpenFileTooltip,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.editConfig,
|
||||
Description: self.c.Tr.EditConfig,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
Handler: self.editConfig,
|
||||
Description: self.c.Tr.EditConfig,
|
||||
Tooltip: self.c.Tr.EditFileTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Status.CheckForUpdate),
|
||||
Handler: self.handleCheckForUpdate,
|
||||
Description: self.c.Tr.CheckForUpdate,
|
||||
Key: opts.GetKey(opts.Config.Status.CheckForUpdate),
|
||||
Handler: self.handleCheckForUpdate,
|
||||
Description: self.c.Tr.CheckForUpdate,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Status.RecentRepos),
|
||||
Handler: self.c.Helpers().Repos.CreateRecentReposMenu,
|
||||
Description: self.c.Tr.SwitchRepo,
|
||||
Key: opts.GetKey(opts.Config.Status.RecentRepos),
|
||||
Handler: self.c.Helpers().Repos.CreateRecentReposMenu,
|
||||
Description: self.c.Tr.SwitchRepo,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Status.AllBranchesLogGraph),
|
||||
|
@ -46,6 +46,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
Description: self.c.Tr.Enter,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.EnterSubmoduleTooltip,
|
||||
map[string]string{"escape": keybindings.Label(opts.Config.Universal.Return)}),
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
@ -58,6 +59,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Remove,
|
||||
Tooltip: self.c.Tr.RemoveSubmoduleTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Submodules.Update),
|
||||
@ -65,11 +67,13 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Update,
|
||||
Tooltip: self.c.Tr.SubmoduleUpdateTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewSubmodule,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewSubmodule,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Edit),
|
||||
|
@ -39,12 +39,14 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Checkout,
|
||||
Tooltip: self.c.Tr.TagCheckoutTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.create,
|
||||
Description: self.c.Tr.NewTag,
|
||||
Tooltip: self.c.Tr.NewTagTooltip,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.create,
|
||||
Description: self.c.Tr.NewTag,
|
||||
Tooltip: self.c.Tr.NewTagTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
@ -53,6 +55,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Tooltip: self.c.Tr.TagDeleteTooltip,
|
||||
OpensMenu: true,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Branches.PushTag),
|
||||
@ -60,6 +63,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.PushTag,
|
||||
Tooltip: self.c.Tr.PushTagTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
@ -67,6 +71,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Reset,
|
||||
Tooltip: self.c.Tr.ResetTooltip,
|
||||
DisplayOnScreen: true,
|
||||
OpensMenu: true,
|
||||
},
|
||||
}
|
||||
|
@ -37,9 +37,10 @@ func NewWorktreesController(
|
||||
func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewWorktree,
|
||||
Key: opts.GetKey(opts.Config.Universal.New),
|
||||
Handler: self.add,
|
||||
Description: self.c.Tr.NewWorktree,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
@ -47,6 +48,7 @@ func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*t
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Switch,
|
||||
Tooltip: self.c.Tr.SwitchToWorktreeTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
@ -65,6 +67,7 @@ func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*t
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Remove,
|
||||
Tooltip: self.c.Tr.RemoveWorktreeTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@ type ICommitFileTreeViewModel interface {
|
||||
|
||||
type CommitFileTreeViewModel struct {
|
||||
sync.RWMutex
|
||||
ICommitFileTree
|
||||
types.IListCursor
|
||||
ICommitFileTree
|
||||
|
||||
// this is e.g. the commit for which we're viewing the files
|
||||
ref types.Ref
|
||||
@ -37,7 +37,7 @@ var _ ICommitFileTreeViewModel = &CommitFileTreeViewModel{}
|
||||
|
||||
func NewCommitFileTreeViewModel(getFiles func() []*models.CommitFile, log *logrus.Entry, showTree bool) *CommitFileTreeViewModel {
|
||||
fileTree := NewCommitFileTree(getFiles, log, showTree)
|
||||
listCursor := traits.NewListCursor(fileTree)
|
||||
listCursor := traits.NewListCursor(fileTree.Len)
|
||||
return &CommitFileTreeViewModel{
|
||||
ICommitFileTree: fileTree,
|
||||
IListCursor: listCursor,
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -138,7 +139,8 @@ func (self *FileTree) GetAllItems() []*FileNode {
|
||||
}
|
||||
|
||||
func (self *FileTree) Len() int {
|
||||
return self.tree.Size(self.collapsedPaths) - 1 // ignoring root
|
||||
// -1 because we're ignoring the root
|
||||
return utils.Max(self.tree.Size(self.collapsedPaths)-1, 0)
|
||||
}
|
||||
|
||||
func (self *FileTree) GetItem(index int) types.HasUrn {
|
||||
|
@ -21,15 +21,15 @@ type IFileTreeViewModel interface {
|
||||
// after the files are refreshed
|
||||
type FileTreeViewModel struct {
|
||||
sync.RWMutex
|
||||
IFileTree
|
||||
types.IListCursor
|
||||
IFileTree
|
||||
}
|
||||
|
||||
var _ IFileTreeViewModel = &FileTreeViewModel{}
|
||||
|
||||
func NewFileTreeViewModel(getFiles func() []*models.File, log *logrus.Entry, showTree bool) *FileTreeViewModel {
|
||||
fileTree := NewFileTree(getFiles, log, showTree)
|
||||
listCursor := traits.NewListCursor(fileTree)
|
||||
listCursor := traits.NewListCursor(fileTree.Len)
|
||||
return &FileTreeViewModel{
|
||||
IFileTree: fileTree,
|
||||
IListCursor: listCursor,
|
||||
@ -54,6 +54,10 @@ func (self *FileTreeViewModel) GetSelectedItemId() string {
|
||||
}
|
||||
|
||||
func (self *FileTreeViewModel) GetSelectedItems() ([]*FileNode, int, int) {
|
||||
if self.Len() == 0 {
|
||||
return nil, 0, 0
|
||||
}
|
||||
|
||||
startIdx, endIdx := self.GetSelectionRange()
|
||||
|
||||
nodes := []*FileNode{}
|
||||
|
@ -165,6 +165,8 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.renderContextOptionsMap()
|
||||
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
|
@ -4,9 +4,13 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
@ -14,30 +18,89 @@ type OptionsMapMgr struct {
|
||||
c *helpers.HelperCommon
|
||||
}
|
||||
|
||||
func (gui *Gui) renderContextOptionsMap(c types.Context) {
|
||||
func (gui *Gui) renderContextOptionsMap() {
|
||||
// In demos, we render our own content to this view
|
||||
if gui.integrationTest != nil && gui.integrationTest.IsDemo() {
|
||||
return
|
||||
}
|
||||
mgr := OptionsMapMgr{c: gui.c}
|
||||
mgr.renderContextOptionsMap(c)
|
||||
mgr.renderContextOptionsMap()
|
||||
}
|
||||
|
||||
// render the options available for the current context at the bottom of the screen
|
||||
func (self *OptionsMapMgr) renderContextOptionsMap(c types.Context) {
|
||||
bindingsToDisplay := lo.Filter(c.GetKeybindings(self.c.KeybindingsOpts()), func(binding *types.Binding, _ int) bool {
|
||||
return binding.Display
|
||||
// Render the options available for the current context at the bottom of the screen
|
||||
// STYLE GUIDE: we use the default options fg color for most keybindings. We can
|
||||
// only use a different color if we're in a specific mode where the user is likely
|
||||
// to want to press that key. For example, when in cherry-picking mode, we
|
||||
// want to prominently show the keybinding for pasting commits.
|
||||
func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||
currentContext := self.c.CurrentContext()
|
||||
|
||||
currentContextBindings := currentContext.GetKeybindings(self.c.KeybindingsOpts())
|
||||
globalBindings := self.c.Contexts().Global.GetKeybindings(self.c.KeybindingsOpts())
|
||||
|
||||
allBindings := append(currentContextBindings, globalBindings...)
|
||||
|
||||
bindingsToDisplay := lo.Filter(allBindings, func(binding *types.Binding, _ int) bool {
|
||||
return binding.DisplayOnScreen && !binding.IsDisabled()
|
||||
})
|
||||
|
||||
var optionsMap []bindingInfo
|
||||
if len(bindingsToDisplay) == 0 {
|
||||
optionsMap = self.globalOptions()
|
||||
} else {
|
||||
optionsMap = lo.Map(bindingsToDisplay, func(binding *types.Binding, _ int) bindingInfo {
|
||||
return bindingInfo{
|
||||
key: keybindings.LabelFromKey(binding.Key),
|
||||
description: binding.Description,
|
||||
}
|
||||
optionsMap := lo.Map(bindingsToDisplay, func(binding *types.Binding, _ int) bindingInfo {
|
||||
displayStyle := theme.OptionsFgColor
|
||||
if binding.DisplayStyle != nil {
|
||||
displayStyle = *binding.DisplayStyle
|
||||
}
|
||||
|
||||
description := binding.Description
|
||||
if binding.ShortDescription != "" {
|
||||
description = binding.ShortDescription
|
||||
}
|
||||
|
||||
return bindingInfo{
|
||||
key: keybindings.LabelFromKey(binding.Key),
|
||||
description: description,
|
||||
style: displayStyle,
|
||||
}
|
||||
})
|
||||
|
||||
// Mode-specific local keybindings
|
||||
if currentContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY {
|
||||
if self.c.Modes().CherryPicking.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Commits.PasteCommits),
|
||||
description: self.c.Tr.PasteCommits,
|
||||
style: style.FgCyan,
|
||||
})
|
||||
}
|
||||
|
||||
if self.c.Model().BisectInfo.Started() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions),
|
||||
description: self.c.Tr.ViewBisectOptions,
|
||||
style: style.FgGreen,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Mode-specific global keybindings
|
||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh.IsRebasing() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
||||
description: self.c.Tr.ViewRebaseOptions,
|
||||
style: style.FgYellow,
|
||||
})
|
||||
} else if self.c.Model().WorkingTreeStateAtLastCommitRefresh.IsMerging() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
||||
description: self.c.Tr.ViewMergeOptions,
|
||||
style: style.FgYellow,
|
||||
})
|
||||
}
|
||||
|
||||
if self.c.Git().Patch.PatchBuilder.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu),
|
||||
description: self.c.Tr.ViewPatchOptions,
|
||||
style: style.FgYellow,
|
||||
})
|
||||
}
|
||||
|
||||
@ -45,49 +108,41 @@ func (self *OptionsMapMgr) renderContextOptionsMap(c types.Context) {
|
||||
}
|
||||
|
||||
func (self *OptionsMapMgr) formatBindingInfos(bindingInfos []bindingInfo) string {
|
||||
return strings.Join(
|
||||
lo.Map(bindingInfos, func(bindingInfo bindingInfo, _ int) string {
|
||||
return fmt.Sprintf("%s: %s", bindingInfo.key, bindingInfo.description)
|
||||
}),
|
||||
", ")
|
||||
width := self.c.Views().Options.Width() - 4 // -4 for the padding
|
||||
var builder strings.Builder
|
||||
ellipsis := "…"
|
||||
separator := " | "
|
||||
|
||||
length := 0
|
||||
|
||||
for i, info := range bindingInfos {
|
||||
plainText := fmt.Sprintf("%s: %s", info.description, info.key)
|
||||
|
||||
// Check if adding the next formatted string exceeds the available width
|
||||
if i > 0 && length+len(separator)+len(plainText) > width {
|
||||
builder.WriteString(theme.OptionsFgColor.Sprint(separator + ellipsis))
|
||||
break
|
||||
}
|
||||
|
||||
formatted := info.style.Sprintf(plainText)
|
||||
|
||||
if i > 0 {
|
||||
builder.WriteString(theme.OptionsFgColor.Sprint(separator))
|
||||
length += len(separator)
|
||||
}
|
||||
builder.WriteString(formatted)
|
||||
length += len(plainText)
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (self *OptionsMapMgr) renderOptions(options string) {
|
||||
self.c.SetViewContent(self.c.Views().Options, options)
|
||||
}
|
||||
|
||||
func (self *OptionsMapMgr) globalOptions() []bindingInfo {
|
||||
keybindingConfig := self.c.UserConfig.Keybinding
|
||||
|
||||
return []bindingInfo{
|
||||
{
|
||||
key: fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollUpMain), keybindings.Label(keybindingConfig.Universal.ScrollDownMain)),
|
||||
description: self.c.Tr.Scroll,
|
||||
},
|
||||
{
|
||||
key: keybindings.Label(keybindingConfig.Universal.Return),
|
||||
description: self.c.Tr.Cancel,
|
||||
},
|
||||
{
|
||||
key: keybindings.Label(keybindingConfig.Universal.Quit),
|
||||
description: self.c.Tr.Quit,
|
||||
},
|
||||
{
|
||||
key: keybindings.Label(keybindingConfig.Universal.OptionMenuAlt1),
|
||||
description: self.c.Tr.Keybindings,
|
||||
},
|
||||
{
|
||||
key: fmt.Sprintf("%s-%s", keybindings.Label(keybindingConfig.Universal.JumpToBlock[0]), keybindings.Label(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])),
|
||||
description: self.c.Tr.Jump,
|
||||
},
|
||||
{
|
||||
key: fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollLeft), keybindings.Label(keybindingConfig.Universal.ScrollRight)),
|
||||
description: self.c.Tr.ScrollLeftRight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type bindingInfo struct {
|
||||
key string
|
||||
description string
|
||||
style style.TextStyle
|
||||
}
|
||||
|
@ -11,21 +11,25 @@ type Key interface{} // FIXME: find out how to get `gocui.Key | rune`
|
||||
// is only handled if the given view has focus, or handled globally if the view
|
||||
// is ""
|
||||
type Binding struct {
|
||||
ViewName string
|
||||
Handler func() error
|
||||
Key Key
|
||||
Modifier gocui.Modifier
|
||||
Description string
|
||||
ViewName string
|
||||
Handler func() error
|
||||
Key Key
|
||||
Modifier gocui.Modifier
|
||||
Description string
|
||||
// If defined, this is used in place of Description when showing the keybinding
|
||||
// in the options view at the bottom left of the screen.
|
||||
ShortDescription string
|
||||
Alternative string
|
||||
Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet
|
||||
OpensMenu bool
|
||||
|
||||
// If true, the keybinding will appear at the bottom of the screen. If
|
||||
// the given view has no bindings with Display: true, the default keybindings
|
||||
// will be displayed instead.
|
||||
// TODO: implement this
|
||||
Display bool
|
||||
// If true, the keybinding will appear at the bottom of the screen.
|
||||
// Even if set to true, the keybinding will not be displayed if it is currently
|
||||
// disabled. We could instead display it with a strikethrough, but there's
|
||||
// limited realestate to show all the keybindings we want, so we're hiding it instead.
|
||||
DisplayOnScreen bool
|
||||
// if unset, the binding will be displayed in the default color. Only applies to the keybinding
|
||||
// on-screen, not in the keybindings menu.
|
||||
DisplayStyle *style.TextStyle
|
||||
|
||||
// to be displayed if the keybinding is highlighted from within a menu
|
||||
@ -39,6 +43,10 @@ type Binding struct {
|
||||
GetDisabledReason func() *DisabledReason
|
||||
}
|
||||
|
||||
func (Binding *Binding) IsDisabled() bool {
|
||||
return Binding.GetDisabledReason != nil && Binding.GetDisabledReason() != nil
|
||||
}
|
||||
|
||||
// A guard is a decorator which checks something before executing a handler
|
||||
// and potentially early-exits if some precondition hasn't been met.
|
||||
type Guard func(func() error) func() error
|
||||
|
@ -94,7 +94,6 @@ func (gui *Gui) createAllViews() error {
|
||||
(*mapping.viewPtr).SelBgColor = theme.GocuiSelectedLineBgColor
|
||||
}
|
||||
|
||||
gui.Views.Options.FgColor = theme.OptionsColor
|
||||
gui.Views.Options.Frame = false
|
||||
|
||||
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
|
||||
|
@ -62,3 +62,29 @@ func (self *Common) SelectPatchOption(matcher *TextMatcher) {
|
||||
|
||||
self.t.ExpectPopup().Menu().Title(Equals("Patch options")).Select(matcher).Confirm()
|
||||
}
|
||||
|
||||
func (self *Common) ResetBisect() {
|
||||
self.t.Views().Commits().
|
||||
Focus().
|
||||
Press(self.t.keys.Commits.ViewBisectOptions).
|
||||
Tap(func() {
|
||||
self.t.ExpectPopup().Menu().
|
||||
Title(Equals("Bisect")).
|
||||
Select(Contains("Reset bisect")).
|
||||
Confirm()
|
||||
|
||||
self.t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Reset 'git bisect'")).
|
||||
Content(Contains("Are you sure you want to reset 'git bisect'?")).
|
||||
Confirm()
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Common) ResetCustomPatch() {
|
||||
self.t.GlobalPress(self.t.keys.Universal.CreatePatchOptionsMenu)
|
||||
|
||||
self.t.ExpectPopup().Menu().
|
||||
Title(Equals("Patch options")).
|
||||
Select(Contains("Reset patch")).
|
||||
Confirm()
|
||||
}
|
||||
|
@ -147,3 +147,7 @@ func (self *Views) Search() *ViewDriver {
|
||||
func (self *Views) Tooltip() *ViewDriver {
|
||||
return self.regularView("tooltip")
|
||||
}
|
||||
|
||||
func (self *Views) Options() *ViewDriver {
|
||||
return self.regularView("options")
|
||||
}
|
||||
|
@ -269,6 +269,7 @@ var tests = []*components.IntegrationTest{
|
||||
ui.Accordion,
|
||||
ui.DoublePopup,
|
||||
ui.EmptyMenu,
|
||||
ui.ModeSpecificKeybindingSuggestions,
|
||||
ui.OpenLinkFailure,
|
||||
ui.RangeSelect,
|
||||
ui.SwitchTabFromMenu,
|
||||
|
118
pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go
Normal file
118
pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go
Normal file
@ -0,0 +1,118 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var ModeSpecificKeybindingSuggestions = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "When in various modes, we should corresponding keybinding suggestions onscreen",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateNCommits(2)
|
||||
shell.NewBranch("base-branch")
|
||||
shared.MergeConflictsSetup(shell)
|
||||
shell.Checkout("base-branch")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
rebaseSuggestion := "View rebase options: m"
|
||||
cherryPickSuggestion := "Paste (cherry-pick): V"
|
||||
bisectSuggestion := "View bisect options: b"
|
||||
customPatchSuggestion := "View custom patch options: <c-p>"
|
||||
mergeSuggestion := "View merge options: m"
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("commit 02").IsSelected(),
|
||||
Contains("commit 01"),
|
||||
).
|
||||
Tap(func() {
|
||||
// These suggestions are mode-specific so are not shown by default
|
||||
t.Views().Options().Content(
|
||||
DoesNotContain(rebaseSuggestion).
|
||||
DoesNotContain(mergeSuggestion).
|
||||
DoesNotContain(cherryPickSuggestion).
|
||||
DoesNotContain(bisectSuggestion).
|
||||
DoesNotContain(customPatchSuggestion),
|
||||
)
|
||||
}).
|
||||
// Start an interactive rebase
|
||||
Press(keys.Universal.Edit).
|
||||
Tap(func() {
|
||||
// Confirm the rebase suggestion now appears
|
||||
t.Views().Options().Content(Contains(rebaseSuggestion))
|
||||
}).
|
||||
Press(keys.Commits.CherryPickCopy).
|
||||
Tap(func() {
|
||||
// Confirm the cherry pick suggestion now appears
|
||||
t.Views().Options().Content(Contains(cherryPickSuggestion))
|
||||
// Importantly, we show multiple of these suggestions at once
|
||||
t.Views().Options().Content(Contains(rebaseSuggestion))
|
||||
}).
|
||||
// Cancel the cherry pick
|
||||
PressEscape().
|
||||
Tap(func() {
|
||||
t.Views().Options().Content(DoesNotContain(cherryPickSuggestion))
|
||||
}).
|
||||
// Cancel the rebase
|
||||
Tap(func() {
|
||||
t.Common().AbortRebase()
|
||||
|
||||
t.Views().Options().Content(DoesNotContain(rebaseSuggestion))
|
||||
}).
|
||||
Press(keys.Commits.ViewBisectOptions).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Bisect")).
|
||||
Select(MatchesRegexp("Mark.* as bad")).
|
||||
Confirm()
|
||||
|
||||
t.Views().Options().Content(Contains(bisectSuggestion))
|
||||
|
||||
// Cancel bisect
|
||||
t.Common().ResetBisect()
|
||||
|
||||
t.Views().Options().Content(DoesNotContain(bisectSuggestion))
|
||||
}).
|
||||
// Enter commit files view
|
||||
PressEnter()
|
||||
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
// Add a commit file to the patch
|
||||
Press(keys.Universal.Select).
|
||||
Tap(func() {
|
||||
t.Views().Options().Content(Contains(customPatchSuggestion))
|
||||
|
||||
t.Common().ResetCustomPatch()
|
||||
|
||||
t.Views().Options().Content(DoesNotContain(customPatchSuggestion))
|
||||
})
|
||||
|
||||
// Test merge options suggestion
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
NavigateToLine(Contains("first-change-branch")).
|
||||
Press(keys.Universal.Select).
|
||||
NavigateToLine(Contains("second-change-branch")).
|
||||
Press(keys.Branches.MergeIntoCurrentBranch).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Merge")).
|
||||
Content(Contains("Are you sure you want to merge")).
|
||||
Confirm()
|
||||
|
||||
t.Common().AcknowledgeConflicts()
|
||||
|
||||
t.Views().Options().Content(Contains(mergeSuggestion))
|
||||
|
||||
t.Common().AbortMerge()
|
||||
|
||||
t.Views().Options().Content(DoesNotContain(mergeSuggestion))
|
||||
})
|
||||
},
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user