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:
Stefan Haller
2026-05-25 15:18:18 +02:00
parent 22a508fdba
commit 3d18ee8f91
20 changed files with 101 additions and 81 deletions
+3 -3
View File
@@ -145,7 +145,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
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 {
@@ -156,7 +156,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
bindingsByHeader,
func(header header, hBindings []*types.Binding) headerWithBindings {
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{
@@ -214,7 +214,7 @@ func formatTitle(title string) string {
}
func formatBinding(binding *types.Binding) string {
action := config.LabelForKey(binding.Key)
action := config.LabelForKey(binding.Key[0])
description := binding.Description
if binding.Alternative != "" {
action += fmt.Sprintf(" (%s)", binding.Alternative)
+29 -29
View File
@@ -28,7 +28,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
expected: []*bindingSection{
@@ -38,7 +38,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -50,7 +50,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "",
Description: "quit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
expected: []*bindingSection{
@@ -60,7 +60,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "",
Description: "quit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -72,17 +72,17 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "submodules",
Description: "drop submodule",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
expected: []*bindingSection{
@@ -92,12 +92,12 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -107,7 +107,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "submodules",
Description: "drop submodule",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -119,23 +119,23 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "scroll",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
{
ViewName: "commits",
Description: "revert commit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
expected: []*bindingSection{
@@ -145,7 +145,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "scroll",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
},
@@ -156,7 +156,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "commits",
Description: "revert commit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -166,12 +166,12 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -183,34 +183,34 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "scroll",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
{
ViewName: "commits",
Description: "revert commit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "commits",
Description: "scroll",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
{
ViewName: "commits",
Description: "page up",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
},
@@ -221,13 +221,13 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "scroll",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
{
ViewName: "commits",
Description: "page up",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
Tag: "navigation",
},
},
@@ -238,7 +238,7 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "commits",
Description: "revert commit",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
@@ -248,12 +248,12 @@ func TestGetBindingSections(t *testing.T) {
{
ViewName: "files",
Description: "stage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
{
ViewName: "files",
Description: "unstage file",
Key: gocui.NewKeyRune('a'),
Key: []gocui.Key{gocui.NewKeyRune('a')},
},
},
},
+8
View File
@@ -205,3 +205,11 @@ func GetValidatedKeyBindingKey(label string) gocui.Key {
return key
}
func GetValidatedKeyBindingKeys(label string) []gocui.Key {
k := GetValidatedKeyBindingKey(label)
if !k.IsSet() {
return nil
}
return []gocui.Key{k}
}
+9 -4
View File
@@ -5,6 +5,7 @@ import (
"strings"
"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/types"
"github.com/jesseduffield/lazygit/pkg/i18n"
@@ -73,7 +74,11 @@ func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
func() []*types.MenuItem { return self.menuItems },
func(item *types.MenuItem) []string {
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
@@ -138,8 +143,8 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
}
keyLabel := ""
if item.Key.IsSet() {
keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Key))
if len(item.Key) > 0 {
keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Key[0]))
}
checkMark := ""
@@ -205,7 +210,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
basicBindings := self.ListContextTrait.GetKeybindings(opts)
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 {
+5 -5
View File
@@ -3,9 +3,9 @@ package helpers
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,
// avoiding the noise of `gocui.NewKeyRune('a')` at every call site. There is an intentionally
// identical helper in the controllers package so that callers in either package can use the
// unqualified form.
func menuKey(r rune) gocui.Key {
return gocui.NewKeyRune(r)
// avoiding the noise of `[]gocui.Key{gocui.NewKeyRune('a')}` at every call site. There is an
// intentionally identical helper in the controllers package so that callers in either package can
// use the unqualified form.
func menuKey(r rune) []gocui.Key {
return []gocui.Key{gocui.NewKeyRune(r)}
}
@@ -39,7 +39,7 @@ const (
func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
type optionAndKey struct {
option string
key gocui.Key
key []gocui.Key
}
options := []optionAndKey{
+3 -3
View File
@@ -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 {
type sortMenuOption struct {
key gocui.Key
key []gocui.Key
label string
description string
sortOrder string
@@ -260,7 +260,7 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error {
type strengthWithKey struct {
strength string
label string
key gocui.Key
key []gocui.Key
tooltip string
}
strengths := []strengthWithKey{
@@ -318,7 +318,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error {
if len(branches) > 0 {
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 {
key = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key
}
+5 -5
View File
@@ -3,9 +3,9 @@ package controllers
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,
// avoiding the noise of `gocui.NewKeyRune('a')` at every call site. There is an intentionally
// identical helper in the helpers package so that callers in either package can use the unqualified
// form.
func menuKey(r rune) gocui.Key {
return gocui.NewKeyRune(r)
// avoiding the noise of `[]gocui.Key{gocui.NewKeyRune('a')}` at every call site. There is an
// intentionally identical helper in the helpers package so that callers in either package can use
// the unqualified form.
func menuKey(r rune) []gocui.Key {
return []gocui.Key{gocui.NewKeyRune(r)}
}
+1 -1
View File
@@ -27,7 +27,7 @@ func NewPromptController(
func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*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() },
Description: self.c.Tr.Confirm,
DisplayOnScreen: true,
@@ -24,7 +24,7 @@ func NewSearchPromptController(
func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Key: gocui.NewKeyName(gocui.KeyEnter),
Key: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)},
Handler: self.confirm,
},
{
+2 -2
View File
@@ -15,7 +15,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error {
Items: []*types.MenuItem{
{
Label: gui.c.Tr.ToggleShowCommandLog,
Key: gocui.NewKeyRune('t'),
Key: []gocui.Key{gocui.NewKeyRune('t')},
OnPress: func() error {
currentContext := gui.c.Context().CurrentStatic()
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,
Key: gocui.NewKeyRune('f'),
Key: []gocui.Key{gocui.NewKeyRune('f')},
OnPress: gui.handleFocusCommandLog,
},
},
+14 -12
View File
@@ -69,7 +69,7 @@ func (gui *Gui) keybindingOpts() types.KeybindingsOpts {
}
return types.KeybindingsOpts{
GetKey: config.GetValidatedKeyBindingKey,
GetKey: config.GetValidatedKeyBindingKeys,
Config: keybindingConfig,
Guards: guards,
}
@@ -176,7 +176,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
},
{
ViewName: "information",
Key: gocui.NewKeyName(gocui.MouseLeft),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)},
Handler: gui.handleInfoClick,
},
{
@@ -196,26 +196,26 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
},
{
ViewName: "main",
Key: gocui.NewKeyName(gocui.MouseWheelDown),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
Handler: gui.scrollDownMain,
Description: gui.c.Tr.ScrollDown,
Alternative: "fn+up",
},
{
ViewName: "main",
Key: gocui.NewKeyName(gocui.MouseWheelUp),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
Handler: gui.scrollUpMain,
Description: gui.c.Tr.ScrollUp,
Alternative: "fn+down",
},
{
ViewName: "secondary",
Key: gocui.NewKeyName(gocui.MouseWheelDown),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
Handler: gui.scrollDownSecondary,
},
{
ViewName: "secondary",
Key: gocui.NewKeyName(gocui.MouseWheelUp),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
Handler: gui.scrollUpSecondary,
},
{
@@ -240,12 +240,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
},
{
ViewName: "confirmation",
Key: gocui.NewKeyName(gocui.MouseWheelUp),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
Handler: gui.scrollUpConfirmationPanel,
},
{
ViewName: "confirmation",
Key: gocui.NewKeyName(gocui.MouseWheelDown),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
Handler: gui.scrollDownConfirmationPanel,
},
{
@@ -287,12 +287,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
},
{
ViewName: "extras",
Key: gocui.NewKeyName(gocui.MouseWheelUp),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)},
Handler: gui.scrollUpExtra,
},
{
ViewName: "extras",
Key: gocui.NewKeyName(gocui.MouseWheelDown),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)},
Handler: gui.scrollDownExtra,
},
{
@@ -352,7 +352,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
{
ViewName: "extras",
Tag: "navigation",
Key: gocui.NewKeyName(gocui.MouseLeft),
Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)},
Handler: gui.handleFocusCommandLog,
},
}
@@ -448,7 +448,9 @@ func (gui *Gui) SetKeybinding(binding *types.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 {
+4 -2
View File
@@ -46,8 +46,10 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
maxColumnSize = max(maxColumnSize, len(item.LabelColumns))
// Remove all item keybindings that are the same as one of the essential bindings
if !opts.KeepConflictingKeybindings && lo.Contains(essentialKeys, item.Key) {
item.Key = gocui.Key{}
if !opts.KeepConflictingKeybindings {
item.Key = lo.Filter(item.Key, func(k gocui.Key, _ int) bool {
return !lo.Contains(essentialKeys, k)
})
}
}
+3 -3
View File
@@ -41,12 +41,12 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
globalBindings := self.c.Contexts().Global.GetKeybindings(self.c.KeybindingsOpts())
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
}))
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 {
@@ -60,7 +60,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
}
return bindingInfo{
key: config.LabelForKey(binding.Key),
key: config.LabelForKey(binding.Key[0]),
description: binding.GetShortDescription(),
style: displayStyle,
}
+4 -3
View File
@@ -2,6 +2,7 @@ package custom_commands
import (
"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/types"
"github.com/jesseduffield/lazygit/pkg/i18n"
@@ -45,7 +46,7 @@ func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) {
}
bindings = append(bindings, &types.Binding{
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,
Description: getCustomCommandsMenuDescription(customCommand, self.c.Tr),
OpensMenu: true,
@@ -72,7 +73,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
}
menuItems = append(menuItems, &types.MenuItem{
Label: subCommand.GetDescription(),
Key: config.GetValidatedKeyBindingKey(subCommand.Key),
Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
OnPress: handler,
OpensMenu: true,
})
@@ -92,7 +93,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
menuItems = append(menuItems, &types.MenuItem{
Label: subCommand.GetDescription(),
Key: config.GetValidatedKeyBindingKey(subCommand.Key),
Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
OnPress: self.handlerCreator.call(subCommand),
})
}
@@ -232,7 +232,7 @@ func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrapp
OnPress: func() error {
return wrappedF(option.Value)
},
Key: config.GetValidatedKeyBindingKey(option.Key),
Key: []gocui.Key{config.GetValidatedKeyBindingKey(option.Key)},
}
})
@@ -5,6 +5,7 @@ import (
"strings"
"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/controllers/helpers"
"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 &types.Binding{
ViewName: viewName,
Key: config.GetValidatedKeyBindingKey(customCommand.Key),
Key: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)},
Handler: handler,
Description: customCommand.GetDescription(),
}
+4 -3
View File
@@ -259,9 +259,10 @@ type MenuItem struct {
// Only applies when Label is used
OpensMenu bool
// If Key is defined it allows the user to press the key to invoke the menu
// item, as opposed to having to navigate to it
Key gocui.Key
// If Key is non-empty, the user can press any of these keys to invoke the
// menu item, as opposed to having to navigate to it. Only the first key is
// 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
// checkboxes and radio buttons,
+1 -1
View File
@@ -239,7 +239,7 @@ type OnFocusLostOpts struct {
type ContextKey string
type KeybindingsOpts struct {
GetKey func(key string) gocui.Key
GetKey func(key string) []gocui.Key
Config config.KeybindingConfig
Guards KeybindingGuards
}
+1 -1
View File
@@ -11,7 +11,7 @@ import (
type Binding struct {
ViewName string
Handler func() error
Key gocui.Key
Key []gocui.Key
Description string
// 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.