mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Use a slice of keys for each binding
This is a pure refactor in preparation for letting users configure multiple alternate bindings for a single command. Every Binding still has exactly one key, so nothing changes visibly: the cheatsheet, the on-screen options bar, and the keybindings menu all render identically. When a Binding ends up with multiple keys, the on-screen options bar will show only the first (to avoid clutter); the cheatsheet will show all of them (in a later commit). For now both paths take Key[0]. MenuItem.Key is changed in the same way, it also has a slice of keys now. In this commit we keep the name `Key` in Binding, KeybindingOpts and MenuItem, instead of renaming them to `Keys` right away, in order to keep the diff a bit more readable. We'll do the rename separately in the next commit.
This commit is contained in:
parent
22a508fdba
commit
3d18ee8f91
|
|
@ -145,7 +145,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return (binding.Description != "" || binding.Alternative != "") && binding.Key.IsSet()
|
return (binding.Description != "" || binding.Alternative != "") && len(binding.Key) > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
bindingsByHeader := lo.GroupBy(bindingsToDisplay, func(binding *types.Binding) header {
|
bindingsByHeader := lo.GroupBy(bindingsToDisplay, func(binding *types.Binding) header {
|
||||||
|
|
@ -156,7 +156,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
|
||||||
bindingsByHeader,
|
bindingsByHeader,
|
||||||
func(header header, hBindings []*types.Binding) headerWithBindings {
|
func(header header, hBindings []*types.Binding) headerWithBindings {
|
||||||
uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string {
|
uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string {
|
||||||
return binding.Description + config.LabelForKey(binding.Key)
|
return binding.Description + config.LabelForKey(binding.Key[0])
|
||||||
})
|
})
|
||||||
|
|
||||||
return headerWithBindings{
|
return headerWithBindings{
|
||||||
|
|
@ -214,7 +214,7 @@ func formatTitle(title string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatBinding(binding *types.Binding) string {
|
func formatBinding(binding *types.Binding) string {
|
||||||
action := config.LabelForKey(binding.Key)
|
action := config.LabelForKey(binding.Key[0])
|
||||||
description := binding.Description
|
description := binding.Description
|
||||||
if binding.Alternative != "" {
|
if binding.Alternative != "" {
|
||||||
action += fmt.Sprintf(" (%s)", binding.Alternative)
|
action += fmt.Sprintf(" (%s)", binding.Alternative)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: []*bindingSection{
|
expected: []*bindingSection{
|
||||||
|
|
@ -38,7 +38,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -50,7 +50,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "",
|
ViewName: "",
|
||||||
Description: "quit",
|
Description: "quit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: []*bindingSection{
|
expected: []*bindingSection{
|
||||||
|
|
@ -60,7 +60,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "",
|
ViewName: "",
|
||||||
Description: "quit",
|
Description: "quit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -72,17 +72,17 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "submodules",
|
ViewName: "submodules",
|
||||||
Description: "drop submodule",
|
Description: "drop submodule",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: []*bindingSection{
|
expected: []*bindingSection{
|
||||||
|
|
@ -92,12 +92,12 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -107,7 +107,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "submodules",
|
ViewName: "submodules",
|
||||||
Description: "drop submodule",
|
Description: "drop submodule",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -119,23 +119,23 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "scroll",
|
Description: "scroll",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "revert commit",
|
Description: "revert commit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: []*bindingSection{
|
expected: []*bindingSection{
|
||||||
|
|
@ -145,7 +145,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "scroll",
|
Description: "scroll",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -156,7 +156,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "revert commit",
|
Description: "revert commit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -166,12 +166,12 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -183,34 +183,34 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "scroll",
|
Description: "scroll",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "revert commit",
|
Description: "revert commit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "scroll",
|
Description: "scroll",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "page up",
|
Description: "page up",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -221,13 +221,13 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "scroll",
|
Description: "scroll",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "page up",
|
Description: "page up",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -238,7 +238,7 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "commits",
|
ViewName: "commits",
|
||||||
Description: "revert commit",
|
Description: "revert commit",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -248,12 +248,12 @@ func TestGetBindingSections(t *testing.T) {
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "stage file",
|
Description: "stage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "files",
|
ViewName: "files",
|
||||||
Description: "unstage file",
|
Description: "unstage file",
|
||||||
Key: gocui.NewKeyRune('a'),
|
Key: []gocui.Key{gocui.NewKeyRune('a')},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -205,3 +205,11 @@ func GetValidatedKeyBindingKey(label string) gocui.Key {
|
||||||
|
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetValidatedKeyBindingKeys(label string) []gocui.Key {
|
||||||
|
k := GetValidatedKeyBindingKey(label)
|
||||||
|
if !k.IsSet() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []gocui.Key{k}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
|
@ -73,7 +74,11 @@ func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
|
||||||
func() []*types.MenuItem { return self.menuItems },
|
func() []*types.MenuItem { return self.menuItems },
|
||||||
func(item *types.MenuItem) []string {
|
func(item *types.MenuItem) []string {
|
||||||
if filterKeybindings {
|
if filterKeybindings {
|
||||||
return []string{config.LabelForKey(item.Key)}
|
// Allow searching all configured keybindings of each item, even though only the
|
||||||
|
// first one is shown in the menu.
|
||||||
|
return lo.Map(item.Key, func(k gocui.Key, _ int) string {
|
||||||
|
return config.LabelForKey(k)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.LabelColumns
|
return item.LabelColumns
|
||||||
|
|
@ -138,8 +143,8 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
keyLabel := ""
|
keyLabel := ""
|
||||||
if item.Key.IsSet() {
|
if len(item.Key) > 0 {
|
||||||
keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Key))
|
keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Key[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
checkMark := ""
|
checkMark := ""
|
||||||
|
|
@ -205,7 +210,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
|
||||||
func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
basicBindings := self.ListContextTrait.GetKeybindings(opts)
|
basicBindings := self.ListContextTrait.GetKeybindings(opts)
|
||||||
menuItemsWithKeys := lo.Filter(self.menuItems, func(item *types.MenuItem, _ int) bool {
|
menuItemsWithKeys := lo.Filter(self.menuItems, func(item *types.MenuItem, _ int) bool {
|
||||||
return item.Key.IsSet()
|
return len(item.Key) > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
menuItemBindings := lo.Map(menuItemsWithKeys, func(item *types.MenuItem, _ int) *types.Binding {
|
menuItemBindings := lo.Map(menuItemsWithKeys, func(item *types.MenuItem, _ int) *types.Binding {
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ package helpers
|
||||||
import "github.com/jesseduffield/lazygit/pkg/gocui"
|
import "github.com/jesseduffield/lazygit/pkg/gocui"
|
||||||
|
|
||||||
// menuKey is a shorthand for constructing a key value for a menu item from a single rune literal,
|
// menuKey is a shorthand for constructing a key value for a menu item from a single rune literal,
|
||||||
// avoiding the noise of `gocui.NewKeyRune('a')` at every call site. There is an intentionally
|
// avoiding the noise of `[]gocui.Key{gocui.NewKeyRune('a')}` at every call site. There is an
|
||||||
// identical helper in the controllers package so that callers in either package can use the
|
// intentionally identical helper in the controllers package so that callers in either package can
|
||||||
// unqualified form.
|
// use the unqualified form.
|
||||||
func menuKey(r rune) gocui.Key {
|
func menuKey(r rune) []gocui.Key {
|
||||||
return gocui.NewKeyRune(r)
|
return []gocui.Key{gocui.NewKeyRune(r)}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ const (
|
||||||
func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
|
func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
|
||||||
type optionAndKey struct {
|
type optionAndKey struct {
|
||||||
option string
|
option string
|
||||||
key gocui.Key
|
key []gocui.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
options := []optionAndKey{
|
options := []optionAndKey{
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string
|
||||||
|
|
||||||
func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, menuPrompt string, onSelected func(sortOrder string) error, currentValue string) error {
|
func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, menuPrompt string, onSelected func(sortOrder string) error, currentValue string) error {
|
||||||
type sortMenuOption struct {
|
type sortMenuOption struct {
|
||||||
key gocui.Key
|
key []gocui.Key
|
||||||
label string
|
label string
|
||||||
description string
|
description string
|
||||||
sortOrder string
|
sortOrder string
|
||||||
|
|
@ -260,7 +260,7 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error {
|
||||||
type strengthWithKey struct {
|
type strengthWithKey struct {
|
||||||
strength string
|
strength string
|
||||||
label string
|
label string
|
||||||
key gocui.Key
|
key []gocui.Key
|
||||||
tooltip string
|
tooltip string
|
||||||
}
|
}
|
||||||
strengths := []strengthWithKey{
|
strengths := []strengthWithKey{
|
||||||
|
|
@ -318,7 +318,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error {
|
||||||
|
|
||||||
if len(branches) > 0 {
|
if len(branches) > 0 {
|
||||||
menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem {
|
menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem {
|
||||||
var key gocui.Key
|
var key []gocui.Key
|
||||||
if index < 9 {
|
if index < 9 {
|
||||||
key = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key
|
key = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ package controllers
|
||||||
import "github.com/jesseduffield/lazygit/pkg/gocui"
|
import "github.com/jesseduffield/lazygit/pkg/gocui"
|
||||||
|
|
||||||
// menuKey is a shorthand for constructing a key value for a menu item from a single rune literal,
|
// menuKey is a shorthand for constructing a key value for a menu item from a single rune literal,
|
||||||
// avoiding the noise of `gocui.NewKeyRune('a')` at every call site. There is an intentionally
|
// avoiding the noise of `[]gocui.Key{gocui.NewKeyRune('a')}` at every call site. There is an
|
||||||
// identical helper in the helpers package so that callers in either package can use the unqualified
|
// intentionally identical helper in the helpers package so that callers in either package can use
|
||||||
// form.
|
// the unqualified form.
|
||||||
func menuKey(r rune) gocui.Key {
|
func menuKey(r rune) []gocui.Key {
|
||||||
return gocui.NewKeyRune(r)
|
return []gocui.Key{gocui.NewKeyRune(r)}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func NewPromptController(
|
||||||
func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
bindings := []*types.Binding{
|
bindings := []*types.Binding{
|
||||||
{
|
{
|
||||||
Key: gocui.NewKeyName(gocui.KeyEnter),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)},
|
||||||
Handler: func() error { return self.context().State.OnConfirm() },
|
Handler: func() error { return self.context().State.OnConfirm() },
|
||||||
Description: self.c.Tr.Confirm,
|
Description: self.c.Tr.Confirm,
|
||||||
DisplayOnScreen: true,
|
DisplayOnScreen: true,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ func NewSearchPromptController(
|
||||||
func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
return []*types.Binding{
|
return []*types.Binding{
|
||||||
{
|
{
|
||||||
Key: gocui.NewKeyName(gocui.KeyEnter),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)},
|
||||||
Handler: self.confirm,
|
Handler: self.confirm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error {
|
||||||
Items: []*types.MenuItem{
|
Items: []*types.MenuItem{
|
||||||
{
|
{
|
||||||
Label: gui.c.Tr.ToggleShowCommandLog,
|
Label: gui.c.Tr.ToggleShowCommandLog,
|
||||||
Key: gocui.NewKeyRune('t'),
|
Key: []gocui.Key{gocui.NewKeyRune('t')},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
currentContext := gui.c.Context().CurrentStatic()
|
currentContext := gui.c.Context().CurrentStatic()
|
||||||
if gui.c.State().GetShowExtrasWindow() && currentContext.GetKey() == context.COMMAND_LOG_CONTEXT_KEY {
|
if gui.c.State().GetShowExtrasWindow() && currentContext.GetKey() == context.COMMAND_LOG_CONTEXT_KEY {
|
||||||
|
|
@ -30,7 +30,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: gui.c.Tr.FocusCommandLog,
|
Label: gui.c.Tr.FocusCommandLog,
|
||||||
Key: gocui.NewKeyRune('f'),
|
Key: []gocui.Key{gocui.NewKeyRune('f')},
|
||||||
OnPress: gui.handleFocusCommandLog,
|
OnPress: gui.handleFocusCommandLog,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func (gui *Gui) keybindingOpts() types.KeybindingsOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.KeybindingsOpts{
|
return types.KeybindingsOpts{
|
||||||
GetKey: config.GetValidatedKeyBindingKey,
|
GetKey: config.GetValidatedKeyBindingKeys,
|
||||||
Config: keybindingConfig,
|
Config: keybindingConfig,
|
||||||
Guards: guards,
|
Guards: guards,
|
||||||
}
|
}
|
||||||
|
|
@ -176,7 +176,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "information",
|
ViewName: "information",
|
||||||
Key: gocui.NewKeyName(gocui.MouseLeft),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)},
|
||||||
Handler: gui.handleInfoClick,
|
Handler: gui.handleInfoClick,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -196,26 +196,26 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "main",
|
ViewName: "main",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
|
||||||
Handler: gui.scrollDownMain,
|
Handler: gui.scrollDownMain,
|
||||||
Description: gui.c.Tr.ScrollDown,
|
Description: gui.c.Tr.ScrollDown,
|
||||||
Alternative: "fn+up",
|
Alternative: "fn+up",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "main",
|
ViewName: "main",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
|
||||||
Handler: gui.scrollUpMain,
|
Handler: gui.scrollUpMain,
|
||||||
Description: gui.c.Tr.ScrollUp,
|
Description: gui.c.Tr.ScrollUp,
|
||||||
Alternative: "fn+down",
|
Alternative: "fn+down",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "secondary",
|
ViewName: "secondary",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
|
||||||
Handler: gui.scrollDownSecondary,
|
Handler: gui.scrollDownSecondary,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "secondary",
|
ViewName: "secondary",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
|
||||||
Handler: gui.scrollUpSecondary,
|
Handler: gui.scrollUpSecondary,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -240,12 +240,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "confirmation",
|
ViewName: "confirmation",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
|
||||||
Handler: gui.scrollUpConfirmationPanel,
|
Handler: gui.scrollUpConfirmationPanel,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "confirmation",
|
ViewName: "confirmation",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
|
||||||
Handler: gui.scrollDownConfirmationPanel,
|
Handler: gui.scrollDownConfirmationPanel,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -287,12 +287,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "extras",
|
ViewName: "extras",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
|
||||||
Handler: gui.scrollUpExtra,
|
Handler: gui.scrollUpExtra,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "extras",
|
ViewName: "extras",
|
||||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
|
||||||
Handler: gui.scrollDownExtra,
|
Handler: gui.scrollDownExtra,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -352,7 +352,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
||||||
{
|
{
|
||||||
ViewName: "extras",
|
ViewName: "extras",
|
||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
Key: gocui.NewKeyName(gocui.MouseLeft),
|
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)},
|
||||||
Handler: gui.handleFocusCommandLog,
|
Handler: gui.handleFocusCommandLog,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +448,9 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) {
|
||||||
return gui.callKeybindingHandler(binding)
|
return gui.callKeybindingHandler(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.g.SetKeybinding(binding.ViewName, binding.Key, handler)
|
for _, key := range binding.Key {
|
||||||
|
gui.g.SetKeybinding(binding.ViewName, key, handler)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
|
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,10 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
||||||
maxColumnSize = max(maxColumnSize, len(item.LabelColumns))
|
maxColumnSize = max(maxColumnSize, len(item.LabelColumns))
|
||||||
|
|
||||||
// Remove all item keybindings that are the same as one of the essential bindings
|
// Remove all item keybindings that are the same as one of the essential bindings
|
||||||
if !opts.KeepConflictingKeybindings && lo.Contains(essentialKeys, item.Key) {
|
if !opts.KeepConflictingKeybindings {
|
||||||
item.Key = gocui.Key{}
|
item.Key = lo.Filter(item.Key, func(k gocui.Key, _ int) bool {
|
||||||
|
return !lo.Contains(essentialKeys, k)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||||
globalBindings := self.c.Contexts().Global.GetKeybindings(self.c.KeybindingsOpts())
|
globalBindings := self.c.Contexts().Global.GetKeybindings(self.c.KeybindingsOpts())
|
||||||
|
|
||||||
currentContextKeys := set.NewFromSlice(
|
currentContextKeys := set.NewFromSlice(
|
||||||
lo.Map(currentContextBindings, func(binding *types.Binding, _ int) gocui.Key {
|
lo.FlatMap(currentContextBindings, func(binding *types.Binding, _ int) []gocui.Key {
|
||||||
return binding.Key
|
return binding.Key
|
||||||
}))
|
}))
|
||||||
|
|
||||||
allBindings := append(currentContextBindings, lo.Filter(globalBindings, func(b *types.Binding, _ int) bool {
|
allBindings := append(currentContextBindings, lo.Filter(globalBindings, func(b *types.Binding, _ int) bool {
|
||||||
return !currentContextKeys.Includes(b.Key)
|
return len(b.Key) == 0 || !currentContextKeys.Includes(b.Key[0])
|
||||||
})...)
|
})...)
|
||||||
|
|
||||||
bindingsToDisplay := lo.Filter(allBindings, func(binding *types.Binding, _ int) bool {
|
bindingsToDisplay := lo.Filter(allBindings, func(binding *types.Binding, _ int) bool {
|
||||||
|
|
@ -60,7 +60,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindingInfo{
|
return bindingInfo{
|
||||||
key: config.LabelForKey(binding.Key),
|
key: config.LabelForKey(binding.Key[0]),
|
||||||
description: binding.GetShortDescription(),
|
description: binding.GetShortDescription(),
|
||||||
style: displayStyle,
|
style: displayStyle,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package custom_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
|
@ -45,7 +46,7 @@ func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) {
|
||||||
}
|
}
|
||||||
bindings = append(bindings, &types.Binding{
|
bindings = append(bindings, &types.Binding{
|
||||||
ViewName: "", // custom commands menus are global; we filter the commands inside by context
|
ViewName: "", // custom commands menus are global; we filter the commands inside by context
|
||||||
Key: config.GetValidatedKeyBindingKey(customCommand.Key),
|
Key: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)},
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
Description: getCustomCommandsMenuDescription(customCommand, self.c.Tr),
|
Description: getCustomCommandsMenuDescription(customCommand, self.c.Tr),
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
|
|
@ -72,7 +73,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
|
||||||
}
|
}
|
||||||
menuItems = append(menuItems, &types.MenuItem{
|
menuItems = append(menuItems, &types.MenuItem{
|
||||||
Label: subCommand.GetDescription(),
|
Label: subCommand.GetDescription(),
|
||||||
Key: config.GetValidatedKeyBindingKey(subCommand.Key),
|
Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
|
||||||
OnPress: handler,
|
OnPress: handler,
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
})
|
})
|
||||||
|
|
@ -92,7 +93,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
|
||||||
|
|
||||||
menuItems = append(menuItems, &types.MenuItem{
|
menuItems = append(menuItems, &types.MenuItem{
|
||||||
Label: subCommand.GetDescription(),
|
Label: subCommand.GetDescription(),
|
||||||
Key: config.GetValidatedKeyBindingKey(subCommand.Key),
|
Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
|
||||||
OnPress: self.handlerCreator.call(subCommand),
|
OnPress: self.handlerCreator.call(subCommand),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrapp
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return wrappedF(option.Value)
|
return wrappedF(option.Value)
|
||||||
},
|
},
|
||||||
Key: config.GetValidatedKeyBindingKey(option.Key),
|
Key: []gocui.Key{config.GetValidatedKeyBindingKey(option.Key)},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
|
@ -35,7 +36,7 @@ func (self *KeybindingCreator) call(customCommand config.CustomCommand, handler
|
||||||
return lo.Map(viewNames, func(viewName string, _ int) *types.Binding {
|
return lo.Map(viewNames, func(viewName string, _ int) *types.Binding {
|
||||||
return &types.Binding{
|
return &types.Binding{
|
||||||
ViewName: viewName,
|
ViewName: viewName,
|
||||||
Key: config.GetValidatedKeyBindingKey(customCommand.Key),
|
Key: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)},
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
Description: customCommand.GetDescription(),
|
Description: customCommand.GetDescription(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,10 @@ type MenuItem struct {
|
||||||
// Only applies when Label is used
|
// Only applies when Label is used
|
||||||
OpensMenu bool
|
OpensMenu bool
|
||||||
|
|
||||||
// If Key is defined it allows the user to press the key to invoke the menu
|
// If Key is non-empty, the user can press any of these keys to invoke the
|
||||||
// item, as opposed to having to navigate to it
|
// menu item, as opposed to having to navigate to it. Only the first key is
|
||||||
Key gocui.Key
|
// shown in the menu; the alternates are matched silently.
|
||||||
|
Key []gocui.Key
|
||||||
|
|
||||||
// A widget to show in front of the menu item. Supported widget types are
|
// A widget to show in front of the menu item. Supported widget types are
|
||||||
// checkboxes and radio buttons,
|
// checkboxes and radio buttons,
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ type OnFocusLostOpts struct {
|
||||||
type ContextKey string
|
type ContextKey string
|
||||||
|
|
||||||
type KeybindingsOpts struct {
|
type KeybindingsOpts struct {
|
||||||
GetKey func(key string) gocui.Key
|
GetKey func(key string) []gocui.Key
|
||||||
Config config.KeybindingConfig
|
Config config.KeybindingConfig
|
||||||
Guards KeybindingGuards
|
Guards KeybindingGuards
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
type Binding struct {
|
type Binding struct {
|
||||||
ViewName string
|
ViewName string
|
||||||
Handler func() error
|
Handler func() error
|
||||||
Key gocui.Key
|
Key []gocui.Key
|
||||||
Description string
|
Description string
|
||||||
// DescriptionFunc is used instead of Description if non-nil, and is useful for dynamic
|
// DescriptionFunc is used instead of Description if non-nil, and is useful for dynamic
|
||||||
// descriptions that change depending on context. Important: this must not be an expensive call.
|
// descriptions that change depending on context. Important: this must not be an expensive call.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue