Convert custom command Key fields to Keybinding

CustomCommand.Key and CustomCommandMenuOption.Key are user-configured
keybindings just like the built-in ones. Converting them to the Keybinding type
lets a user assign multiple keys to the same custom command, e.g. `key: [a, b]`,
the same way they would for any other keybinding.

The validator iterates over the elements rather than checking a single string,
the binding registration goes through GetValidatedKeyBindingKeys to register
every alternate, and the existing error messages use .String() so a multi-key
binding renders sensibly.

CustomCommandPrompt.Key (a form field name, not a keybinding) stays a plain
string.
This commit is contained in:
Stefan Haller
2026-05-25 15:32:47 +02:00
parent 3ecca88bd8
commit fbcf562e29
36 changed files with 103 additions and 81 deletions
+4 -4
View File
@@ -667,8 +667,8 @@ type CustomCommandAfterHook struct {
}
type CustomCommand struct {
// The key to trigger the command. Use a single letter or one of the values from https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md
Key string `yaml:"key"`
// The key to trigger the command. Use a single letter or one of the values from https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md. To bind several alternates to the same command, use a sequence (e.g. `[a, b]`).
Key Keybinding `yaml:"key"`
// Instead of defining a single custom command, create a menu of custom commands. Useful for grouping related commands together under a single keybinding, and for keeping them out of the global keybindings menu.
// When using this, all other fields except Key and Description are ignored and must be empty.
CommandMenu []CustomCommand `yaml:"commandMenu"`
@@ -753,8 +753,8 @@ type CustomCommandMenuOption struct {
Description string `yaml:"description"`
// The value that will be used in the command
Value string `yaml:"value" jsonschema:"example=feature,minLength=1"`
// Keybinding to invoke this menu option without needing to navigate to it
Key string `yaml:"key"`
// Keybinding to invoke this menu option without needing to navigate to it. Accepts either a single key or a sequence of alternates.
Key Keybinding `yaml:"key"`
}
type CustomIconsConfig struct {
+12 -8
View File
@@ -126,10 +126,12 @@ func validateKeybindings(keybindingConfig KeybindingConfig) error {
return nil
}
func validateCustomCommandKey(key string) error {
if !isValidKeybindingKey(key) {
return fmt.Errorf("Unrecognized key '%s' for custom command. For permitted values see %s",
key, constants.Links.Docs.CustomKeybindings)
func validateCustomCommandKey(key Keybinding) error {
for _, k := range key {
if !isValidKeybindingKey(k) {
return fmt.Errorf("Unrecognized key '%s' for custom command. For permitted values see %s",
k, constants.Links.Docs.CustomKeybindings)
}
}
return nil
}
@@ -150,7 +152,7 @@ func validateCustomCommands(customCommands []CustomCommand) error {
customCommand.After != nil {
commandRef := ""
if len(customCommand.Key) > 0 {
commandRef = fmt.Sprintf(" with key '%s'", customCommand.Key)
commandRef = fmt.Sprintf(" with key '%s'", customCommand.Key.String())
}
return fmt.Errorf("Error with custom command%s: it is not allowed to use both commandMenu and any of the other fields except key and description.", commandRef)
}
@@ -176,9 +178,11 @@ func validateCustomCommands(customCommands []CustomCommand) error {
func validateCustomCommandPrompt(prompt CustomCommandPrompt) error {
for _, option := range prompt.Options {
if !isValidKeybindingKey(option.Key) {
return fmt.Errorf("Unrecognized key '%s' for custom command prompt option. For permitted values see %s",
option.Key, constants.Links.Docs.CustomKeybindings)
for _, k := range option.Key {
if !isValidKeybindingKey(k) {
return fmt.Errorf("Unrecognized key '%s' for custom command prompt option. For permitted values see %s",
k, constants.Links.Docs.CustomKeybindings)
}
}
}
+11 -11
View File
@@ -146,7 +146,7 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, value string) {
config.CustomCommands = []CustomCommand{
{
Key: value,
Key: Keybinding{value},
Command: "echo 'hello'",
},
}
@@ -164,10 +164,10 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, value string) {
config.CustomCommands = []CustomCommand{
{
Key: "X",
Key: Keybinding{"X"},
Description: "My Custom Commands",
CommandMenu: []CustomCommand{
{Key: value, Command: "echo 'hello'", Context: "global"},
{Key: Keybinding{value}, Command: "echo 'hello'", Context: "global"},
},
},
}
@@ -185,12 +185,12 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, value string) {
config.CustomCommands = []CustomCommand{
{
Key: "X",
Key: Keybinding{"X"},
Description: "My Custom Commands",
Prompts: []CustomCommandPrompt{
{
Options: []CustomCommandMenuOption{
{Key: value},
{Key: Keybinding{value}},
},
},
},
@@ -229,10 +229,10 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, _ string) {
config.CustomCommands = []CustomCommand{
{
Key: "X",
Key: Keybinding{"X"},
Description: "My Custom Commands",
CommandMenu: []CustomCommand{
{Key: "1", Command: "echo 'hello'", Context: "global"},
{Key: Keybinding{"1"}, Command: "echo 'hello'", Context: "global"},
},
},
}
@@ -246,10 +246,10 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, _ string) {
config.CustomCommands = []CustomCommand{
{
Key: "X",
Key: Keybinding{"X"},
Context: "global", // context is not allowed for submenus
CommandMenu: []CustomCommand{
{Key: "1", Command: "echo 'hello'", Context: "global"},
{Key: Keybinding{"1"}, Command: "echo 'hello'", Context: "global"},
},
},
}
@@ -263,10 +263,10 @@ func TestUserConfigValidate_enums(t *testing.T) {
setup: func(config *UserConfig, _ string) {
config.CustomCommands = []CustomCommand{
{
Key: "X",
Key: Keybinding{"X"},
LoadingText: "loading", // other properties are not allowed for submenus (using loadingText as an example)
CommandMenu: []CustomCommand{
{Key: "1", Command: "echo 'hello'", Context: "global"},
{Key: Keybinding{"1"}, Command: "echo 'hello'", Context: "global"},
},
},
}
+3 -4
View File
@@ -2,7 +2,6 @@ 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"
@@ -46,7 +45,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
Keys: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)},
Keys: config.GetValidatedKeyBindingKeys(customCommand.Key),
Handler: handler,
Description: getCustomCommandsMenuDescription(customCommand, self.c.Tr),
OpensMenu: true,
@@ -73,7 +72,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
}
menuItems = append(menuItems, &types.MenuItem{
Label: subCommand.GetDescription(),
Keys: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
Keys: config.GetValidatedKeyBindingKeys(subCommand.Key),
OnPress: handler,
OpensMenu: true,
})
@@ -93,7 +92,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e
menuItems = append(menuItems, &types.MenuItem{
Label: subCommand.GetDescription(),
Keys: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)},
Keys: config.GetValidatedKeyBindingKeys(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)
},
Keys: []gocui.Key{config.GetValidatedKeyBindingKey(option.Key)},
Keys: config.GetValidatedKeyBindingKeys(option.Key),
}
})
@@ -5,7 +5,6 @@ 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"
@@ -36,7 +35,7 @@ func (self *KeybindingCreator) call(customCommand config.CustomCommand, handler
return lo.Map(viewNames, func(viewName string, _ int) *types.Binding {
return &types.Binding{
ViewName: viewName,
Keys: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)},
Keys: config.GetValidatedKeyBindingKeys(customCommand.Key),
Handler: handler,
Description: customCommand.GetDescription(),
}
@@ -81,9 +80,9 @@ func formatUnknownContextError(customCommand config.CustomCommand) error {
return string(key)
})
return fmt.Errorf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", "))
return fmt.Errorf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key.String(), customCommand.Command, strings.Join(allContextKeyStrings, ", "))
}
func formatContextNotProvidedError(customCommand config.CustomCommand) error {
return fmt.Errorf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key, customCommand.Command)
return fmt.Errorf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key.String(), customCommand.Command)
}
@@ -17,12 +17,12 @@ var CustomCommandsInPerRepoConfig = NewIntegrationTest(NewIntegrationTestArgs{
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "global",
Command: "printf 'global X' > file.txt",
},
{
Key: "Y",
Key: config.Keybinding{"Y"},
Context: "global",
Command: "printf 'global Y' > file.txt",
},
@@ -17,7 +17,7 @@ var AccessCommitProperties = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "commits",
Command: "printf '%s\n%s\n%s' '{{ .SelectedLocalCommit.Name }}' '{{ .SelectedLocalCommit.Hash }}' '{{ .SelectedLocalCommit.Sha }}' > file.txt",
},
@@ -15,7 +15,7 @@ var BasicCommand = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: "touch myfile",
},
@@ -16,7 +16,7 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "m",
Key: config.Keybinding{"m"},
Context: "localBranches",
Command: "git merge {{ .SelectedLocalBranch.Name | quote }}",
After: &config.CustomCommandAfterHook{
@@ -15,7 +15,7 @@ var ConditionalPromptFalseString = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo "{{.Form.Choice}}" > result.txt`,
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var ConditionalPromptFalseValue = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo "{{.Form.Word}} {{.Form.Extra}}" > result.txt`,
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo "{{.Form.Choice}}{{if .Form.Detail}} {{.Form.Detail}}{{end}}" > result.txt`,
Prompts: []config.CustomCommandPrompt{
@@ -28,13 +28,13 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{
Name: "first",
Description: "First option",
Value: "FIRST",
Key: "1",
Key: config.Keybinding{"1"},
},
{
Name: "second",
Description: "Second option",
Value: "SECOND",
Key: "H",
Key: config.Keybinding{"H"},
},
},
},
@@ -13,21 +13,21 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "x",
Key: config.Keybinding{"x"},
Description: "My Custom Commands",
CommandMenu: []config.CustomCommand{
{
Key: "1",
Key: config.Keybinding{"1"},
Context: "global",
Command: "touch myfile-global",
},
{
Key: "2",
Key: config.Keybinding{"2"},
Context: "files",
Command: "touch myfile-files",
},
{
Key: "3",
Key: config.Keybinding{"3"},
Context: "commits",
Command: "touch myfile-commits",
},
@@ -13,29 +13,29 @@ var CustomCommandsSubmenuWithSpecialKeybindings = NewIntegrationTest(NewIntegrat
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "x",
Key: config.Keybinding{"x"},
Description: "My Custom Commands",
CommandMenu: []config.CustomCommand{
{
Key: "j",
Key: config.Keybinding{"j"},
Context: "global",
Command: "echo j",
Output: "popup",
},
{
Key: "H",
Key: config.Keybinding{"H"},
Context: "global",
Command: "echo H",
Output: "popup",
},
{
Key: "y",
Key: config.Keybinding{"y"},
Context: "global",
Command: "echo y",
Output: "popup",
},
{
Key: "<down>",
Key: config.Keybinding{"<down>"},
Context: "global",
Command: "echo down",
Output: "popup",
@@ -15,7 +15,7 @@ var FormPrompts = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo {{.Form.FileContent | quote}} > {{.Form.FileName | quote}}`,
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "global",
Command: "touch myfile",
},
@@ -21,7 +21,7 @@ var MenuFromCommand = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: `echo "{{index .PromptResponses 0}} {{index .PromptResponses 1}} {{ .SelectedLocalBranch.Name }}" > output.txt`,
Prompts: []config.CustomCommandPrompt{
@@ -20,7 +20,7 @@ var MenuFromCommandsOutput = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: "git checkout {{ index .PromptResponses 1 }}",
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var MenuPromptWithKeys = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo {{.Form.Choice | quote}} > result.txt`,
Prompts: []config.CustomCommandPrompt{
@@ -28,19 +28,19 @@ var MenuPromptWithKeys = NewIntegrationTest(NewIntegrationTestArgs{
Name: "first",
Description: "First option",
Value: "FIRST",
Key: "1",
Key: config.Keybinding{"1"},
},
{
Name: "second",
Description: "Second option",
Value: "SECOND",
Key: "H",
Key: config.Keybinding{"H"},
},
{
Name: "third",
Description: "Third option",
Value: "THIRD",
Key: "3",
Key: config.Keybinding{"3"},
},
},
},
@@ -15,7 +15,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "commits, reflogCommits",
Command: "touch myfile",
},
@@ -15,7 +15,7 @@ var MultiplePrompts = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "files",
Command: `echo "{{index .PromptResponses 1}}" > {{index .PromptResponses 0}}`,
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var RunCommand = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: `git checkout {{.Form.Branch}}`,
Prompts: []config.CustomCommandPrompt{
@@ -15,7 +15,7 @@ var SelectedCommit = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "global",
Command: "printf '%s' '{{ .SelectedCommit.Name }}' > file.txt",
},
@@ -15,7 +15,7 @@ var SelectedCommitRange = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "global",
Command: `git log --format="%s" {{.SelectedCommitRange.From}}^..{{.SelectedCommitRange.To}} > file.txt`,
},
@@ -19,7 +19,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "global",
Command: "printf '%s' '{{ .SelectedPath }}' > file.txt",
},
@@ -17,17 +17,17 @@ var SelectedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "submodules",
Command: "printf '%s' '{{ .SelectedSubmodule.Path }}' > file.txt",
},
{
Key: "U",
Key: config.Keybinding{"U"},
Context: "submodules",
Command: "printf '%s' '{{ .SelectedSubmodule.Url }}' > file.txt",
},
{
Key: "N",
Key: config.Keybinding{"N"},
Context: "submodules",
Command: "printf '%s' '{{ .SelectedSubmodule.Name }}' > file.txt",
},
@@ -17,13 +17,13 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "commits",
Command: "printf '%s' '{{ .SelectedLocalCommit.Name }}'",
Output: "popup",
},
{
Key: "Y",
Key: config.Keybinding{"Y"},
Context: "commits",
Command: "printf '%s' '{{ .SelectedLocalCommit.Name }}'",
Output: "popup",
@@ -22,7 +22,7 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: `git checkout {{.Form.Branch}}`,
Prompts: []config.CustomCommandPrompt{
@@ -22,7 +22,7 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: `git checkout {{.Form.Branch}}`,
Prompts: []config.CustomCommandPrompt{
+1 -1
View File
@@ -28,7 +28,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "a",
Key: config.Keybinding{"a"},
Context: "localBranches",
Command: `git checkout {{.Form.Branch}}`,
Prompts: []config.CustomCommandPrompt{
@@ -12,7 +12,7 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "X",
Key: config.Keybinding{"X"},
Context: "commits",
Command: "git -c core.editor=: rebase -i -x false HEAD^^",
},
+1 -1
View File
@@ -12,7 +12,7 @@ var Enter = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "e",
Key: config.Keybinding{"e"},
Context: "files",
Command: "git commit --allow-empty -m \"empty commit\"",
},
+1 -1
View File
@@ -12,7 +12,7 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "e",
Key: config.Keybinding{"e"},
Context: "files",
Command: "git commit --allow-empty -m \"empty commit\" && echo \"my_file content\" > my_file",
},
@@ -12,7 +12,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
{
Key: "d",
Key: config.Keybinding{"d"},
Context: "worktrees",
Command: "git worktree remove {{ .SelectedWorktree.Path | quote }}",
},
+24 -4
View File
@@ -60,8 +60,18 @@
"CustomCommand": {
"properties": {
"key": {
"type": "string",
"description": "The key to trigger the command. Use a single letter or one of the values from https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md"
"oneOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "The key to trigger the command. Use a single letter or one of the values from https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md. To bind several alternates to the same command, use a sequence (e.g. `[a, b]`)."
},
"commandMenu": {
"items": {
@@ -165,8 +175,18 @@
]
},
"key": {
"type": "string",
"description": "Keybinding to invoke this menu option without needing to navigate to it"
"oneOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "Keybinding to invoke this menu option without needing to navigate to it. Accepts either a single key or a sequence of alternates."
}
},
"additionalProperties": false,