From 880064b9870e6b494fb06d6fb95c8559d61f6f39 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 25 May 2026 15:16:25 +0200 Subject: [PATCH 01/17] Use the isolated test env for shell commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shell.RunShellCommand was passing os.Environ() to its child, while its sibling runCommandWithOutputAndEnv has used the minimal NewTestEnvironment since late 2023 when env isolation was introduced; the sh path was just missed. This matters when integration tests run from inside a `git rebase -x` exec in a linked worktree: git sets GIT_DIR=
/.git/worktrees/ for the exec, and it leaks all the way down through bash, just, go test, and the test process, into every git invocation RunShellCommand spawns. cmd.Dir becomes irrelevant — git resolves GIT_DIR over cwd-based discovery, with the work-tree taken from the gitdir file (i.e. the worktree root). So `git checkout -b conflict` in a test fixture creates the branch on the real worktree and switches its HEAD, hijacking the in-progress rebase and trashing the working tree. (In the main worktree git doesn't set GIT_DIR for rebase exec, which is why the bug was only visible from linked worktrees.) Using self.env also incidentally restores GIT_CONFIG_GLOBAL for shell commands, so commits made via RunShellCommand are now authored by the test config's CI identity rather than whatever the host's ~/.gitconfig resolves to. --- pkg/integration/components/shell.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go index 2e5fa01ce..70b12146a 100644 --- a/pkg/integration/components/shell.go +++ b/pkg/integration/components/shell.go @@ -77,7 +77,7 @@ func (self *Shell) RunShellCommand(cmdStr string) *Shell { } cmd := exec.Command(shell, shellArg, cmdStr) - cmd.Env = os.Environ() + cmd.Env = self.env cmd.Dir = self.dir output, err := cmd.CombinedOutput() From 5bd91977ee39c7274200a52c5b494398748306fe Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 25 May 2026 12:49:54 +0200 Subject: [PATCH 02/17] Add script for checking all commits in a branch --- scripts/check_commit.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 scripts/check_commit.sh diff --git a/scripts/check_commit.sh b/scripts/check_commit.sh new file mode 100755 index 000000000..9cc5e5c7b --- /dev/null +++ b/scripts/check_commit.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Run some tests on the current commit, similar to what CI does; useful for +# checking every commit in a branch with `git rebase -x scripts/check_commit.sh master`. + +set -e + +git diff --quiet || { + echo "Error: there are unstaged changes. Please stage or stash them before running this script." + exit 1 +} + +just test +just lint +just generate +git diff --quiet || { + echo "Error: auto-generated files not up to date." + exit 1 +} From 5a363578b4bd2fc35c86a51d9316872d75cec0a5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 17 May 2026 15:37:48 +0200 Subject: [PATCH 03/17] Remove unused text KeybindingsLegend Should have been removed in 74a6ea85c82. --- pkg/i18n/english.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 31b18dca0..ea8e42da4 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -614,7 +614,6 @@ type TranslationSet struct { SelectRemoteRepository string FetchingPullRequests string Keybindings string - KeybindingsLegend string KeybindingsMenuSectionLocal string KeybindingsMenuSectionGlobal string KeybindingsMenuSectionNavigation string From 3c279614bf26c34c32f3cb418474249723c4ce4c Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 12 May 2026 09:25:19 +0200 Subject: [PATCH 04/17] Change SetKeybinding to not return an error It always returned nil. --- pkg/gocui/gui.go | 3 +- pkg/gui/keybindings.go | 8 ++-- pkg/integration/clients/tui.go | 74 +++++++++++----------------------- 3 files changed, 28 insertions(+), 57 deletions(-) diff --git a/pkg/gocui/gui.go b/pkg/gocui/gui.go index 645329d6b..579dfe21d 100644 --- a/pkg/gocui/gui.go +++ b/pkg/gocui/gui.go @@ -546,10 +546,9 @@ func (g *Gui) CurrentView() *View { // SetKeybinding creates a new keybinding. If viewname equals to "" // (empty string) then the keybinding will apply to all views. key must // be a rune or a Key. -func (g *Gui) SetKeybinding(viewname string, key Key, handler func(*Gui, *View) error) error { +func (g *Gui) SetKeybinding(viewname string, key Key, handler func(*Gui, *View) error) { kb := newKeybinding(viewname, key, handler) g.keybindings = append(g.keybindings, kb) - return nil } // DeleteKeybindings deletes all keybindings of view. diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 082d99ecc..11a3fbc6a 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -418,9 +418,7 @@ func (gui *Gui) resetKeybindings() error { bindings, mouseBindings := gui.GetInitialKeybindingsWithCustomCommands() for _, binding := range bindings { - if err := gui.SetKeybinding(binding); err != nil { - return err - } + gui.SetKeybinding(binding) } for _, binding := range mouseBindings { @@ -445,12 +443,12 @@ func (gui *Gui) resetKeybindings() error { return nil } -func (gui *Gui) SetKeybinding(binding *types.Binding) error { +func (gui *Gui) SetKeybinding(binding *types.Binding) { handler := func(g *gocui.Gui, v *gocui.View) error { return gui.callKeybindingHandler(binding) } - return gui.g.SetKeybinding(binding.ViewName, binding.Key, handler) + gui.g.SetKeybinding(binding.ViewName, binding.Key, handler) } func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error { diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index c4f8f94ab..0f07b5b19 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -43,7 +43,7 @@ func RunTUI(raceDetector bool) { g.SetManagerFunc(app.layout) - if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowUp), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowUp), func(*gocui.Gui, *gocui.View) error { if app.itemIdx > 0 { app.itemIdx-- } @@ -53,11 +53,9 @@ func RunTUI(raceDetector bool) { } listView.FocusPoint(0, app.itemIdx, true) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowDown), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowDown), func(*gocui.Gui, *gocui.View) error { if app.itemIdx < len(app.filteredTests)-1 { app.itemIdx++ } @@ -68,19 +66,13 @@ func RunTUI(raceDetector bool) { } listView.FocusPoint(0, app.itemIdx, true) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyStrMod("c", gocui.ModCtrl), quit); err != nil { - log.Panicln(err) - } + g.SetKeybinding("list", gocui.NewKeyStrMod("c", gocui.ModCtrl), quit) - if err := g.SetKeybinding("list", gocui.NewKeyRune('q'), quit); err != nil { - log.Panicln(err) - } + g.SetKeybinding("list", gocui.NewKeyRune('q'), quit) - if err := g.SetKeybinding("list", gocui.NewKeyRune('s'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('s'), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -89,11 +81,9 @@ func RunTUI(raceDetector bool) { suspendAndRunTest(currentTest, true, false, raceDetector, 0) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyEnter), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyEnter), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -102,11 +92,9 @@ func RunTUI(raceDetector bool) { suspendAndRunTest(currentTest, false, false, raceDetector, 0) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyRune('t'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('t'), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -115,11 +103,9 @@ func RunTUI(raceDetector bool) { suspendAndRunTest(currentTest, false, false, raceDetector, SLOW_INPUT_DELAY) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyRune('d'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('d'), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -128,11 +114,9 @@ func RunTUI(raceDetector bool) { suspendAndRunTest(currentTest, false, true, raceDetector, 0) return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyRune('o'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('o'), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -144,11 +128,9 @@ func RunTUI(raceDetector bool) { } return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyRune('O'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('O'), func(*gocui.Gui, *gocui.View) error { currentTest := app.getCurrentTest() if currentTest == nil { return nil @@ -160,11 +142,9 @@ func RunTUI(raceDetector bool) { } return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("list", gocui.NewKeyRune('/'), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("list", gocui.NewKeyRune('/'), func(*gocui.Gui, *gocui.View) error { app.filtering = true if _, err := g.SetCurrentView("editor"); err != nil { return err @@ -176,12 +156,10 @@ func RunTUI(raceDetector bool) { editorView.Clear() return nil - }); err != nil { - log.Panicln(err) - } + }) // not using the editor yet, but will use it to help filter the list - if err := g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEsc), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEsc), func(*gocui.Gui, *gocui.View) error { app.filtering = false if _, err := g.SetCurrentView("list"); err != nil { return err @@ -194,11 +172,9 @@ func RunTUI(raceDetector bool) { app.editorView.Reset() return nil - }); err != nil { - log.Panicln(err) - } + }) - if err := g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEnter), func(*gocui.Gui, *gocui.View) error { + g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEnter), func(*gocui.Gui, *gocui.View) error { app.filtering = false if _, err := g.SetCurrentView("list"); err != nil { @@ -208,9 +184,7 @@ func RunTUI(raceDetector bool) { app.renderTests() return nil - }); err != nil { - log.Panicln(err) - } + }) err = g.MainLoop() g.Close() From 12cfb9be1ffd5ae79ed8feae5ca3a8c17a4e122f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 11 May 2026 09:20:22 +0200 Subject: [PATCH 05/17] Remove OptionMenuAlt1 For legacy reasons, OptionMenu was set to ``, and OptionMenuAlt1 to `?`. This doesn't make a lot of sense any more; get rid of OptionMenuAlt1 and bind OptionMenu to `?` by default. This is a breaking change for users who rebound OptionMenuAlt1 in their config, but it doesn't strike me as very likely, and it's easy enough to fix. --- docs-master/Config.md | 3 +-- pkg/config/user_config.go | 4 +--- pkg/gui/controllers/global_controller.go | 17 +++++------------ .../tests/ui/switch_tab_from_menu.go | 2 +- schema-master/config.json | 4 ---- 5 files changed, 8 insertions(+), 22 deletions(-) diff --git a/docs-master/Config.md b/docs-master/Config.md index 05d3b6d20..b24329548 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -643,8 +643,7 @@ keybinding: # on Mac forwardDeleteWord: - optionMenu: - optionMenu-alt1: '?' + optionMenu: '?' select: goInto: confirm: diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index ddb0c0876..3d59782e5 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -459,7 +459,6 @@ type KeybindingUniversalConfig struct { BackspaceWord string `yaml:"backspaceWord"` // on Mac ForwardDeleteWord string `yaml:"forwardDeleteWord"` // on Mac OptionMenu string `yaml:"optionMenu"` - OptionMenuAlt1 string `yaml:"optionMenu-alt1"` Select string `yaml:"select"` GoInto string `yaml:"goInto"` Confirm string `yaml:"confirm"` @@ -941,8 +940,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig { MoveWordRight: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), BackspaceWord: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), ForwardDeleteWord: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - OptionMenu: "", - OptionMenuAlt1: "?", + OptionMenu: "?", Select: "", GoInto: "", Confirm: "", diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index d7f18fcb4..f8f981525 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -75,21 +75,14 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type DisplayOnScreen: true, }, { - ViewName: "", - Key: opts.GetKey(opts.Config.Universal.OptionMenu), - Handler: self.createOptionsMenu, - OpensMenu: true, - }, - { - ViewName: "", - Key: opts.GetKey(opts.Config.Universal.OptionMenuAlt1), - // we have the description on the alt key and not the main key for legacy reasons - // (the original main key was 'x' but we've reassigned that to other purposes) + ViewName: "", + Key: opts.GetKey(opts.Config.Universal.OptionMenu), Description: self.c.Tr.OpenKeybindingsMenu, - Handler: self.createOptionsMenu, ShortDescription: self.c.Tr.Keybindings, - DisplayOnScreen: true, + Handler: self.createOptionsMenu, GetDisabledReason: self.optionsMenuDisabledReason, + OpensMenu: true, + DisplayOnScreen: true, }, { ViewName: "", diff --git a/pkg/integration/tests/ui/switch_tab_from_menu.go b/pkg/integration/tests/ui/switch_tab_from_menu.go index 61bd991ab..fbcdbd954 100644 --- a/pkg/integration/tests/ui/switch_tab_from_menu.go +++ b/pkg/integration/tests/ui/switch_tab_from_menu.go @@ -14,7 +14,7 @@ var SwitchTabFromMenu = NewIntegrationTest(NewIntegrationTestArgs{ }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Files().IsFocused(). - Press(keys.Universal.OptionMenuAlt1) + Press(keys.Universal.OptionMenu) t.ExpectPopup().Menu().Title(Equals("Keybindings")). Select(Contains("Next tab")). diff --git a/schema-master/config.json b/schema-master/config.json index 549b80877..d6ad8116d 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -1431,10 +1431,6 @@ "default": "\u003cctrl+delete\u003e" }, "optionMenu": { - "type": "string", - "default": "\u003cdisabled\u003e" - }, - "optionMenu-alt1": { "type": "string", "default": "?" }, From 22a508fdba53f7fd9a8d0a450d1fedcc586e329f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 10 May 2026 16:53:33 +0200 Subject: [PATCH 06/17] Add menuKey helper to reduce noise on menu item literals Constructing a menu item key from a literal character requires gocui.NewKeyRune('r'), which is a bit noisy. Add a private menuKey helper in both the controllers and helpers packages so the common case in either reads as menuKey('r'). Duplicating the one-liner is cheaper than a cross-package import dependency and avoids forcing every controller file to qualify the call. The reason for doing this now is that we are going to change MenuItem.Key to a slice of keys later in the branch, which means we'd have to add `[]gocui.Key{` at each call site, making them even more noisy. With the menuKey helper we can just change its signature and leave all clients unchanged. --- .../controllers/basic_commits_controller.go | 15 ++++--- pkg/gui/controllers/bisect_controller.go | 17 ++++---- pkg/gui/controllers/branches_controller.go | 16 ++++---- .../controllers/commits_files_controller.go | 12 +++--- .../custom_patch_options_menu_action.go | 18 ++++----- pkg/gui/controllers/files_controller.go | 40 +++++++++---------- pkg/gui/controllers/git_flow_controller.go | 9 ++--- pkg/gui/controllers/helpers/commits_helper.go | 6 +-- pkg/gui/controllers/helpers/menu_key.go | 11 +++++ .../helpers/merge_and_rebase_helper.go | 26 ++++++------ pkg/gui/controllers/helpers/refs_helper.go | 18 ++++----- .../helpers/working_tree_helper.go | 9 ++--- .../controllers/local_commits_controller.go | 18 ++++----- pkg/gui/controllers/menu_key.go | 11 +++++ pkg/gui/controllers/submodules_controller.go | 8 ++-- pkg/gui/controllers/tags_controller.go | 6 +-- .../controllers/workspace_reset_controller.go | 14 +++---- 17 files changed, 136 insertions(+), 118 deletions(-) create mode 100644 pkg/gui/controllers/helpers/menu_key.go create mode 100644 pkg/gui/controllers/menu_key.go diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index f425addb5..60605cf44 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -6,7 +6,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -164,14 +163,14 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitSubjectToClipboard(commit) }, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), }, { Label: self.c.Tr.CommitMessage, OnPress: func() error { return self.copyCommitMessageToClipboard(commit) }, - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), }, { Label: self.c.Tr.CommitMessageBody, @@ -179,28 +178,28 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitMessageBodyToClipboard(commitMessageBody) }, - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), }, { Label: self.c.Tr.CommitURL, OnPress: func() error { return self.copyCommitURLToClipboard(commit) }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), }, { Label: self.c.Tr.CommitDiff, OnPress: func() error { return self.copyCommitDiffToClipboard(commit) }, - Key: gocui.NewKeyRune('d'), + Key: menuKey('d'), }, { Label: self.c.Tr.CommitAuthor, OnPress: func() error { return self.copyAuthorToClipboard(commit) }, - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), }, } @@ -209,7 +208,7 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitTagsToClipboard(commit) }, - Key: gocui.NewKeyRune('t'), + Key: menuKey('t'), } if len(commit.Tags) == 0 { diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 15c37b88a..d86d34f93 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -6,7 +6,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -102,7 +101,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortHashToMark, info.OldTerm()), @@ -115,7 +114,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: gocui.NewKeyRune('g'), + Key: menuKey('g'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortHashToMark), @@ -128,7 +127,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), }, } if info.GetCurrentHash() != "" && info.GetCurrentHash() != commit.Hash() { @@ -143,7 +142,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('S'), + Key: menuKey('S'), })) } menuItems = append(menuItems, lo.ToPtr(types.MenuItem{ @@ -151,7 +150,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c OnPress: func() error { return self.c.Helpers().Bisect.Reset() }, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), })) return self.c.Menu(types.CreateMenuOptions{ @@ -180,7 +179,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortHash(), info.OldTerm()), @@ -198,7 +197,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('g'), + Key: menuKey('g'), }, { Label: self.c.Tr.Bisect.ChooseTerms, @@ -223,7 +222,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, }) return nil }, - Key: gocui.NewKeyRune('t'), + Key: menuKey('t'), }, }, }) diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 268e94134..9fc595952 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -300,7 +300,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc ) viewDivergenceFromBaseBranchItem := &types.MenuItem{ LabelColumns: []string{label}, - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), OnPress: func() error { branch := self.context().GetSelected() if branch == nil { @@ -333,7 +333,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc }) return nil }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), } setUpstreamItem := &types.MenuItem{ @@ -358,7 +358,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }) }, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), } upstreamResetOptions := utils.ResolvePlaceholderString( @@ -391,7 +391,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }, Tooltip: upstreamResetTooltip, - Key: gocui.NewKeyRune('g'), + Key: menuKey('g'), } upstreamRebaseItem := &types.MenuItem{ @@ -404,7 +404,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }, Tooltip: upstreamRebaseTooltip, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), } if !selectedBranch.IsTrackingRemote() { @@ -624,7 +624,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { localDeleteItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalBranches, self.c.Tr.DeleteLocalBranch), - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), OnPress: func() error { return self.localDelete(branches) }, @@ -635,7 +635,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { remoteDeleteItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteRemoteBranches, self.c.Tr.DeleteRemoteBranch), - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), OnPress: func() error { return self.remoteDelete(branches) }, @@ -648,7 +648,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { deleteBothItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalAndRemoteBranches, self.c.Tr.DeleteLocalAndRemoteBranch), - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), OnPress: func() error { return self.localAndRemoteDelete(branches) }, diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index b12819c39..3d5527293 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -230,7 +230,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('n'), + Key: menuKey('n'), } copyRelativePathItem := &types.MenuItem{ Label: self.c.Tr.CopyRelativeFilePath, @@ -242,7 +242,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('p'), + Key: menuKey('p'), } copyAbsolutePathItem := &types.MenuItem{ Label: self.c.Tr.CopyAbsoluteFilePath, @@ -258,7 +258,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('P'), + Key: menuKey('P'), } copyFileDiffItem := &types.MenuItem{ Label: self.c.Tr.CopySelectedDiff, @@ -266,7 +266,7 @@ func (self *CommitFilesController) openCopyMenu() error { return self.copyDiffToClipboard(node.GetPath(), self.c.Tr.FileDiffCopiedToast) }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), } copyAllDiff := &types.MenuItem{ Label: self.c.Tr.CopyAllFilesDiff, @@ -274,7 +274,7 @@ func (self *CommitFilesController) openCopyMenu() error { return self.copyDiffToClipboard(".", self.c.Tr.AllFilesDiffCopiedToast) }, DisabledReason: self.require(self.itemsSelected())(), - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), } copyFileContentItem := &types.MenuItem{ Label: self.c.Tr.CopyFileContent, @@ -295,7 +295,7 @@ func (self *CommitFilesController) openCopyMenu() error { } return nil }))(), - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), } return self.c.Menu(types.CreateMenuOptions{ diff --git a/pkg/gui/controllers/custom_patch_options_menu_action.go b/pkg/gui/controllers/custom_patch_options_menu_action.go index 9ef990f79..979e048c0 100644 --- a/pkg/gui/controllers/custom_patch_options_menu_action.go +++ b/pkg/gui/controllers/custom_patch_options_menu_action.go @@ -31,19 +31,19 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: self.c.Tr.ResetPatch, Tooltip: self.c.Tr.ResetPatchTooltip, OnPress: self.c.Helpers().PatchBuilding.Reset, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), }, { Label: self.c.Tr.ApplyPatch, Tooltip: self.c.Tr.ApplyPatchTooltip, OnPress: func() error { return self.handleApplyPatch(false) }, - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), }, { Label: self.c.Tr.ApplyPatchInReverse, Tooltip: self.c.Tr.ApplyPatchInReverseTooltip, OnPress: func() error { return self.handleApplyPatch(true) }, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), }, } @@ -53,25 +53,25 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, utils.ShortHash(self.c.Git().Patch.PatchBuilder.To)), Tooltip: self.c.Tr.RemovePatchFromOriginalCommitTooltip, OnPress: self.handleDeletePatchFromCommit, - Key: gocui.NewKeyRune('d'), + Key: menuKey('d'), }, { Label: self.c.Tr.MovePatchOutIntoIndex, Tooltip: self.c.Tr.MovePatchOutIntoIndexTooltip, OnPress: self.handleMovePatchIntoWorkingTree, - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), }, { Label: self.c.Tr.MovePatchIntoNewCommit, Tooltip: self.c.Tr.MovePatchIntoNewCommitTooltip, OnPress: self.handlePullPatchIntoNewCommit, - Key: gocui.NewKeyRune('n'), + Key: menuKey('n'), }, { Label: self.c.Tr.MovePatchIntoNewCommitBefore, Tooltip: self.c.Tr.MovePatchIntoNewCommitBeforeTooltip, OnPress: self.handlePullPatchIntoNewCommitBefore, - Key: gocui.NewKeyRune('N'), + Key: menuKey('N'), }, }...) @@ -93,7 +93,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Hash()), Tooltip: self.c.Tr.MovePatchToSelectedCommitTooltip, OnPress: self.handleMovePatchToSelectedCommit, - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), DisabledReason: disabledReason, }, }, menuItems[1:]..., @@ -107,7 +107,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error { { Label: self.c.Tr.CopyPatchToClipboard, OnPress: func() error { return self.copyPatchToClipboard() }, - Key: gocui.NewKeyRune('y'), + Key: menuKey('y'), }, }...) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index c8d50d54d..5fc1540d2 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -671,14 +671,14 @@ func (self *FilesController) handleNonInlineConflict(file *models.File) error { OnPress: func() error { return handle(self.c.Git().WorkingTree.StageFile, self.c.Tr.Actions.ResolveConflictByKeepingFile) }, - Key: gocui.NewKeyRune('k'), + Key: menuKey('k'), } deleteItem := &types.MenuItem{ Label: self.c.Tr.MergeConflictDeleteFile, OnPress: func() error { return handle(self.c.Git().WorkingTree.RemoveConflictedFile, self.c.Tr.Actions.ResolveConflictByDeletingFile) }, - Key: gocui.NewKeyRune('d'), + Key: menuKey('d'), } items := []*types.MenuItem{} switch file.ShortStatus { @@ -856,7 +856,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error } return nil }, - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), }, { LabelColumns: []string{self.c.Tr.ExcludeFile}, @@ -866,7 +866,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error } return nil }, - Key: gocui.NewKeyRune('e'), + Key: menuKey('e'), }, }, }) @@ -950,7 +950,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayStaged) }, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged), }, { @@ -958,7 +958,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayUnstaged) }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged), }, { @@ -966,7 +966,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayTracked) }, - Key: gocui.NewKeyRune('t'), + Key: menuKey('t'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked), }, { @@ -974,7 +974,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayUntracked) }, - Key: gocui.NewKeyRune('T'), + Key: menuKey('T'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUntracked), }, { @@ -982,7 +982,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayAll) }, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayAll), }, }, @@ -1092,7 +1092,7 @@ func (self *FilesController) createStashMenu() error { } return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashAllChanges) }, - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), }, { Label: self.c.Tr.StashAllChangesKeepIndex, @@ -1103,14 +1103,14 @@ func (self *FilesController) createStashMenu() error { // if there are no staged files it behaves the same as Stash.Save return self.handleStashSave(self.c.Git().Stash.StashAndKeepIndex, self.c.Tr.Actions.StashAllChangesKeepIndex) }, - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), }, { Label: self.c.Tr.StashIncludeUntrackedChanges, OnPress: func() error { return self.handleStashSave(self.c.Git().Stash.StashIncludeUntrackedChanges, self.c.Tr.Actions.StashIncludeUntrackedChanges) }, - Key: gocui.NewKeyRune('U'), + Key: menuKey('U'), }, { Label: self.c.Tr.StashStagedChanges, @@ -1121,7 +1121,7 @@ func (self *FilesController) createStashMenu() error { } return self.handleStashSave(self.c.Git().Stash.SaveStagedChanges, self.c.Tr.Actions.StashStagedChanges) }, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), }, { Label: self.c.Tr.StashUnstagedChanges, @@ -1135,7 +1135,7 @@ func (self *FilesController) createStashMenu() error { // ordinary stash return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashUnstagedChanges) }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), }, }, }) @@ -1182,7 +1182,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('n'), + Key: menuKey('n'), } copyRelativePathItem := &types.MenuItem{ Label: self.c.Tr.CopyRelativeFilePath, @@ -1194,7 +1194,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('p'), + Key: menuKey('p'), } copyAbsolutePathItem := &types.MenuItem{ Label: self.c.Tr.CopyAbsoluteFilePath, @@ -1210,7 +1210,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: gocui.NewKeyRune('P'), + Key: menuKey('P'), } copyFileDiffItem := &types.MenuItem{ Label: self.c.Tr.CopySelectedDiff, @@ -1236,7 +1236,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, ))(), - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), } copyAllDiff := &types.MenuItem{ Label: self.c.Tr.CopyAllFilesDiff, @@ -1261,7 +1261,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, )(), - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), } return self.c.Menu(types.CreateMenuOptions{ @@ -1528,7 +1528,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error { self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}}) return nil }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.DiscardUnstagedTooltip, map[string]string{ diff --git a/pkg/gui/controllers/git_flow_controller.go b/pkg/gui/controllers/git_flow_controller.go index 2fcb4e5f5..6e6bec95d 100644 --- a/pkg/gui/controllers/git_flow_controller.go +++ b/pkg/gui/controllers/git_flow_controller.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -83,22 +82,22 @@ func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) er { Label: "start feature", OnPress: startHandler("feature"), - Key: gocui.NewKeyRune('f'), + Key: menuKey('f'), }, { Label: "start hotfix", OnPress: startHandler("hotfix"), - Key: gocui.NewKeyRune('h'), + Key: menuKey('h'), }, { Label: "start bugfix", OnPress: startHandler("bugfix"), - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), }, { Label: "start release", OnPress: startHandler("release"), - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), }, }, }) diff --git a/pkg/gui/controllers/helpers/commits_helper.go b/pkg/gui/controllers/helpers/commits_helper.go index 810861401..c9b21250a 100644 --- a/pkg/gui/controllers/helpers/commits_helper.go +++ b/pkg/gui/controllers/helpers/commits_helper.go @@ -228,7 +228,7 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S OnPress: func() error { return self.SwitchToEditor() }, - Key: gocui.NewKeyRune('e'), + Key: menuKey('e'), DisabledReason: disabledReasonForOpenInEditor, }, { @@ -236,14 +236,14 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S OnPress: func() error { return self.addCoAuthor(suggestionFunc) }, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), }, { Label: self.c.Tr.PasteCommitMessageFromClipboard, OnPress: func() error { return self.pasteCommitMessageFromClipboard() }, - Key: gocui.NewKeyRune('p'), + Key: menuKey('p'), }, } return self.c.Menu(types.CreateMenuOptions{ diff --git a/pkg/gui/controllers/helpers/menu_key.go b/pkg/gui/controllers/helpers/menu_key.go new file mode 100644 index 000000000..7b43a66fc --- /dev/null +++ b/pkg/gui/controllers/helpers/menu_key.go @@ -0,0 +1,11 @@ +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) +} diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 986f61b16..ae042b8cb 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -43,13 +43,13 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { } options := []optionAndKey{ - {option: REBASE_OPTION_CONTINUE, key: gocui.NewKeyRune('c')}, - {option: REBASE_OPTION_ABORT, key: gocui.NewKeyRune('a')}, + {option: REBASE_OPTION_CONTINUE, key: menuKey('c')}, + {option: REBASE_OPTION_ABORT, key: menuKey('a')}, } if self.c.Git().Status.WorkingTreeState().CanSkip() { options = append(options, optionAndKey{ - option: REBASE_OPTION_SKIP, key: gocui.NewKeyRune('s'), + option: REBASE_OPTION_SKIP, key: menuKey('s'), }) } @@ -198,7 +198,7 @@ func (self *MergeAndRebaseHelper) PromptForConflictHandling() error { OnPress: func() error { return self.genericMergeCommand(REBASE_OPTION_ABORT) }, - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), }, }, HideCancel: true, @@ -284,7 +284,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.SimpleRebase, map[string]string{"ref": ref}, ), - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), DisabledReason: disabledReason, OnPress: func() error { self.c.LogAction(self.c.Tr.Actions.RebaseBranch) @@ -308,7 +308,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.InteractiveRebase, map[string]string{"ref": ref}, ), - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), DisabledReason: disabledReason, Tooltip: self.c.Tr.InteractiveRebaseTooltip, OnPress: func() error { @@ -334,7 +334,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.RebaseOntoBaseBranch, map[string]string{"baseBranch": ShortBranchName(baseBranch)}, ), - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), DisabledReason: baseBranchDisabledReason, Tooltip: self.c.Tr.RebaseOntoBaseBranchTooltip, OnPress: func() error { @@ -392,7 +392,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e firstRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR), - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeFastForwardTooltip, map[string]string{ @@ -406,7 +406,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e secondRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeNonFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_NON_FAST_FORWARD), - Key: gocui.NewKeyRune('n'), + Key: menuKey('n'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeNonFastForwardTooltip, map[string]string{ @@ -419,7 +419,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e firstRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeNonFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR), - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeNonFastForwardTooltip, map[string]string{ @@ -432,7 +432,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e secondRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_FAST_FORWARD), - Key: gocui.NewKeyRune('f'), + Key: menuKey('f'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeFastForwardTooltip, map[string]string{ @@ -464,7 +464,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e { Label: self.c.Tr.SquashMergeUncommitted, OnPress: self.SquashMergeUncommitted(refName), - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.SquashMergeUncommittedTooltip, map[string]string{ @@ -475,7 +475,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e { Label: self.c.Tr.SquashMergeCommitted, OnPress: self.SquashMergeCommitted(refName, checkedOutBranchName), - Key: gocui.NewKeyRune('S'), + Key: menuKey('S'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.SquashMergeCommittedTooltip, map[string]string{ diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 43c8c93c6..6771bf301 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -222,9 +222,9 @@ func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, menuPromp sortOrder string } availableSortOptions := map[string]sortMenuOption{ - "recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, key: gocui.NewKeyRune('r')}, - "alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", key: gocui.NewKeyRune('a')}, - "date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", key: gocui.NewKeyRune('d')}, + "recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, key: menuKey('r')}, + "alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", key: menuKey('a')}, + "date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", key: menuKey('d')}, } sortOptions := make([]sortMenuOption, 0, len(sortOptionsOrder)) for _, key := range sortOptionsOrder { @@ -265,9 +265,9 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error { } strengths := []strengthWithKey{ // not i18'ing because it's git terminology - {strength: "mixed", label: "Mixed reset", key: gocui.NewKeyRune('m'), tooltip: self.c.Tr.ResetMixedTooltip}, - {strength: "soft", label: "Soft reset", key: gocui.NewKeyRune('s'), tooltip: self.c.Tr.ResetSoftTooltip}, - {strength: "hard", label: "Hard reset", key: gocui.NewKeyRune('h'), tooltip: self.c.Tr.ResetHardTooltip}, + {strength: "mixed", label: "Mixed reset", key: menuKey('m'), tooltip: self.c.Tr.ResetMixedTooltip}, + {strength: "soft", label: "Soft reset", key: menuKey('s'), tooltip: self.c.Tr.ResetSoftTooltip}, + {strength: "hard", label: "Hard reset", key: menuKey('h'), tooltip: self.c.Tr.ResetHardTooltip}, } menuItems := lo.Map(strengths, func(row strengthWithKey, _ int) *types.MenuItem { @@ -312,7 +312,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) return self.CheckoutRef(hash, types.CheckoutRefOptions{}) }, - Key: gocui.NewKeyRune('d'), + Key: menuKey('d'), }, } @@ -320,7 +320,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem { var key gocui.Key if index < 9 { - key = gocui.NewKeyRune(rune(index + 1 + '0')) // Convert 1-based index to key + key = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key } return &types.MenuItem{ LabelColumns: []string{fmt.Sprintf(self.c.Tr.Actions.CheckoutBranchAtCommit, branch.Name)}, @@ -336,7 +336,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { LabelColumns: []string{self.c.Tr.Actions.CheckoutBranch}, OnPress: func() error { return nil }, DisabledReason: &types.DisabledReason{Text: self.c.Tr.NoBranchesFoundAtCommitTooltip}, - Key: gocui.NewKeyRune('1'), + Key: menuKey('1'), }) } diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 28aeb56f6..dba2341a7 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -10,7 +10,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "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/style" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -383,7 +382,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--ours") }, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), }, { LabelColumns: []string{ @@ -393,7 +392,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--theirs") }, - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), }, { LabelColumns: []string{ @@ -403,7 +402,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--union") }, - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), }, { LabelColumns: []string{ @@ -411,7 +410,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin cmdColor.Sprint("git mergetool"), }, OnPress: self.OpenMergeTool, - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), }, }, }) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 31c746750..0683147b9 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -361,7 +361,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star Items: []*types.MenuItem{ { Label: self.c.Tr.Fixup, - Key: gocui.NewKeyRune('f'), + Key: menuKey('f'), OnPress: func() error { return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error { self.c.LogAction(self.c.Tr.Actions.FixupCommit) @@ -372,7 +372,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star }, { Label: self.c.Tr.FixupKeepMessage, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), OnPress: func() error { return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error { self.c.LogAction(self.c.Tr.Actions.FixupCommitKeepMessage) @@ -403,7 +403,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error Items: []*types.MenuItem{ { Label: self.c.Tr.FixupDiscardMessage, - Key: gocui.NewKeyRune('f'), + Key: menuKey('f'), OnPress: func() error { return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "") }, @@ -411,7 +411,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error }, { Label: self.c.Tr.FixupKeepMessage, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), OnPress: func() error { return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "-C") }, @@ -1000,7 +1000,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err Items: []*types.MenuItem{ { Label: self.c.Tr.FixupMenu_Fixup, - Key: gocui.NewKeyRune('f'), + Key: menuKey('f'), OnPress: func() error { return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit) @@ -1024,7 +1024,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err }, { Label: self.c.Tr.FixupMenu_AmendWithChanges, - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), OnPress: func() error { return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { return self.createAmendCommit(commit, true) @@ -1035,7 +1035,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err }, { Label: self.c.Tr.FixupMenu_AmendWithoutChanges, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), OnPress: func() error { return self.createAmendCommit(commit, false) }, Tooltip: self.c.Tr.FixupMenu_AmendWithoutChangesTooltip, }, @@ -1134,14 +1134,14 @@ func (self *LocalCommitsController) squashFixupCommits() error { Label: self.c.Tr.SquashCommitsInCurrentBranch, OnPress: self.squashAllFixupsInCurrentBranch, DisabledReason: self.canFindCommitForSquashFixupsInCurrentBranch(), - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), Tooltip: self.c.Tr.SquashCommitsInCurrentBranchTooltip, }, { Label: self.c.Tr.SquashCommitsAboveSelectedCommit, OnPress: self.withItem(self.squashAllFixupsAboveSelectedCommit), DisabledReason: self.singleItemSelected()(), - Key: gocui.NewKeyRune('a'), + Key: menuKey('a'), Tooltip: self.c.Tr.SquashCommitsAboveSelectedTooltip, }, }, diff --git a/pkg/gui/controllers/menu_key.go b/pkg/gui/controllers/menu_key.go new file mode 100644 index 000000000..afafe1c0b --- /dev/null +++ b/pkg/gui/controllers/menu_key.go @@ -0,0 +1,11 @@ +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) +} diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index f6e12cfe4..0a4904b2e 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -233,7 +233,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: gocui.NewKeyRune('i'), + Key: menuKey('i'), }, { LabelColumns: []string{self.c.Tr.BulkUpdateSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateCmdObj().ToString())}, @@ -248,7 +248,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), }, { LabelColumns: []string{self.c.Tr.BulkUpdateRecursiveSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateRecursivelyCmdObj().ToString())}, @@ -263,7 +263,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), }, { LabelColumns: []string{self.c.Tr.BulkDeinitSubmodules, style.FgRed.Sprint(self.c.Git().Submodule.BulkDeinitCmdObj().ToString())}, @@ -278,7 +278,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: gocui.NewKeyRune('d'), + Key: menuKey('d'), }, }, }) diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 1e274c077..352ec05e6 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -282,14 +282,14 @@ func (self *TagsController) delete(tag *models.Tag) error { menuItems := []*types.MenuItem{ { Label: self.c.Tr.DeleteLocalTag, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), OnPress: func() error { return self.localDelete(tag) }, }, { Label: self.c.Tr.DeleteRemoteTag, - Key: gocui.NewKeyRune('r'), + Key: menuKey('r'), OpensMenu: true, OnPress: func() error { return self.remoteDelete(tag) @@ -297,7 +297,7 @@ func (self *TagsController) delete(tag *models.Tag) error { }, { Label: self.c.Tr.DeleteLocalAndRemoteTag, - Key: gocui.NewKeyRune('b'), + Key: menuKey('b'), OpensMenu: true, OnPress: func() error { return self.localAndRemoteDelete(tag) diff --git a/pkg/gui/controllers/workspace_reset_controller.go b/pkg/gui/controllers/workspace_reset_controller.go index 48ccfd298..c6b68fb96 100644 --- a/pkg/gui/controllers/workspace_reset_controller.go +++ b/pkg/gui/controllers/workspace_reset_controller.go @@ -53,7 +53,7 @@ func (self *FilesController) createResetMenu() error { }) return nil }, - Key: gocui.NewKeyRune('x'), + Key: menuKey('x'), Tooltip: self.c.Tr.NukeDescription, }, { @@ -72,7 +72,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: gocui.NewKeyRune('u'), + Key: menuKey('u'), }, { LabelColumns: []string{ @@ -90,7 +90,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: gocui.NewKeyRune('c'), + Key: menuKey('c'), }, { LabelColumns: []string{ @@ -115,7 +115,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: gocui.NewKeyRune('S'), + Key: menuKey('S'), }, { LabelColumns: []string{ @@ -133,7 +133,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: gocui.NewKeyRune('s'), + Key: menuKey('s'), }, { LabelColumns: []string{ @@ -151,7 +151,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: gocui.NewKeyRune('m'), + Key: menuKey('m'), }, { LabelColumns: []string{ @@ -176,7 +176,7 @@ func (self *FilesController) createResetMenu() error { }, }) }, - Key: gocui.NewKeyRune('h'), + Key: menuKey('h'), }, } From 3d18ee8f91c7b33a66a5fc964e46837e13a7c957 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 3 May 2026 22:44:53 +0200 Subject: [PATCH 07/17] 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. --- pkg/cheatsheet/generate.go | 6 +- pkg/cheatsheet/generate_test.go | 58 +++++++++---------- pkg/config/keynames.go | 8 +++ pkg/gui/context/menu_context.go | 13 +++-- pkg/gui/controllers/helpers/menu_key.go | 10 ++-- .../helpers/merge_and_rebase_helper.go | 2 +- pkg/gui/controllers/helpers/refs_helper.go | 6 +- pkg/gui/controllers/menu_key.go | 10 ++-- pkg/gui/controllers/prompt_controller.go | 2 +- .../controllers/search_prompt_controller.go | 2 +- pkg/gui/extras_panel.go | 4 +- pkg/gui/keybindings.go | 26 +++++---- pkg/gui/menu_panel.go | 6 +- pkg/gui/options_map.go | 6 +- pkg/gui/services/custom_commands/client.go | 7 ++- .../custom_commands/handler_creator.go | 2 +- .../custom_commands/keybinding_creator.go | 3 +- pkg/gui/types/common.go | 7 ++- pkg/gui/types/context.go | 2 +- pkg/gui/types/keybindings.go | 2 +- 20 files changed, 101 insertions(+), 81 deletions(-) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 3b5c490b8..22bc0c505 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -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) diff --git a/pkg/cheatsheet/generate_test.go b/pkg/cheatsheet/generate_test.go index bae2ec498..3ff066244 100644 --- a/pkg/cheatsheet/generate_test.go +++ b/pkg/cheatsheet/generate_test.go @@ -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')}, }, }, }, diff --git a/pkg/config/keynames.go b/pkg/config/keynames.go index 943a2f37a..7f361dec8 100644 --- a/pkg/config/keynames.go +++ b/pkg/config/keynames.go @@ -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} +} diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index e9fece612..03b8d51c4 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -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 { diff --git a/pkg/gui/controllers/helpers/menu_key.go b/pkg/gui/controllers/helpers/menu_key.go index 7b43a66fc..d4271fa5b 100644 --- a/pkg/gui/controllers/helpers/menu_key.go +++ b/pkg/gui/controllers/helpers/menu_key.go @@ -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)} } diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index ae042b8cb..48c342446 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -39,7 +39,7 @@ const ( func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { type optionAndKey struct { option string - key gocui.Key + key []gocui.Key } options := []optionAndKey{ diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 6771bf301..ae560941f 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -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 } diff --git a/pkg/gui/controllers/menu_key.go b/pkg/gui/controllers/menu_key.go index afafe1c0b..95993801b 100644 --- a/pkg/gui/controllers/menu_key.go +++ b/pkg/gui/controllers/menu_key.go @@ -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)} } diff --git a/pkg/gui/controllers/prompt_controller.go b/pkg/gui/controllers/prompt_controller.go index 1ff40a0ef..9a1fd63c9 100644 --- a/pkg/gui/controllers/prompt_controller.go +++ b/pkg/gui/controllers/prompt_controller.go @@ -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, diff --git a/pkg/gui/controllers/search_prompt_controller.go b/pkg/gui/controllers/search_prompt_controller.go index d5c2f5c3c..b3b9918e6 100644 --- a/pkg/gui/controllers/search_prompt_controller.go +++ b/pkg/gui/controllers/search_prompt_controller.go @@ -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, }, { diff --git a/pkg/gui/extras_panel.go b/pkg/gui/extras_panel.go index 03e82345a..468d8f290 100644 --- a/pkg/gui/extras_panel.go +++ b/pkg/gui/extras_panel.go @@ -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, }, }, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 11a3fbc6a..038ae5d49 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -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 { diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 248da40fb..20079700c 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -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) + }) } } diff --git a/pkg/gui/options_map.go b/pkg/gui/options_map.go index c6360e27c..2771a6c25 100644 --- a/pkg/gui/options_map.go +++ b/pkg/gui/options_map.go @@ -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, } diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go index 4b927cf68..6d30ab310 100644 --- a/pkg/gui/services/custom_commands/client.go +++ b/pkg/gui/services/custom_commands/client.go @@ -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), }) } diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 412fc7de6..60a4555d8 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -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)}, } }) diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go index 644e6af45..52456323a 100644 --- a/pkg/gui/services/custom_commands/keybinding_creator.go +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -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(), } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 5856bb5e0..475cafeab 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -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, diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 35201c6cf..69d76ea78 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -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 } diff --git a/pkg/gui/types/keybindings.go b/pkg/gui/types/keybindings.go index 63079ccc7..3b3e512d8 100644 --- a/pkg/gui/types/keybindings.go +++ b/pkg/gui/types/keybindings.go @@ -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. From 26366641c0bf13c7ad4124728c2c1eaa728db226 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 10 May 2026 17:09:20 +0200 Subject: [PATCH 08/17] Rename Key to Keys in Binding, KeybindingsOpts, and MenuItem This is a straight rename with no other code changes. Doing it in a separate commit to keep the diff of the previous one somewhat readable. --- pkg/cheatsheet/generate.go | 6 +- pkg/cheatsheet/generate_test.go | 58 +++++----- pkg/gui/context/menu_context.go | 10 +- .../controllers/basic_commits_controller.go | 34 +++--- pkg/gui/controllers/bisect_controller.go | 18 +-- pkg/gui/controllers/branches_controller.go | 56 ++++----- .../commit_description_controller.go | 10 +- .../controllers/commit_message_controller.go | 12 +- .../controllers/commits_files_controller.go | 36 +++--- .../controllers/confirmation_controller.go | 6 +- .../controllers/context_lines_controller.go | 4 +- .../custom_patch_options_menu_action.go | 18 +-- pkg/gui/controllers/files_controller.go | 92 +++++++-------- pkg/gui/controllers/filter_controller.go | 2 +- pkg/gui/controllers/git_flow_controller.go | 10 +- pkg/gui/controllers/global_controller.go | 34 +++--- pkg/gui/controllers/helpers/commits_helper.go | 6 +- .../helpers/merge_and_rebase_helper.go | 30 ++--- pkg/gui/controllers/helpers/refs_helper.go | 30 ++--- .../helpers/working_tree_helper.go | 8 +- .../jump_to_side_window_controller.go | 2 +- pkg/gui/controllers/list_controller.go | 30 ++--- .../controllers/local_commits_controller.go | 68 +++++------ pkg/gui/controllers/main_view_controller.go | 6 +- pkg/gui/controllers/menu_controller.go | 6 +- .../controllers/merge_conflicts_controller.go | 34 +++--- pkg/gui/controllers/options_menu_action.go | 2 +- .../controllers/patch_building_controller.go | 10 +- .../controllers/patch_explorer_controller.go | 42 +++---- pkg/gui/controllers/prompt_controller.go | 6 +- .../controllers/remote_branches_controller.go | 18 +-- pkg/gui/controllers/remotes_controller.go | 12 +- .../rename_similarity_threshold_controller.go | 4 +- pkg/gui/controllers/search_controller.go | 2 +- .../controllers/search_prompt_controller.go | 8 +- pkg/gui/controllers/side_window_controller.go | 12 +- pkg/gui/controllers/snake_controller.go | 10 +- pkg/gui/controllers/staging_controller.go | 22 ++-- pkg/gui/controllers/stash_controller.go | 10 +- pkg/gui/controllers/status_controller.go | 12 +- pkg/gui/controllers/submodules_controller.go | 24 ++-- pkg/gui/controllers/suggestions_controller.go | 10 +- .../switch_to_diff_files_controller.go | 2 +- .../switch_to_focused_main_view_controller.go | 2 +- .../switch_to_sub_commits_controller.go | 2 +- pkg/gui/controllers/sync_controller.go | 4 +- pkg/gui/controllers/tags_controller.go | 18 +-- pkg/gui/controllers/undo_controller.go | 4 +- .../controllers/view_selection_controller.go | 20 ++-- .../controllers/workspace_reset_controller.go | 14 +-- .../worktree_options_controller.go | 2 +- pkg/gui/controllers/worktrees_controller.go | 10 +- pkg/gui/extras_panel.go | 4 +- pkg/gui/keybindings.go | 108 +++++++++--------- pkg/gui/menu_panel.go | 2 +- pkg/gui/options_map.go | 6 +- pkg/gui/services/custom_commands/client.go | 6 +- .../custom_commands/handler_creator.go | 2 +- .../custom_commands/keybinding_creator.go | 2 +- pkg/gui/types/common.go | 4 +- pkg/gui/types/context.go | 6 +- pkg/gui/types/keybindings.go | 2 +- 62 files changed, 525 insertions(+), 525 deletions(-) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 22bc0c505..bd2eff624 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -145,7 +145,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b return false } - return (binding.Description != "" || binding.Alternative != "") && len(binding.Key) > 0 + return (binding.Description != "" || binding.Alternative != "") && len(binding.Keys) > 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[0]) + return binding.Description + config.LabelForKey(binding.Keys[0]) }) return headerWithBindings{ @@ -214,7 +214,7 @@ func formatTitle(title string) string { } func formatBinding(binding *types.Binding) string { - action := config.LabelForKey(binding.Key[0]) + action := config.LabelForKey(binding.Keys[0]) description := binding.Description if binding.Alternative != "" { action += fmt.Sprintf(" (%s)", binding.Alternative) diff --git a/pkg/cheatsheet/generate_test.go b/pkg/cheatsheet/generate_test.go index 3ff066244..373fcaa35 100644 --- a/pkg/cheatsheet/generate_test.go +++ b/pkg/cheatsheet/generate_test.go @@ -28,7 +28,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, expected: []*bindingSection{ @@ -38,7 +38,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -50,7 +50,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "", Description: "quit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, expected: []*bindingSection{ @@ -60,7 +60,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "", Description: "quit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -72,17 +72,17 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "submodules", Description: "drop submodule", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, expected: []*bindingSection{ @@ -92,12 +92,12 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -107,7 +107,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "submodules", Description: "drop submodule", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -119,23 +119,23 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "scroll", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, { ViewName: "commits", Description: "revert commit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, expected: []*bindingSection{ @@ -145,7 +145,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "scroll", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, }, @@ -156,7 +156,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "commits", Description: "revert commit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -166,12 +166,12 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -183,34 +183,34 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "scroll", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, { ViewName: "commits", Description: "revert commit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "commits", Description: "scroll", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, { ViewName: "commits", Description: "page up", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, }, @@ -221,13 +221,13 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "scroll", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, { ViewName: "commits", Description: "page up", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, Tag: "navigation", }, }, @@ -238,7 +238,7 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "commits", Description: "revert commit", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, @@ -248,12 +248,12 @@ func TestGetBindingSections(t *testing.T) { { ViewName: "files", Description: "stage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, { ViewName: "files", Description: "unstage file", - Key: []gocui.Key{gocui.NewKeyRune('a')}, + Keys: []gocui.Key{gocui.NewKeyRune('a')}, }, }, }, diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 03b8d51c4..9feef1e4c 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -76,7 +76,7 @@ func NewMenuViewModel(c *ContextCommon) *MenuViewModel { if filterKeybindings { // 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 lo.Map(item.Keys, func(k gocui.Key, _ int) string { return config.LabelForKey(k) }) } @@ -143,8 +143,8 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string { } keyLabel := "" - if len(item.Key) > 0 { - keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Key[0])) + if len(item.Keys) > 0 { + keyLabel = style.FgCyan.Sprint(config.LabelForKey(item.Keys[0])) } checkMark := "" @@ -210,12 +210,12 @@ 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 len(item.Key) > 0 + return len(item.Keys) > 0 }) menuItemBindings := lo.Map(menuItemsWithKeys, func(item *types.MenuItem, _ int) *types.Binding { return &types.Binding{ - Key: item.Key, + Keys: item.Keys, Handler: func() error { return self.OnMenuPress(item) }, } }) diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 60605cf44..3e019bf18 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -51,7 +51,7 @@ func NewBasicCommitsController(c *ControllerCommon, context ContainsCommits) *Ba func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), + Keys: opts.GetKeys(opts.Config.Commits.CheckoutCommit), Handler: self.withItem(self.checkout), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Checkout, @@ -59,7 +59,7 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard), + Keys: opts.GetKeys(opts.Config.Commits.CopyCommitAttributeToClipboard), Handler: self.withItem(self.copyCommitAttribute), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CopyCommitAttributeToClipboard, @@ -67,13 +67,13 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.OpenInBrowser), + Keys: opts.GetKeys(opts.Config.Commits.OpenInBrowser), Handler: self.withItem(self.openInBrowser), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenCommitInBrowser, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.withItem(self.newBranch), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CreateNewBranchFromCommit, @@ -83,14 +83,14 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ // panel. But I find it important that this ends up next to "New Branch", and I couldn't // find another way to achieve this. It's not such a big deal to have it in subcommits and // reflog too, I'd say. - Key: opts.GetKey(opts.Config.Branches.MoveCommitsToNewBranch), + Keys: opts.GetKeys(opts.Config.Branches.MoveCommitsToNewBranch), Handler: self.c.Helpers().Refs.MoveCommitsToNewBranch, GetDisabledReason: self.c.Helpers().Refs.CanMoveCommitsToNewBranch, Description: self.c.Tr.MoveCommitsToNewBranch, Tooltip: self.c.Tr.MoveCommitsToNewBranchTooltip, }, { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewResetOptions), Handler: self.withItem(self.createResetMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ViewResetOptions, @@ -99,7 +99,7 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Keys: opts.GetKeys(opts.Config.Commits.CherryPickCopy), Handler: self.withItem(self.copyRange), GetDisabledReason: self.require(self.itemRangeSelected(self.canCopyCommits)), Description: self.c.Tr.CherryPickCopy, @@ -112,18 +112,18 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Keys: opts.GetKeys(opts.Config.Commits.ResetCherryPick), Handler: self.c.Helpers().CherryPick.Reset, Description: self.c.Tr.ResetCherryPick, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(self.openDiffTool), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenDiffTool, }, { - Key: opts.GetKey(opts.Config.Commits.SelectCommitsOfCurrentBranch), + Keys: opts.GetKeys(opts.Config.Commits.SelectCommitsOfCurrentBranch), Handler: self.selectCommitsOfCurrentBranch, GetDisabledReason: self.require(self.canSelectCommitsOfCurrentBranch), Description: self.c.Tr.SelectCommitsOfCurrentBranch, @@ -163,14 +163,14 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitSubjectToClipboard(commit) }, - Key: menuKey('s'), + Keys: menuKey('s'), }, { Label: self.c.Tr.CommitMessage, OnPress: func() error { return self.copyCommitMessageToClipboard(commit) }, - Key: menuKey('m'), + Keys: menuKey('m'), }, { Label: self.c.Tr.CommitMessageBody, @@ -178,28 +178,28 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitMessageBodyToClipboard(commitMessageBody) }, - Key: menuKey('b'), + Keys: menuKey('b'), }, { Label: self.c.Tr.CommitURL, OnPress: func() error { return self.copyCommitURLToClipboard(commit) }, - Key: menuKey('u'), + Keys: menuKey('u'), }, { Label: self.c.Tr.CommitDiff, OnPress: func() error { return self.copyCommitDiffToClipboard(commit) }, - Key: menuKey('d'), + Keys: menuKey('d'), }, { Label: self.c.Tr.CommitAuthor, OnPress: func() error { return self.copyAuthorToClipboard(commit) }, - Key: menuKey('a'), + Keys: menuKey('a'), }, } @@ -208,7 +208,7 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e OnPress: func() error { return self.copyCommitTagsToClipboard(commit) }, - Key: menuKey('t'), + Keys: menuKey('t'), } if len(commit.Tags) == 0 { diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index d86d34f93..1066237c1 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -38,7 +38,7 @@ func NewBisectController( func (self *BisectController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Commits.ViewBisectOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewBisectOptions), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.openMenu)), Description: self.c.Tr.ViewBisectOptions, OpensMenu: true, @@ -101,7 +101,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: menuKey('b'), + Keys: menuKey('b'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortHashToMark, info.OldTerm()), @@ -114,7 +114,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: menuKey('g'), + Keys: menuKey('g'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortHashToMark), @@ -127,7 +127,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: singleItemIfNotBisecting, - Key: menuKey('s'), + Keys: menuKey('s'), }, } if info.GetCurrentHash() != "" && info.GetCurrentHash() != commit.Hash() { @@ -142,7 +142,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c return self.afterMark(selectCurrentAfter, waitToReselect) }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('S'), + Keys: menuKey('S'), })) } menuItems = append(menuItems, lo.ToPtr(types.MenuItem{ @@ -150,7 +150,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c OnPress: func() error { return self.c.Helpers().Bisect.Reset() }, - Key: menuKey('r'), + Keys: menuKey('r'), })) return self.c.Menu(types.CreateMenuOptions{ @@ -179,7 +179,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('b'), + Keys: menuKey('b'), }, { Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortHash(), info.OldTerm()), @@ -197,7 +197,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('g'), + Keys: menuKey('g'), }, { Label: self.c.Tr.Bisect.ChooseTerms, @@ -222,7 +222,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, }) return nil }, - Key: menuKey('t'), + Keys: menuKey('t'), }, }, }) diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 9fc595952..24ef84d54 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -45,7 +45,7 @@ func NewBranchesController( func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.press), GetDisabledReason: self.require( self.singleItemSelected(), @@ -56,64 +56,64 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(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.MoveCommitsToNewBranch), + Keys: opts.GetKeys(opts.Config.Branches.MoveCommitsToNewBranch), Handler: self.c.Helpers().Refs.MoveCommitsToNewBranch, GetDisabledReason: self.c.Helpers().Refs.CanMoveCommitsToNewBranch, Description: self.c.Tr.MoveCommitsToNewBranch, Tooltip: self.c.Tr.MoveCommitsToNewBranchTooltip, }, { - Key: opts.GetKey(opts.Config.Branches.CreatePullRequest), + Keys: opts.GetKeys(opts.Config.Branches.CreatePullRequest), Handler: self.withItem(self.handleCreatePullRequest), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CreatePullRequest, }, { - Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions), + Keys: opts.GetKeys(opts.Config.Branches.ViewPullRequestOptions), Handler: self.withItem(self.handleCreatePullRequestMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CreatePullRequestOptions, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Branches.OpenPullRequestInBrowser), + Keys: opts.GetKeys(opts.Config.Branches.OpenPullRequestInBrowser), Handler: self.withItem(self.openPRInBrowser), GetDisabledReason: self.require(self.singleItemSelected(self.branchHasPR)), Description: self.c.Tr.OpenPullRequestInBrowser, }, { - Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL), + Keys: opts.GetKeys(opts.Config.Branches.CopyPullRequestURL), Handler: self.copyPullRequestURL, GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CopyPullRequestURL, }, { - Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName), + Keys: opts.GetKeys(opts.Config.Branches.CheckoutBranchByName), Handler: self.checkoutByName, Description: self.c.Tr.CheckoutByName, Tooltip: self.c.Tr.CheckoutByNameTooltip, }, { - Key: opts.GetKey(opts.Config.Branches.CheckoutPreviousBranch), + Keys: opts.GetKeys(opts.Config.Branches.CheckoutPreviousBranch), Handler: self.checkoutPreviousBranch, Description: self.c.Tr.CheckoutPreviousBranch, }, { - Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch), + Keys: opts.GetKeys(opts.Config.Branches.ForceCheckoutBranch), Handler: self.forceCheckout, GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ForceCheckout, Tooltip: self.c.Tr.ForceCheckoutTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.delete), GetDisabledReason: self.require(self.itemRangeSelected(self.branchesAreReal)), Description: self.c.Tr.Delete, @@ -122,7 +122,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.RebaseBranch), + Keys: opts.GetKeys(opts.Config.Branches.RebaseBranch), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.rebase)), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.RebaseBranch, @@ -131,7 +131,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), + Keys: opts.GetKeys(opts.Config.Branches.MergeIntoCurrentBranch), Handler: opts.Guards.OutsideFilterMode(self.merge), GetDisabledReason: self.require(self.singleItemSelected(self.notMergingIntoYourself)), Description: self.c.Tr.Merge, @@ -140,26 +140,26 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Branches.FastForward), + Keys: opts.GetKeys(opts.Config.Branches.FastForward), Handler: self.withItem(self.fastForward), GetDisabledReason: self.require(self.singleItemSelected(self.branchIsReal)), Description: self.c.Tr.FastForward, Tooltip: self.c.Tr.FastForwardTooltip, }, { - Key: opts.GetKey(opts.Config.Branches.CreateTag), + Keys: opts.GetKeys(opts.Config.Branches.CreateTag), Handler: self.withItem(self.createTag), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.NewTag, }, { - Key: opts.GetKey(opts.Config.Branches.SortOrder), + Keys: opts.GetKeys(opts.Config.Branches.SortOrder), Handler: self.createSortMenu, Description: self.c.Tr.SortOrder, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewResetOptions), Handler: self.withItem(self.createResetMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ViewResetOptions, @@ -167,13 +167,13 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.RenameBranch), + Keys: opts.GetKeys(opts.Config.Branches.RenameBranch), Handler: self.withItem(self.rename), GetDisabledReason: self.require(self.singleItemSelected(self.branchIsReal)), Description: self.c.Tr.RenameBranch, }, { - Key: opts.GetKey(opts.Config.Branches.SetUpstream), + Keys: opts.GetKeys(opts.Config.Branches.SetUpstream), Handler: self.withItem(self.viewUpstreamOptions), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ViewBranchUpstreamOptions, @@ -183,7 +183,7 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(func(selectedBranch *models.Branch) error { return self.c.Helpers().Diff.OpenDiffToolForRef(selectedBranch) }), @@ -300,7 +300,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc ) viewDivergenceFromBaseBranchItem := &types.MenuItem{ LabelColumns: []string{label}, - Key: menuKey('b'), + Keys: menuKey('b'), OnPress: func() error { branch := self.context().GetSelected() if branch == nil { @@ -333,7 +333,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc }) return nil }, - Key: menuKey('u'), + Keys: menuKey('u'), } setUpstreamItem := &types.MenuItem{ @@ -358,7 +358,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }) }, - Key: menuKey('s'), + Keys: menuKey('s'), } upstreamResetOptions := utils.ResolvePlaceholderString( @@ -391,7 +391,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }, Tooltip: upstreamResetTooltip, - Key: menuKey('g'), + Keys: menuKey('g'), } upstreamRebaseItem := &types.MenuItem{ @@ -404,7 +404,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc return nil }, Tooltip: upstreamRebaseTooltip, - Key: menuKey('r'), + Keys: menuKey('r'), } if !selectedBranch.IsTrackingRemote() { @@ -624,7 +624,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { localDeleteItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalBranches, self.c.Tr.DeleteLocalBranch), - Key: menuKey('c'), + Keys: menuKey('c'), OnPress: func() error { return self.localDelete(branches) }, @@ -635,7 +635,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { remoteDeleteItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteRemoteBranches, self.c.Tr.DeleteRemoteBranch), - Key: menuKey('r'), + Keys: menuKey('r'), OnPress: func() error { return self.remoteDelete(branches) }, @@ -648,7 +648,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error { deleteBothItem := &types.MenuItem{ Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalAndRemoteBranches, self.c.Tr.DeleteLocalAndRemoteBranch), - Key: menuKey('b'), + Keys: menuKey('b'), OnPress: func() error { return self.localAndRemoteDelete(branches) }, diff --git a/pkg/gui/controllers/commit_description_controller.go b/pkg/gui/controllers/commit_description_controller.go index 63f6876e5..0e5102e3e 100644 --- a/pkg/gui/controllers/commit_description_controller.go +++ b/pkg/gui/controllers/commit_description_controller.go @@ -25,23 +25,23 @@ func NewCommitDescriptionController( func (self *CommitDescriptionController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Keys: opts.GetKeys(opts.Config.Universal.TogglePanel), Handler: self.handleTogglePanel, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.close, }, { - Key: opts.GetKey(opts.Config.Universal.ConfirmInEditor), + Keys: opts.GetKeys(opts.Config.Universal.ConfirmInEditor), Handler: self.confirm, }, { - Key: opts.GetKey(opts.Config.Universal.ConfirmInEditorAlt), + Keys: opts.GetKeys(opts.Config.Universal.ConfirmInEditorAlt), Handler: self.confirm, }, { - Key: opts.GetKey(opts.Config.CommitMessage.CommitMenu), + Keys: opts.GetKeys(opts.Config.CommitMessage.CommitMenu), Handler: self.openCommitMenu, }, } diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go index e1561690c..4743598f6 100644 --- a/pkg/gui/controllers/commit_message_controller.go +++ b/pkg/gui/controllers/commit_message_controller.go @@ -29,29 +29,29 @@ func NewCommitMessageController( func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), + Keys: opts.GetKeys(opts.Config.Universal.SubmitEditorText), Handler: self.confirm, Description: self.c.Tr.Confirm, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.close, Description: self.c.Tr.Close, }, { - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.handlePreviousCommit, }, { - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.handleNextCommit, }, { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Keys: opts.GetKeys(opts.Config.Universal.TogglePanel), Handler: self.handleTogglePanel, }, { - Key: opts.GetKey(opts.Config.CommitMessage.CommitMenu), + Keys: opts.GetKeys(opts.Config.CommitMessage.CommitMenu), Handler: self.openCommitMenu, }, } diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 3d5527293..eed9d02b9 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -45,13 +45,13 @@ func NewCommitFilesController( func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Files.CopyFileInfoToClipboard), + Keys: opts.GetKeys(opts.Config.Files.CopyFileInfoToClipboard), Handler: self.openCopyMenu, Description: self.c.Tr.CopyToClipboardMenu, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile), + Keys: opts.GetKeys(opts.Config.CommitFiles.CheckoutCommitFile), Handler: self.withItem(self.checkout), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Checkout, @@ -59,7 +59,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.discard), GetDisabledReason: self.require(self.itemsSelected(self.canDiscardFileChanges)), Description: self.c.Tr.Discard, @@ -67,14 +67,14 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenFile), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.withItem(self.open), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.withItems(self.edit), GetDisabledReason: self.require(self.itemsSelected(self.canEditFiles)), Description: self.c.Tr.Edit, @@ -82,13 +82,13 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(self.openDiffTool), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenDiffTool, }, { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItems(self.toggleForPatch), GetDisabledReason: self.require(self.itemsSelected()), Description: self.c.Tr.ToggleAddToPatch, @@ -98,7 +98,7 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Files.ToggleStagedAll), + Keys: opts.GetKeys(opts.Config.Files.ToggleStagedAll), Handler: self.withItem(self.toggleAllForPatch), Description: self.c.Tr.ToggleAllInPatch, Tooltip: utils.ResolvePlaceholderString(self.c.Tr.ToggleAllInPatchTooltip, @@ -106,27 +106,27 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] ), }, { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.EnterCommitFile, Tooltip: self.c.Tr.EnterCommitFileTooltip, }, { - Key: opts.GetKey(opts.Config.Files.ToggleTreeView), + Keys: opts.GetKeys(opts.Config.Files.ToggleTreeView), Handler: self.toggleTreeView, Description: self.c.Tr.ToggleTreeView, Tooltip: self.c.Tr.ToggleTreeViewTooltip, }, { - Key: opts.GetKey(opts.Config.Files.CollapseAll), + Keys: opts.GetKeys(opts.Config.Files.CollapseAll), Handler: self.collapseAll, Description: self.c.Tr.CollapseAll, Tooltip: self.c.Tr.CollapseAllTooltip, GetDisabledReason: self.require(self.isInTreeMode), }, { - Key: opts.GetKey(opts.Config.Files.ExpandAll), + Keys: opts.GetKeys(opts.Config.Files.ExpandAll), Handler: self.expandAll, Description: self.c.Tr.ExpandAll, Tooltip: self.c.Tr.ExpandAllTooltip, @@ -230,7 +230,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('n'), + Keys: menuKey('n'), } copyRelativePathItem := &types.MenuItem{ Label: self.c.Tr.CopyRelativeFilePath, @@ -242,7 +242,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('p'), + Keys: menuKey('p'), } copyAbsolutePathItem := &types.MenuItem{ Label: self.c.Tr.CopyAbsoluteFilePath, @@ -258,7 +258,7 @@ func (self *CommitFilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('P'), + Keys: menuKey('P'), } copyFileDiffItem := &types.MenuItem{ Label: self.c.Tr.CopySelectedDiff, @@ -266,7 +266,7 @@ func (self *CommitFilesController) openCopyMenu() error { return self.copyDiffToClipboard(node.GetPath(), self.c.Tr.FileDiffCopiedToast) }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('s'), + Keys: menuKey('s'), } copyAllDiff := &types.MenuItem{ Label: self.c.Tr.CopyAllFilesDiff, @@ -274,7 +274,7 @@ func (self *CommitFilesController) openCopyMenu() error { return self.copyDiffToClipboard(".", self.c.Tr.AllFilesDiffCopiedToast) }, DisabledReason: self.require(self.itemsSelected())(), - Key: menuKey('a'), + Keys: menuKey('a'), } copyFileContentItem := &types.MenuItem{ Label: self.c.Tr.CopyFileContent, @@ -295,7 +295,7 @@ func (self *CommitFilesController) openCopyMenu() error { } return nil }))(), - Key: menuKey('c'), + Keys: menuKey('c'), } return self.c.Menu(types.CreateMenuOptions{ diff --git a/pkg/gui/controllers/confirmation_controller.go b/pkg/gui/controllers/confirmation_controller.go index 206818f40..990b2b09e 100644 --- a/pkg/gui/controllers/confirmation_controller.go +++ b/pkg/gui/controllers/confirmation_controller.go @@ -24,19 +24,19 @@ func NewConfirmationController( func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Confirm), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(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.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: self.handleCopyToClipboard, Description: self.c.Tr.CopyToClipboardMenu, DisplayOnScreen: true, diff --git a/pkg/gui/controllers/context_lines_controller.go b/pkg/gui/controllers/context_lines_controller.go index a1ce9f518..022364c07 100644 --- a/pkg/gui/controllers/context_lines_controller.go +++ b/pkg/gui/controllers/context_lines_controller.go @@ -30,13 +30,13 @@ func NewContextLinesController( func (self *ContextLinesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.IncreaseContextInDiffView), + Keys: opts.GetKeys(opts.Config.Universal.IncreaseContextInDiffView), Handler: self.Increase, Description: self.c.Tr.IncreaseContextInDiffView, Tooltip: self.c.Tr.IncreaseContextInDiffViewTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.DecreaseContextInDiffView), + Keys: opts.GetKeys(opts.Config.Universal.DecreaseContextInDiffView), Handler: self.Decrease, Description: self.c.Tr.DecreaseContextInDiffView, Tooltip: self.c.Tr.DecreaseContextInDiffViewTooltip, diff --git a/pkg/gui/controllers/custom_patch_options_menu_action.go b/pkg/gui/controllers/custom_patch_options_menu_action.go index 979e048c0..cabba4739 100644 --- a/pkg/gui/controllers/custom_patch_options_menu_action.go +++ b/pkg/gui/controllers/custom_patch_options_menu_action.go @@ -31,19 +31,19 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: self.c.Tr.ResetPatch, Tooltip: self.c.Tr.ResetPatchTooltip, OnPress: self.c.Helpers().PatchBuilding.Reset, - Key: menuKey('c'), + Keys: menuKey('c'), }, { Label: self.c.Tr.ApplyPatch, Tooltip: self.c.Tr.ApplyPatchTooltip, OnPress: func() error { return self.handleApplyPatch(false) }, - Key: menuKey('a'), + Keys: menuKey('a'), }, { Label: self.c.Tr.ApplyPatchInReverse, Tooltip: self.c.Tr.ApplyPatchInReverseTooltip, OnPress: func() error { return self.handleApplyPatch(true) }, - Key: menuKey('r'), + Keys: menuKey('r'), }, } @@ -53,25 +53,25 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, utils.ShortHash(self.c.Git().Patch.PatchBuilder.To)), Tooltip: self.c.Tr.RemovePatchFromOriginalCommitTooltip, OnPress: self.handleDeletePatchFromCommit, - Key: menuKey('d'), + Keys: menuKey('d'), }, { Label: self.c.Tr.MovePatchOutIntoIndex, Tooltip: self.c.Tr.MovePatchOutIntoIndexTooltip, OnPress: self.handleMovePatchIntoWorkingTree, - Key: menuKey('i'), + Keys: menuKey('i'), }, { Label: self.c.Tr.MovePatchIntoNewCommit, Tooltip: self.c.Tr.MovePatchIntoNewCommitTooltip, OnPress: self.handlePullPatchIntoNewCommit, - Key: menuKey('n'), + Keys: menuKey('n'), }, { Label: self.c.Tr.MovePatchIntoNewCommitBefore, Tooltip: self.c.Tr.MovePatchIntoNewCommitBeforeTooltip, OnPress: self.handlePullPatchIntoNewCommitBefore, - Key: menuKey('N'), + Keys: menuKey('N'), }, }...) @@ -93,7 +93,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error { Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Hash()), Tooltip: self.c.Tr.MovePatchToSelectedCommitTooltip, OnPress: self.handleMovePatchToSelectedCommit, - Key: menuKey('m'), + Keys: menuKey('m'), DisabledReason: disabledReason, }, }, menuItems[1:]..., @@ -107,7 +107,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error { { Label: self.c.Tr.CopyPatchToClipboard, OnPress: func() error { return self.copyPatchToClipboard() }, - Key: menuKey('y'), + Keys: menuKey('y'), }, }...) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 5fc1540d2..8ea4425e6 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -42,7 +42,7 @@ func NewFilesController( func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItems(self.press), GetDisabledReason: self.require(self.withFileTreeViewModelMutex(self.itemsSelected())), Description: self.c.Tr.Stage, @@ -50,46 +50,46 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Files.OpenStatusFilter), + Keys: opts.GetKeys(opts.Config.Files.OpenStatusFilter), Handler: self.handleStatusFilterPressed, Description: self.c.Tr.FileFilter, }, { - Key: opts.GetKey(opts.Config.Files.CopyFileInfoToClipboard), + Keys: opts.GetKeys(opts.Config.Files.CopyFileInfoToClipboard), Handler: self.openCopyMenu, Description: self.c.Tr.CopyToClipboardMenu, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Files.CommitChanges), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithoutHook), Handler: self.c.Helpers().WorkingTree.HandleWIPCommitPress, Description: self.c.Tr.CommitChangesWithoutHook, }, { - Key: opts.GetKey(opts.Config.Files.AmendLastCommit), + Keys: opts.GetKeys(opts.Config.Files.AmendLastCommit), Handler: self.handleAmendCommitPress, Description: self.c.Tr.AmendLastCommit, }, { - Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor), + Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithEditor), Handler: self.c.Helpers().WorkingTree.HandleCommitEditorPress, Description: self.c.Tr.CommitChangesWithEditor, }, { - Key: opts.GetKey(opts.Config.Files.FindBaseCommitForFixup), + Keys: opts.GetKeys(opts.Config.Files.FindBaseCommitForFixup), Handler: self.c.Helpers().FixupHelper.HandleFindBaseCommitForFixupPress, Description: self.c.Tr.FindBaseCommitForFixup, Tooltip: self.c.Tr.FindBaseCommitForFixupTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.withItems(self.edit), GetDisabledReason: self.require(self.withFileTreeViewModelMutex(self.itemsSelected(self.canEditFiles))), Description: self.c.Tr.Edit, @@ -97,53 +97,53 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenFile), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.Open, GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Files.IgnoreFile), + Keys: opts.GetKeys(opts.Config.Files.IgnoreFile), Handler: self.withItem(self.ignoreOrExcludeMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Actions.IgnoreExcludeFile, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Files.RefreshFiles), + Keys: opts.GetKeys(opts.Config.Files.RefreshFiles), Handler: self.refresh, Description: self.c.Tr.RefreshFiles, }, { - Key: opts.GetKey(opts.Config.Files.StashAllChanges), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Files.ViewStashOptions), Handler: self.createStashMenu, Description: self.c.Tr.ViewStashOptions, Tooltip: self.c.Tr.ViewStashOptionsTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Files.ToggleStagedAll), + Keys: opts.GetKeys(opts.Config.Files.ToggleStagedAll), Handler: self.toggleStagedAll, Description: self.c.Tr.ToggleStagedAll, Tooltip: self.c.Tr.ToggleStagedAllTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.enter, GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.FileEnter, Tooltip: self.c.Tr.FileEnterTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.remove), GetDisabledReason: self.withFileTreeViewModelMutex(self.require(self.itemsSelected(self.canRemove))), Description: self.c.Tr.Discard, @@ -152,13 +152,13 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewResetOptions), Handler: self.createResetToUpstreamMenu, Description: self.c.Tr.ViewResetToUpstreamOptions, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Files.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Files.ViewResetOptions), Handler: self.createResetMenu, Description: self.c.Tr.Reset, Tooltip: self.c.Tr.FileResetOptionsTooltip, @@ -166,19 +166,19 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Files.ToggleTreeView), + Keys: opts.GetKeys(opts.Config.Files.ToggleTreeView), Handler: self.toggleTreeView, Description: self.c.Tr.ToggleTreeView, Tooltip: self.c.Tr.ToggleTreeViewTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(self.openDiffTool), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenDiffTool, }, { - Key: opts.GetKey(opts.Config.Files.OpenMergeOptions), + Keys: opts.GetKeys(opts.Config.Files.OpenMergeOptions), Handler: self.withItems(self.openMergeConflictMenu), Description: self.c.Tr.ViewMergeConflictOptions, Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip, @@ -187,20 +187,20 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Files.Fetch), + Keys: opts.GetKeys(opts.Config.Files.Fetch), Handler: self.fetch, Description: self.c.Tr.Fetch, Tooltip: self.c.Tr.FetchTooltip, }, { - Key: opts.GetKey(opts.Config.Files.CollapseAll), + Keys: opts.GetKeys(opts.Config.Files.CollapseAll), Handler: self.collapseAll, Description: self.c.Tr.CollapseAll, Tooltip: self.c.Tr.CollapseAllTooltip, GetDisabledReason: self.require(self.isInTreeMode), }, { - Key: opts.GetKey(opts.Config.Files.ExpandAll), + Keys: opts.GetKeys(opts.Config.Files.ExpandAll), Handler: self.expandAll, Description: self.c.Tr.ExpandAll, Tooltip: self.c.Tr.ExpandAllTooltip, @@ -671,14 +671,14 @@ func (self *FilesController) handleNonInlineConflict(file *models.File) error { OnPress: func() error { return handle(self.c.Git().WorkingTree.StageFile, self.c.Tr.Actions.ResolveConflictByKeepingFile) }, - Key: menuKey('k'), + Keys: menuKey('k'), } deleteItem := &types.MenuItem{ Label: self.c.Tr.MergeConflictDeleteFile, OnPress: func() error { return handle(self.c.Git().WorkingTree.RemoveConflictedFile, self.c.Tr.Actions.ResolveConflictByDeletingFile) }, - Key: menuKey('d'), + Keys: menuKey('d'), } items := []*types.MenuItem{} switch file.ShortStatus { @@ -856,7 +856,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error } return nil }, - Key: menuKey('i'), + Keys: menuKey('i'), }, { LabelColumns: []string{self.c.Tr.ExcludeFile}, @@ -866,7 +866,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error } return nil }, - Key: menuKey('e'), + Keys: menuKey('e'), }, }, }) @@ -950,7 +950,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayStaged) }, - Key: menuKey('s'), + Keys: menuKey('s'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged), }, { @@ -958,7 +958,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayUnstaged) }, - Key: menuKey('u'), + Keys: menuKey('u'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged), }, { @@ -966,7 +966,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayTracked) }, - Key: menuKey('t'), + Keys: menuKey('t'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked), }, { @@ -974,7 +974,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayUntracked) }, - Key: menuKey('T'), + Keys: menuKey('T'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUntracked), }, { @@ -982,7 +982,7 @@ func (self *FilesController) handleStatusFilterPressed() error { OnPress: func() error { return self.setStatusFiltering(filetree.DisplayAll) }, - Key: menuKey('r'), + Keys: menuKey('r'), Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayAll), }, }, @@ -1092,7 +1092,7 @@ func (self *FilesController) createStashMenu() error { } return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashAllChanges) }, - Key: menuKey('a'), + Keys: menuKey('a'), }, { Label: self.c.Tr.StashAllChangesKeepIndex, @@ -1103,14 +1103,14 @@ func (self *FilesController) createStashMenu() error { // if there are no staged files it behaves the same as Stash.Save return self.handleStashSave(self.c.Git().Stash.StashAndKeepIndex, self.c.Tr.Actions.StashAllChangesKeepIndex) }, - Key: menuKey('i'), + Keys: menuKey('i'), }, { Label: self.c.Tr.StashIncludeUntrackedChanges, OnPress: func() error { return self.handleStashSave(self.c.Git().Stash.StashIncludeUntrackedChanges, self.c.Tr.Actions.StashIncludeUntrackedChanges) }, - Key: menuKey('U'), + Keys: menuKey('U'), }, { Label: self.c.Tr.StashStagedChanges, @@ -1121,7 +1121,7 @@ func (self *FilesController) createStashMenu() error { } return self.handleStashSave(self.c.Git().Stash.SaveStagedChanges, self.c.Tr.Actions.StashStagedChanges) }, - Key: menuKey('s'), + Keys: menuKey('s'), }, { Label: self.c.Tr.StashUnstagedChanges, @@ -1135,7 +1135,7 @@ func (self *FilesController) createStashMenu() error { // ordinary stash return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashUnstagedChanges) }, - Key: menuKey('u'), + Keys: menuKey('u'), }, }, }) @@ -1182,7 +1182,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('n'), + Keys: menuKey('n'), } copyRelativePathItem := &types.MenuItem{ Label: self.c.Tr.CopyRelativeFilePath, @@ -1194,7 +1194,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('p'), + Keys: menuKey('p'), } copyAbsolutePathItem := &types.MenuItem{ Label: self.c.Tr.CopyAbsoluteFilePath, @@ -1210,7 +1210,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, DisabledReason: self.require(self.singleItemSelected())(), - Key: menuKey('P'), + Keys: menuKey('P'), } copyFileDiffItem := &types.MenuItem{ Label: self.c.Tr.CopySelectedDiff, @@ -1236,7 +1236,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, ))(), - Key: menuKey('s'), + Keys: menuKey('s'), } copyAllDiff := &types.MenuItem{ Label: self.c.Tr.CopyAllFilesDiff, @@ -1261,7 +1261,7 @@ func (self *FilesController) openCopyMenu() error { return nil }, )(), - Key: menuKey('a'), + Keys: menuKey('a'), } return self.c.Menu(types.CreateMenuOptions{ @@ -1502,7 +1502,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error { self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}}) return nil }, - Key: self.c.KeybindingsOpts().GetKey(self.c.UserConfig().Keybinding.Files.ConfirmDiscard), + Keys: self.c.KeybindingsOpts().GetKeys(self.c.UserConfig().Keybinding.Files.ConfirmDiscard), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.DiscardAllTooltip, map[string]string{ @@ -1528,7 +1528,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error { self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}}) return nil }, - Key: menuKey('u'), + Keys: menuKey('u'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.DiscardUnstagedTooltip, map[string]string{ diff --git a/pkg/gui/controllers/filter_controller.go b/pkg/gui/controllers/filter_controller.go index 8b049b26c..358fb8ed5 100644 --- a/pkg/gui/controllers/filter_controller.go +++ b/pkg/gui/controllers/filter_controller.go @@ -36,7 +36,7 @@ func (self *FilterController) Context() types.Context { func (self *FilterController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.StartSearch), + Keys: opts.GetKeys(opts.Config.Universal.StartSearch), Handler: self.OpenFilterPrompt, Description: self.c.Tr.StartFilter, }, diff --git a/pkg/gui/controllers/git_flow_controller.go b/pkg/gui/controllers/git_flow_controller.go index 6e6bec95d..9e892e97f 100644 --- a/pkg/gui/controllers/git_flow_controller.go +++ b/pkg/gui/controllers/git_flow_controller.go @@ -35,7 +35,7 @@ func NewGitFlowController( func (self *GitFlowController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Branches.ViewGitFlowOptions), + Keys: opts.GetKeys(opts.Config.Branches.ViewGitFlowOptions), Handler: self.withItem(self.handleCreateGitFlowMenu), Description: self.c.Tr.GitFlowOptions, OpensMenu: true, @@ -82,22 +82,22 @@ func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) er { Label: "start feature", OnPress: startHandler("feature"), - Key: menuKey('f'), + Keys: menuKey('f'), }, { Label: "start hotfix", OnPress: startHandler("hotfix"), - Key: menuKey('h'), + Keys: menuKey('h'), }, { Label: "start bugfix", OnPress: startHandler("bugfix"), - Key: menuKey('b'), + Keys: menuKey('b'), }, { Label: "start release", OnPress: startHandler("release"), - Key: menuKey('r'), + Keys: menuKey('r'), }, }, }) diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index f8f981525..5528e10e7 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -23,20 +23,20 @@ func NewGlobalController( func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.ExecuteShellCommand), + Keys: opts.GetKeys(opts.Config.Universal.ExecuteShellCommand), Handler: self.shellCommand, Description: self.c.Tr.ExecuteShellCommand, Tooltip: self.c.Tr.ExecuteShellCommandTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.CreatePatchOptionsMenu), + Keys: opts.GetKeys(opts.Config.Universal.CreatePatchOptionsMenu), Handler: self.createCustomPatchOptionsMenu, Description: self.c.Tr.ViewPatchOptions, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.CreateRebaseOptionsMenu), + Keys: opts.GetKeys(opts.Config.Universal.CreateRebaseOptionsMenu), Handler: opts.Guards.NoPopupPanel(self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu), Description: self.c.Tr.ViewMergeRebaseOptions, Tooltip: self.c.Tr.ViewMergeRebaseOptionsTooltip, @@ -44,30 +44,30 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type GetDisabledReason: self.canShowRebaseOptions, }, { - Key: opts.GetKey(opts.Config.Universal.Refresh), + Keys: opts.GetKeys(opts.Config.Universal.Refresh), Handler: opts.Guards.NoPopupPanel(self.refresh), Description: self.c.Tr.Refresh, Tooltip: self.c.Tr.RefreshTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.NextScreenMode), + Keys: opts.GetKeys(opts.Config.Universal.NextScreenMode), Handler: opts.Guards.NoPopupPanel(self.nextScreenMode), Description: self.c.Tr.NextScreenMode, }, { - Key: opts.GetKey(opts.Config.Universal.PrevScreenMode), + Keys: opts.GetKeys(opts.Config.Universal.PrevScreenMode), Handler: opts.Guards.NoPopupPanel(self.prevScreenMode), Description: self.c.Tr.PrevScreenMode, }, { - Key: opts.GetKey(opts.Config.Universal.CyclePagers), + Keys: opts.GetKeys(opts.Config.Universal.CyclePagers), Handler: opts.Guards.NoPopupPanel(self.cyclePagers), GetDisabledReason: self.canCyclePagers, Description: self.c.Tr.CyclePagers, Tooltip: self.c.Tr.CyclePagersTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.escape, Description: self.c.Tr.Cancel, DescriptionFunc: self.escapeDescription, @@ -76,7 +76,7 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.OptionMenu), + Keys: opts.GetKeys(opts.Config.Universal.OptionMenu), Description: self.c.Tr.OpenKeybindingsMenu, ShortDescription: self.c.Tr.Keybindings, Handler: self.createOptionsMenu, @@ -86,41 +86,41 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.FilteringMenu), + Keys: opts.GetKeys(opts.Config.Universal.FilteringMenu), Handler: opts.Guards.NoPopupPanel(self.createFilteringMenu), Description: self.c.Tr.OpenFilteringMenu, Tooltip: self.c.Tr.OpenFilteringMenuTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.DiffingMenu), + Keys: opts.GetKeys(opts.Config.Universal.DiffingMenu), Handler: opts.Guards.NoPopupPanel(self.createDiffingMenu), Description: self.c.Tr.ViewDiffingOptions, Tooltip: self.c.Tr.ViewDiffingOptionsTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.DiffingMenuAlt), + Keys: opts.GetKeys(opts.Config.Universal.DiffingMenuAlt), Handler: opts.Guards.NoPopupPanel(self.createDiffingMenu), Description: self.c.Tr.ViewDiffingOptions, Tooltip: self.c.Tr.ViewDiffingOptionsTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.Quit), + Keys: opts.GetKeys(opts.Config.Universal.Quit), Description: self.c.Tr.Quit, Handler: self.quit, }, { - Key: opts.GetKey(opts.Config.Universal.QuitAlt1), + Keys: opts.GetKeys(opts.Config.Universal.QuitAlt1), Handler: self.quit, }, { - Key: opts.GetKey(opts.Config.Universal.QuitWithoutChangingDirectory), + Keys: opts.GetKeys(opts.Config.Universal.QuitWithoutChangingDirectory), Handler: self.quitWithoutChangingDirectory, }, { - Key: opts.GetKey(opts.Config.Universal.SuspendApp), + Keys: opts.GetKeys(opts.Config.Universal.SuspendApp), Handler: self.c.Helpers().SuspendResume.SuspendApp, Description: self.c.Tr.SuspendApp, GetDisabledReason: func() *types.DisabledReason { @@ -133,7 +133,7 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type }, }, { - Key: opts.GetKey(opts.Config.Universal.ToggleWhitespaceInDiffView), + Keys: opts.GetKeys(opts.Config.Universal.ToggleWhitespaceInDiffView), Handler: self.toggleWhitespace, Description: self.c.Tr.ToggleWhitespaceInDiffView, Tooltip: self.c.Tr.ToggleWhitespaceInDiffViewTooltip, diff --git a/pkg/gui/controllers/helpers/commits_helper.go b/pkg/gui/controllers/helpers/commits_helper.go index c9b21250a..5e50ba7b2 100644 --- a/pkg/gui/controllers/helpers/commits_helper.go +++ b/pkg/gui/controllers/helpers/commits_helper.go @@ -228,7 +228,7 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S OnPress: func() error { return self.SwitchToEditor() }, - Key: menuKey('e'), + Keys: menuKey('e'), DisabledReason: disabledReasonForOpenInEditor, }, { @@ -236,14 +236,14 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S OnPress: func() error { return self.addCoAuthor(suggestionFunc) }, - Key: menuKey('c'), + Keys: menuKey('c'), }, { Label: self.c.Tr.PasteCommitMessageFromClipboard, OnPress: func() error { return self.pasteCommitMessageFromClipboard() }, - Key: menuKey('p'), + Keys: menuKey('p'), }, } return self.c.Menu(types.CreateMenuOptions{ diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 48c342446..cd141c697 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -39,17 +39,17 @@ const ( func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { type optionAndKey struct { option string - key []gocui.Key + keys []gocui.Key } options := []optionAndKey{ - {option: REBASE_OPTION_CONTINUE, key: menuKey('c')}, - {option: REBASE_OPTION_ABORT, key: menuKey('a')}, + {option: REBASE_OPTION_CONTINUE, keys: menuKey('c')}, + {option: REBASE_OPTION_ABORT, keys: menuKey('a')}, } if self.c.Git().Status.WorkingTreeState().CanSkip() { options = append(options, optionAndKey{ - option: REBASE_OPTION_SKIP, key: menuKey('s'), + option: REBASE_OPTION_SKIP, keys: menuKey('s'), }) } @@ -59,7 +59,7 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { OnPress: func() error { return self.genericMergeCommand(row.option) }, - Key: row.key, + Keys: row.keys, } }) @@ -198,7 +198,7 @@ func (self *MergeAndRebaseHelper) PromptForConflictHandling() error { OnPress: func() error { return self.genericMergeCommand(REBASE_OPTION_ABORT) }, - Key: menuKey('a'), + Keys: menuKey('a'), }, }, HideCancel: true, @@ -284,7 +284,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.SimpleRebase, map[string]string{"ref": ref}, ), - Key: menuKey('s'), + Keys: menuKey('s'), DisabledReason: disabledReason, OnPress: func() error { self.c.LogAction(self.c.Tr.Actions.RebaseBranch) @@ -308,7 +308,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.InteractiveRebase, map[string]string{"ref": ref}, ), - Key: menuKey('i'), + Keys: menuKey('i'), DisabledReason: disabledReason, Tooltip: self.c.Tr.InteractiveRebaseTooltip, OnPress: func() error { @@ -334,7 +334,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { Label: utils.ResolvePlaceholderString(self.c.Tr.RebaseOntoBaseBranch, map[string]string{"baseBranch": ShortBranchName(baseBranch)}, ), - Key: menuKey('b'), + Keys: menuKey('b'), DisabledReason: baseBranchDisabledReason, Tooltip: self.c.Tr.RebaseOntoBaseBranchTooltip, OnPress: func() error { @@ -392,7 +392,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e firstRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR), - Key: menuKey('m'), + Keys: menuKey('m'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeFastForwardTooltip, map[string]string{ @@ -406,7 +406,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e secondRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeNonFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_NON_FAST_FORWARD), - Key: menuKey('n'), + Keys: menuKey('n'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeNonFastForwardTooltip, map[string]string{ @@ -419,7 +419,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e firstRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeNonFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR), - Key: menuKey('m'), + Keys: menuKey('m'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeNonFastForwardTooltip, map[string]string{ @@ -432,7 +432,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e secondRegularMergeItem = &types.MenuItem{ Label: self.c.Tr.RegularMergeFastForward, OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_FAST_FORWARD), - Key: menuKey('f'), + Keys: menuKey('f'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.RegularMergeFastForwardTooltip, map[string]string{ @@ -464,7 +464,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e { Label: self.c.Tr.SquashMergeUncommitted, OnPress: self.SquashMergeUncommitted(refName), - Key: menuKey('s'), + Keys: menuKey('s'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.SquashMergeUncommittedTooltip, map[string]string{ @@ -475,7 +475,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e { Label: self.c.Tr.SquashMergeCommitted, OnPress: self.SquashMergeCommitted(refName, checkedOutBranchName), - Key: menuKey('S'), + Keys: menuKey('S'), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.SquashMergeCommittedTooltip, map[string]string{ diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index ae560941f..a3db043ef 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -216,15 +216,15 @@ 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 + keys []gocui.Key label string description string sortOrder string } availableSortOptions := map[string]sortMenuOption{ - "recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, key: menuKey('r')}, - "alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", key: menuKey('a')}, - "date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", key: menuKey('d')}, + "recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, keys: menuKey('r')}, + "alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", keys: menuKey('a')}, + "date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", keys: menuKey('d')}, } sortOptions := make([]sortMenuOption, 0, len(sortOptionsOrder)) for _, key := range sortOptionsOrder { @@ -245,7 +245,7 @@ func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, menuPromp OnPress: func() error { return onSelected(opt.sortOrder) }, - Key: opt.key, + Keys: opt.keys, Widget: types.MakeMenuRadioButton(opt.sortOrder == currentValue), } }) @@ -260,14 +260,14 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error { type strengthWithKey struct { strength string label string - key []gocui.Key + keys []gocui.Key tooltip string } strengths := []strengthWithKey{ // not i18'ing because it's git terminology - {strength: "mixed", label: "Mixed reset", key: menuKey('m'), tooltip: self.c.Tr.ResetMixedTooltip}, - {strength: "soft", label: "Soft reset", key: menuKey('s'), tooltip: self.c.Tr.ResetSoftTooltip}, - {strength: "hard", label: "Hard reset", key: menuKey('h'), tooltip: self.c.Tr.ResetHardTooltip}, + {strength: "mixed", label: "Mixed reset", keys: menuKey('m'), tooltip: self.c.Tr.ResetMixedTooltip}, + {strength: "soft", label: "Soft reset", keys: menuKey('s'), tooltip: self.c.Tr.ResetSoftTooltip}, + {strength: "hard", label: "Hard reset", keys: menuKey('h'), tooltip: self.c.Tr.ResetHardTooltip}, } menuItems := lo.Map(strengths, func(row strengthWithKey, _ int) *types.MenuItem { @@ -287,7 +287,7 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error { }, }) }, - Key: row.key, + Keys: row.keys, Tooltip: row.tooltip, } }) @@ -312,15 +312,15 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) return self.CheckoutRef(hash, types.CheckoutRefOptions{}) }, - Key: menuKey('d'), + Keys: menuKey('d'), }, } if len(branches) > 0 { menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem { - var key []gocui.Key + var keys []gocui.Key if index < 9 { - key = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key + keys = menuKey(rune(index + 1 + '0')) // Convert 1-based index to key } return &types.MenuItem{ LabelColumns: []string{fmt.Sprintf(self.c.Tr.Actions.CheckoutBranchAtCommit, branch.Name)}, @@ -328,7 +328,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { self.c.LogAction(self.c.Tr.Actions.CheckoutBranch) return self.CheckoutRef(branch.RefName(), types.CheckoutRefOptions{}) }, - Key: key, + Keys: keys, } })...) } else { @@ -336,7 +336,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error { LabelColumns: []string{self.c.Tr.Actions.CheckoutBranch}, OnPress: func() error { return nil }, DisabledReason: &types.DisabledReason{Text: self.c.Tr.NoBranchesFoundAtCommitTooltip}, - Key: menuKey('1'), + Keys: menuKey('1'), }) } diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index dba2341a7..3ad2c54cf 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -382,7 +382,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--ours") }, - Key: menuKey('c'), + Keys: menuKey('c'), }, { LabelColumns: []string{ @@ -392,7 +392,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--theirs") }, - Key: menuKey('i'), + Keys: menuKey('i'), }, { LabelColumns: []string{ @@ -402,7 +402,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin OnPress: func() error { return onMergeStrategySelected("--union") }, - Key: menuKey('b'), + Keys: menuKey('b'), }, { LabelColumns: []string{ @@ -410,7 +410,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin cmdColor.Sprint("git mergetool"), }, OnPress: self.OpenMergeTool, - Key: menuKey('m'), + Keys: menuKey('m'), }, }, }) diff --git a/pkg/gui/controllers/jump_to_side_window_controller.go b/pkg/gui/controllers/jump_to_side_window_controller.go index 6a08e3758..2ea8ac762 100644 --- a/pkg/gui/controllers/jump_to_side_window_controller.go +++ b/pkg/gui/controllers/jump_to_side_window_controller.go @@ -39,7 +39,7 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt return &types.Binding{ ViewName: "", // by default the keys are 1, 2, 3, etc - Key: opts.GetKey(opts.Config.Universal.JumpToBlock[index]), + Keys: opts.GetKeys(opts.Config.Universal.JumpToBlock[index]), Handler: opts.Guards.NoPopupPanel(self.goToSideWindow(window)), } }) diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index dba08552c..854e14ffa 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -271,26 +271,26 @@ func (self *ListController) isFocused() bool { func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.HandlePrevPage, Description: self.c.Tr.PrevPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.HandleNextPage, Description: self.c.Tr.NextPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), Handler: self.HandleGotoTop}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), Handler: self.HandleGotoBottom}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.HandlePrevLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.HandlePrevLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.HandleNextLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.HandleNextLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: self.HandlePrevPage, Description: self.c.Tr.PrevPage}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.HandleNextPage, Description: self.c.Tr.NextPage}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: self.HandleGotoTop}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: self.HandleGotoBottom}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight}, } if self.context.RangeSelectEnabled() { bindings = append(bindings, []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ToggleRangeSelect), Handler: self.HandleToggleRangeSelect, Description: self.c.Tr.ToggleRangeSelect}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.RangeSelectDown), Handler: self.HandleRangeSelectDown, Description: self.c.Tr.RangeSelectDown}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.RangeSelectUp), Handler: self.HandleRangeSelectUp, Description: self.c.Tr.RangeSelectUp}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ToggleRangeSelect), Handler: self.HandleToggleRangeSelect, Description: self.c.Tr.ToggleRangeSelect}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.RangeSelectDown), Handler: self.HandleRangeSelectDown, Description: self.c.Tr.RangeSelectDown}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.RangeSelectUp), Handler: self.HandleRangeSelectUp, Description: self.c.Tr.RangeSelectUp}, }..., ) } diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 0683147b9..b0cad6586 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -56,7 +56,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Commits.SquashDown), + Keys: opts.GetKeys(opts.Config.Commits.SquashDown), Handler: opts.Guards.OutsideFilterMode(self.withItemsRange(self.squashDown)), GetDisabledReason: self.require( self.itemRangeSelected( @@ -69,7 +69,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup), + Keys: opts.GetKeys(opts.Config.Commits.MarkCommitAsFixup), Handler: opts.Guards.OutsideFilterMode(self.withItemsRange(self.fixup)), GetDisabledReason: self.require( self.itemRangeSelected( @@ -82,7 +82,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.SetFixupMessage), + Keys: opts.GetKeys(opts.Config.Commits.SetFixupMessage), Handler: self.withItem(self.setFixupMessage), GetDisabledReason: self.require( self.singleItemSelected(self.canSetFixupMessage), @@ -91,7 +91,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Tooltip: self.c.Tr.SetFixupMessageTooltip, }, { - Key: opts.GetKey(opts.Config.Commits.RenameCommit), + Keys: opts.GetKeys(opts.Config.Commits.RenameCommit), Handler: self.withItem(self.reword), GetDisabledReason: self.require( self.singleItemSelected(self.rewordEnabled), @@ -102,7 +102,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor), + Keys: opts.GetKeys(opts.Config.Commits.RenameCommitWithEditor), Handler: self.withItem(self.rewordEditor), GetDisabledReason: self.require( self.singleItemSelected(self.rewordEnabled), @@ -110,7 +110,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.RewordCommitEditor, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItemsRange(self.drop), GetDisabledReason: self.require( self.itemRangeSelected( @@ -122,7 +122,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(editCommitKey), + Keys: opts.GetKeys(editCommitKey), Handler: opts.Guards.OutsideFilterMode(self.withItemsRange(self.edit)), GetDisabledReason: self.require( self.itemRangeSelected(self.midRebaseCommandEnabled), @@ -136,7 +136,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ // The user-facing description here is 'Start interactive rebase' but internally // we're calling it 'quick-start interactive rebase' to differentiate it from // when you manually select the base commit. - Key: opts.GetKey(opts.Config.Commits.StartInteractiveRebase), + Keys: opts.GetKeys(opts.Config.Commits.StartInteractiveRebase), Handler: opts.Guards.OutsideFilterMode(self.quickStartInteractiveRebase), GetDisabledReason: self.require(self.notMidRebase(self.c.Tr.AlreadyRebasing), self.canFindCommitForQuickStart), Description: self.c.Tr.QuickStartInteractiveRebase, @@ -145,7 +145,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }), }, { - Key: opts.GetKey(opts.Config.Commits.PickCommit), + Keys: opts.GetKeys(opts.Config.Commits.PickCommit), Handler: opts.Guards.OutsideFilterMode(self.withItems(self.pick)), GetDisabledReason: self.require( self.itemRangeSelected(self.pickEnabled), @@ -154,7 +154,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Tooltip: self.c.Tr.PickCommitTooltip, }, { - Key: opts.GetKey(opts.Config.Commits.CreateFixupCommit), + Keys: opts.GetKeys(opts.Config.Commits.CreateFixupCommit), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.createFixupCommit)), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CreateFixupCommit, @@ -166,7 +166,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ ), }, { - Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits), + Keys: opts.GetKeys(opts.Config.Commits.SquashAboveCommits), Handler: opts.Guards.OutsideFilterMode(self.squashFixupCommits), GetDisabledReason: self.require( self.notMidRebase(self.c.Tr.AlreadyRebasing), @@ -176,7 +176,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.MoveDownCommit), + Keys: opts.GetKeys(opts.Config.Commits.MoveDownCommit), Handler: opts.Guards.OutsideFilterMode(self.withItemsRange(self.moveDown)), GetDisabledReason: self.require(self.itemRangeSelected( self.midRebaseMoveCommandEnabled, @@ -185,7 +185,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.MoveDownCommit, }, { - Key: opts.GetKey(opts.Config.Commits.MoveUpCommit), + Keys: opts.GetKeys(opts.Config.Commits.MoveUpCommit), Handler: opts.Guards.OutsideFilterMode(self.withItemsRange(self.moveUp)), GetDisabledReason: self.require(self.itemRangeSelected( self.midRebaseMoveCommandEnabled, @@ -194,14 +194,14 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.MoveUpCommit, }, { - Key: opts.GetKey(opts.Config.Commits.PasteCommits), + Keys: opts.GetKeys(opts.Config.Commits.PasteCommits), Handler: opts.Guards.OutsideFilterMode(self.paste), GetDisabledReason: self.require(self.canPaste), Description: self.c.Tr.PasteCommits, DisplayStyle: &style.FgCyan, }, { - Key: opts.GetKey(opts.Config.Commits.MarkCommitAsBaseForRebase), + Keys: opts.GetKeys(opts.Config.Commits.MarkCommitAsBaseForRebase), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.markAsBaseCommit)), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.MarkAsBaseCommit, @@ -210,13 +210,13 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ // overriding this navigation keybinding because we might need to load // more commits on demand { - Key: opts.GetKey(opts.Config.Universal.StartSearch), + Keys: opts.GetKeys(opts.Config.Universal.StartSearch), Handler: self.openSearch, Description: self.c.Tr.StartSearch, Tag: "navigation", }, { - Key: opts.GetKey(opts.Config.Commits.AmendToCommit), + Keys: opts.GetKeys(opts.Config.Commits.AmendToCommit), Handler: self.withItem(self.amendTo), GetDisabledReason: self.require(self.singleItemSelected(self.canAmend)), Description: self.c.Tr.Amend, @@ -224,7 +224,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.ResetCommitAuthor), + Keys: opts.GetKeys(opts.Config.Commits.ResetCommitAuthor), Handler: self.withItemsRange(self.amendAttribute), GetDisabledReason: self.require(self.itemRangeSelected(self.canAmendRange)), Description: self.c.Tr.AmendCommitAttribute, @@ -232,28 +232,28 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.RevertCommit), + Keys: opts.GetKeys(opts.Config.Commits.RevertCommit), Handler: self.withItemsRange(self.revert), GetDisabledReason: self.require(self.itemRangeSelected()), Description: self.c.Tr.Revert, Tooltip: self.c.Tr.RevertCommitTooltip, }, { - Key: opts.GetKey(opts.Config.Commits.CreateTag), + Keys: opts.GetKeys(opts.Config.Commits.CreateTag), Handler: self.withItem(self.createTag), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.TagCommit, Tooltip: self.c.Tr.TagCommitTooltip, }, { - Key: opts.GetKey(opts.Config.Commits.OpenLogMenu), + Keys: opts.GetKeys(opts.Config.Commits.OpenLogMenu), Handler: self.handleOpenLogMenu, Description: self.c.Tr.OpenLogMenu, Tooltip: self.c.Tr.OpenLogMenuTooltip, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.OpenPullRequestInBrowser), + Keys: opts.GetKeys(opts.Config.Commits.OpenPullRequestInBrowser), Handler: self.openPRInBrowser, GetDisabledReason: self.checkedOutBranchHasPR, Description: self.c.Tr.OpenPullRequestInBrowser, @@ -361,7 +361,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star Items: []*types.MenuItem{ { Label: self.c.Tr.Fixup, - Key: menuKey('f'), + Keys: menuKey('f'), OnPress: func() error { return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error { self.c.LogAction(self.c.Tr.Actions.FixupCommit) @@ -372,7 +372,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star }, { Label: self.c.Tr.FixupKeepMessage, - Key: menuKey('c'), + Keys: menuKey('c'), OnPress: func() error { return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error { self.c.LogAction(self.c.Tr.Actions.FixupCommitKeepMessage) @@ -403,7 +403,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error Items: []*types.MenuItem{ { Label: self.c.Tr.FixupDiscardMessage, - Key: menuKey('f'), + Keys: menuKey('f'), OnPress: func() error { return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "") }, @@ -411,7 +411,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error }, { Label: self.c.Tr.FixupKeepMessage, - Key: menuKey('c'), + Keys: menuKey('c'), OnPress: func() error { return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "-C") }, @@ -864,19 +864,19 @@ func (self *LocalCommitsController) amendAttribute(commits []*models.Commit, sta { Label: self.c.Tr.ResetAuthor, OnPress: func() error { return self.resetAuthor(start, end) }, - Key: opts.GetKey(opts.Config.AmendAttribute.ResetAuthor), + Keys: opts.GetKeys(opts.Config.AmendAttribute.ResetAuthor), Tooltip: self.c.Tr.ResetAuthorTooltip, }, { Label: self.c.Tr.SetAuthor, OnPress: func() error { return self.setAuthor(start, end) }, - Key: opts.GetKey(opts.Config.AmendAttribute.SetAuthor), + Keys: opts.GetKeys(opts.Config.AmendAttribute.SetAuthor), Tooltip: self.c.Tr.SetAuthorTooltip, }, { Label: self.c.Tr.AddCoAuthor, OnPress: func() error { return self.addCoAuthor(start, end) }, - Key: opts.GetKey(opts.Config.AmendAttribute.AddCoAuthor), + Keys: opts.GetKeys(opts.Config.AmendAttribute.AddCoAuthor), Tooltip: self.c.Tr.AddCoAuthorTooltip, }, }, @@ -1000,7 +1000,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err Items: []*types.MenuItem{ { Label: self.c.Tr.FixupMenu_Fixup, - Key: menuKey('f'), + Keys: menuKey('f'), OnPress: func() error { return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit) @@ -1024,7 +1024,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err }, { Label: self.c.Tr.FixupMenu_AmendWithChanges, - Key: menuKey('a'), + Keys: menuKey('a'), OnPress: func() error { return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { return self.createAmendCommit(commit, true) @@ -1035,7 +1035,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err }, { Label: self.c.Tr.FixupMenu_AmendWithoutChanges, - Key: menuKey('r'), + Keys: menuKey('r'), OnPress: func() error { return self.createAmendCommit(commit, false) }, Tooltip: self.c.Tr.FixupMenu_AmendWithoutChangesTooltip, }, @@ -1134,14 +1134,14 @@ func (self *LocalCommitsController) squashFixupCommits() error { Label: self.c.Tr.SquashCommitsInCurrentBranch, OnPress: self.squashAllFixupsInCurrentBranch, DisabledReason: self.canFindCommitForSquashFixupsInCurrentBranch(), - Key: menuKey('b'), + Keys: menuKey('b'), Tooltip: self.c.Tr.SquashCommitsInCurrentBranchTooltip, }, { Label: self.c.Tr.SquashCommitsAboveSelectedCommit, OnPress: self.withItem(self.squashAllFixupsAboveSelectedCommit), DisabledReason: self.singleItemSelected()(), - Key: menuKey('a'), + Keys: menuKey('a'), Tooltip: self.c.Tr.SquashCommitsAboveSelectedTooltip, }, }, diff --git a/pkg/gui/controllers/main_view_controller.go b/pkg/gui/controllers/main_view_controller.go index 58d88485a..6eb6c86e3 100644 --- a/pkg/gui/controllers/main_view_controller.go +++ b/pkg/gui/controllers/main_view_controller.go @@ -32,21 +32,21 @@ func NewMainViewController( func (self *MainViewController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Keys: opts.GetKeys(opts.Config.Universal.TogglePanel), Handler: self.togglePanel, Description: self.c.Tr.ToggleStagingView, Tooltip: self.c.Tr.ToggleStagingViewTooltip, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.escape, Description: self.c.Tr.ExitFocusedMainView, DisplayOnScreen: true, }, { // overriding this because we want to read all of the task's output before we start searching - Key: opts.GetKey(opts.Config.Universal.StartSearch), + Keys: opts.GetKeys(opts.Config.Universal.StartSearch), Handler: self.openSearch, Description: self.c.Tr.StartSearch, Tag: "navigation", diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index a2c77e457..283c2bbdf 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -33,19 +33,19 @@ func NewMenuController( func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.press), GetDisabledReason: self.require(self.singleItemSelected()), }, { - Key: opts.GetKey(opts.Config.Universal.ConfirmMenu), + Keys: opts.GetKeys(opts.Config.Universal.ConfirmMenu), Handler: self.withItem(self.press), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Execute, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.close, Description: self.c.Tr.CloseCancel, DisplayOnScreen: true, diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index 1de192928..a539e710f 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -28,91 +28,91 @@ func NewMergeConflictsController( func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withRenderAndFocus(self.HandlePickHunk), Description: self.c.Tr.PickHunk, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Main.PickBothHunks), + Keys: opts.GetKeys(opts.Config.Main.PickBothHunks), Handler: self.withRenderAndFocus(self.HandlePickAllHunks), Description: self.c.Tr.PickAllHunks, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.withRenderAndFocus(self.PrevConflictHunk), Description: self.c.Tr.SelectPrevHunk, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.withRenderAndFocus(self.NextConflictHunk), Description: self.c.Tr.SelectNextHunk, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.PrevBlock), + Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), Handler: self.withRenderAndFocus(self.PrevConflict), Description: self.c.Tr.PrevConflict, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.NextBlock), + Keys: opts.GetKeys(opts.Config.Universal.NextBlock), Handler: self.withRenderAndFocus(self.NextConflict), Description: self.c.Tr.NextConflict, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Undo), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.HandleOpenFile, Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), Handler: self.withRenderAndFocus(self.PrevConflict), }, { - Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), Handler: self.withRenderAndFocus(self.NextConflict), }, { - Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.withRenderAndFocus(self.PrevConflictHunk), }, { - Key: opts.GetKey(opts.Config.Universal.NextItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.withRenderAndFocus(self.NextConflictHunk), }, { - Key: opts.GetKey(opts.Config.Universal.ScrollLeft), + Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.withRenderAndFocus(self.HandleScrollLeft), Description: self.c.Tr.ScrollLeft, Tag: "navigation", }, { - Key: opts.GetKey(opts.Config.Universal.ScrollRight), + Keys: opts.GetKeys(opts.Config.Universal.ScrollRight), Handler: self.withRenderAndFocus(self.HandleScrollRight), Description: self.c.Tr.ScrollRight, Tag: "navigation", }, { - Key: opts.GetKey(opts.Config.Files.OpenMergeOptions), + Keys: opts.GetKeys(opts.Config.Files.OpenMergeOptions), Handler: self.openMergeConflictMenu, Description: self.c.Tr.ViewMergeConflictOptions, Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip, @@ -120,7 +120,7 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.Escape, Description: self.c.Tr.ReturnToFilesPanel, }, diff --git a/pkg/gui/controllers/options_menu_action.go b/pkg/gui/controllers/options_menu_action.go index e711f9df6..e49c02386 100644 --- a/pkg/gui/controllers/options_menu_action.go +++ b/pkg/gui/controllers/options_menu_action.go @@ -33,7 +33,7 @@ func (self *OptionsMenuAction) Call() error { return self.c.IGuiCommon.CallKeybindingHandler(binding) }, - Key: binding.Key, + Keys: binding.Keys, Tooltip: binding.Tooltip, DisabledReason: disabledReason, Section: section, diff --git a/pkg/gui/controllers/patch_building_controller.go b/pkg/gui/controllers/patch_building_controller.go index 3557a3879..dd8c89fff 100644 --- a/pkg/gui/controllers/patch_building_controller.go +++ b/pkg/gui/controllers/patch_building_controller.go @@ -27,25 +27,25 @@ func NewPatchBuildingController( func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.OpenFile), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.OpenFile, Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.EditFile, Description: self.c.Tr.EditFile, Tooltip: self.c.Tr.EditFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.ToggleSelectionAndRefresh, Description: self.c.Tr.ToggleSelectionForPatch, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.discardSelection, GetDisabledReason: self.getDisabledReasonForDiscard, Description: self.c.Tr.RemoveSelectionFromPatch, @@ -53,7 +53,7 @@ func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.Escape, Description: self.c.Tr.ExitCustomPatchBuilder, DescriptionFunc: self.EscapeDescription, diff --git a/pkg/gui/controllers/patch_explorer_controller.go b/pkg/gui/controllers/patch_explorer_controller.go index 9c0ef078f..14bce304e 100644 --- a/pkg/gui/controllers/patch_explorer_controller.go +++ b/pkg/gui/controllers/patch_explorer_controller.go @@ -41,61 +41,61 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) return []*types.Binding{ { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.withRenderAndFocus(self.HandlePrevLine), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.withRenderAndFocus(self.HandlePrevLine), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.NextItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.withRenderAndFocus(self.HandleNextLine), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.withRenderAndFocus(self.HandleNextLine), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.RangeSelectUp), + Keys: opts.GetKeys(opts.Config.Universal.RangeSelectUp), Handler: self.withRenderAndFocus(self.HandlePrevLineRange), Description: self.c.Tr.RangeSelectUp, }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.RangeSelectDown), + Keys: opts.GetKeys(opts.Config.Universal.RangeSelectDown), Handler: self.withRenderAndFocus(self.HandleNextLineRange), Description: self.c.Tr.RangeSelectDown, }, { - Key: opts.GetKey(opts.Config.Universal.PrevBlock), + Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), Handler: self.withRenderAndFocus(self.HandlePrevHunk), Description: self.c.Tr.PrevHunk, }, { - Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), Handler: self.withRenderAndFocus(self.HandlePrevHunk), }, { - Key: opts.GetKey(opts.Config.Universal.NextBlock), + Keys: opts.GetKeys(opts.Config.Universal.NextBlock), Handler: self.withRenderAndFocus(self.HandleNextHunk), Description: self.c.Tr.NextHunk, }, { - Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), Handler: self.withRenderAndFocus(self.HandleNextHunk), }, { - Key: opts.GetKey(opts.Config.Universal.ToggleRangeSelect), + Keys: opts.GetKeys(opts.Config.Universal.ToggleRangeSelect), Handler: self.withRenderAndFocus(self.HandleToggleSelectRange), Description: self.c.Tr.ToggleRangeSelect, }, { - Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk), + Keys: opts.GetKeys(opts.Config.Main.ToggleSelectHunk), Handler: self.withRenderAndFocus(self.HandleToggleSelectHunk), Description: self.c.Tr.ToggleSelectHunk, DescriptionFunc: func() string { @@ -109,50 +109,50 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.PrevPage), + Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: self.withRenderAndFocus(self.HandlePrevPage), Description: self.c.Tr.PrevPage, }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.NextPage), + Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.withRenderAndFocus(self.HandleNextPage), Description: self.c.Tr.NextPage, }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.GotoTop), + Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.withRenderAndFocus(self.HandleGotoTop), Description: self.c.Tr.GotoTop, }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.GotoBottom), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Description: self.c.Tr.GotoBottom, Handler: self.withRenderAndFocus(self.HandleGotoBottom), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: self.withRenderAndFocus(self.HandleGotoTop), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: self.withRenderAndFocus(self.HandleGotoBottom), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.ScrollLeft), + Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.withRenderAndFocus(self.HandleScrollLeft), }, { Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.ScrollRight), + Keys: opts.GetKeys(opts.Config.Universal.ScrollRight), Handler: self.withRenderAndFocus(self.HandleScrollRight), }, { - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: self.withLock(self.CopySelectedToClipboard), Description: self.c.Tr.CopySelectedTextToClipboard, }, diff --git a/pkg/gui/controllers/prompt_controller.go b/pkg/gui/controllers/prompt_controller.go index 9a1fd63c9..abcf73ef5 100644 --- a/pkg/gui/controllers/prompt_controller.go +++ b/pkg/gui/controllers/prompt_controller.go @@ -27,19 +27,19 @@ func NewPromptController( func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)}, Handler: func() error { return self.context().State.OnConfirm() }, Description: self.c.Tr.Confirm, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Universal.TogglePanel), Handler: func() error { if len(self.c.Contexts().Suggestions.State.Suggestions) > 0 { self.switchToSuggestions() diff --git a/pkg/gui/controllers/remote_branches_controller.go b/pkg/gui/controllers/remote_branches_controller.go index 3a0350477..3a49c0114 100644 --- a/pkg/gui/controllers/remote_branches_controller.go +++ b/pkg/gui/controllers/remote_branches_controller.go @@ -35,7 +35,7 @@ func NewRemoteBranchesController( func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.checkoutBranch), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Checkout, @@ -43,13 +43,13 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.withItem(self.newLocalBranch), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.NewBranch, }, { - Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), + Keys: opts.GetKeys(opts.Config.Branches.MergeIntoCurrentBranch), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.merge)), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Merge, @@ -57,7 +57,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.RebaseBranch), + Keys: opts.GetKeys(opts.Config.Branches.RebaseBranch), Handler: opts.Guards.OutsideFilterMode(self.withItem(self.rebase)), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.RebaseBranch, @@ -65,7 +65,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.delete), GetDisabledReason: self.require(self.itemRangeSelected()), Description: self.c.Tr.Delete, @@ -73,7 +73,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.SetUpstream), + Keys: opts.GetKeys(opts.Config.Branches.SetUpstream), Handler: self.withItem(self.setAsUpstream), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.SetAsUpstream, @@ -81,13 +81,13 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.SortOrder), + Keys: opts.GetKeys(opts.Config.Branches.SortOrder), Handler: self.createSortMenu, Description: self.c.Tr.SortOrder, OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewResetOptions), Handler: self.withItem(self.createResetMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ViewResetOptions, @@ -95,7 +95,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(func(selectedBranch *models.RemoteBranch) error { return self.c.Helpers().Diff.OpenDiffToolForRef(selectedBranch) }), diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index c07626649..b2e30f231 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -45,20 +45,20 @@ func NewRemotesController( func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.ViewBranches, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.add, Description: self.c.Tr.NewRemote, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItem(self.remove), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Remove, @@ -66,7 +66,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.withItem(self.edit), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Edit, @@ -74,7 +74,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.FetchRemote), + Keys: opts.GetKeys(opts.Config.Branches.FetchRemote), Handler: self.withItem(self.fetch), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Fetch, @@ -82,7 +82,7 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.AddForkRemote), + Keys: opts.GetKeys(opts.Config.Branches.AddForkRemote), Handler: self.addFork, GetDisabledReason: self.hasOriginRemote(), Description: self.c.Tr.AddForkRemote, diff --git a/pkg/gui/controllers/rename_similarity_threshold_controller.go b/pkg/gui/controllers/rename_similarity_threshold_controller.go index 2d5f52bc0..78b8bb7f4 100644 --- a/pkg/gui/controllers/rename_similarity_threshold_controller.go +++ b/pkg/gui/controllers/rename_similarity_threshold_controller.go @@ -28,13 +28,13 @@ func NewRenameSimilarityThresholdController( func (self *RenameSimilarityThresholdController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.IncreaseRenameSimilarityThreshold), + Keys: opts.GetKeys(opts.Config.Universal.IncreaseRenameSimilarityThreshold), Handler: self.Increase, Description: self.c.Tr.IncreaseRenameSimilarityThreshold, Tooltip: self.c.Tr.IncreaseRenameSimilarityThresholdTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.DecreaseRenameSimilarityThreshold), + Keys: opts.GetKeys(opts.Config.Universal.DecreaseRenameSimilarityThreshold), Handler: self.Decrease, Description: self.c.Tr.DecreaseRenameSimilarityThreshold, Tooltip: self.c.Tr.DecreaseRenameSimilarityThresholdTooltip, diff --git a/pkg/gui/controllers/search_controller.go b/pkg/gui/controllers/search_controller.go index 395784d10..f1d5efe2a 100644 --- a/pkg/gui/controllers/search_controller.go +++ b/pkg/gui/controllers/search_controller.go @@ -36,7 +36,7 @@ func (self *SearchController) Context() types.Context { func (self *SearchController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.StartSearch), + Keys: opts.GetKeys(opts.Config.Universal.StartSearch), Handler: self.OpenSearchPrompt, Description: self.c.Tr.StartSearch, }, diff --git a/pkg/gui/controllers/search_prompt_controller.go b/pkg/gui/controllers/search_prompt_controller.go index b3b9918e6..1ce02abf0 100644 --- a/pkg/gui/controllers/search_prompt_controller.go +++ b/pkg/gui/controllers/search_prompt_controller.go @@ -24,19 +24,19 @@ func NewSearchPromptController( func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.KeyEnter)}, Handler: self.confirm, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.cancel, }, { - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.prevHistory, }, { - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.nextHistory, }, } diff --git a/pkg/gui/controllers/side_window_controller.go b/pkg/gui/controllers/side_window_controller.go index 94706eb8f..f09a5bbdb 100644 --- a/pkg/gui/controllers/side_window_controller.go +++ b/pkg/gui/controllers/side_window_controller.go @@ -35,12 +35,12 @@ func NewSideWindowController( func (self *SideWindowController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - {Key: opts.GetKey(opts.Config.Universal.PrevBlock), Handler: self.previousSideWindow}, - {Key: opts.GetKey(opts.Config.Universal.NextBlock), Handler: self.nextSideWindow}, - {Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), Handler: self.previousSideWindow}, - {Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), Handler: self.nextSideWindow}, - {Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt2), Handler: self.previousSideWindow}, - {Key: opts.GetKey(opts.Config.Universal.NextBlockAlt2), Handler: self.nextSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), Handler: self.previousSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.NextBlock), Handler: self.nextSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), Handler: self.previousSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), Handler: self.nextSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt2), Handler: self.previousSideWindow}, + {Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt2), Handler: self.nextSideWindow}, } } diff --git a/pkg/gui/controllers/snake_controller.go b/pkg/gui/controllers/snake_controller.go index a2a2030b7..b059ce787 100644 --- a/pkg/gui/controllers/snake_controller.go +++ b/pkg/gui/controllers/snake_controller.go @@ -24,23 +24,23 @@ func NewSnakeController( func (self *SnakeController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.SetDirection(snake.Down), }, { - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.SetDirection(snake.Up), }, { - Key: opts.GetKey(opts.Config.Universal.PrevBlock), + Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), Handler: self.SetDirection(snake.Left), }, { - Key: opts.GetKey(opts.Config.Universal.NextBlock), + Keys: opts.GetKeys(opts.Config.Universal.NextBlock), Handler: self.SetDirection(snake.Right), }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.Escape, }, } diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index 75042f46a..8d876acda 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -41,69 +41,69 @@ func NewStagingController( func (self *StagingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.OpenFile, Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.EditFile, Description: self.c.Tr.EditFile, Tooltip: self.c.Tr.EditFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: self.Escape, Description: self.c.Tr.ReturnToFilesPanel, DescriptionFunc: self.EscapeDescription, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Main.EditSelectHunk), Handler: self.EditHunkAndRefresh, Description: self.c.Tr.EditHunk, Tooltip: self.c.Tr.EditHunkTooltip, }, { - Key: opts.GetKey(opts.Config.Files.CommitChanges), + Keys: opts.GetKeys(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.CommitChangesWithoutHook), + Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithoutHook), Handler: self.c.Helpers().WorkingTree.HandleWIPCommitPress, Description: self.c.Tr.CommitChangesWithoutHook, }, { - Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor), + Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithEditor), Handler: self.c.Helpers().WorkingTree.HandleCommitEditorPress, Description: self.c.Tr.CommitChangesWithEditor, }, { - Key: opts.GetKey(opts.Config.Files.FindBaseCommitForFixup), + Keys: opts.GetKeys(opts.Config.Files.FindBaseCommitForFixup), Handler: self.c.Helpers().FixupHelper.HandleFindBaseCommitForFixupPress, Description: self.c.Tr.FindBaseCommitForFixup, Tooltip: self.c.Tr.FindBaseCommitForFixupTooltip, diff --git a/pkg/gui/controllers/stash_controller.go b/pkg/gui/controllers/stash_controller.go index 20dc2826e..49abedd9f 100644 --- a/pkg/gui/controllers/stash_controller.go +++ b/pkg/gui/controllers/stash_controller.go @@ -36,7 +36,7 @@ func NewStashController( func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.handleStashApply), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Apply, @@ -44,7 +44,7 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Stash.PopStash), + Keys: opts.GetKeys(opts.Config.Stash.PopStash), Handler: self.withItem(self.handleStashPop), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Pop, @@ -52,7 +52,7 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.handleStashDrop), GetDisabledReason: self.require(self.itemRangeSelected()), Description: self.c.Tr.Drop, @@ -60,14 +60,14 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.withItem(self.handleNewBranchOffStashEntry), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.NewBranch, Tooltip: self.c.Tr.NewBranchFromStashTooltip, }, { - Key: opts.GetKey(opts.Config.Stash.RenameStash), + Keys: opts.GetKeys(opts.Config.Stash.RenameStash), Handler: self.withItem(self.handleRenameStashEntry), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.RenameStash, diff --git a/pkg/gui/controllers/status_controller.go b/pkg/gui/controllers/status_controller.go index a3e08e384..f29ee97f0 100644 --- a/pkg/gui/controllers/status_controller.go +++ b/pkg/gui/controllers/status_controller.go @@ -34,37 +34,37 @@ func NewStatusController( func (self *StatusController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.OpenFile), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.openConfig, Description: self.c.Tr.OpenConfig, Tooltip: self.c.Tr.OpenFileTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Status.CheckForUpdate), Handler: self.handleCheckForUpdate, Description: self.c.Tr.CheckForUpdate, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Status.RecentRepos), + Keys: opts.GetKeys(opts.Config.Status.RecentRepos), Handler: self.c.Helpers().Repos.CreateRecentReposMenu, Description: self.c.Tr.SwitchRepo, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Status.AllBranchesLogGraph), + Keys: opts.GetKeys(opts.Config.Status.AllBranchesLogGraph), Handler: func() error { self.switchToOrRotateAllBranchesLogs(); return nil }, Description: self.c.Tr.AllBranchesLogGraph, }, { - Key: opts.GetKey(opts.Config.Status.AllBranchesLogGraphReverse), + Keys: opts.GetKeys(opts.Config.Status.AllBranchesLogGraphReverse), Handler: func() error { self.switchToOrRotateAllBranchesLogsBackward(); return nil }, Description: self.c.Tr.AllBranchesLogGraphReverse, }, diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 0a4904b2e..7d6be1e82 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -39,7 +39,7 @@ func NewSubmodulesController( func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Enter, @@ -48,12 +48,12 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItem(self.remove), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Remove, @@ -61,7 +61,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Submodules.Update), + Keys: opts.GetKeys(opts.Config.Submodules.Update), Handler: self.withItem(self.update), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Update, @@ -69,26 +69,26 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.add, Description: self.c.Tr.NewSubmodule, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.withItem(self.editURL), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.EditSubmoduleUrl, }, { - Key: opts.GetKey(opts.Config.Submodules.Init), + Keys: opts.GetKeys(opts.Config.Submodules.Init), Handler: self.withItem(self.init), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Initialize, Tooltip: self.c.Tr.InitSubmoduleTooltip, }, { - Key: opts.GetKey(opts.Config.Submodules.BulkMenu), + Keys: opts.GetKeys(opts.Config.Submodules.BulkMenu), Handler: self.openBulkActionsMenu, Description: self.c.Tr.ViewBulkSubmoduleOptions, OpensMenu: true, @@ -233,7 +233,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: menuKey('i'), + Keys: menuKey('i'), }, { LabelColumns: []string{self.c.Tr.BulkUpdateSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateCmdObj().ToString())}, @@ -248,7 +248,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: menuKey('u'), + Keys: menuKey('u'), }, { LabelColumns: []string{self.c.Tr.BulkUpdateRecursiveSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateRecursivelyCmdObj().ToString())}, @@ -263,7 +263,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: menuKey('r'), + Keys: menuKey('r'), }, { LabelColumns: []string{self.c.Tr.BulkDeinitSubmodules, style.FgRed.Sprint(self.c.Git().Submodule.BulkDeinitCmdObj().ToString())}, @@ -278,7 +278,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error { return nil }) }, - Key: menuKey('d'), + Keys: menuKey('d'), }, }, }) diff --git a/pkg/gui/controllers/suggestions_controller.go b/pkg/gui/controllers/suggestions_controller.go index e5de7619b..0553050e5 100644 --- a/pkg/gui/controllers/suggestions_controller.go +++ b/pkg/gui/controllers/suggestions_controller.go @@ -32,26 +32,26 @@ func NewSuggestionsController( func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.ConfirmSuggestion), + Keys: opts.GetKeys(opts.Config.Universal.ConfirmSuggestion), Handler: func() error { return self.context().State.OnConfirm() }, GetDisabledReason: self.require(self.singleItemSelected()), }, { - Key: opts.GetKey(opts.Config.Universal.Return), + Keys: opts.GetKeys(opts.Config.Universal.Return), Handler: func() error { return self.context().State.OnClose() }, }, { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Keys: opts.GetKeys(opts.Config.Universal.TogglePanel), Handler: self.switchToPrompt, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: func() error { return self.context().State.OnDeleteSuggestion() }, }, { - Key: opts.GetKey(opts.Config.Universal.Edit), + Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: func() error { if self.context().State.AllowEditSuggestion { if selectedItem := self.c.Contexts().Suggestions.GetSelected(); selectedItem != nil { diff --git a/pkg/gui/controllers/switch_to_diff_files_controller.go b/pkg/gui/controllers/switch_to_diff_files_controller.go index 94c3c5712..c2ff4d674 100644 --- a/pkg/gui/controllers/switch_to_diff_files_controller.go +++ b/pkg/gui/controllers/switch_to_diff_files_controller.go @@ -40,7 +40,7 @@ func NewSwitchToDiffFilesController( func (self *SwitchToDiffFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.enter, GetDisabledReason: self.canEnter, Description: self.c.Tr.ViewItemFiles, diff --git a/pkg/gui/controllers/switch_to_focused_main_view_controller.go b/pkg/gui/controllers/switch_to_focused_main_view_controller.go index 5161a5c83..5606a0bab 100644 --- a/pkg/gui/controllers/switch_to_focused_main_view_controller.go +++ b/pkg/gui/controllers/switch_to_focused_main_view_controller.go @@ -29,7 +29,7 @@ func NewSwitchToFocusedMainViewController( func (self *SwitchToFocusedMainViewController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.FocusMainView), + Keys: opts.GetKeys(opts.Config.Universal.FocusMainView), Handler: self.handleFocusMainView, Description: self.c.Tr.FocusMainView, Tag: "global", diff --git a/pkg/gui/controllers/switch_to_sub_commits_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go index 8bee8d7e6..4d723d061 100644 --- a/pkg/gui/controllers/switch_to_sub_commits_controller.go +++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go @@ -47,7 +47,7 @@ func (self *SwitchToSubCommitsController) GetKeybindings(opts types.KeybindingsO { Handler: self.viewCommits, GetDisabledReason: self.require(self.singleItemSelected()), - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Description: self.c.Tr.ViewCommits, }, } diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 00178b1bb..4e66e2708 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -32,14 +32,14 @@ func NewSyncController( func (self *SyncController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Push), + Keys: opts.GetKeys(opts.Config.Universal.Push), Handler: opts.Guards.NoPopupPanel(self.HandlePush), GetDisabledReason: self.getDisabledReasonForPushOrPull, Description: self.c.Tr.Push, Tooltip: self.c.Tr.PushTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Pull), + Keys: opts.GetKeys(opts.Config.Universal.Pull), Handler: opts.Guards.NoPopupPanel(self.HandlePull), GetDisabledReason: self.getDisabledReasonForPushOrPull, Description: self.c.Tr.Pull, diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 352ec05e6..a10f9a374 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -39,7 +39,7 @@ func NewTagsController( func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.checkout), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Checkout, @@ -47,14 +47,14 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(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), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItem(self.delete), Description: self.c.Tr.Delete, GetDisabledReason: self.require(self.singleItemSelected()), @@ -63,7 +63,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Branches.PushTag), + Keys: opts.GetKeys(opts.Config.Branches.PushTag), Handler: self.withItem(self.push), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.PushTag, @@ -71,7 +71,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Keys: opts.GetKeys(opts.Config.Commits.ViewResetOptions), Handler: self.withItem(self.createResetMenu), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Reset, @@ -80,7 +80,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. OpensMenu: true, }, { - Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Keys: opts.GetKeys(opts.Config.Universal.OpenDiffTool), Handler: self.withItem(func(selectedTag *models.Tag) error { return self.c.Helpers().Diff.OpenDiffToolForRef(selectedTag) }), @@ -282,14 +282,14 @@ func (self *TagsController) delete(tag *models.Tag) error { menuItems := []*types.MenuItem{ { Label: self.c.Tr.DeleteLocalTag, - Key: menuKey('c'), + Keys: menuKey('c'), OnPress: func() error { return self.localDelete(tag) }, }, { Label: self.c.Tr.DeleteRemoteTag, - Key: menuKey('r'), + Keys: menuKey('r'), OpensMenu: true, OnPress: func() error { return self.remoteDelete(tag) @@ -297,7 +297,7 @@ func (self *TagsController) delete(tag *models.Tag) error { }, { Label: self.c.Tr.DeleteLocalAndRemoteTag, - Key: menuKey('b'), + Keys: menuKey('b'), OpensMenu: true, OnPress: func() error { return self.localAndRemoteDelete(tag) diff --git a/pkg/gui/controllers/undo_controller.go b/pkg/gui/controllers/undo_controller.go index 02e27ddce..775e871a4 100644 --- a/pkg/gui/controllers/undo_controller.go +++ b/pkg/gui/controllers/undo_controller.go @@ -53,13 +53,13 @@ type reflogAction struct { func (self *UndoController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.Undo), + Keys: opts.GetKeys(opts.Config.Universal.Undo), Handler: self.reflogUndo, Description: self.c.Tr.UndoReflog, Tooltip: self.c.Tr.UndoTooltip, }, { - Key: opts.GetKey(opts.Config.Universal.Redo), + Keys: opts.GetKeys(opts.Config.Universal.Redo), Handler: self.reflogRedo, Description: self.c.Tr.RedoReflog, Tooltip: self.c.Tr.RedoTooltip, diff --git a/pkg/gui/controllers/view_selection_controller.go b/pkg/gui/controllers/view_selection_controller.go index 0d69c5109..710fd37cb 100644 --- a/pkg/gui/controllers/view_selection_controller.go +++ b/pkg/gui/controllers/view_selection_controller.go @@ -36,16 +36,16 @@ func (self *ViewSelectionController) Context() types.Context { func (self *ViewSelectionController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.handlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.handlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.handleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.handleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.handlePrevPage, Description: self.c.Tr.PrevPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), Handler: self.handleGotoTop}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), Handler: self.handleGotoBottom}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.handlePrevLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.handlePrevLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.handleNextLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.handleNextLine}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: self.handlePrevPage, Description: self.c.Tr.PrevPage}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: self.handleGotoTop}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: self.handleGotoBottom}, } } diff --git a/pkg/gui/controllers/workspace_reset_controller.go b/pkg/gui/controllers/workspace_reset_controller.go index c6b68fb96..9a9005254 100644 --- a/pkg/gui/controllers/workspace_reset_controller.go +++ b/pkg/gui/controllers/workspace_reset_controller.go @@ -53,7 +53,7 @@ func (self *FilesController) createResetMenu() error { }) return nil }, - Key: menuKey('x'), + Keys: menuKey('x'), Tooltip: self.c.Tr.NukeDescription, }, { @@ -72,7 +72,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: menuKey('u'), + Keys: menuKey('u'), }, { LabelColumns: []string{ @@ -90,7 +90,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: menuKey('c'), + Keys: menuKey('c'), }, { LabelColumns: []string{ @@ -115,7 +115,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: menuKey('S'), + Keys: menuKey('S'), }, { LabelColumns: []string{ @@ -133,7 +133,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: menuKey('s'), + Keys: menuKey('s'), }, { LabelColumns: []string{ @@ -151,7 +151,7 @@ func (self *FilesController) createResetMenu() error { ) return nil }, - Key: menuKey('m'), + Keys: menuKey('m'), }, { LabelColumns: []string{ @@ -176,7 +176,7 @@ func (self *FilesController) createResetMenu() error { }, }) }, - Key: menuKey('h'), + Keys: menuKey('h'), }, } diff --git a/pkg/gui/controllers/worktree_options_controller.go b/pkg/gui/controllers/worktree_options_controller.go index 0cdf4d008..b1123e2a8 100644 --- a/pkg/gui/controllers/worktree_options_controller.go +++ b/pkg/gui/controllers/worktree_options_controller.go @@ -36,7 +36,7 @@ func NewWorktreeOptionsController(c *ControllerCommon, context CanViewWorktreeOp func (self *WorktreeOptionsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Worktrees.ViewWorktreeOptions), + Keys: opts.GetKeys(opts.Config.Worktrees.ViewWorktreeOptions), Handler: self.withItem(self.viewWorktreeOptions), Description: self.c.Tr.ViewWorktreeOptions, OpensMenu: true, diff --git a/pkg/gui/controllers/worktrees_controller.go b/pkg/gui/controllers/worktrees_controller.go index 0e34ec59f..5128ad716 100644 --- a/pkg/gui/controllers/worktrees_controller.go +++ b/pkg/gui/controllers/worktrees_controller.go @@ -39,13 +39,13 @@ func NewWorktreesController( func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: opts.GetKey(opts.Config.Universal.New), + Keys: opts.GetKeys(opts.Config.Universal.New), Handler: self.add, Description: self.c.Tr.NewWorktree, DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.Select), + Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Switch, @@ -53,18 +53,18 @@ func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*t DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.GoInto), + Keys: opts.GetKeys(opts.Config.Universal.GoInto), Handler: self.withItem(self.enter), GetDisabledReason: self.require(self.singleItemSelected()), }, { - Key: opts.GetKey(opts.Config.Universal.OpenFile), + Keys: opts.GetKeys(opts.Config.Universal.OpenFile), Handler: self.withItem(self.open), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.OpenInEditor, }, { - Key: opts.GetKey(opts.Config.Universal.Remove), + Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItem(self.remove), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Remove, diff --git a/pkg/gui/extras_panel.go b/pkg/gui/extras_panel.go index 468d8f290..980c31d45 100644 --- a/pkg/gui/extras_panel.go +++ b/pkg/gui/extras_panel.go @@ -15,7 +15,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error { Items: []*types.MenuItem{ { Label: gui.c.Tr.ToggleShowCommandLog, - Key: []gocui.Key{gocui.NewKeyRune('t')}, + Keys: []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.Key{gocui.NewKeyRune('f')}, + Keys: []gocui.Key{gocui.NewKeyRune('f')}, OnPress: gui.handleFocusCommandLog, }, }, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 038ae5d49..7bab622b7 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -69,9 +69,9 @@ func (gui *Gui) keybindingOpts() types.KeybindingsOpts { } return types.KeybindingsOpts{ - GetKey: config.GetValidatedKeyBindingKeys, - Config: keybindingConfig, - Guards: guards, + GetKeys: config.GetValidatedKeyBindingKeys, + Config: keybindingConfig, + Guards: guards, } } @@ -81,114 +81,114 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin bindings := []*types.Binding{ { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.OpenRecentRepos), + Keys: opts.GetKeys(opts.Config.Universal.OpenRecentRepos), Handler: opts.Guards.NoPopupPanel(gui.helpers.Repos.CreateRecentReposMenu), Description: gui.c.Tr.SwitchRepo, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollUpMain), + Keys: opts.GetKeys(opts.Config.Universal.ScrollUpMain), Handler: gui.scrollUpMain, Alternative: "fn+up/shift+k", Description: gui.c.Tr.ScrollUpMainWindow, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollDownMain), + Keys: opts.GetKeys(opts.Config.Universal.ScrollDownMain), Handler: gui.scrollDownMain, Alternative: "fn+down/shift+j", Description: gui.c.Tr.ScrollDownMainWindow, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt1), + Keys: opts.GetKeys(opts.Config.Universal.ScrollUpMainAlt1), Handler: gui.scrollUpMain, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt1), + Keys: opts.GetKeys(opts.Config.Universal.ScrollDownMainAlt1), Handler: gui.scrollDownMain, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt2), + Keys: opts.GetKeys(opts.Config.Universal.ScrollUpMainAlt2), Handler: gui.scrollUpMain, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt2), + Keys: opts.GetKeys(opts.Config.Universal.ScrollDownMainAlt2), Handler: gui.scrollDownMain, }, { ViewName: "files", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyPathToClipboard, }, { ViewName: "localBranches", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyBranchNameToClipboard, }, { ViewName: "remoteBranches", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyBranchNameToClipboard, }, { ViewName: "tags", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyTagToClipboard, }, { ViewName: "commits", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemCommitHashToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "commits", - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Keys: opts.GetKeys(opts.Config.Commits.ResetCherryPick), Handler: gui.helpers.CherryPick.Reset, Description: gui.c.Tr.ResetCherryPick, }, { ViewName: "reflogCommits", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "subCommits", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemCommitHashToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "information", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)}, Handler: gui.handleInfoClick, }, { ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopyPathToClipboard, }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ExtrasMenu), + Keys: opts.GetKeys(opts.Config.Universal.ExtrasMenu), Handler: opts.Guards.NoPopupPanel(gui.handleCreateExtrasMenuPanel), Description: gui.c.Tr.OpenCommandLogMenu, Tooltip: gui.c.Tr.OpenCommandLogMenuTooltip, @@ -196,163 +196,163 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin }, { ViewName: "main", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, Handler: gui.scrollDownMain, Description: gui.c.Tr.ScrollDown, Alternative: "fn+up", }, { ViewName: "main", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, Handler: gui.scrollUpMain, Description: gui.c.Tr.ScrollUp, Alternative: "fn+down", }, { ViewName: "secondary", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, Handler: gui.scrollDownSecondary, }, { ViewName: "secondary", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, Handler: gui.scrollUpSecondary, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.NextItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.NextPage), + Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: gui.pageDownConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.PrevPage), + Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: gui.pageUpConfirmationPanel, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.GotoTop), + Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: gui.goToConfirmationPanelTop, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: gui.goToConfirmationPanelTop, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.GotoBottom), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: gui.goToConfirmationPanelBottom, }, { ViewName: "confirmation", - Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: gui.goToConfirmationPanelBottom, }, { ViewName: "submodules", - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, Description: gui.c.Tr.CopySubmoduleNameToClipboard, }, { ViewName: "extras", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, Handler: gui.scrollUpExtra, }, { ViewName: "extras", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, Handler: gui.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: gui.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.PrevItem), + Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: gui.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.NextItem), + Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: gui.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", - Key: opts.GetKey(opts.Config.Universal.NextItemAlt), + Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: gui.scrollDownExtra, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.NextPage), + Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: gui.pageDownExtrasPanel, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.PrevPage), + Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: gui.pageUpExtrasPanel, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.GotoTop), + Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: gui.goToExtrasPanelTop, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: gui.goToExtrasPanelTop, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.GotoBottom), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: gui.goToExtrasPanelBottom, }, { ViewName: "extras", - Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), + Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: gui.goToExtrasPanelBottom, }, { ViewName: "extras", Tag: "navigation", - Key: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)}, + Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseLeft)}, Handler: gui.handleFocusCommandLog, }, } @@ -372,14 +372,14 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin bindings = append(bindings, []*types.Binding{ { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.NextTab), + Keys: opts.GetKeys(opts.Config.Universal.NextTab), Handler: opts.Guards.NoPopupPanel(gui.handleNextTab), Description: gui.c.Tr.NextTab, Tag: "navigation", }, { ViewName: "", - Key: opts.GetKey(opts.Config.Universal.PrevTab), + Keys: opts.GetKeys(opts.Config.Universal.PrevTab), Handler: opts.Guards.NoPopupPanel(gui.handlePrevTab), Description: gui.c.Tr.PrevTab, Tag: "navigation", @@ -448,7 +448,7 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) { return gui.callKeybindingHandler(binding) } - for _, key := range binding.Key { + for _, key := range binding.Keys { gui.g.SetKeybinding(binding.ViewName, key, handler) } } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 20079700c..e43ac1d29 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -47,7 +47,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error { // Remove all item keybindings that are the same as one of the essential bindings if !opts.KeepConflictingKeybindings { - item.Key = lo.Filter(item.Key, func(k gocui.Key, _ int) bool { + item.Keys = lo.Filter(item.Keys, func(k gocui.Key, _ int) bool { return !lo.Contains(essentialKeys, k) }) } diff --git a/pkg/gui/options_map.go b/pkg/gui/options_map.go index 2771a6c25..c0d0fcfff 100644 --- a/pkg/gui/options_map.go +++ b/pkg/gui/options_map.go @@ -42,11 +42,11 @@ func (self *OptionsMapMgr) renderContextOptionsMap() { currentContextKeys := set.NewFromSlice( lo.FlatMap(currentContextBindings, func(binding *types.Binding, _ int) []gocui.Key { - return binding.Key + return binding.Keys })) allBindings := append(currentContextBindings, lo.Filter(globalBindings, func(b *types.Binding, _ int) bool { - return len(b.Key) == 0 || !currentContextKeys.Includes(b.Key[0]) + return len(b.Keys) == 0 || !currentContextKeys.Includes(b.Keys[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[0]), + key: config.LabelForKey(binding.Keys[0]), description: binding.GetShortDescription(), style: displayStyle, } diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go index 6d30ab310..0884e0cce 100644 --- a/pkg/gui/services/custom_commands/client.go +++ b/pkg/gui/services/custom_commands/client.go @@ -46,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: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)}, + Keys: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)}, Handler: handler, Description: getCustomCommandsMenuDescription(customCommand, self.c.Tr), OpensMenu: true, @@ -73,7 +73,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e } menuItems = append(menuItems, &types.MenuItem{ Label: subCommand.GetDescription(), - Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)}, + Keys: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)}, OnPress: handler, OpensMenu: true, }) @@ -93,7 +93,7 @@ func (self *Client) showCustomCommandsMenu(customCommand config.CustomCommand) e menuItems = append(menuItems, &types.MenuItem{ Label: subCommand.GetDescription(), - Key: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)}, + Keys: []gocui.Key{config.GetValidatedKeyBindingKey(subCommand.Key)}, OnPress: self.handlerCreator.call(subCommand), }) } diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 60a4555d8..5f3fd27a0 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -232,7 +232,7 @@ func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrapp OnPress: func() error { return wrappedF(option.Value) }, - Key: []gocui.Key{config.GetValidatedKeyBindingKey(option.Key)}, + Keys: []gocui.Key{config.GetValidatedKeyBindingKey(option.Key)}, } }) diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go index 52456323a..ee0e01fa4 100644 --- a/pkg/gui/services/custom_commands/keybinding_creator.go +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -36,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: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)}, + Keys: []gocui.Key{config.GetValidatedKeyBindingKey(customCommand.Key)}, Handler: handler, Description: customCommand.GetDescription(), } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 475cafeab..92f004634 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -259,10 +259,10 @@ type MenuItem struct { // Only applies when Label is used OpensMenu bool - // If Key is non-empty, the user can press any of these keys to invoke the + // If Keys 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 + Keys []gocui.Key // A widget to show in front of the menu item. Supported widget types are // checkboxes and radio buttons, diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 69d76ea78..dcf4b9a1a 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -239,9 +239,9 @@ type OnFocusLostOpts struct { type ContextKey string type KeybindingsOpts struct { - GetKey func(key string) []gocui.Key - Config config.KeybindingConfig - Guards KeybindingGuards + GetKeys func(key string) []gocui.Key + Config config.KeybindingConfig + Guards KeybindingGuards } type ( diff --git a/pkg/gui/types/keybindings.go b/pkg/gui/types/keybindings.go index 3b3e512d8..337162d76 100644 --- a/pkg/gui/types/keybindings.go +++ b/pkg/gui/types/keybindings.go @@ -11,7 +11,7 @@ import ( type Binding struct { ViewName string Handler func() error - Key []gocui.Key + Keys []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. From f08a49fe52556d15c35b43ca1407ff8f8f237b06 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 9 May 2026 20:22:43 +0200 Subject: [PATCH 09/17] Render every key for a binding in the cheatsheet The cheatsheet has been showing only the first key of each binding since Binding.Key became Binding.Keys; collapse the list back into a single comma-separated cell so users can see all the alternates at a glance once bindings start carrying more than one key. --- pkg/cheatsheet/generate.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index bd2eff624..a9cee6494 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -22,6 +22,7 @@ import ( "github.com/jesseduffield/lazycore/pkg/utils" "github.com/jesseduffield/lazygit/pkg/app" "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/samber/lo" @@ -156,7 +157,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.Keys[0]) + return binding.Description + keyLabels(binding.Keys) }) return headerWithBindings{ @@ -213,8 +214,14 @@ func formatTitle(title string) string { return fmt.Sprintf("\n## %s\n\n", title) } +func keyLabels(keys []gocui.Key) string { + return strings.Join(lo.Map(keys, func(k gocui.Key, _ int) string { + return config.LabelForKey(k) + }), ", ") +} + func formatBinding(binding *types.Binding) string { - action := config.LabelForKey(binding.Keys[0]) + action := keyLabels(binding.Keys) description := binding.Description if binding.Alternative != "" { action += fmt.Sprintf(" (%s)", binding.Alternative) From 06b8d5a1e469456d4be91c7864fef52ebab29d00 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 4 May 2026 07:21:42 +0200 Subject: [PATCH 10/17] Add Keybinding type that accepts a string or a sequence of strings Each user-configurable keybinding is currently a single string in the YAML config. To let users assign alternate keys to a command, introduce a Keybinding type that decodes from either a scalar (the existing single-key form, kept for backward compatibility and for a simpler config file) or a sequence of strings. Marshalling collapses single-element slices back to a scalar so configs and generated docs round-trip cleanly. JSONSchema describes the type as a oneOf union so editors validate either form; subsequent commits will inline the union into the generated schema and start using Keybinding as the field type. --- pkg/config/keybinding.go | 79 ++++++++++++++++++ pkg/config/keybinding_test.go | 151 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 pkg/config/keybinding.go create mode 100644 pkg/config/keybinding_test.go diff --git a/pkg/config/keybinding.go b/pkg/config/keybinding.go new file mode 100644 index 000000000..bf605d44f --- /dev/null +++ b/pkg/config/keybinding.go @@ -0,0 +1,79 @@ +package config + +import ( + "encoding/json" + "fmt" + + "github.com/karimkhaleel/jsonschema" + "github.com/samber/lo" + "gopkg.in/yaml.v3" +) + +// Keybinding represents the value of a single keybinding entry in the user's +// config. It's a slice of key strings to allow alternates, but for backward +// compatibility (and because most bindings only have one key) it can be +// written in YAML/JSON as either a single scalar string or as a sequence of +// strings. +type Keybinding []string + +func (k *Keybinding) UnmarshalYAML(node *yaml.Node) error { + var ss []string + switch node.Kind { + case yaml.ScalarNode: + var s string + if err := node.Decode(&s); err != nil { + return err + } + ss = []string{s} + case yaml.SequenceNode: + if err := node.Decode(&ss); err != nil { + return err + } + default: + return fmt.Errorf("expected a string or a sequence of strings for keybinding, got %v", node.Tag) + } + // Drop empty and entries so clients never have to special-case + // them: an empty Keybinding means "no key bound", a non-empty one is + // guaranteed to contain only real keys. + *k = lo.Filter(ss, func(s string, _ int) bool { + return s != "" && s != "" + }) + return nil +} + +func (k Keybinding) MarshalYAML() (any, error) { + if len(k) == 1 { + return k[0], nil + } + // Render multi-key bindings in flow style (`[a, b]`) rather than the default + // block style, which is more compact and reads better in the generated docs. + node := &yaml.Node{ + Kind: yaml.SequenceNode, + Style: yaml.FlowStyle, + } + for _, s := range k { + node.Content = append(node.Content, &yaml.Node{ + Kind: yaml.ScalarNode, + Value: s, + }) + } + return node, nil +} + +func (k Keybinding) MarshalJSON() ([]byte, error) { + if len(k) == 1 { + return json.Marshal(k[0]) + } + return json.Marshal([]string(k)) +} + +// JSONSchema lets the schema generator describe this type as a union of a +// string and an array of strings instead of just an array. +func (Keybinding) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + {Type: "string"}, + {Type: "array", Items: &jsonschema.Schema{Type: "string"}}, + }, + } +} diff --git a/pkg/config/keybinding_test.go b/pkg/config/keybinding_test.go new file mode 100644 index 000000000..d3406412c --- /dev/null +++ b/pkg/config/keybinding_test.go @@ -0,0 +1,151 @@ +package config + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" +) + +func TestKeybindingUnmarshalYAML(t *testing.T) { + scenarios := []struct { + name string + input string + expected Keybinding + wantErr bool + }{ + { + name: "scalar string", + input: `q`, + expected: Keybinding{"q"}, + }, + { + name: "scalar with special characters", + input: ``, + expected: Keybinding{""}, + }, + { + name: "sequence with one element", + input: `[q]`, + expected: Keybinding{"q"}, + }, + { + name: "sequence with multiple elements", + input: `["q", ""]`, + expected: Keybinding{"q", ""}, + }, + { + name: "empty sequence", + input: `[]`, + expected: Keybinding{}, + }, + { + name: "scalar decodes to empty", + input: ``, + expected: Keybinding{}, + }, + { + name: "scalar empty string decodes to empty", + input: `""`, + expected: Keybinding{}, + }, + { + name: " entries are filtered out of a sequence", + input: `["q", "", ""]`, + expected: Keybinding{"q", ""}, + }, + { + name: "mapping is rejected", + input: `{key: q}`, + wantErr: true, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + var k Keybinding + err := yaml.Unmarshal([]byte(s.input), &k) + if s.wantErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, s.expected, k) + }) + } +} + +func TestKeybindingMarshalYAML(t *testing.T) { + scenarios := []struct { + name string + input Keybinding + expected string + }{ + { + name: "single key emits a scalar", + input: Keybinding{"q"}, + expected: "q\n", + }, + { + name: "multiple keys emit a flow sequence", + input: Keybinding{"q", ""}, + expected: "[q, ]\n", + }, + { + name: "empty keybinding emits an empty sequence", + input: Keybinding{}, + expected: "[]\n", + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + out, err := yaml.Marshal(s.input) + assert.NoError(t, err) + assert.Equal(t, s.expected, string(out)) + }) + } +} + +func TestKeybindingMarshalJSON(t *testing.T) { + scenarios := []struct { + name string + input Keybinding + expected string + }{ + { + name: "single key emits a string", + input: Keybinding{"q"}, + expected: `"q"`, + }, + { + name: "multiple keys emit an array", + input: Keybinding{"q", "esc"}, + expected: `["q","esc"]`, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + out, err := json.Marshal(s.input) + assert.NoError(t, err) + assert.Equal(t, s.expected, string(out)) + }) + } +} + +func TestKeybindingYAMLRoundTrip(t *testing.T) { + scenarios := []Keybinding{ + {"q"}, + {"q", ""}, + {"", "", ""}, + } + for _, original := range scenarios { + out, err := yaml.Marshal(original) + assert.NoError(t, err) + var decoded Keybinding + assert.NoError(t, yaml.Unmarshal(out, &decoded)) + assert.Equal(t, original, decoded) + } +} From 5748d82073a126c2b8b5c13705e3f41b0e1527c7 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 10 May 2026 08:22:44 +0200 Subject: [PATCH 11/17] Convert keybinding fields to Keybinding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now every keybinding config field was a plain string. That meant a user couldn't ask for two keys to invoke a command — the config silently accepted only one form. Convert every string-typed field across all 13 KeybindingXxxConfig structs to Keybinding so the union type extends to every command. Defaults wrap their single-key value in Keybinding{...} so the generated Config.md still renders one scalar key per binding. The alt fields keep their separate Binding registrations for now: this commit does not yet introduce the merge mechanism that folds them into the main field — that comes in a follow-up. Consumers previously calling opts.GetKeys on a string field now call opts.GetKeys on the Keybinding, or take .String() / Keys[0] where a single value is needed. Adds a Keybinding.String helper for rendering, schema-generator work that inlines the Keybinding union into each consuming property, and a unit test covering the user-facing scalar/sequence YAML forms for quit. --- docs-master/Config.md | 5 +- docs-master/Custom_Command_Keybindings.md | 4 +- docs-master/keybindings/Custom_Keybindings.md | 2 + pkg/config/keybinding.go | 7 + pkg/config/keybinding_test.go | 31 + pkg/config/keynames.go | 11 +- pkg/config/user_config.go | 653 +++--- pkg/config/user_config_validation_test.go | 2 +- pkg/gocui/edit.go | 18 +- pkg/gocui/gui.go | 20 +- pkg/gui/context/commit_message_context.go | 4 +- .../controllers/basic_commits_controller.go | 4 +- .../commit_description_controller.go | 19 +- .../controllers/commit_message_controller.go | 5 +- pkg/gui/controllers/helpers/tags_helper.go | 4 +- .../jump_to_side_window_controller.go | 3 +- .../controllers/local_commits_controller.go | 6 +- pkg/gui/controllers/submodules_controller.go | 2 +- pkg/gui/controllers/sync_controller.go | 4 +- pkg/gui/gui.go | 16 +- pkg/gui/menu_panel.go | 8 +- pkg/gui/options_map.go | 8 +- pkg/gui/types/context.go | 2 +- pkg/gui/views.go | 2 +- .../commit_description_panel_driver.go | 2 +- .../components/commit_message_panel_driver.go | 2 +- pkg/integration/components/prompt_driver.go | 12 +- pkg/integration/components/test_driver.go | 4 +- pkg/integration/components/view_driver.go | 13 +- pkg/integration/tests/commit/search.go | 14 +- .../custom_commands_in_per_repo_config.go | 6 +- .../access_commit_properties.go | 2 +- .../tests/custom_commands/basic_command.go | 2 +- .../custom_commands/check_for_conflicts.go | 2 +- .../conditional_prompt_false_string.go | 2 +- .../conditional_prompt_false_value.go | 2 +- .../custom_commands/conditional_prompts.go | 8 +- .../custom_commands_submenu.go | 6 +- ...mmands_submenu_with_special_keybindings.go | 10 +- .../tests/custom_commands/form_prompts.go | 2 +- .../tests/custom_commands/global_context.go | 6 +- .../custom_commands/menu_from_command.go | 2 +- .../menu_from_commands_output.go | 2 +- .../custom_commands/menu_prompt_with_keys.go | 4 +- .../custom_commands/multiple_contexts.go | 6 +- .../tests/custom_commands/multiple_prompts.go | 2 +- .../tests/custom_commands/run_command.go | 2 +- .../tests/custom_commands/selected_commit.go | 14 +- .../custom_commands/selected_commit_range.go | 4 +- .../tests/custom_commands/selected_path.go | 4 +- .../custom_commands/selected_submodule.go | 6 +- .../custom_commands/show_output_in_panel.go | 4 +- .../custom_commands/suggestions_command.go | 2 +- .../custom_commands/suggestions_preset.go | 2 +- pkg/integration/tests/demo/custom_command.go | 2 +- .../filter_menu_with_no_keybindings.go | 4 +- .../interactive_rebase/show_exec_todos.go | 2 +- .../tests/misc/disabled_keybindings.go | 26 - pkg/integration/tests/submodule/enter.go | 2 +- pkg/integration/tests/submodule/reset.go | 2 +- pkg/integration/tests/test_list.go | 1 - ...disable_switch_tab_with_panel_jump_keys.go | 4 +- .../ui/switch_tab_with_panel_jump_keys.go | 10 +- .../tests/worktree/custom_command.go | 2 +- pkg/jsonschema/generate.go | 52 + schema-master/config.json | 1948 +++++++++++++++-- 66 files changed, 2370 insertions(+), 674 deletions(-) delete mode 100644 pkg/integration/tests/misc/disabled_keybindings.go diff --git a/docs-master/Config.md b/docs-master/Config.md index b24329548..4e9a4617a 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -591,7 +591,10 @@ notARepository: prompt # view the output of the subprocess before returning to Lazygit. promptToReturnFromSubprocess: true -# Keybindings +# Keybindings. +# Each binding can be a single key or a list of keys; see +# https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md +# for the syntax. keybinding: universal: quit: q diff --git a/docs-master/Custom_Command_Keybindings.md b/docs-master/Custom_Command_Keybindings.md index c8036ea41..55e14d5f1 100644 --- a/docs-master/Custom_Command_Keybindings.md +++ b/docs-master/Custom_Command_Keybindings.md @@ -50,7 +50,7 @@ Custom command keybindings will appear alongside inbuilt keybindings when you vi For a given custom command, here are the allowed fields: | _field_ | _description_ | required | |-----------------|----------------------|-| -| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no | +| key | The key to trigger the command. Use a single key or list of keys, as described in [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no | | command | The command to run (using Go template syntax for placeholder values) | yes | | context | The context in which to listen for the key (see [below](#contexts)) | yes | | prompts | A list of prompts that will request user input before running the final command | no | @@ -193,7 +193,7 @@ The permitted option fields are: | name | The first part of the label | no | | description | The second part of the label | no | | value | the value that will be used in the command | yes | -| key | Keybinding to invoke this menu option without needing to navigate to it. Can be a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | no | +| key | Keybinding to invoke this menu option without needing to navigate to it. Use a single key or list of keys, as described in [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | no | If an option has no name the value will be displayed to the user in place of the name, so you're allowed to only include the value like so: diff --git a/docs-master/keybindings/Custom_Keybindings.md b/docs-master/keybindings/Custom_Keybindings.md index ad24070a3..998aae14c 100644 --- a/docs-master/keybindings/Custom_Keybindings.md +++ b/docs-master/keybindings/Custom_Keybindings.md @@ -7,6 +7,8 @@ A keybinding is one of: - A special key name in angle brackets, e.g. ``, ``, ``. - A key with modifiers in angle brackets, e.g. ``, ``. - The literal string `` to disable a binding. +- A list of any of the above, to bind multiple keys to the same action: + `quit: [q, ]`. ### Modifiers diff --git a/pkg/config/keybinding.go b/pkg/config/keybinding.go index bf605d44f..f552707e5 100644 --- a/pkg/config/keybinding.go +++ b/pkg/config/keybinding.go @@ -3,6 +3,7 @@ package config import ( "encoding/json" "fmt" + "strings" "github.com/karimkhaleel/jsonschema" "github.com/samber/lo" @@ -67,6 +68,12 @@ func (k Keybinding) MarshalJSON() ([]byte, error) { return json.Marshal([]string(k)) } +// String renders the keybinding as a human-readable label, joining +// alternates with " or " for use in help text. +func (k Keybinding) String() string { + return strings.Join(k, " or ") +} + // JSONSchema lets the schema generator describe this type as a union of a // string and an array of strings instead of just an array. func (Keybinding) JSONSchema() *jsonschema.Schema { diff --git a/pkg/config/keybinding_test.go b/pkg/config/keybinding_test.go index d3406412c..9bf3ed442 100644 --- a/pkg/config/keybinding_test.go +++ b/pkg/config/keybinding_test.go @@ -149,3 +149,34 @@ func TestKeybindingYAMLRoundTrip(t *testing.T) { assert.Equal(t, original, decoded) } } + +func TestKeybindingConfigYAMLAcceptsBothForms(t *testing.T) { + scenarios := []struct { + name string + yaml string + expected Keybinding + }{ + { + name: "scalar form", + yaml: "quit: q\n", + expected: Keybinding{"q"}, + }, + { + name: "sequence form", + yaml: "quit: [q, ]\n", + expected: Keybinding{"q", ""}, + }, + { + name: "block sequence form", + yaml: "quit:\n - q\n - \n", + expected: Keybinding{"q", ""}, + }, + } + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + var cfg KeybindingUniversalConfig + assert.NoError(t, yaml.Unmarshal([]byte(s.yaml), &cfg)) + assert.Equal(t, s.expected, cfg.Quit) + }) + } +} diff --git a/pkg/config/keynames.go b/pkg/config/keynames.go index 7f361dec8..da5b8dbae 100644 --- a/pkg/config/keynames.go +++ b/pkg/config/keynames.go @@ -206,10 +206,9 @@ 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} +func GetValidatedKeyBindingKeys(labels Keybinding) []gocui.Key { + return lo.FilterMap(labels, func(label string, _ int) (gocui.Key, bool) { + k := GetValidatedKeyBindingKey(label) + return k, k.IsSet() + }) } diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 3d59782e5..bbd568e8d 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -36,7 +36,8 @@ type UserConfig struct { NotARepository string `yaml:"notARepository" jsonschema:"enum=prompt,enum=create,enum=skip,enum=quit"` // If true, display a confirmation when subprocess terminates. This allows you to view the output of the subprocess before returning to Lazygit. PromptToReturnFromSubprocess bool `yaml:"promptToReturnFromSubprocess"` - // Keybindings + // Keybindings. + // Each binding can be a single key or a list of keys; see https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md for the syntax. Keybinding KeybindingConfig `yaml:"keybinding"` } @@ -422,202 +423,202 @@ type KeybindingConfig struct { // damn looks like we have some inconsistencies here with -alt and -alt1 type KeybindingUniversalConfig struct { - Quit string `yaml:"quit"` - QuitAlt1 string `yaml:"quit-alt1"` - SuspendApp string `yaml:"suspendApp"` - Return string `yaml:"return"` - QuitWithoutChangingDirectory string `yaml:"quitWithoutChangingDirectory"` - TogglePanel string `yaml:"togglePanel"` - PrevItem string `yaml:"prevItem"` - NextItem string `yaml:"nextItem"` - PrevItemAlt string `yaml:"prevItem-alt"` - NextItemAlt string `yaml:"nextItem-alt"` - PrevPage string `yaml:"prevPage"` - NextPage string `yaml:"nextPage"` - ScrollLeft string `yaml:"scrollLeft"` - ScrollRight string `yaml:"scrollRight"` - GotoTop string `yaml:"gotoTop"` - GotoBottom string `yaml:"gotoBottom"` - GotoTopAlt string `yaml:"gotoTop-alt"` - GotoBottomAlt string `yaml:"gotoBottom-alt"` - ToggleRangeSelect string `yaml:"toggleRangeSelect"` - RangeSelectDown string `yaml:"rangeSelectDown"` - RangeSelectUp string `yaml:"rangeSelectUp"` - PrevBlock string `yaml:"prevBlock"` - NextBlock string `yaml:"nextBlock"` - PrevBlockAlt string `yaml:"prevBlock-alt"` - NextBlockAlt string `yaml:"nextBlock-alt"` - NextBlockAlt2 string `yaml:"nextBlock-alt2"` - PrevBlockAlt2 string `yaml:"prevBlock-alt2"` - JumpToBlock []string `yaml:"jumpToBlock"` - FocusMainView string `yaml:"focusMainView"` - NextMatch string `yaml:"nextMatch"` - PrevMatch string `yaml:"prevMatch"` - StartSearch string `yaml:"startSearch"` - MoveWordLeft string `yaml:"moveWordLeft"` // on Mac - MoveWordRight string `yaml:"moveWordRight"` // on Mac - BackspaceWord string `yaml:"backspaceWord"` // on Mac - ForwardDeleteWord string `yaml:"forwardDeleteWord"` // on Mac - OptionMenu string `yaml:"optionMenu"` - Select string `yaml:"select"` - GoInto string `yaml:"goInto"` - Confirm string `yaml:"confirm"` - ConfirmMenu string `yaml:"confirmMenu"` - ConfirmSuggestion string `yaml:"confirmSuggestion"` - ConfirmInEditor string `yaml:"confirmInEditor"` // on Mac - ConfirmInEditorAlt string `yaml:"confirmInEditor-alt"` - Remove string `yaml:"remove"` - New string `yaml:"new"` - Edit string `yaml:"edit"` - OpenFile string `yaml:"openFile"` - ScrollUpMain string `yaml:"scrollUpMain"` - ScrollDownMain string `yaml:"scrollDownMain"` - ScrollUpMainAlt1 string `yaml:"scrollUpMain-alt1"` - ScrollDownMainAlt1 string `yaml:"scrollDownMain-alt1"` - ScrollUpMainAlt2 string `yaml:"scrollUpMain-alt2"` - ScrollDownMainAlt2 string `yaml:"scrollDownMain-alt2"` - ExecuteShellCommand string `yaml:"executeShellCommand"` - CreateRebaseOptionsMenu string `yaml:"createRebaseOptionsMenu"` - Push string `yaml:"pushFiles"` // 'Files' appended for legacy reasons - Pull string `yaml:"pullFiles"` // 'Files' appended for legacy reasons - Refresh string `yaml:"refresh"` - CreatePatchOptionsMenu string `yaml:"createPatchOptionsMenu"` - NextTab string `yaml:"nextTab"` - PrevTab string `yaml:"prevTab"` - NextScreenMode string `yaml:"nextScreenMode"` - PrevScreenMode string `yaml:"prevScreenMode"` - CyclePagers string `yaml:"cyclePagers"` - Undo string `yaml:"undo"` - Redo string `yaml:"redo"` - FilteringMenu string `yaml:"filteringMenu"` - DiffingMenu string `yaml:"diffingMenu"` - DiffingMenuAlt string `yaml:"diffingMenu-alt"` - CopyToClipboard string `yaml:"copyToClipboard"` - OpenRecentRepos string `yaml:"openRecentRepos"` - SubmitEditorText string `yaml:"submitEditorText"` - ExtrasMenu string `yaml:"extrasMenu"` - ToggleWhitespaceInDiffView string `yaml:"toggleWhitespaceInDiffView"` - IncreaseContextInDiffView string `yaml:"increaseContextInDiffView"` - DecreaseContextInDiffView string `yaml:"decreaseContextInDiffView"` - IncreaseRenameSimilarityThreshold string `yaml:"increaseRenameSimilarityThreshold"` - DecreaseRenameSimilarityThreshold string `yaml:"decreaseRenameSimilarityThreshold"` - OpenDiffTool string `yaml:"openDiffTool"` + Quit Keybinding `yaml:"quit"` + QuitAlt1 Keybinding `yaml:"quit-alt1"` + SuspendApp Keybinding `yaml:"suspendApp"` + Return Keybinding `yaml:"return"` + QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"` + TogglePanel Keybinding `yaml:"togglePanel"` + PrevItem Keybinding `yaml:"prevItem"` + NextItem Keybinding `yaml:"nextItem"` + PrevItemAlt Keybinding `yaml:"prevItem-alt"` + NextItemAlt Keybinding `yaml:"nextItem-alt"` + PrevPage Keybinding `yaml:"prevPage"` + NextPage Keybinding `yaml:"nextPage"` + ScrollLeft Keybinding `yaml:"scrollLeft"` + ScrollRight Keybinding `yaml:"scrollRight"` + GotoTop Keybinding `yaml:"gotoTop"` + GotoBottom Keybinding `yaml:"gotoBottom"` + GotoTopAlt Keybinding `yaml:"gotoTop-alt"` + GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"` + ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"` + RangeSelectDown Keybinding `yaml:"rangeSelectDown"` + RangeSelectUp Keybinding `yaml:"rangeSelectUp"` + PrevBlock Keybinding `yaml:"prevBlock"` + NextBlock Keybinding `yaml:"nextBlock"` + PrevBlockAlt Keybinding `yaml:"prevBlock-alt"` + NextBlockAlt Keybinding `yaml:"nextBlock-alt"` + NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"` + PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"` + JumpToBlock []string `yaml:"jumpToBlock"` + FocusMainView Keybinding `yaml:"focusMainView"` + NextMatch Keybinding `yaml:"nextMatch"` + PrevMatch Keybinding `yaml:"prevMatch"` + StartSearch Keybinding `yaml:"startSearch"` + MoveWordLeft Keybinding `yaml:"moveWordLeft"` // on Mac + MoveWordRight Keybinding `yaml:"moveWordRight"` // on Mac + BackspaceWord Keybinding `yaml:"backspaceWord"` // on Mac + ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // on Mac + OptionMenu Keybinding `yaml:"optionMenu"` + Select Keybinding `yaml:"select"` + GoInto Keybinding `yaml:"goInto"` + Confirm Keybinding `yaml:"confirm"` + ConfirmMenu Keybinding `yaml:"confirmMenu"` + ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"` + ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // on Mac + ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"` + Remove Keybinding `yaml:"remove"` + New Keybinding `yaml:"new"` + Edit Keybinding `yaml:"edit"` + OpenFile Keybinding `yaml:"openFile"` + ScrollUpMain Keybinding `yaml:"scrollUpMain"` + ScrollDownMain Keybinding `yaml:"scrollDownMain"` + ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"` + ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"` + ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"` + ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"` + ExecuteShellCommand Keybinding `yaml:"executeShellCommand"` + CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"` + Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons + Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons + Refresh Keybinding `yaml:"refresh"` + CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"` + NextTab Keybinding `yaml:"nextTab"` + PrevTab Keybinding `yaml:"prevTab"` + NextScreenMode Keybinding `yaml:"nextScreenMode"` + PrevScreenMode Keybinding `yaml:"prevScreenMode"` + CyclePagers Keybinding `yaml:"cyclePagers"` + Undo Keybinding `yaml:"undo"` + Redo Keybinding `yaml:"redo"` + FilteringMenu Keybinding `yaml:"filteringMenu"` + DiffingMenu Keybinding `yaml:"diffingMenu"` + DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"` + CopyToClipboard Keybinding `yaml:"copyToClipboard"` + OpenRecentRepos Keybinding `yaml:"openRecentRepos"` + SubmitEditorText Keybinding `yaml:"submitEditorText"` + ExtrasMenu Keybinding `yaml:"extrasMenu"` + ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"` + IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"` + DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"` + IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"` + DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"` + OpenDiffTool Keybinding `yaml:"openDiffTool"` } type KeybindingStatusConfig struct { - CheckForUpdate string `yaml:"checkForUpdate"` - RecentRepos string `yaml:"recentRepos"` - AllBranchesLogGraph string `yaml:"allBranchesLogGraph"` - AllBranchesLogGraphReverse string `yaml:"allBranchesLogGraphReverse"` + CheckForUpdate Keybinding `yaml:"checkForUpdate"` + RecentRepos Keybinding `yaml:"recentRepos"` + AllBranchesLogGraph Keybinding `yaml:"allBranchesLogGraph"` + AllBranchesLogGraphReverse Keybinding `yaml:"allBranchesLogGraphReverse"` } type KeybindingFilesConfig struct { - CommitChanges string `yaml:"commitChanges"` - CommitChangesWithoutHook string `yaml:"commitChangesWithoutHook"` - AmendLastCommit string `yaml:"amendLastCommit"` - CommitChangesWithEditor string `yaml:"commitChangesWithEditor"` - FindBaseCommitForFixup string `yaml:"findBaseCommitForFixup"` - ConfirmDiscard string `yaml:"confirmDiscard"` - IgnoreFile string `yaml:"ignoreFile"` - RefreshFiles string `yaml:"refreshFiles"` - StashAllChanges string `yaml:"stashAllChanges"` - ViewStashOptions string `yaml:"viewStashOptions"` - ToggleStagedAll string `yaml:"toggleStagedAll"` - ViewResetOptions string `yaml:"viewResetOptions"` - Fetch string `yaml:"fetch"` - ToggleTreeView string `yaml:"toggleTreeView"` - OpenMergeOptions string `yaml:"openMergeOptions"` - OpenStatusFilter string `yaml:"openStatusFilter"` - CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"` - CollapseAll string `yaml:"collapseAll"` - ExpandAll string `yaml:"expandAll"` + CommitChanges Keybinding `yaml:"commitChanges"` + CommitChangesWithoutHook Keybinding `yaml:"commitChangesWithoutHook"` + AmendLastCommit Keybinding `yaml:"amendLastCommit"` + CommitChangesWithEditor Keybinding `yaml:"commitChangesWithEditor"` + FindBaseCommitForFixup Keybinding `yaml:"findBaseCommitForFixup"` + ConfirmDiscard Keybinding `yaml:"confirmDiscard"` + IgnoreFile Keybinding `yaml:"ignoreFile"` + RefreshFiles Keybinding `yaml:"refreshFiles"` + StashAllChanges Keybinding `yaml:"stashAllChanges"` + ViewStashOptions Keybinding `yaml:"viewStashOptions"` + ToggleStagedAll Keybinding `yaml:"toggleStagedAll"` + ViewResetOptions Keybinding `yaml:"viewResetOptions"` + Fetch Keybinding `yaml:"fetch"` + ToggleTreeView Keybinding `yaml:"toggleTreeView"` + OpenMergeOptions Keybinding `yaml:"openMergeOptions"` + OpenStatusFilter Keybinding `yaml:"openStatusFilter"` + CopyFileInfoToClipboard Keybinding `yaml:"copyFileInfoToClipboard"` + CollapseAll Keybinding `yaml:"collapseAll"` + ExpandAll Keybinding `yaml:"expandAll"` } type KeybindingBranchesConfig struct { - CreatePullRequest string `yaml:"createPullRequest"` - ViewPullRequestOptions string `yaml:"viewPullRequestOptions"` - OpenPullRequestInBrowser string `yaml:"openPullRequestInBrowser"` - CopyPullRequestURL string `yaml:"copyPullRequestURL"` - CheckoutBranchByName string `yaml:"checkoutBranchByName"` - ForceCheckoutBranch string `yaml:"forceCheckoutBranch"` - CheckoutPreviousBranch string `yaml:"checkoutPreviousBranch"` - RebaseBranch string `yaml:"rebaseBranch"` - RenameBranch string `yaml:"renameBranch"` - MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"` - MoveCommitsToNewBranch string `yaml:"moveCommitsToNewBranch"` - ViewGitFlowOptions string `yaml:"viewGitFlowOptions"` - FastForward string `yaml:"fastForward"` - CreateTag string `yaml:"createTag"` - PushTag string `yaml:"pushTag"` - SetUpstream string `yaml:"setUpstream"` - FetchRemote string `yaml:"fetchRemote"` - AddForkRemote string `yaml:"addForkRemote"` - SortOrder string `yaml:"sortOrder"` + CreatePullRequest Keybinding `yaml:"createPullRequest"` + ViewPullRequestOptions Keybinding `yaml:"viewPullRequestOptions"` + OpenPullRequestInBrowser Keybinding `yaml:"openPullRequestInBrowser"` + CopyPullRequestURL Keybinding `yaml:"copyPullRequestURL"` + CheckoutBranchByName Keybinding `yaml:"checkoutBranchByName"` + ForceCheckoutBranch Keybinding `yaml:"forceCheckoutBranch"` + CheckoutPreviousBranch Keybinding `yaml:"checkoutPreviousBranch"` + RebaseBranch Keybinding `yaml:"rebaseBranch"` + RenameBranch Keybinding `yaml:"renameBranch"` + MergeIntoCurrentBranch Keybinding `yaml:"mergeIntoCurrentBranch"` + MoveCommitsToNewBranch Keybinding `yaml:"moveCommitsToNewBranch"` + ViewGitFlowOptions Keybinding `yaml:"viewGitFlowOptions"` + FastForward Keybinding `yaml:"fastForward"` + CreateTag Keybinding `yaml:"createTag"` + PushTag Keybinding `yaml:"pushTag"` + SetUpstream Keybinding `yaml:"setUpstream"` + FetchRemote Keybinding `yaml:"fetchRemote"` + AddForkRemote Keybinding `yaml:"addForkRemote"` + SortOrder Keybinding `yaml:"sortOrder"` } type KeybindingWorktreesConfig struct { - ViewWorktreeOptions string `yaml:"viewWorktreeOptions"` + ViewWorktreeOptions Keybinding `yaml:"viewWorktreeOptions"` } type KeybindingCommitsConfig struct { - SquashDown string `yaml:"squashDown"` - RenameCommit string `yaml:"renameCommit"` - RenameCommitWithEditor string `yaml:"renameCommitWithEditor"` - ViewResetOptions string `yaml:"viewResetOptions"` - MarkCommitAsFixup string `yaml:"markCommitAsFixup"` - SetFixupMessage string `yaml:"setFixupMessage"` - CreateFixupCommit string `yaml:"createFixupCommit"` - SquashAboveCommits string `yaml:"squashAboveCommits"` - MoveDownCommit string `yaml:"moveDownCommit"` - MoveUpCommit string `yaml:"moveUpCommit"` - AmendToCommit string `yaml:"amendToCommit"` - ResetCommitAuthor string `yaml:"resetCommitAuthor"` - PickCommit string `yaml:"pickCommit"` - RevertCommit string `yaml:"revertCommit"` - CherryPickCopy string `yaml:"cherryPickCopy"` - PasteCommits string `yaml:"pasteCommits"` - MarkCommitAsBaseForRebase string `yaml:"markCommitAsBaseForRebase"` - CreateTag string `yaml:"tagCommit"` - CheckoutCommit string `yaml:"checkoutCommit"` - ResetCherryPick string `yaml:"resetCherryPick"` - CopyCommitAttributeToClipboard string `yaml:"copyCommitAttributeToClipboard"` - OpenLogMenu string `yaml:"openLogMenu"` - OpenInBrowser string `yaml:"openInBrowser"` - OpenPullRequestInBrowser string `yaml:"openPullRequestInBrowser"` - ViewBisectOptions string `yaml:"viewBisectOptions"` - StartInteractiveRebase string `yaml:"startInteractiveRebase"` - SelectCommitsOfCurrentBranch string `yaml:"selectCommitsOfCurrentBranch"` + SquashDown Keybinding `yaml:"squashDown"` + RenameCommit Keybinding `yaml:"renameCommit"` + RenameCommitWithEditor Keybinding `yaml:"renameCommitWithEditor"` + ViewResetOptions Keybinding `yaml:"viewResetOptions"` + MarkCommitAsFixup Keybinding `yaml:"markCommitAsFixup"` + SetFixupMessage Keybinding `yaml:"setFixupMessage"` + CreateFixupCommit Keybinding `yaml:"createFixupCommit"` + SquashAboveCommits Keybinding `yaml:"squashAboveCommits"` + MoveDownCommit Keybinding `yaml:"moveDownCommit"` + MoveUpCommit Keybinding `yaml:"moveUpCommit"` + AmendToCommit Keybinding `yaml:"amendToCommit"` + ResetCommitAuthor Keybinding `yaml:"resetCommitAuthor"` + PickCommit Keybinding `yaml:"pickCommit"` + RevertCommit Keybinding `yaml:"revertCommit"` + CherryPickCopy Keybinding `yaml:"cherryPickCopy"` + PasteCommits Keybinding `yaml:"pasteCommits"` + MarkCommitAsBaseForRebase Keybinding `yaml:"markCommitAsBaseForRebase"` + CreateTag Keybinding `yaml:"tagCommit"` + CheckoutCommit Keybinding `yaml:"checkoutCommit"` + ResetCherryPick Keybinding `yaml:"resetCherryPick"` + CopyCommitAttributeToClipboard Keybinding `yaml:"copyCommitAttributeToClipboard"` + OpenLogMenu Keybinding `yaml:"openLogMenu"` + OpenInBrowser Keybinding `yaml:"openInBrowser"` + OpenPullRequestInBrowser Keybinding `yaml:"openPullRequestInBrowser"` + ViewBisectOptions Keybinding `yaml:"viewBisectOptions"` + StartInteractiveRebase Keybinding `yaml:"startInteractiveRebase"` + SelectCommitsOfCurrentBranch Keybinding `yaml:"selectCommitsOfCurrentBranch"` } type KeybindingAmendAttributeConfig struct { - ResetAuthor string `yaml:"resetAuthor"` - SetAuthor string `yaml:"setAuthor"` - AddCoAuthor string `yaml:"addCoAuthor"` + ResetAuthor Keybinding `yaml:"resetAuthor"` + SetAuthor Keybinding `yaml:"setAuthor"` + AddCoAuthor Keybinding `yaml:"addCoAuthor"` } type KeybindingStashConfig struct { - PopStash string `yaml:"popStash"` - RenameStash string `yaml:"renameStash"` + PopStash Keybinding `yaml:"popStash"` + RenameStash Keybinding `yaml:"renameStash"` } type KeybindingCommitFilesConfig struct { - CheckoutCommitFile string `yaml:"checkoutCommitFile"` + CheckoutCommitFile Keybinding `yaml:"checkoutCommitFile"` } type KeybindingMainConfig struct { - ToggleSelectHunk string `yaml:"toggleSelectHunk"` - PickBothHunks string `yaml:"pickBothHunks"` - EditSelectHunk string `yaml:"editSelectHunk"` + ToggleSelectHunk Keybinding `yaml:"toggleSelectHunk"` + PickBothHunks Keybinding `yaml:"pickBothHunks"` + EditSelectHunk Keybinding `yaml:"editSelectHunk"` } type KeybindingSubmodulesConfig struct { - Init string `yaml:"init"` - Update string `yaml:"update"` - BulkMenu string `yaml:"bulkMenu"` + Init Keybinding `yaml:"init"` + Update Keybinding `yaml:"update"` + BulkMenu Keybinding `yaml:"bulkMenu"` } type KeybindingCommitMessageConfig struct { - CommitMenu string `yaml:"commitMenu"` + CommitMenu Keybinding `yaml:"commitMenu"` } // OSConfig contains config on the level of the os @@ -904,191 +905,191 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig { PromptToReturnFromSubprocess: true, Keybinding: KeybindingConfig{ Universal: KeybindingUniversalConfig{ - Quit: "q", - QuitAlt1: "", - SuspendApp: "", - Return: "", - QuitWithoutChangingDirectory: "Q", - TogglePanel: "", - PrevItem: "", - NextItem: "", - PrevItemAlt: "k", - NextItemAlt: "j", - PrevPage: ",", - NextPage: ".", - ScrollLeft: "H", - ScrollRight: "L", - GotoTop: "<", - GotoBottom: ">", - GotoTopAlt: "", - GotoBottomAlt: "", - ToggleRangeSelect: "v", - RangeSelectDown: "", - RangeSelectUp: "", - PrevBlock: "", - NextBlock: "", - PrevBlockAlt: "h", - NextBlockAlt: "l", - PrevBlockAlt2: "", - NextBlockAlt2: "", + Quit: Keybinding{"q"}, + QuitAlt1: Keybinding{""}, + SuspendApp: Keybinding{""}, + Return: Keybinding{""}, + QuitWithoutChangingDirectory: Keybinding{"Q"}, + TogglePanel: Keybinding{""}, + PrevItem: Keybinding{""}, + NextItem: Keybinding{""}, + PrevItemAlt: Keybinding{"k"}, + NextItemAlt: Keybinding{"j"}, + PrevPage: Keybinding{","}, + NextPage: Keybinding{"."}, + ScrollLeft: Keybinding{"H"}, + ScrollRight: Keybinding{"L"}, + GotoTop: Keybinding{"<"}, + GotoBottom: Keybinding{">"}, + GotoTopAlt: Keybinding{""}, + GotoBottomAlt: Keybinding{""}, + ToggleRangeSelect: Keybinding{"v"}, + RangeSelectDown: Keybinding{""}, + RangeSelectUp: Keybinding{""}, + PrevBlock: Keybinding{""}, + NextBlock: Keybinding{""}, + PrevBlockAlt: Keybinding{"h"}, + NextBlockAlt: Keybinding{"l"}, + PrevBlockAlt2: Keybinding{""}, + NextBlockAlt2: Keybinding{""}, JumpToBlock: []string{"1", "2", "3", "4", "5"}, - FocusMainView: "0", - NextMatch: "n", - PrevMatch: "N", - StartSearch: "/", - MoveWordLeft: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - MoveWordRight: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - BackspaceWord: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - ForwardDeleteWord: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - OptionMenu: "?", - Select: "", - GoInto: "", - Confirm: "", - ConfirmMenu: "", - ConfirmSuggestion: "", - ConfirmInEditor: platformKeyBinding(platform, map[string]string{"darwin": ""}, ""), - ConfirmInEditorAlt: "", - Remove: "d", - New: "n", - Edit: "e", - OpenFile: "o", - OpenRecentRepos: "", - ScrollUpMain: "", - ScrollDownMain: "", - ScrollUpMainAlt1: "K", - ScrollDownMainAlt1: "J", - ScrollUpMainAlt2: "", - ScrollDownMainAlt2: "", - ExecuteShellCommand: ":", - CreateRebaseOptionsMenu: "m", - Push: "P", - Pull: "p", - Refresh: "R", - CreatePatchOptionsMenu: "", - NextTab: "]", - PrevTab: "[", - NextScreenMode: "+", - PrevScreenMode: "_", - CyclePagers: "|", - Undo: "z", - Redo: "Z", - FilteringMenu: "", - DiffingMenu: "W", - DiffingMenuAlt: "", - CopyToClipboard: "", - SubmitEditorText: "", - ExtrasMenu: "@", - ToggleWhitespaceInDiffView: "", - IncreaseContextInDiffView: "}", - DecreaseContextInDiffView: "{", - IncreaseRenameSimilarityThreshold: ")", - DecreaseRenameSimilarityThreshold: "(", - OpenDiffTool: "", + FocusMainView: Keybinding{"0"}, + NextMatch: Keybinding{"n"}, + PrevMatch: Keybinding{"N"}, + StartSearch: Keybinding{"/"}, + MoveWordLeft: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": ""}, "")}, + MoveWordRight: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": ""}, "")}, + BackspaceWord: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": ""}, "")}, + ForwardDeleteWord: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": ""}, "")}, + OptionMenu: Keybinding{"?"}, + Select: Keybinding{""}, + GoInto: Keybinding{""}, + Confirm: Keybinding{""}, + ConfirmMenu: Keybinding{""}, + ConfirmSuggestion: Keybinding{""}, + ConfirmInEditor: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": ""}, "")}, + ConfirmInEditorAlt: Keybinding{""}, + Remove: Keybinding{"d"}, + New: Keybinding{"n"}, + Edit: Keybinding{"e"}, + OpenFile: Keybinding{"o"}, + OpenRecentRepos: Keybinding{""}, + ScrollUpMain: Keybinding{""}, + ScrollDownMain: Keybinding{""}, + ScrollUpMainAlt1: Keybinding{"K"}, + ScrollDownMainAlt1: Keybinding{"J"}, + ScrollUpMainAlt2: Keybinding{""}, + ScrollDownMainAlt2: Keybinding{""}, + ExecuteShellCommand: Keybinding{":"}, + CreateRebaseOptionsMenu: Keybinding{"m"}, + Push: Keybinding{"P"}, + Pull: Keybinding{"p"}, + Refresh: Keybinding{"R"}, + CreatePatchOptionsMenu: Keybinding{""}, + NextTab: Keybinding{"]"}, + PrevTab: Keybinding{"["}, + NextScreenMode: Keybinding{"+"}, + PrevScreenMode: Keybinding{"_"}, + CyclePagers: Keybinding{"|"}, + Undo: Keybinding{"z"}, + Redo: Keybinding{"Z"}, + FilteringMenu: Keybinding{""}, + DiffingMenu: Keybinding{"W"}, + DiffingMenuAlt: Keybinding{""}, + CopyToClipboard: Keybinding{""}, + SubmitEditorText: Keybinding{""}, + ExtrasMenu: Keybinding{"@"}, + ToggleWhitespaceInDiffView: Keybinding{""}, + IncreaseContextInDiffView: Keybinding{"}"}, + DecreaseContextInDiffView: Keybinding{"{"}, + IncreaseRenameSimilarityThreshold: Keybinding{")"}, + DecreaseRenameSimilarityThreshold: Keybinding{"("}, + OpenDiffTool: Keybinding{""}, }, Status: KeybindingStatusConfig{ - CheckForUpdate: "u", - RecentRepos: "", - AllBranchesLogGraph: "a", - AllBranchesLogGraphReverse: "A", + CheckForUpdate: Keybinding{"u"}, + RecentRepos: Keybinding{""}, + AllBranchesLogGraph: Keybinding{"a"}, + AllBranchesLogGraphReverse: Keybinding{"A"}, }, Files: KeybindingFilesConfig{ - CommitChanges: "c", - CommitChangesWithoutHook: "w", - AmendLastCommit: "A", - CommitChangesWithEditor: "C", - FindBaseCommitForFixup: "", - IgnoreFile: "i", - RefreshFiles: "r", - StashAllChanges: "s", - ViewStashOptions: "S", - ToggleStagedAll: "a", - ViewResetOptions: "D", - Fetch: "f", - ToggleTreeView: "`", - OpenMergeOptions: "M", - OpenStatusFilter: "", - ConfirmDiscard: "x", - CopyFileInfoToClipboard: "y", - CollapseAll: "-", - ExpandAll: "=", + CommitChanges: Keybinding{"c"}, + CommitChangesWithoutHook: Keybinding{"w"}, + AmendLastCommit: Keybinding{"A"}, + CommitChangesWithEditor: Keybinding{"C"}, + FindBaseCommitForFixup: Keybinding{""}, + IgnoreFile: Keybinding{"i"}, + RefreshFiles: Keybinding{"r"}, + StashAllChanges: Keybinding{"s"}, + ViewStashOptions: Keybinding{"S"}, + ToggleStagedAll: Keybinding{"a"}, + ViewResetOptions: Keybinding{"D"}, + Fetch: Keybinding{"f"}, + ToggleTreeView: Keybinding{"`"}, + OpenMergeOptions: Keybinding{"M"}, + OpenStatusFilter: Keybinding{""}, + ConfirmDiscard: Keybinding{"x"}, + CopyFileInfoToClipboard: Keybinding{"y"}, + CollapseAll: Keybinding{"-"}, + ExpandAll: Keybinding{"="}, }, Branches: KeybindingBranchesConfig{ - CopyPullRequestURL: "", - CreatePullRequest: "o", - ViewPullRequestOptions: "O", - OpenPullRequestInBrowser: "G", - CheckoutBranchByName: "c", - ForceCheckoutBranch: "F", - CheckoutPreviousBranch: "-", - RebaseBranch: "r", - RenameBranch: "R", - MergeIntoCurrentBranch: "M", - MoveCommitsToNewBranch: "N", - ViewGitFlowOptions: "i", - FastForward: "f", - CreateTag: "T", - PushTag: "P", - SetUpstream: "u", - FetchRemote: "f", - AddForkRemote: "F", - SortOrder: "s", + CopyPullRequestURL: Keybinding{""}, + CreatePullRequest: Keybinding{"o"}, + ViewPullRequestOptions: Keybinding{"O"}, + OpenPullRequestInBrowser: Keybinding{"G"}, + CheckoutBranchByName: Keybinding{"c"}, + ForceCheckoutBranch: Keybinding{"F"}, + CheckoutPreviousBranch: Keybinding{"-"}, + RebaseBranch: Keybinding{"r"}, + RenameBranch: Keybinding{"R"}, + MergeIntoCurrentBranch: Keybinding{"M"}, + MoveCommitsToNewBranch: Keybinding{"N"}, + ViewGitFlowOptions: Keybinding{"i"}, + FastForward: Keybinding{"f"}, + CreateTag: Keybinding{"T"}, + PushTag: Keybinding{"P"}, + SetUpstream: Keybinding{"u"}, + FetchRemote: Keybinding{"f"}, + AddForkRemote: Keybinding{"F"}, + SortOrder: Keybinding{"s"}, }, Worktrees: KeybindingWorktreesConfig{ - ViewWorktreeOptions: "w", + ViewWorktreeOptions: Keybinding{"w"}, }, Commits: KeybindingCommitsConfig{ - SquashDown: "s", - RenameCommit: "r", - RenameCommitWithEditor: "R", - ViewResetOptions: "g", - MarkCommitAsFixup: "f", - SetFixupMessage: "c", - CreateFixupCommit: "F", - SquashAboveCommits: "S", - MoveDownCommit: "", - MoveUpCommit: "", - AmendToCommit: "A", - ResetCommitAuthor: "a", - PickCommit: "p", - RevertCommit: "t", - CherryPickCopy: "C", - PasteCommits: "V", - MarkCommitAsBaseForRebase: "B", - CreateTag: "T", - CheckoutCommit: "", - ResetCherryPick: "", - CopyCommitAttributeToClipboard: "y", - OpenLogMenu: "", - OpenInBrowser: "o", - OpenPullRequestInBrowser: "G", - ViewBisectOptions: "b", - StartInteractiveRebase: "i", - SelectCommitsOfCurrentBranch: "*", + SquashDown: Keybinding{"s"}, + RenameCommit: Keybinding{"r"}, + RenameCommitWithEditor: Keybinding{"R"}, + ViewResetOptions: Keybinding{"g"}, + MarkCommitAsFixup: Keybinding{"f"}, + SetFixupMessage: Keybinding{"c"}, + CreateFixupCommit: Keybinding{"F"}, + SquashAboveCommits: Keybinding{"S"}, + MoveDownCommit: Keybinding{""}, + MoveUpCommit: Keybinding{""}, + AmendToCommit: Keybinding{"A"}, + ResetCommitAuthor: Keybinding{"a"}, + PickCommit: Keybinding{"p"}, + RevertCommit: Keybinding{"t"}, + CherryPickCopy: Keybinding{"C"}, + PasteCommits: Keybinding{"V"}, + MarkCommitAsBaseForRebase: Keybinding{"B"}, + CreateTag: Keybinding{"T"}, + CheckoutCommit: Keybinding{""}, + ResetCherryPick: Keybinding{""}, + CopyCommitAttributeToClipboard: Keybinding{"y"}, + OpenLogMenu: Keybinding{""}, + OpenInBrowser: Keybinding{"o"}, + OpenPullRequestInBrowser: Keybinding{"G"}, + ViewBisectOptions: Keybinding{"b"}, + StartInteractiveRebase: Keybinding{"i"}, + SelectCommitsOfCurrentBranch: Keybinding{"*"}, }, AmendAttribute: KeybindingAmendAttributeConfig{ - ResetAuthor: "a", - SetAuthor: "A", - AddCoAuthor: "c", + ResetAuthor: Keybinding{"a"}, + SetAuthor: Keybinding{"A"}, + AddCoAuthor: Keybinding{"c"}, }, Stash: KeybindingStashConfig{ - PopStash: "g", - RenameStash: "r", + PopStash: Keybinding{"g"}, + RenameStash: Keybinding{"r"}, }, CommitFiles: KeybindingCommitFilesConfig{ - CheckoutCommitFile: "c", + CheckoutCommitFile: Keybinding{"c"}, }, Main: KeybindingMainConfig{ - ToggleSelectHunk: "a", - PickBothHunks: "b", - EditSelectHunk: "E", + ToggleSelectHunk: Keybinding{"a"}, + PickBothHunks: Keybinding{"b"}, + EditSelectHunk: Keybinding{"E"}, }, Submodules: KeybindingSubmodulesConfig{ - Init: "i", - Update: "u", - BulkMenu: "b", + Init: Keybinding{"i"}, + Update: Keybinding{"u"}, + BulkMenu: Keybinding{"b"}, }, CommitMessage: KeybindingCommitMessageConfig{ - CommitMenu: "", + CommitMenu: Keybinding{""}, }, }, } diff --git a/pkg/config/user_config_validation_test.go b/pkg/config/user_config_validation_test.go index a2841684d..6474ac3b0 100644 --- a/pkg/config/user_config_validation_test.go +++ b/pkg/config/user_config_validation_test.go @@ -114,7 +114,7 @@ func TestUserConfigValidate_enums(t *testing.T) { { name: "Keybindings", setup: func(config *UserConfig, value string) { - config.Keybinding.Universal.Quit = value + config.Keybinding.Universal.Quit = Keybinding{value} }, testCases: []testCase{ {value: "", valid: true}, diff --git a/pkg/gocui/edit.go b/pkg/gocui/edit.go index 76823364e..649379fb6 100644 --- a/pkg/gocui/edit.go +++ b/pkg/gocui/edit.go @@ -4,6 +4,8 @@ package gocui +import "github.com/samber/lo" + // Editor interface must be satisfied by gocui editors. type Editor interface { Edit(v *View, key Key) bool @@ -23,19 +25,19 @@ func (f EditorFunc) Edit(v *View, key Key) bool { var DefaultEditor Editor = EditorFunc(SimpleEditor) var ( - moveWordLeftKeybinding = NewKey(KeyArrowLeft, "", ModCtrl) - moveWordRightKeybinding = NewKey(KeyArrowRight, "", ModCtrl) - backspaceWordKeybinding = NewKey(KeyBackspace, "", ModCtrl) - forwardDeleteWordKeybinding = NewKey(KeyDelete, "", ModCtrl) + moveWordLeftKeybinding = []Key{NewKey(KeyArrowLeft, "", ModCtrl)} + moveWordRightKeybinding = []Key{NewKey(KeyArrowRight, "", ModCtrl)} + backspaceWordKeybinding = []Key{NewKey(KeyBackspace, "", ModCtrl)} + forwardDeleteWordKeybinding = []Key{NewKey(KeyDelete, "", ModCtrl)} ) // SimpleEditor is used as the default gocui editor. func SimpleEditor(v *View, key Key) bool { switch { - case key.Equals(backspaceWordKeybinding), + case lo.SomeBy(backspaceWordKeybinding, func(k Key) bool { return key.Equals(k) }), key.Equals(NewKeyStrMod("w", ModCtrl)): v.TextArea.BackSpaceWord() - case key.Equals(forwardDeleteWordKeybinding), + case lo.SomeBy(forwardDeleteWordKeybinding, func(k Key) bool { return key.Equals(k) }), key.Equals(NewKeyStrMod("d", ModAlt)): v.TextArea.ForwardDeleteWord() case key.Equals(NewKeyName(KeyBackspace)), @@ -49,13 +51,13 @@ func SimpleEditor(v *View, key Key) bool { case key.Equals(NewKeyName(KeyArrowUp)): v.TextArea.MoveCursorUp() case key.Equals(NewKeyStrMod("b", ModAlt)), - key.Equals(moveWordLeftKeybinding): + lo.SomeBy(moveWordLeftKeybinding, func(k Key) bool { return key.Equals(k) }): v.TextArea.MoveLeftWord() case key.Equals(NewKeyName(KeyArrowLeft)), key.Equals(NewKeyStrMod("b", ModCtrl)): v.TextArea.MoveCursorLeft() case key.Equals(NewKeyStrMod("f", ModAlt)), - key.Equals(moveWordRightKeybinding): + lo.SomeBy(moveWordRightKeybinding, func(k Key) bool { return key.Equals(k) }): v.TextArea.MoveRightWord() case key.Equals(NewKeyName(KeyArrowRight)), key.Equals(NewKeyStrMod("f", ModCtrl)): diff --git a/pkg/gocui/gui.go b/pkg/gocui/gui.go index 579dfe21d..7b691f6d7 100644 --- a/pkg/gocui/gui.go +++ b/pkg/gocui/gui.go @@ -178,9 +178,9 @@ type Gui struct { OnSearchEscape func() error - SearchEscapeKey Key - NextSearchMatchKey Key - PrevSearchMatchKey Key + SearchEscapeKeys []Key + NextSearchMatchKeys []Key + PrevSearchMatchKeys []Key ErrorHandler func(error) error @@ -256,9 +256,9 @@ func NewGui(opts NewGuiOpts) (*Gui, error) { g.SupportOverlaps = opts.SupportOverlaps // default keys for when searching strings in a view - g.SearchEscapeKey = NewKeyName(KeyEsc) - g.NextSearchMatchKey = NewKeyRune('n') - g.PrevSearchMatchKey = NewKeyRune('N') + g.SearchEscapeKeys = []Key{NewKeyName(KeyEsc)} + g.NextSearchMatchKeys = []Key{NewKeyRune('n')} + g.PrevSearchMatchKeys = []Key{NewKeyRune('N')} g.playRecording = opts.PlayRecording @@ -1525,11 +1525,11 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error { // if we're searching, and we've hit n/N/Esc, we ignore the default keybinding if v != nil && v.IsSearching() { - if ev.Key.Equals(g.NextSearchMatchKey) { + if lo.SomeBy(g.NextSearchMatchKeys, func(k Key) bool { return ev.Key.Equals(k) }) { return v.gotoNextMatch() - } else if ev.Key.Equals(g.PrevSearchMatchKey) { + } else if lo.SomeBy(g.PrevSearchMatchKeys, func(k Key) bool { return ev.Key.Equals(k) }) { return v.gotoPreviousMatch() - } else if ev.Key.Equals(g.SearchEscapeKey) { + } else if lo.SomeBy(g.SearchEscapeKeys, func(k Key) bool { return ev.Key.Equals(k) }) { v.searcher.clearSearch() if g.OnSearchEscape != nil { if err := g.OnSearchEscape(); err != nil { @@ -1669,7 +1669,7 @@ func (g *Gui) Snapshot() string { return builder.String() } -func (g *Gui) SetEditKeybindings(moveWordLeft, moveWordRight, backspaceWord, forwardDeleteWord Key) { +func (g *Gui) SetEditKeybindings(moveWordLeft, moveWordRight, backspaceWord, forwardDeleteWord []Key) { moveWordLeftKeybinding = moveWordLeft moveWordRightKeybinding = moveWordRight backspaceWordKeybinding = backspaceWord diff --git a/pkg/gui/context/commit_message_context.go b/pkg/gui/context/commit_message_context.go index d14dc609b..7db3a085b 100644 --- a/pkg/gui/context/commit_message_context.go +++ b/pkg/gui/context/commit_message_context.go @@ -166,8 +166,8 @@ func (self *CommitMessageContext) SetPanelState( self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle, map[string]string{ - "togglePanelKeyBinding": self.c.UserConfig().Keybinding.Universal.TogglePanel, - "commitMenuKeybinding": self.c.UserConfig().Keybinding.CommitMessage.CommitMenu, + "togglePanelKeyBinding": self.c.UserConfig().Keybinding.Universal.TogglePanel.String(), + "commitMenuKeybinding": self.c.UserConfig().Keybinding.CommitMessage.CommitMenu.String(), }) self.c.Views().CommitDescription.Visible = true diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 3e019bf18..2ddb5055e 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -105,8 +105,8 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.CherryPickCopy, Tooltip: utils.ResolvePlaceholderString(self.c.Tr.CherryPickCopyTooltip, map[string]string{ - "paste": opts.Config.Commits.PasteCommits, - "escape": opts.Config.Universal.Return, + "paste": opts.Config.Commits.PasteCommits.String(), + "escape": opts.Config.Universal.Return.String(), }, ), DisplayOnScreen: true, diff --git a/pkg/gui/controllers/commit_description_controller.go b/pkg/gui/controllers/commit_description_controller.go index 0e5102e3e..755fddb56 100644 --- a/pkg/gui/controllers/commit_description_controller.go +++ b/pkg/gui/controllers/commit_description_controller.go @@ -4,6 +4,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type CommitDescriptionController struct { @@ -67,22 +68,24 @@ func (self *CommitDescriptionController) GetMouseKeybindings(opts types.Keybindi func (self *CommitDescriptionController) GetOnFocus() func(types.OnFocusOpts) { return func(types.OnFocusOpts) { footer := "" - if self.c.UserConfig().Keybinding.Universal.ConfirmInEditor != "" || self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt != "" { - if self.c.UserConfig().Keybinding.Universal.ConfirmInEditor == "" { + mainDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor) > 0 + altDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt) > 0 + if !mainDisabled || !altDisabled { + if mainDisabled { footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter, map[string]string{ - "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt, + "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(), }) - } else if self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt == "" { + } else if altDisabled { footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter, map[string]string{ - "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor, + "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(), }) } else { footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooterTwoBindings, map[string]string{ - "confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor, - "confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt, + "confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(), + "confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(), }) } } @@ -112,7 +115,7 @@ func (self *CommitDescriptionController) handleTogglePanel() error { // ctrl key or fn key, which is unlikely to occur in pasted text. And if // they mapped some *other* command to "", then we're totally out of // luck. - if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "" { + if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.TogglePanel, "") { // Handling tabs in pasted commit messages is not optimal, but hopefully // good enough for now. We simply insert 4 spaces without worrying about // column alignment. This works well enough for leading indentation, diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go index 4743598f6..098f42d30 100644 --- a/pkg/gui/controllers/commit_message_controller.go +++ b/pkg/gui/controllers/commit_message_controller.go @@ -8,6 +8,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type CommitMessageController struct { @@ -123,7 +124,7 @@ func (self *CommitMessageController) handleTogglePanel() error { // ctrl key or fn key, which is unlikely to occur in pasted text. And if // they mapped some *other* command to "", then we're totally out of // luck. - if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "" { + if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.TogglePanel, "") { // It is unlikely that a pasted commit message contains a tab in the // subject line, so it shouldn't matter too much how we handle it. // Simply insert 4 spaces instead; all that matters is that we don't @@ -183,7 +184,7 @@ func (self *CommitMessageController) confirm() error { // to some ctrl key or fn key, which is unlikely to occur in pasted text. // And if they mapped some *other* command to "", then we're totally // out of luck. - if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.SubmitEditorText == "" { + if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.SubmitEditorText, "") { return self.switchToCommitDescription() } diff --git a/pkg/gui/controllers/helpers/tags_helper.go b/pkg/gui/controllers/helpers/tags_helper.go index 6a7e47219..650e4162c 100644 --- a/pkg/gui/controllers/helpers/tags_helper.go +++ b/pkg/gui/controllers/helpers/tags_helper.go @@ -28,8 +28,8 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error { self.c.Tr.ForceTagPrompt, map[string]string{ "tagName": tagName, - "cancelKey": self.c.UserConfig().Keybinding.Universal.Return, - "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm, + "cancelKey": self.c.UserConfig().Keybinding.Universal.Return.String(), + "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm.String(), }, ) force := self.c.Git().Tag.HasTag(tagName) diff --git a/pkg/gui/controllers/jump_to_side_window_controller.go b/pkg/gui/controllers/jump_to_side_window_controller.go index 2ea8ac762..31228e3a6 100644 --- a/pkg/gui/controllers/jump_to_side_window_controller.go +++ b/pkg/gui/controllers/jump_to_side_window_controller.go @@ -3,6 +3,7 @@ package controllers import ( "log" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/samber/lo" ) @@ -39,7 +40,7 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt return &types.Binding{ ViewName: "", // by default the keys are 1, 2, 3, etc - Keys: opts.GetKeys(opts.Config.Universal.JumpToBlock[index]), + Keys: opts.GetKeys(config.Keybinding{opts.Config.Universal.JumpToBlock[index]}), Handler: opts.Guards.NoPopupPanel(self.goToSideWindow(window)), } }) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index b0cad6586..4ab436bbc 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -141,7 +141,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ GetDisabledReason: self.require(self.notMidRebase(self.c.Tr.AlreadyRebasing), self.canFindCommitForQuickStart), Description: self.c.Tr.QuickStartInteractiveRebase, Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{ - "editKey": editCommitKey, + "editKey": editCommitKey.String(), }), }, { @@ -161,7 +161,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Tooltip: utils.ResolvePlaceholderString( self.c.Tr.CreateFixupCommitTooltip, map[string]string{ - "squashAbove": opts.Config.Commits.SquashAboveCommits, + "squashAbove": opts.Config.Commits.SquashAboveCommits.String(), }, ), }, @@ -679,7 +679,7 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() ( if !ok || index == 0 { errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{ - "editKey": self.c.UserConfig().Keybinding.Universal.Edit, + "editKey": self.c.UserConfig().Keybinding.Universal.Edit.String(), }) return nil, errors.New(errorMsg) diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 7d6be1e82..97b7ff3dd 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -44,7 +44,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Enter, Tooltip: utils.ResolvePlaceholderString(self.c.Tr.EnterSubmoduleTooltip, - map[string]string{"escape": opts.Config.Universal.Return}), + map[string]string{"escape": opts.Config.Universal.Return.String()}), DisplayOnScreen: true, }, { diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 4e66e2708..649b53338 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -256,8 +256,8 @@ func (self *SyncController) forcePushPrompt() string { return utils.ResolvePlaceholderString( self.c.Tr.ForcePushPrompt, map[string]string{ - "cancelKey": self.c.UserConfig().Keybinding.Universal.Return, - "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm, + "cancelKey": self.c.UserConfig().Keybinding.Universal.Return.String(), + "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm.String(), }, ) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 458e33804..e2881cca1 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -472,15 +472,15 @@ func (gui *Gui) onUserConfigLoaded() error { gui.setColorScheme() gui.configureViewProperties() - gui.g.SearchEscapeKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.Return) - gui.g.NextSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.NextMatch) - gui.g.PrevSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.PrevMatch) + gui.g.SearchEscapeKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.Return) + gui.g.NextSearchMatchKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.NextMatch) + gui.g.PrevSearchMatchKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.PrevMatch) gui.g.SetEditKeybindings( - config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordLeft), - config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordRight), - config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.BackspaceWord), - config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.ForwardDeleteWord), + config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.MoveWordLeft), + config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.MoveWordRight), + config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.BackspaceWord), + config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.ForwardDeleteWord), ) gui.g.ShowListFooter = userConfig.Gui.ShowListFooter @@ -1089,7 +1089,7 @@ func (gui *Gui) showIntroPopupMessage() { introMessage := utils.ResolvePlaceholderString( gui.c.Tr.IntroPopupMessage, map[string]string{ - "confirmationKey": gui.c.UserConfig().Keybinding.Universal.Confirm, + "confirmationKey": gui.c.UserConfig().Keybinding.Universal.Confirm.String(), }, ) diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index e43ac1d29..336f7601b 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -28,10 +28,10 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error { maxColumnSize := 1 essentialKeys := []gocui.Key{ - config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu), - config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.Return), - config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.PrevItem), - config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.NextItem), + config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu)[0], + config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.Return)[0], + config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.PrevItem)[0], + config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.NextItem)[0], } for _, item := range opts.Items { diff --git a/pkg/gui/options_map.go b/pkg/gui/options_map.go index c0d0fcfff..890d2f2de 100644 --- a/pkg/gui/options_map.go +++ b/pkg/gui/options_map.go @@ -70,7 +70,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() { if currentContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { if self.c.Modes().CherryPicking.Active() { optionsMap = utils.Prepend(optionsMap, bindingInfo{ - key: self.c.KeybindingsOpts().Config.Commits.PasteCommits, + key: self.c.KeybindingsOpts().Config.Commits.PasteCommits.String(), description: self.c.Tr.PasteCommits, style: style.FgCyan, }) @@ -78,7 +78,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() { if self.c.Model().BisectInfo.Started() { optionsMap = utils.Prepend(optionsMap, bindingInfo{ - key: self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions, + key: self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions.String(), description: self.c.Tr.ViewBisectOptions, style: style.FgGreen, }) @@ -88,7 +88,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() { // Mode-specific global keybindings if state := self.c.Model().WorkingTreeStateAtLastCommitRefresh; state.Any() { optionsMap = utils.Prepend(optionsMap, bindingInfo{ - key: self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu, + key: self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu.String(), description: state.OptionsMapTitle(self.c.Tr), style: style.FgYellow, }) @@ -96,7 +96,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() { if self.c.Git().Patch.PatchBuilder.Active() { optionsMap = utils.Prepend(optionsMap, bindingInfo{ - key: self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu, + key: self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu.String(), description: self.c.Tr.ViewPatchOptions, style: style.FgYellow, }) diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index dcf4b9a1a..416b39b95 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -239,7 +239,7 @@ type OnFocusLostOpts struct { type ContextKey string type KeybindingsOpts struct { - GetKeys func(key string) []gocui.Key + GetKeys func(keys config.Keybinding) []gocui.Key Config config.KeybindingConfig Guards KeybindingGuards } diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 093257998..297da143f 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -236,7 +236,7 @@ func (gui *Gui) configureViewProperties() { gui.Views.Stash.TitlePrefix = jumpLabels[4] - gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView) + gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView[0]) } else { gui.Views.Status.TitlePrefix = "" diff --git a/pkg/integration/components/commit_description_panel_driver.go b/pkg/integration/components/commit_description_panel_driver.go index caf6d1b8a..6281e756b 100644 --- a/pkg/integration/components/commit_description_panel_driver.go +++ b/pkg/integration/components/commit_description_panel_driver.go @@ -42,7 +42,7 @@ func (self *CommitDescriptionPanelDriver) GoToBeginning() *CommitDescriptionPane } func (self *CommitDescriptionPanelDriver) AddCoAuthor(author string) *CommitDescriptionPanelDriver { - self.t.press(self.t.keys.CommitMessage.CommitMenu) + self.t.press(self.t.keys.CommitMessage.CommitMenu[0]) self.t.ExpectPopup().Menu().Title(Equals("Commit Menu")). Select(Contains("Add co-author")). Confirm() diff --git a/pkg/integration/components/commit_message_panel_driver.go b/pkg/integration/components/commit_message_panel_driver.go index 047cc59b1..f24950f13 100644 --- a/pkg/integration/components/commit_message_panel_driver.go +++ b/pkg/integration/components/commit_message_panel_driver.go @@ -73,6 +73,6 @@ func (self *CommitMessagePanelDriver) SelectNextMessage() *CommitMessagePanelDri } func (self *CommitMessagePanelDriver) OpenCommitMenu() *CommitMessagePanelDriver { - self.t.press(self.t.keys.CommitMessage.CommitMenu) + self.t.press(self.t.keys.CommitMessage.CommitMenu[0]) return self } diff --git a/pkg/integration/components/prompt_driver.go b/pkg/integration/components/prompt_driver.go index 2c29dd7c4..1000af007 100644 --- a/pkg/integration/components/prompt_driver.go +++ b/pkg/integration/components/prompt_driver.go @@ -68,7 +68,7 @@ func (self *PromptDriver) SuggestionTopLines(matchers ...*TextMatcher) *PromptDr } func (self *PromptDriver) ConfirmFirstSuggestion() { - self.t.press(self.t.keys.Universal.TogglePanel) + self.t.press(self.t.keys.Universal.TogglePanel[0]) self.t.Views().Suggestions(). IsFocused(). SelectedLineIdx(0). @@ -76,7 +76,7 @@ func (self *PromptDriver) ConfirmFirstSuggestion() { } func (self *PromptDriver) ConfirmSuggestion(matcher *TextMatcher) { - self.t.press(self.t.keys.Universal.TogglePanel) + self.t.press(self.t.keys.Universal.TogglePanel[0]) self.t.Views().Suggestions(). IsFocused(). NavigateToLine(matcher). @@ -84,19 +84,19 @@ func (self *PromptDriver) ConfirmSuggestion(matcher *TextMatcher) { } func (self *PromptDriver) DeleteSuggestion(matcher *TextMatcher) *PromptDriver { - self.t.press(self.t.keys.Universal.TogglePanel) + self.t.press(self.t.keys.Universal.TogglePanel[0]) self.t.Views().Suggestions(). IsFocused(). NavigateToLine(matcher) - self.t.press(self.t.keys.Universal.Remove) + self.t.press(self.t.keys.Universal.Remove[0]) return self } func (self *PromptDriver) EditSuggestion(matcher *TextMatcher) *PromptDriver { - self.t.press(self.t.keys.Universal.TogglePanel) + self.t.press(self.t.keys.Universal.TogglePanel[0]) self.t.Views().Suggestions(). IsFocused(). NavigateToLine(matcher) - self.t.press(self.t.keys.Universal.Edit) + self.t.press(self.t.keys.Universal.Edit[0]) return self } diff --git a/pkg/integration/components/test_driver.go b/pkg/integration/components/test_driver.go index a1775239c..8294f3b46 100644 --- a/pkg/integration/components/test_driver.go +++ b/pkg/integration/components/test_driver.go @@ -52,8 +52,8 @@ func (self *TestDriver) click(x, y int) { // Should only be used in specific cases where you're doing something weird! // E.g. invoking a global keybinding from within a popup. // You probably shouldn't use this function, and should instead go through a view like t.Views().Commit().Focus().Press(...) -func (self *TestDriver) GlobalPress(keyStr string) { - self.press(keyStr) +func (self *TestDriver) GlobalPress(key config.Keybinding) { + self.press(key[0]) } func (self *TestDriver) typeContent(content string) { diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index ee7c5b68a..8b1650c32 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/samber/lo" ) @@ -376,11 +377,11 @@ func (self *ViewDriver) Focus() *ViewDriver { currentViewTabIndex := lo.IndexOf(window.viewNames, currentViewName) if tabIndex > currentViewTabIndex { for range tabIndex - currentViewTabIndex { - self.t.press(self.t.keys.Universal.NextTab) + self.t.press(self.t.keys.Universal.NextTab[0]) } } else if tabIndex < currentViewTabIndex { for range currentViewTabIndex - tabIndex { - self.t.press(self.t.keys.Universal.PrevTab) + self.t.press(self.t.keys.Universal.PrevTab[0]) } } @@ -407,10 +408,10 @@ func (self *ViewDriver) IsFocused() *ViewDriver { return self } -func (self *ViewDriver) Press(keyStr string) *ViewDriver { +func (self *ViewDriver) Press(key config.Keybinding) *ViewDriver { self.IsFocused() - self.t.press(keyStr) + self.t.press(key[0]) return self } @@ -423,10 +424,10 @@ func (self *ViewDriver) Delay() *ViewDriver { // for use when typing or navigating, because in demos we want that to happen // faster -func (self *ViewDriver) PressFast(keyStr string) *ViewDriver { +func (self *ViewDriver) PressFast(key config.Keybinding) *ViewDriver { self.IsFocused() - self.t.pressFast(keyStr) + self.t.pressFast(key[0]) return self } diff --git a/pkg/integration/tests/commit/search.go b/pkg/integration/tests/commit/search.go index 5439a1b32..25f6bb233 100644 --- a/pkg/integration/tests/commit/search.go +++ b/pkg/integration/tests/commit/search.go @@ -58,7 +58,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two").IsSelected(), Contains("one"), ). - Press("n"). + Press(config.Keybinding{"n"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (3 of 3)")) }). @@ -68,7 +68,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two"), Contains("one").IsSelected(), ). - Press("n"). + Press(config.Keybinding{"n"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)")) }). @@ -78,7 +78,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two"), Contains("one"), ). - Press("n"). + Press(config.Keybinding{"n"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (2 of 3)")) }). @@ -88,7 +88,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two").IsSelected(), Contains("one"), ). - Press("N"). + Press(config.Keybinding{"N"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)")) }). @@ -98,7 +98,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two"), Contains("one"), ). - Press("N"). + Press(config.Keybinding{"N"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (3 of 3)")) }). @@ -112,7 +112,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)")) }). - Press("N"). + Press(config.Keybinding{"N"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)")) }). @@ -146,7 +146,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{ Contains("two"), Contains("one"), ). - Press("n"). + Press(config.Keybinding{"n"}). Tap(func() { t.Views().Search().IsVisible().Content(Contains("matches for 't' (1 of 2)")) }). diff --git a/pkg/integration/tests/config/custom_commands_in_per_repo_config.go b/pkg/integration/tests/config/custom_commands_in_per_repo_config.go index 81f8724aa..4a66cd43c 100644 --- a/pkg/integration/tests/config/custom_commands_in_per_repo_config.go +++ b/pkg/integration/tests/config/custom_commands_in_per_repo_config.go @@ -48,13 +48,13 @@ customCommands: ).Confirm() t.Views().Status().Content(Contains("other → master")) - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("../other/file.txt", Equals("global X")) - t.GlobalPress("Y") + t.GlobalPress(config.Keybinding{"Y"}) t.FileSystem().FileContent("../other/file.txt", Equals("local Y")) - t.GlobalPress("Z") + t.GlobalPress(config.Keybinding{"Z"}) t.FileSystem().FileContent("../other/file.txt", Equals("local Z")) }, }) diff --git a/pkg/integration/tests/custom_commands/access_commit_properties.go b/pkg/integration/tests/custom_commands/access_commit_properties.go index 22d1d0631..a1ba84a27 100644 --- a/pkg/integration/tests/custom_commands/access_commit_properties.go +++ b/pkg/integration/tests/custom_commands/access_commit_properties.go @@ -29,7 +29,7 @@ var AccessCommitProperties = NewIntegrationTest(NewIntegrationTestArgs{ Lines( Contains("my change").IsSelected(), ). - Press("X") + Press(config.Keybinding{"X"}) hash := t.Git().GetCommitHash("HEAD") t.FileSystem().FileContent("file.txt", Equals(fmt.Sprintf("my change\n%s\n%s", hash, hash))) diff --git a/pkg/integration/tests/custom_commands/basic_command.go b/pkg/integration/tests/custom_commands/basic_command.go index 10a9058b7..b50acc792 100644 --- a/pkg/integration/tests/custom_commands/basic_command.go +++ b/pkg/integration/tests/custom_commands/basic_command.go @@ -25,7 +25,7 @@ var BasicCommand = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). IsEmpty(). IsFocused(). - Press("a"). + Press(config.Keybinding{"a"}). Lines( Contains("myfile"), ) diff --git a/pkg/integration/tests/custom_commands/check_for_conflicts.go b/pkg/integration/tests/custom_commands/check_for_conflicts.go index d3376b456..70f528a6d 100644 --- a/pkg/integration/tests/custom_commands/check_for_conflicts.go +++ b/pkg/integration/tests/custom_commands/check_for_conflicts.go @@ -35,7 +35,7 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{ Contains("second-change-branch"), ). NavigateToLine(Contains("second-change-branch")). - Press("m") + Press(config.Keybinding{"m"}) t.Common().AcknowledgeConflicts() }, diff --git a/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go b/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go index a60db1036..d2c6beadb 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go +++ b/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go @@ -55,7 +55,7 @@ var ConditionalPromptFalseString = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Files(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Menu().Title(Equals("Pick one")).Select(Contains("foo")).Confirm() diff --git a/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go b/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go index 44378ce22..4a0326669 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go +++ b/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go @@ -37,7 +37,7 @@ var ConditionalPromptFalseValue = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Files(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt().Title(Equals("Enter a word")).Type("false").Confirm() diff --git a/pkg/integration/tests/custom_commands/conditional_prompts.go b/pkg/integration/tests/custom_commands/conditional_prompts.go index 36aab67df..4f1f97531 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompts.go +++ b/pkg/integration/tests/custom_commands/conditional_prompts.go @@ -52,12 +52,12 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{ // Test 1: Select "first" via key — conditional prompt should be skipped t.Views().Files(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Menu(). Title(Equals("Choose an option")) - t.Views().Menu().Press("1") + t.Views().Menu().Press(config.Keybinding{"1"}) // Detail prompt should be skipped, file should be created directly t.Views().Files(). @@ -75,12 +75,12 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). IsEmpty(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Menu(). Title(Equals("Choose an option")) - t.Views().Menu().Press("H") + t.Views().Menu().Press(config.Keybinding{"H"}) // Detail prompt should appear because Choice == "SECOND" t.ExpectPopup().Prompt().Title(Equals("Enter detail for second option")).Type("extra").Confirm() diff --git a/pkg/integration/tests/custom_commands/custom_commands_submenu.go b/pkg/integration/tests/custom_commands/custom_commands_submenu.go index a8d13cf73..93c670449 100644 --- a/pkg/integration/tests/custom_commands/custom_commands_submenu.go +++ b/pkg/integration/tests/custom_commands/custom_commands_submenu.go @@ -39,7 +39,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). Focus(). IsEmpty(). - Press("x"). + Press(config.Keybinding{"x"}). Tap(func() { t.ExpectPopup().Menu(). Title(Equals("My Custom Commands")). @@ -55,7 +55,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Commits(). Focus(). - Press("x"). + Press(config.Keybinding{"x"}). Tap(func() { t.ExpectPopup().Menu(). Title(Equals("My Custom Commands")). @@ -63,7 +63,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{ Contains("1 touch myfile-global"), Contains("3 touch myfile-commits"), ) - t.GlobalPress("3") + t.GlobalPress(config.Keybinding{"3"}) }) t.Views().Files(). diff --git a/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go b/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go index a1f62aff6..29638ee92 100644 --- a/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go +++ b/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go @@ -43,13 +43,13 @@ var CustomCommandsSubmenuWithSpecialKeybindings = NewIntegrationTest(NewIntegrat }, }, } - cfg.GetUserConfig().Keybinding.Universal.ConfirmMenu = "y" + cfg.GetUserConfig().Keybinding.Universal.ConfirmMenu = config.Keybinding{"y"} }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Files(). Focus(). IsEmpty(). - Press("x"). + Press(config.Keybinding{"x"}). Tap(func() { t.ExpectPopup().Menu(). Title(Equals("My Custom Commands")). @@ -59,14 +59,14 @@ var CustomCommandsSubmenuWithSpecialKeybindings = NewIntegrationTest(NewIntegrat Contains(" echo y"), Contains(" echo down"), ) - t.GlobalPress("j") + t.GlobalPress(config.Keybinding{"j"}) t.ExpectPopup().Alert().Title(Equals("echo j")).Content(Equals("j")).Confirm() }). - Press("x"). + Press(config.Keybinding{"x"}). Tap(func() { t.ExpectPopup().Menu(). Title(Equals("My Custom Commands")) - t.GlobalPress("H") + t.GlobalPress(config.Keybinding{"H"}) t.ExpectPopup().Alert().Title(Equals("echo H")).Content(Equals("H")).Confirm() }) }, diff --git a/pkg/integration/tests/custom_commands/form_prompts.go b/pkg/integration/tests/custom_commands/form_prompts.go index ccb2339de..3e051cb8e 100644 --- a/pkg/integration/tests/custom_commands/form_prompts.go +++ b/pkg/integration/tests/custom_commands/form_prompts.go @@ -59,7 +59,7 @@ var FormPrompts = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). IsEmpty(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt().Title(Equals("Enter a file name")).Type("my file").Confirm() diff --git a/pkg/integration/tests/custom_commands/global_context.go b/pkg/integration/tests/custom_commands/global_context.go index 82ef53010..274d6a7ba 100644 --- a/pkg/integration/tests/custom_commands/global_context.go +++ b/pkg/integration/tests/custom_commands/global_context.go @@ -25,7 +25,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{ // commits t.Views().Commits(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). @@ -37,7 +37,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{ // branches t.Views().Branches(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). @@ -49,7 +49,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{ // files t.Views().Files(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). diff --git a/pkg/integration/tests/custom_commands/menu_from_command.go b/pkg/integration/tests/custom_commands/menu_from_command.go index 10b8192ba..ae62c9a5c 100644 --- a/pkg/integration/tests/custom_commands/menu_from_command.go +++ b/pkg/integration/tests/custom_commands/menu_from_command.go @@ -48,7 +48,7 @@ var MenuFromCommand = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Branches(). Focus(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Menu().Title(Equals("Choose commit message")).Select(Contains("bar")).Confirm() diff --git a/pkg/integration/tests/custom_commands/menu_from_commands_output.go b/pkg/integration/tests/custom_commands/menu_from_commands_output.go index 591daa5af..7820bc515 100644 --- a/pkg/integration/tests/custom_commands/menu_from_commands_output.go +++ b/pkg/integration/tests/custom_commands/menu_from_commands_output.go @@ -46,7 +46,7 @@ var MenuFromCommandsOutput = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Branches(). Focus(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt(). Title(Equals("Which git command do you want to run?")). diff --git a/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go b/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go index f7f733d9c..d29a049f9 100644 --- a/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go +++ b/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go @@ -51,14 +51,14 @@ var MenuPromptWithKeys = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Files(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Menu(). Title(Equals("Choose an option")) // 'H' is normally a navigation key (ScrollLeft), so this tests that menu item // keybindings have proper precedence over non-essential navigation keys - t.Views().Menu().Press("H") + t.Views().Menu().Press(config.Keybinding{"H"}) t.FileSystem().FileContent("result.txt", Equals("SECOND\n")) }, diff --git a/pkg/integration/tests/custom_commands/multiple_contexts.go b/pkg/integration/tests/custom_commands/multiple_contexts.go index 61d46775b..b53242edc 100644 --- a/pkg/integration/tests/custom_commands/multiple_contexts.go +++ b/pkg/integration/tests/custom_commands/multiple_contexts.go @@ -25,7 +25,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{ // commits t.Views().Commits(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). @@ -37,7 +37,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{ // branches t.Views().Branches(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). @@ -46,7 +46,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{ // files t.Views().ReflogCommits(). Focus(). - Press("X") + Press(config.Keybinding{"X"}) t.Views().Files(). Focus(). diff --git a/pkg/integration/tests/custom_commands/multiple_prompts.go b/pkg/integration/tests/custom_commands/multiple_prompts.go index b40aa77f2..a450f7aee 100644 --- a/pkg/integration/tests/custom_commands/multiple_prompts.go +++ b/pkg/integration/tests/custom_commands/multiple_prompts.go @@ -57,7 +57,7 @@ var MultiplePrompts = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). IsEmpty(). IsFocused(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt().Title(Equals("Enter a file name")).Type("myfile").Confirm() diff --git a/pkg/integration/tests/custom_commands/run_command.go b/pkg/integration/tests/custom_commands/run_command.go index 107b9e285..ca9abb658 100644 --- a/pkg/integration/tests/custom_commands/run_command.go +++ b/pkg/integration/tests/custom_commands/run_command.go @@ -32,7 +32,7 @@ var RunCommand = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Branches(). Focus(). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt(). Title(Equals("Enter a branch name")). diff --git a/pkg/integration/tests/custom_commands/selected_commit.go b/pkg/integration/tests/custom_commands/selected_commit.go index 6288634f1..49595afd0 100644 --- a/pkg/integration/tests/custom_commands/selected_commit.go +++ b/pkg/integration/tests/custom_commands/selected_commit.go @@ -34,34 +34,34 @@ var SelectedCommit = NewIntegrationTest(NewIntegrationTestArgs{ NavigateToLine(Contains("commit 03")) // SubCommits - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 03")) t.Views().SubCommits().PressEnter() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 03")) // ReflogCommits t.Views().ReflogCommits().Focus() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit: commit 02")) t.Views().ReflogCommits().PressEnter() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit: commit 02")) // LocalCommits t.Views().Commits().Focus() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 01")) t.Views().Commits().PressEnter() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 01")) // None of these t.Views().Files().Focus() - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 01")) }, }) diff --git a/pkg/integration/tests/custom_commands/selected_commit_range.go b/pkg/integration/tests/custom_commands/selected_commit_range.go index 1a4b3087c..f335d91d9 100644 --- a/pkg/integration/tests/custom_commands/selected_commit_range.go +++ b/pkg/integration/tests/custom_commands/selected_commit_range.go @@ -29,13 +29,13 @@ var SelectedCommitRange = NewIntegrationTest(NewIntegrationTestArgs{ Contains("commit 01"), ) - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 03\n")) t.Views().Commits().Focus(). Press(keys.Universal.RangeSelectDown) - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("commit 03\ncommit 02\n")) }, }) diff --git a/pkg/integration/tests/custom_commands/selected_path.go b/pkg/integration/tests/custom_commands/selected_path.go index 9dc63ed43..c6c680335 100644 --- a/pkg/integration/tests/custom_commands/selected_path.go +++ b/pkg/integration/tests/custom_commands/selected_path.go @@ -29,7 +29,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). Focus(). NavigateToLine(Contains("file2")) - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("folder2/file2")) t.Views().Commits(). @@ -38,7 +38,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().CommitFiles(). IsFocused(). NavigateToLine(Contains("file1")) - t.GlobalPress("X") + t.GlobalPress(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("folder1/file1")) }, }) diff --git a/pkg/integration/tests/custom_commands/selected_submodule.go b/pkg/integration/tests/custom_commands/selected_submodule.go index c4640017d..d03af03dd 100644 --- a/pkg/integration/tests/custom_commands/selected_submodule.go +++ b/pkg/integration/tests/custom_commands/selected_submodule.go @@ -40,13 +40,13 @@ var SelectedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{ Contains("submodule").IsSelected(), ) - t.Views().Submodules().Press("X") + t.Views().Submodules().Press(config.Keybinding{"X"}) t.FileSystem().FileContent("file.txt", Equals("path/submodule")) - t.Views().Submodules().Press("U") + t.Views().Submodules().Press(config.Keybinding{"U"}) t.FileSystem().FileContent("file.txt", Equals("../submodule")) - t.Views().Submodules().Press("N") + t.Views().Submodules().Press(config.Keybinding{"N"}) t.FileSystem().FileContent("file.txt", Equals("submodule")) }, }) diff --git a/pkg/integration/tests/custom_commands/show_output_in_panel.go b/pkg/integration/tests/custom_commands/show_output_in_panel.go index 9fcab1be3..95765cb5f 100644 --- a/pkg/integration/tests/custom_commands/show_output_in_panel.go +++ b/pkg/integration/tests/custom_commands/show_output_in_panel.go @@ -37,7 +37,7 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{ Lines( Contains("my change").IsSelected(), ). - Press("X") + Press(config.Keybinding{"X"}) t.ExpectPopup().Alert(). // Uses cmd string as title if no outputTitle is provided @@ -46,7 +46,7 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{ Confirm() t.Views().Commits(). - Press("Y") + Press(config.Keybinding{"Y"}) hash := t.Git().GetCommitHash("HEAD") t.ExpectPopup().Alert(). diff --git a/pkg/integration/tests/custom_commands/suggestions_command.go b/pkg/integration/tests/custom_commands/suggestions_command.go index 51bbc2c65..831ecddda 100644 --- a/pkg/integration/tests/custom_commands/suggestions_command.go +++ b/pkg/integration/tests/custom_commands/suggestions_command.go @@ -49,7 +49,7 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{ Contains("branch-three"), Contains("branch-two"), ). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt(). Title(Equals("Enter a branch name")). diff --git a/pkg/integration/tests/custom_commands/suggestions_preset.go b/pkg/integration/tests/custom_commands/suggestions_preset.go index 891ebf725..285d88e01 100644 --- a/pkg/integration/tests/custom_commands/suggestions_preset.go +++ b/pkg/integration/tests/custom_commands/suggestions_preset.go @@ -49,7 +49,7 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{ Contains("branch-three"), Contains("branch-two"), ). - Press("a") + Press(config.Keybinding{"a"}) t.ExpectPopup().Prompt(). Title(Equals("Enter a branch name")). diff --git a/pkg/integration/tests/demo/custom_command.go b/pkg/integration/tests/demo/custom_command.go index a65c2c073..f14a19b5f 100644 --- a/pkg/integration/tests/demo/custom_command.go +++ b/pkg/integration/tests/demo/custom_command.go @@ -63,7 +63,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Branches(). Focus(). Wait(500). - Press("a"). + Press(config.Keybinding{"a"}). Tap(func() { t.Wait(500) diff --git a/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go b/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go index 1d9ef589f..522ee7689 100644 --- a/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go +++ b/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go @@ -9,8 +9,8 @@ var FilterMenuWithNoKeybindings = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Filtering the keybindings menu so that only entries without keybinding are left", ExtraCmdArgs: []string{}, Skip: false, - SetupConfig: func(config *config.AppConfig) { - config.GetUserConfig().Keybinding.Universal.ToggleWhitespaceInDiffView = "" + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Keybinding.Universal.ToggleWhitespaceInDiffView = nil }, SetupRepo: func(shell *Shell) { }, diff --git a/pkg/integration/tests/interactive_rebase/show_exec_todos.go b/pkg/integration/tests/interactive_rebase/show_exec_todos.go index 74d3830f6..959139154 100644 --- a/pkg/integration/tests/interactive_rebase/show_exec_todos.go +++ b/pkg/integration/tests/interactive_rebase/show_exec_todos.go @@ -26,7 +26,7 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Commits(). Focus(). - Press("X"). + Press(config.Keybinding{"X"}). Tap(func() { t.ExpectPopup().Alert().Title(Equals("Error")).Content(Contains("Rebasing (2/4)Executing: false")).Confirm() }). diff --git a/pkg/integration/tests/misc/disabled_keybindings.go b/pkg/integration/tests/misc/disabled_keybindings.go deleted file mode 100644 index 7ab1ba42a..000000000 --- a/pkg/integration/tests/misc/disabled_keybindings.go +++ /dev/null @@ -1,26 +0,0 @@ -package misc - -import ( - "github.com/jesseduffield/lazygit/pkg/config" - . "github.com/jesseduffield/lazygit/pkg/integration/components" -) - -var DisabledKeybindings = NewIntegrationTest(NewIntegrationTestArgs{ - Description: "Confirms you can disable keybindings by setting them to ", - ExtraCmdArgs: []string{}, - Skip: false, - SetupConfig: func(config *config.AppConfig) { - config.GetUserConfig().Keybinding.Universal.PrevItem = "" - config.GetUserConfig().Keybinding.Universal.NextItem = "" - config.GetUserConfig().Keybinding.Universal.NextTab = "" - config.GetUserConfig().Keybinding.Universal.PrevTab = "" - }, - SetupRepo: func(shell *Shell) {}, - Run: func(t *TestDriver, keys config.KeybindingConfig) { - t.Views().Files(). - IsFocused(). - Press("") - - t.Views().Worktrees().IsFocused() - }, -}) diff --git a/pkg/integration/tests/submodule/enter.go b/pkg/integration/tests/submodule/enter.go index 588ae2049..a56dd8910 100644 --- a/pkg/integration/tests/submodule/enter.go +++ b/pkg/integration/tests/submodule/enter.go @@ -44,7 +44,7 @@ var Enter = NewIntegrationTest(NewIntegrationTestArgs{ assertInSubmodule() t.Views().Files().IsFocused(). - Press("e"). + Press(config.Keybinding{"e"}). Tap(func() { t.Views().Commits().Content(Contains("empty commit")) }). diff --git a/pkg/integration/tests/submodule/reset.go b/pkg/integration/tests/submodule/reset.go index 5cd6d58aa..5e7cde7f0 100644 --- a/pkg/integration/tests/submodule/reset.go +++ b/pkg/integration/tests/submodule/reset.go @@ -46,7 +46,7 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{ assertInSubmodule() t.Views().Files().IsFocused(). - Press("e"). + Press(config.Keybinding{"e"}). Tap(func() { t.Views().Commits().Content(Contains("empty commit")) t.Views().Files().Content(Contains("my_file")) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index fdccb08bf..aea37515b 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -334,7 +334,6 @@ var tests = []*components.IntegrationTest{ misc.ConfirmOnQuit, misc.CopyConfirmationMessageToClipboard, misc.CopyToClipboard, - misc.DisabledKeybindings, misc.InitialOpen, misc.RecentReposOnLaunch, patch_building.Apply, diff --git a/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go b/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go index fb1ba5aba..4ca3d1475 100644 --- a/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go +++ b/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go @@ -15,9 +15,9 @@ var DisableSwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArg }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Status().Focus(). - Press(keys.Universal.JumpToBlock[1]) + Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) t.Views().Files().IsFocused(). - Press(keys.Universal.JumpToBlock[1]) + Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) // Despite jumping to an already focused panel, // the tab should not change from the base files view diff --git a/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go b/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go index 4411cb3c6..25676a7ed 100644 --- a/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go +++ b/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go @@ -16,19 +16,19 @@ var SwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArgs{ }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Worktrees().Focus(). - Press(keys.Universal.JumpToBlock[2]) + Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) t.Views().Branches().IsFocused(). - Press(keys.Universal.JumpToBlock[2]) + Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) t.Views().Remotes().IsFocused(). - Press(keys.Universal.JumpToBlock[2]) + Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) t.Views().Tags().IsFocused(). - Press(keys.Universal.JumpToBlock[2]) + Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) t.Views().Branches().IsFocused(). - Press(keys.Universal.JumpToBlock[1]) + Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) // When jumping to a panel from a different one, keep its current tab: t.Views().Worktrees().IsFocused() diff --git a/pkg/integration/tests/worktree/custom_command.go b/pkg/integration/tests/worktree/custom_command.go index 00c3c4c06..a3cddd36a 100644 --- a/pkg/integration/tests/worktree/custom_command.go +++ b/pkg/integration/tests/worktree/custom_command.go @@ -32,7 +32,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{ Contains("linked-worktree"), ). NavigateToLine(Contains("linked-worktree")). - Press("d"). + Press(config.Keybinding{"d"}). Lines( Contains("(main worktree)"), ) diff --git a/pkg/jsonschema/generate.go b/pkg/jsonschema/generate.go index 5e7267e3e..414756b50 100644 --- a/pkg/jsonschema/generate.go +++ b/pkg/jsonschema/generate.go @@ -58,6 +58,7 @@ func customReflect(v *config.UserConfig) *jsonschema.Schema { } filterOutDevComments(r) schema := r.Reflect(v) + inlineKeybindingRefs(schema) defaultConfig := config.GetDefaultConfig() userConfigSchema := schema.Definitions["UserConfig"] @@ -77,6 +78,57 @@ func customReflect(v *config.UserConfig) *jsonschema.Schema { return schema } +// inlineKeybindingRefs replaces every `$ref: #/$defs/Keybinding` in the +// schema with the inlined oneOf union, then drops the Keybinding definition. +// +// The schema generator stores types that implement JSONSchema() as shared +// definitions and uses $ref to point at them. That works for most types +// (where every reference logically points at the same data), but for +// Keybinding fields each property carries its own description and default, +// and writing those onto the shared definition would clobber siblings. +// Inlining sidesteps the issue. +func inlineKeybindingRefs(schema *jsonschema.Schema) { + const ref = "#/$defs/Keybinding" + keybindingDef, ok := schema.Definitions["Keybinding"] + if !ok { + return + } + inline := func(s *jsonschema.Schema) { + desc := s.Description + *s = *keybindingDef + s.Description = desc + } + var visit func(s *jsonschema.Schema) + visit = func(s *jsonschema.Schema) { + if s == nil { + return + } + if s.Properties != nil { + for pair := s.Properties.Oldest(); pair != nil; pair = pair.Next() { + if pair.Value.Ref == ref { + inline(pair.Value) + } else { + visit(pair.Value) + } + } + } + if s.Items != nil { + if s.Items.Ref == ref { + inline(s.Items) + } else { + visit(s.Items) + } + } + if s.AdditionalProperties != nil { + visit(s.AdditionalProperties) + } + } + for _, def := range schema.Definitions { + visit(def) + } + delete(schema.Definitions, "Keybinding") +} + func filterOutDevComments(r *jsonschema.Reflector) { for k, v := range r.CommentMap { commentLines := strings.Split(v, "\n") diff --git a/schema-master/config.json b/schema-master/config.json index d6ad8116d..f2ba2ad46 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -843,15 +843,45 @@ "KeybindingAmendAttributeConfig": { "properties": { "resetAuthor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "a" }, "setAuthor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "A" }, "addCoAuthor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "c" } }, @@ -861,79 +891,269 @@ "KeybindingBranchesConfig": { "properties": { "createPullRequest": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "o" }, "viewPullRequestOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "O" }, "openPullRequestInBrowser": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "G" }, "copyPullRequestURL": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+y\u003e" }, "checkoutBranchByName": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "c" }, "forceCheckoutBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "F" }, "checkoutPreviousBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "-" }, "rebaseBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "r" }, "renameBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "R" }, "mergeIntoCurrentBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "M" }, "moveCommitsToNewBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "N" }, "viewGitFlowOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "i" }, "fastForward": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "f" }, "createTag": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "T" }, "pushTag": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "P" }, "setUpstream": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "u" }, "fetchRemote": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "f" }, "addForkRemote": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "F" }, "sortOrder": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "s" } }, @@ -943,7 +1163,17 @@ "KeybindingCommitFilesConfig": { "properties": { "checkoutCommitFile": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "c" } }, @@ -953,7 +1183,17 @@ "KeybindingCommitMessageConfig": { "properties": { "commitMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+o\u003e" } }, @@ -963,111 +1203,381 @@ "KeybindingCommitsConfig": { "properties": { "squashDown": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "s" }, "renameCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "r" }, "renameCommitWithEditor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "R" }, "viewResetOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "g" }, "markCommitAsFixup": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "f" }, "setFixupMessage": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "c" }, "createFixupCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "F" }, "squashAboveCommits": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "S" }, "moveDownCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+j\u003e" }, "moveUpCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+k\u003e" }, "amendToCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "A" }, "resetCommitAuthor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "a" }, "pickCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "p" }, "revertCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "t" }, "cherryPickCopy": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "C" }, "pasteCommits": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "V" }, "markCommitAsBaseForRebase": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "B" }, "tagCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "T" }, "checkoutCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cspace\u003e" }, "resetCherryPick": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+r\u003e" }, "copyCommitAttributeToClipboard": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "y" }, "openLogMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+l\u003e" }, "openInBrowser": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "o" }, "openPullRequestInBrowser": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "G" }, "viewBisectOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "b" }, "startInteractiveRebase": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "i" }, "selectCommitsOfCurrentBranch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "*" } }, @@ -1115,84 +1625,274 @@ }, "additionalProperties": false, "type": "object", - "description": "Keybindings" + "description": "Keybindings.\nEach binding can be a single key or a list of keys; see https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md for the syntax." }, "KeybindingFilesConfig": { "properties": { "commitChanges": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "c" }, "commitChangesWithoutHook": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "w" }, "amendLastCommit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "A" }, "commitChangesWithEditor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "C" }, "findBaseCommitForFixup": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+f\u003e" }, "confirmDiscard": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "x" }, "ignoreFile": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "i" }, "refreshFiles": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "r" }, "stashAllChanges": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "s" }, "viewStashOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "S" }, "toggleStagedAll": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "a" }, "viewResetOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "D" }, "fetch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "f" }, "toggleTreeView": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "`" }, "openMergeOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "M" }, "openStatusFilter": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+b\u003e" }, "copyFileInfoToClipboard": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "y" }, "collapseAll": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "-" }, "expandAll": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "=" } }, @@ -1202,15 +1902,45 @@ "KeybindingMainConfig": { "properties": { "toggleSelectHunk": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "a" }, "pickBothHunks": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "b" }, "editSelectHunk": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "E" } }, @@ -1220,11 +1950,31 @@ "KeybindingStashConfig": { "properties": { "popStash": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "g" }, "renameStash": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "r" } }, @@ -1234,19 +1984,59 @@ "KeybindingStatusConfig": { "properties": { "checkForUpdate": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "u" }, "recentRepos": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "allBranchesLogGraph": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "a" }, "allBranchesLogGraphReverse": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "A" } }, @@ -1256,15 +2046,45 @@ "KeybindingSubmodulesConfig": { "properties": { "init": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "i" }, "update": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "u" }, "bulkMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "b" } }, @@ -1274,111 +2094,381 @@ "KeybindingUniversalConfig": { "properties": { "quit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "q" }, "quit-alt1": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+c\u003e" }, "suspendApp": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+z\u003e" }, "return": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cesc\u003e" }, "quitWithoutChangingDirectory": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "Q" }, "togglePanel": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003ctab\u003e" }, "prevItem": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cup\u003e" }, "nextItem": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cdown\u003e" }, "prevItem-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "k" }, "nextItem-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "j" }, "prevPage": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "," }, "nextPage": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "." }, "scrollLeft": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "H" }, "scrollRight": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "L" }, "gotoTop": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003c" }, "gotoBottom": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003e" }, "gotoTop-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003chome\u003e" }, "gotoBottom-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cend\u003e" }, "toggleRangeSelect": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "v" }, "rangeSelectDown": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cshift+down\u003e" }, "rangeSelectUp": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cshift+up\u003e" }, "prevBlock": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cleft\u003e" }, "nextBlock": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cright\u003e" }, "prevBlock-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "h" }, "nextBlock-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "l" }, "nextBlock-alt2": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003ctab\u003e" }, "prevBlock-alt2": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cbacktab\u003e" }, "jumpToBlock": { @@ -1395,218 +2485,738 @@ ] }, "focusMainView": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "0" }, "nextMatch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "n" }, "prevMatch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "N" }, "startSearch": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "/" }, "moveWordLeft": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "\u003calt+left\u003e on Mac", "default": "\u003cctrl+left\u003e" }, "moveWordRight": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "\u003calt+right\u003e on Mac", "default": "\u003cctrl+right\u003e" }, "backspaceWord": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "\u003calt+backspace\u003e on Mac", "default": "\u003cctrl+backspace\u003e" }, "forwardDeleteWord": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "\u003calt+delete\u003e on Mac", "default": "\u003cctrl+delete\u003e" }, "optionMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "?" }, "select": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cspace\u003e" }, "goInto": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "confirm": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "confirmMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "confirmSuggestion": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "confirmInEditor": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "\u003cmeta+enter\u003e on Mac", "default": "\u003cctrl+enter\u003e" }, "confirmInEditor-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+s\u003e" }, "remove": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "d" }, "new": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "n" }, "edit": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "e" }, "openFile": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "o" }, "scrollUpMain": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cpgup\u003e" }, "scrollDownMain": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cpgdown\u003e" }, "scrollUpMain-alt1": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "K" }, "scrollDownMain-alt1": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "J" }, "scrollUpMain-alt2": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+u\u003e" }, "scrollDownMain-alt2": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+d\u003e" }, "executeShellCommand": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": ":" }, "createRebaseOptionsMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "m" }, "pushFiles": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "'Files' appended for legacy reasons", "default": "P" }, "pullFiles": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "description": "'Files' appended for legacy reasons", "default": "p" }, "refresh": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "R" }, "createPatchOptionsMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+p\u003e" }, "nextTab": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "]" }, "prevTab": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "[" }, "nextScreenMode": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "+" }, "prevScreenMode": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "_" }, "cyclePagers": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "|" }, "undo": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "z" }, "redo": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "Z" }, "filteringMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+s\u003e" }, "diffingMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "W" }, "diffingMenu-alt": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+e\u003e" }, "copyToClipboard": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+o\u003e" }, "openRecentRepos": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+r\u003e" }, "submitEditorText": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003center\u003e" }, "extrasMenu": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "@" }, "toggleWhitespaceInDiffView": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+w\u003e" }, "increaseContextInDiffView": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "}" }, "decreaseContextInDiffView": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "{" }, "increaseRenameSimilarityThreshold": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": ")" }, "decreaseRenameSimilarityThreshold": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "(" }, "openDiffTool": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "\u003cctrl+t\u003e" } }, @@ -1616,7 +3226,17 @@ "KeybindingWorktreesConfig": { "properties": { "viewWorktreeOptions": { - "type": "string", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], "default": "w" } }, @@ -2062,7 +3682,7 @@ }, "keybinding": { "$ref": "#/$defs/KeybindingConfig", - "description": "Keybindings" + "description": "Keybindings.\nEach binding can be a single key or a list of keys; see https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md for the syntax." } }, "additionalProperties": false, From 3ecca88bd8a809444dbe4895fa80f9d50f2fc287 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 4 May 2026 09:08:29 +0200 Subject: [PATCH 12/17] Convert JumpToBlock to a list of multi-key bindings JumpToBlock is special: each of its 5 elements is the binding for one side window (status / files / branches / commits / stash), not an alternate for a single command. Change the field from []string to []Keybinding so each window slot can have alternates of its own. The schema becomes "an array of 5 keybindings, each itself a string or array of strings", which falls out cleanly from how the Keybinding type inlines into the generated schema. Existing configs (a flat array of 5 strings) keep validating because each element is unmarshalled through Keybinding's scalar-or-sequence decoder. --- pkg/config/keybinding_test.go | 15 ++ pkg/config/user_config.go | 162 +++++++++--------- pkg/config/user_config_validation_test.go | 6 +- .../jump_to_side_window_controller.go | 3 +- pkg/gui/views.go | 11 +- pkg/integration/components/view_driver.go | 2 +- ...disable_switch_tab_with_panel_jump_keys.go | 4 +- .../ui/switch_tab_with_panel_jump_keys.go | 10 +- schema-master/config.json | 12 +- 9 files changed, 127 insertions(+), 98 deletions(-) diff --git a/pkg/config/keybinding_test.go b/pkg/config/keybinding_test.go index 9bf3ed442..a0bff786c 100644 --- a/pkg/config/keybinding_test.go +++ b/pkg/config/keybinding_test.go @@ -180,3 +180,18 @@ func TestKeybindingConfigYAMLAcceptsBothForms(t *testing.T) { }) } } + +func TestJumpToBlockYAMLAcceptsMixedForms(t *testing.T) { + yamlInput := ` +jumpToBlock: + - "1" + - ["2", "@"] + - "3" + - "4" + - "5" +` + var cfg KeybindingUniversalConfig + assert.NoError(t, yaml.Unmarshal([]byte(yamlInput), &cfg)) + expected := []Keybinding{{"1"}, {"2", "@"}, {"3"}, {"4"}, {"5"}} + assert.Equal(t, expected, cfg.JumpToBlock) +} diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index bbd568e8d..dfeced3c0 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -423,86 +423,86 @@ type KeybindingConfig struct { // damn looks like we have some inconsistencies here with -alt and -alt1 type KeybindingUniversalConfig struct { - Quit Keybinding `yaml:"quit"` - QuitAlt1 Keybinding `yaml:"quit-alt1"` - SuspendApp Keybinding `yaml:"suspendApp"` - Return Keybinding `yaml:"return"` - QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"` - TogglePanel Keybinding `yaml:"togglePanel"` - PrevItem Keybinding `yaml:"prevItem"` - NextItem Keybinding `yaml:"nextItem"` - PrevItemAlt Keybinding `yaml:"prevItem-alt"` - NextItemAlt Keybinding `yaml:"nextItem-alt"` - PrevPage Keybinding `yaml:"prevPage"` - NextPage Keybinding `yaml:"nextPage"` - ScrollLeft Keybinding `yaml:"scrollLeft"` - ScrollRight Keybinding `yaml:"scrollRight"` - GotoTop Keybinding `yaml:"gotoTop"` - GotoBottom Keybinding `yaml:"gotoBottom"` - GotoTopAlt Keybinding `yaml:"gotoTop-alt"` - GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"` - ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"` - RangeSelectDown Keybinding `yaml:"rangeSelectDown"` - RangeSelectUp Keybinding `yaml:"rangeSelectUp"` - PrevBlock Keybinding `yaml:"prevBlock"` - NextBlock Keybinding `yaml:"nextBlock"` - PrevBlockAlt Keybinding `yaml:"prevBlock-alt"` - NextBlockAlt Keybinding `yaml:"nextBlock-alt"` - NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"` - PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"` - JumpToBlock []string `yaml:"jumpToBlock"` - FocusMainView Keybinding `yaml:"focusMainView"` - NextMatch Keybinding `yaml:"nextMatch"` - PrevMatch Keybinding `yaml:"prevMatch"` - StartSearch Keybinding `yaml:"startSearch"` - MoveWordLeft Keybinding `yaml:"moveWordLeft"` // on Mac - MoveWordRight Keybinding `yaml:"moveWordRight"` // on Mac - BackspaceWord Keybinding `yaml:"backspaceWord"` // on Mac - ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // on Mac - OptionMenu Keybinding `yaml:"optionMenu"` - Select Keybinding `yaml:"select"` - GoInto Keybinding `yaml:"goInto"` - Confirm Keybinding `yaml:"confirm"` - ConfirmMenu Keybinding `yaml:"confirmMenu"` - ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"` - ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // on Mac - ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"` - Remove Keybinding `yaml:"remove"` - New Keybinding `yaml:"new"` - Edit Keybinding `yaml:"edit"` - OpenFile Keybinding `yaml:"openFile"` - ScrollUpMain Keybinding `yaml:"scrollUpMain"` - ScrollDownMain Keybinding `yaml:"scrollDownMain"` - ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"` - ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"` - ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"` - ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"` - ExecuteShellCommand Keybinding `yaml:"executeShellCommand"` - CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"` - Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons - Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons - Refresh Keybinding `yaml:"refresh"` - CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"` - NextTab Keybinding `yaml:"nextTab"` - PrevTab Keybinding `yaml:"prevTab"` - NextScreenMode Keybinding `yaml:"nextScreenMode"` - PrevScreenMode Keybinding `yaml:"prevScreenMode"` - CyclePagers Keybinding `yaml:"cyclePagers"` - Undo Keybinding `yaml:"undo"` - Redo Keybinding `yaml:"redo"` - FilteringMenu Keybinding `yaml:"filteringMenu"` - DiffingMenu Keybinding `yaml:"diffingMenu"` - DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"` - CopyToClipboard Keybinding `yaml:"copyToClipboard"` - OpenRecentRepos Keybinding `yaml:"openRecentRepos"` - SubmitEditorText Keybinding `yaml:"submitEditorText"` - ExtrasMenu Keybinding `yaml:"extrasMenu"` - ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"` - IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"` - DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"` - IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"` - DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"` - OpenDiffTool Keybinding `yaml:"openDiffTool"` + Quit Keybinding `yaml:"quit"` + QuitAlt1 Keybinding `yaml:"quit-alt1"` + SuspendApp Keybinding `yaml:"suspendApp"` + Return Keybinding `yaml:"return"` + QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"` + TogglePanel Keybinding `yaml:"togglePanel"` + PrevItem Keybinding `yaml:"prevItem"` + NextItem Keybinding `yaml:"nextItem"` + PrevItemAlt Keybinding `yaml:"prevItem-alt"` + NextItemAlt Keybinding `yaml:"nextItem-alt"` + PrevPage Keybinding `yaml:"prevPage"` + NextPage Keybinding `yaml:"nextPage"` + ScrollLeft Keybinding `yaml:"scrollLeft"` + ScrollRight Keybinding `yaml:"scrollRight"` + GotoTop Keybinding `yaml:"gotoTop"` + GotoBottom Keybinding `yaml:"gotoBottom"` + GotoTopAlt Keybinding `yaml:"gotoTop-alt"` + GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"` + ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"` + RangeSelectDown Keybinding `yaml:"rangeSelectDown"` + RangeSelectUp Keybinding `yaml:"rangeSelectUp"` + PrevBlock Keybinding `yaml:"prevBlock"` + NextBlock Keybinding `yaml:"nextBlock"` + PrevBlockAlt Keybinding `yaml:"prevBlock-alt"` + NextBlockAlt Keybinding `yaml:"nextBlock-alt"` + NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"` + PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"` + JumpToBlock []Keybinding `yaml:"jumpToBlock"` + FocusMainView Keybinding `yaml:"focusMainView"` + NextMatch Keybinding `yaml:"nextMatch"` + PrevMatch Keybinding `yaml:"prevMatch"` + StartSearch Keybinding `yaml:"startSearch"` + MoveWordLeft Keybinding `yaml:"moveWordLeft"` // on Mac + MoveWordRight Keybinding `yaml:"moveWordRight"` // on Mac + BackspaceWord Keybinding `yaml:"backspaceWord"` // on Mac + ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // on Mac + OptionMenu Keybinding `yaml:"optionMenu"` + Select Keybinding `yaml:"select"` + GoInto Keybinding `yaml:"goInto"` + Confirm Keybinding `yaml:"confirm"` + ConfirmMenu Keybinding `yaml:"confirmMenu"` + ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"` + ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // on Mac + ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"` + Remove Keybinding `yaml:"remove"` + New Keybinding `yaml:"new"` + Edit Keybinding `yaml:"edit"` + OpenFile Keybinding `yaml:"openFile"` + ScrollUpMain Keybinding `yaml:"scrollUpMain"` + ScrollDownMain Keybinding `yaml:"scrollDownMain"` + ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"` + ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"` + ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"` + ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"` + ExecuteShellCommand Keybinding `yaml:"executeShellCommand"` + CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"` + Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons + Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons + Refresh Keybinding `yaml:"refresh"` + CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"` + NextTab Keybinding `yaml:"nextTab"` + PrevTab Keybinding `yaml:"prevTab"` + NextScreenMode Keybinding `yaml:"nextScreenMode"` + PrevScreenMode Keybinding `yaml:"prevScreenMode"` + CyclePagers Keybinding `yaml:"cyclePagers"` + Undo Keybinding `yaml:"undo"` + Redo Keybinding `yaml:"redo"` + FilteringMenu Keybinding `yaml:"filteringMenu"` + DiffingMenu Keybinding `yaml:"diffingMenu"` + DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"` + CopyToClipboard Keybinding `yaml:"copyToClipboard"` + OpenRecentRepos Keybinding `yaml:"openRecentRepos"` + SubmitEditorText Keybinding `yaml:"submitEditorText"` + ExtrasMenu Keybinding `yaml:"extrasMenu"` + ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"` + IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"` + DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"` + IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"` + DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"` + OpenDiffTool Keybinding `yaml:"openDiffTool"` } type KeybindingStatusConfig struct { @@ -932,7 +932,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig { NextBlockAlt: Keybinding{"l"}, PrevBlockAlt2: Keybinding{""}, NextBlockAlt2: Keybinding{""}, - JumpToBlock: []string{"1", "2", "3", "4", "5"}, + JumpToBlock: []Keybinding{{"1"}, {"2"}, {"3"}, {"4"}, {"5"}}, FocusMainView: Keybinding{"0"}, NextMatch: Keybinding{"n"}, PrevMatch: Keybinding{"N"}, diff --git a/pkg/config/user_config_validation_test.go b/pkg/config/user_config_validation_test.go index 6474ac3b0..ec79c9c3e 100644 --- a/pkg/config/user_config_validation_test.go +++ b/pkg/config/user_config_validation_test.go @@ -4,6 +4,7 @@ import ( "strings" "testing" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) @@ -127,7 +128,10 @@ func TestUserConfigValidate_enums(t *testing.T) { { name: "JumpToBlock keybinding", setup: func(config *UserConfig, value string) { - config.Keybinding.Universal.JumpToBlock = strings.Split(value, ",") + labels := strings.Split(value, ",") + config.Keybinding.Universal.JumpToBlock = lo.Map(labels, func(label string, _ int) Keybinding { + return Keybinding{label} + }) }, testCases: []testCase{ {value: "", valid: false}, diff --git a/pkg/gui/controllers/jump_to_side_window_controller.go b/pkg/gui/controllers/jump_to_side_window_controller.go index 31228e3a6..2ea8ac762 100644 --- a/pkg/gui/controllers/jump_to_side_window_controller.go +++ b/pkg/gui/controllers/jump_to_side_window_controller.go @@ -3,7 +3,6 @@ package controllers import ( "log" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/samber/lo" ) @@ -40,7 +39,7 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt return &types.Binding{ ViewName: "", // by default the keys are 1, 2, 3, etc - Keys: opts.GetKeys(config.Keybinding{opts.Config.Universal.JumpToBlock[index]}), + Keys: opts.GetKeys(opts.Config.Universal.JumpToBlock[index]), Handler: opts.Guards.NoPopupPanel(self.goToSideWindow(window)), } }) diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 297da143f..ecfc0ddcd 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/theme" @@ -210,14 +211,14 @@ func (gui *Gui) configureViewProperties() { gui.Views.CommitDescription.TextArea.AutoWrapWidth = gui.c.UserConfig().Git.Commit.AutoWrapWidth if gui.c.UserConfig().Gui.ShowPanelJumps { - keyToTitlePrefix := func(key string) string { - if key == "" { + keyToTitlePrefix := func(binding config.Keybinding) string { + if len(binding) == 0 { return "" } - return fmt.Sprintf("[%s]", key) + return fmt.Sprintf("[%s]", binding[0]) } jumpBindings := gui.c.UserConfig().Keybinding.Universal.JumpToBlock - jumpLabels := lo.Map(jumpBindings, func(binding string, _ int) string { + jumpLabels := lo.Map(jumpBindings, func(binding config.Keybinding, _ int) string { return keyToTitlePrefix(binding) }) @@ -236,7 +237,7 @@ func (gui *Gui) configureViewProperties() { gui.Views.Stash.TitlePrefix = jumpLabels[4] - gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView[0]) + gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView) } else { gui.Views.Status.TitlePrefix = "" diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index 8b1650c32..e9e5fbbc7 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -363,7 +363,7 @@ func (self *ViewDriver) Focus() *ViewDriver { if lo.Contains(window.viewNames, viewName) { tabIndex := lo.IndexOf(window.viewNames, viewName) // jump to the desired window - self.t.press(self.t.keys.Universal.JumpToBlock[windowIndex]) + self.t.press(self.t.keys.Universal.JumpToBlock[windowIndex][0]) // assert we're in the window before continuing self.t.assertWithRetries(func() (bool, string) { diff --git a/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go b/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go index 4ca3d1475..fb1ba5aba 100644 --- a/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go +++ b/pkg/integration/tests/ui/disable_switch_tab_with_panel_jump_keys.go @@ -15,9 +15,9 @@ var DisableSwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArg }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Status().Focus(). - Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) + Press(keys.Universal.JumpToBlock[1]) t.Views().Files().IsFocused(). - Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) + Press(keys.Universal.JumpToBlock[1]) // Despite jumping to an already focused panel, // the tab should not change from the base files view diff --git a/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go b/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go index 25676a7ed..4411cb3c6 100644 --- a/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go +++ b/pkg/integration/tests/ui/switch_tab_with_panel_jump_keys.go @@ -16,19 +16,19 @@ var SwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArgs{ }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Worktrees().Focus(). - Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) + Press(keys.Universal.JumpToBlock[2]) t.Views().Branches().IsFocused(). - Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) + Press(keys.Universal.JumpToBlock[2]) t.Views().Remotes().IsFocused(). - Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) + Press(keys.Universal.JumpToBlock[2]) t.Views().Tags().IsFocused(). - Press(config.Keybinding{keys.Universal.JumpToBlock[2]}) + Press(keys.Universal.JumpToBlock[2]) t.Views().Branches().IsFocused(). - Press(config.Keybinding{keys.Universal.JumpToBlock[1]}) + Press(keys.Universal.JumpToBlock[1]) // When jumping to a panel from a different one, keep its current tab: t.Views().Worktrees().IsFocused() diff --git a/schema-master/config.json b/schema-master/config.json index f2ba2ad46..495acc1d2 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -2473,7 +2473,17 @@ }, "jumpToBlock": { "items": { - "type": "string" + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] }, "type": "array", "default": [ From fbcf562e296d43854fb0c7ab3f0e213dfb8ac859 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 10 May 2026 17:31:52 +0200 Subject: [PATCH 13/17] 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. --- pkg/config/user_config.go | 8 +++--- pkg/config/user_config_validation.go | 20 +++++++------ pkg/config/user_config_validation_test.go | 22 +++++++-------- pkg/gui/services/custom_commands/client.go | 7 ++--- .../custom_commands/handler_creator.go | 2 +- .../custom_commands/keybinding_creator.go | 7 ++--- .../custom_commands_in_per_repo_config.go | 4 +-- .../access_commit_properties.go | 2 +- .../tests/custom_commands/basic_command.go | 2 +- .../custom_commands/check_for_conflicts.go | 2 +- .../conditional_prompt_false_string.go | 2 +- .../conditional_prompt_false_value.go | 2 +- .../custom_commands/conditional_prompts.go | 6 ++-- .../custom_commands_submenu.go | 8 +++--- ...mmands_submenu_with_special_keybindings.go | 10 +++---- .../tests/custom_commands/form_prompts.go | 2 +- .../tests/custom_commands/global_context.go | 2 +- .../custom_commands/menu_from_command.go | 2 +- .../menu_from_commands_output.go | 2 +- .../custom_commands/menu_prompt_with_keys.go | 8 +++--- .../custom_commands/multiple_contexts.go | 2 +- .../tests/custom_commands/multiple_prompts.go | 2 +- .../tests/custom_commands/run_command.go | 2 +- .../tests/custom_commands/selected_commit.go | 2 +- .../custom_commands/selected_commit_range.go | 2 +- .../tests/custom_commands/selected_path.go | 2 +- .../custom_commands/selected_submodule.go | 6 ++-- .../custom_commands/show_output_in_panel.go | 4 +-- .../custom_commands/suggestions_command.go | 2 +- .../custom_commands/suggestions_preset.go | 2 +- pkg/integration/tests/demo/custom_command.go | 2 +- .../interactive_rebase/show_exec_todos.go | 2 +- pkg/integration/tests/submodule/enter.go | 2 +- pkg/integration/tests/submodule/reset.go | 2 +- .../tests/worktree/custom_command.go | 2 +- schema-master/config.json | 28 ++++++++++++++++--- 36 files changed, 103 insertions(+), 81 deletions(-) diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index dfeced3c0..6461ece75 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -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 { diff --git a/pkg/config/user_config_validation.go b/pkg/config/user_config_validation.go index 7eeab32dd..163fc61c4 100644 --- a/pkg/config/user_config_validation.go +++ b/pkg/config/user_config_validation.go @@ -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) + } } } diff --git a/pkg/config/user_config_validation_test.go b/pkg/config/user_config_validation_test.go index ec79c9c3e..bb2d2580f 100644 --- a/pkg/config/user_config_validation_test.go +++ b/pkg/config/user_config_validation_test.go @@ -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"}, }, }, } diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go index 0884e0cce..3f16b8ba8 100644 --- a/pkg/gui/services/custom_commands/client.go +++ b/pkg/gui/services/custom_commands/client.go @@ -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), }) } diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 5f3fd27a0..19694c481 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -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), } }) diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go index ee0e01fa4..f35fc8fd4 100644 --- a/pkg/gui/services/custom_commands/keybinding_creator.go +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -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) } diff --git a/pkg/integration/tests/config/custom_commands_in_per_repo_config.go b/pkg/integration/tests/config/custom_commands_in_per_repo_config.go index 4a66cd43c..929c7eae9 100644 --- a/pkg/integration/tests/config/custom_commands_in_per_repo_config.go +++ b/pkg/integration/tests/config/custom_commands_in_per_repo_config.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/access_commit_properties.go b/pkg/integration/tests/custom_commands/access_commit_properties.go index a1ba84a27..0823b1033 100644 --- a/pkg/integration/tests/custom_commands/access_commit_properties.go +++ b/pkg/integration/tests/custom_commands/access_commit_properties.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/basic_command.go b/pkg/integration/tests/custom_commands/basic_command.go index b50acc792..f5ae90a96 100644 --- a/pkg/integration/tests/custom_commands/basic_command.go +++ b/pkg/integration/tests/custom_commands/basic_command.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/check_for_conflicts.go b/pkg/integration/tests/custom_commands/check_for_conflicts.go index 70f528a6d..5d7924c90 100644 --- a/pkg/integration/tests/custom_commands/check_for_conflicts.go +++ b/pkg/integration/tests/custom_commands/check_for_conflicts.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go b/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go index d2c6beadb..e8a64ea0d 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go +++ b/pkg/integration/tests/custom_commands/conditional_prompt_false_string.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go b/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go index 4a0326669..15379c7b4 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go +++ b/pkg/integration/tests/custom_commands/conditional_prompt_false_value.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/conditional_prompts.go b/pkg/integration/tests/custom_commands/conditional_prompts.go index 4f1f97531..ef743282a 100644 --- a/pkg/integration/tests/custom_commands/conditional_prompts.go +++ b/pkg/integration/tests/custom_commands/conditional_prompts.go @@ -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"}, }, }, }, diff --git a/pkg/integration/tests/custom_commands/custom_commands_submenu.go b/pkg/integration/tests/custom_commands/custom_commands_submenu.go index 93c670449..18dd51d83 100644 --- a/pkg/integration/tests/custom_commands/custom_commands_submenu.go +++ b/pkg/integration/tests/custom_commands/custom_commands_submenu.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go b/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go index 29638ee92..e79e05991 100644 --- a/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go +++ b/pkg/integration/tests/custom_commands/custom_commands_submenu_with_special_keybindings.go @@ -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: "", + Key: config.Keybinding{""}, Context: "global", Command: "echo down", Output: "popup", diff --git a/pkg/integration/tests/custom_commands/form_prompts.go b/pkg/integration/tests/custom_commands/form_prompts.go index 3e051cb8e..43246b872 100644 --- a/pkg/integration/tests/custom_commands/form_prompts.go +++ b/pkg/integration/tests/custom_commands/form_prompts.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/global_context.go b/pkg/integration/tests/custom_commands/global_context.go index 274d6a7ba..2c4cd464f 100644 --- a/pkg/integration/tests/custom_commands/global_context.go +++ b/pkg/integration/tests/custom_commands/global_context.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/menu_from_command.go b/pkg/integration/tests/custom_commands/menu_from_command.go index ae62c9a5c..51122aa6f 100644 --- a/pkg/integration/tests/custom_commands/menu_from_command.go +++ b/pkg/integration/tests/custom_commands/menu_from_command.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/menu_from_commands_output.go b/pkg/integration/tests/custom_commands/menu_from_commands_output.go index 7820bc515..51444ad52 100644 --- a/pkg/integration/tests/custom_commands/menu_from_commands_output.go +++ b/pkg/integration/tests/custom_commands/menu_from_commands_output.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go b/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go index d29a049f9..4a217f924 100644 --- a/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go +++ b/pkg/integration/tests/custom_commands/menu_prompt_with_keys.go @@ -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"}, }, }, }, diff --git a/pkg/integration/tests/custom_commands/multiple_contexts.go b/pkg/integration/tests/custom_commands/multiple_contexts.go index b53242edc..3c7e07e84 100644 --- a/pkg/integration/tests/custom_commands/multiple_contexts.go +++ b/pkg/integration/tests/custom_commands/multiple_contexts.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/multiple_prompts.go b/pkg/integration/tests/custom_commands/multiple_prompts.go index a450f7aee..8651a330a 100644 --- a/pkg/integration/tests/custom_commands/multiple_prompts.go +++ b/pkg/integration/tests/custom_commands/multiple_prompts.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/run_command.go b/pkg/integration/tests/custom_commands/run_command.go index ca9abb658..afff59590 100644 --- a/pkg/integration/tests/custom_commands/run_command.go +++ b/pkg/integration/tests/custom_commands/run_command.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/selected_commit.go b/pkg/integration/tests/custom_commands/selected_commit.go index 49595afd0..0265759a8 100644 --- a/pkg/integration/tests/custom_commands/selected_commit.go +++ b/pkg/integration/tests/custom_commands/selected_commit.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/selected_commit_range.go b/pkg/integration/tests/custom_commands/selected_commit_range.go index f335d91d9..6ef1305aa 100644 --- a/pkg/integration/tests/custom_commands/selected_commit_range.go +++ b/pkg/integration/tests/custom_commands/selected_commit_range.go @@ -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`, }, diff --git a/pkg/integration/tests/custom_commands/selected_path.go b/pkg/integration/tests/custom_commands/selected_path.go index c6c680335..cad479e4a 100644 --- a/pkg/integration/tests/custom_commands/selected_path.go +++ b/pkg/integration/tests/custom_commands/selected_path.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/selected_submodule.go b/pkg/integration/tests/custom_commands/selected_submodule.go index d03af03dd..0671b4b83 100644 --- a/pkg/integration/tests/custom_commands/selected_submodule.go +++ b/pkg/integration/tests/custom_commands/selected_submodule.go @@ -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", }, diff --git a/pkg/integration/tests/custom_commands/show_output_in_panel.go b/pkg/integration/tests/custom_commands/show_output_in_panel.go index 95765cb5f..4654b9b51 100644 --- a/pkg/integration/tests/custom_commands/show_output_in_panel.go +++ b/pkg/integration/tests/custom_commands/show_output_in_panel.go @@ -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", diff --git a/pkg/integration/tests/custom_commands/suggestions_command.go b/pkg/integration/tests/custom_commands/suggestions_command.go index 831ecddda..e31d6dd8b 100644 --- a/pkg/integration/tests/custom_commands/suggestions_command.go +++ b/pkg/integration/tests/custom_commands/suggestions_command.go @@ -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{ diff --git a/pkg/integration/tests/custom_commands/suggestions_preset.go b/pkg/integration/tests/custom_commands/suggestions_preset.go index 285d88e01..ebd9ee5da 100644 --- a/pkg/integration/tests/custom_commands/suggestions_preset.go +++ b/pkg/integration/tests/custom_commands/suggestions_preset.go @@ -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{ diff --git a/pkg/integration/tests/demo/custom_command.go b/pkg/integration/tests/demo/custom_command.go index f14a19b5f..486b3488a 100644 --- a/pkg/integration/tests/demo/custom_command.go +++ b/pkg/integration/tests/demo/custom_command.go @@ -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{ diff --git a/pkg/integration/tests/interactive_rebase/show_exec_todos.go b/pkg/integration/tests/interactive_rebase/show_exec_todos.go index 959139154..948bfb7d8 100644 --- a/pkg/integration/tests/interactive_rebase/show_exec_todos.go +++ b/pkg/integration/tests/interactive_rebase/show_exec_todos.go @@ -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^^", }, diff --git a/pkg/integration/tests/submodule/enter.go b/pkg/integration/tests/submodule/enter.go index a56dd8910..b768ed40e 100644 --- a/pkg/integration/tests/submodule/enter.go +++ b/pkg/integration/tests/submodule/enter.go @@ -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\"", }, diff --git a/pkg/integration/tests/submodule/reset.go b/pkg/integration/tests/submodule/reset.go index 5e7cde7f0..d671066a1 100644 --- a/pkg/integration/tests/submodule/reset.go +++ b/pkg/integration/tests/submodule/reset.go @@ -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", }, diff --git a/pkg/integration/tests/worktree/custom_command.go b/pkg/integration/tests/worktree/custom_command.go index a3cddd36a..e00c162c3 100644 --- a/pkg/integration/tests/worktree/custom_command.go +++ b/pkg/integration/tests/worktree/custom_command.go @@ -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 }}", }, diff --git a/schema-master/config.json b/schema-master/config.json index 495acc1d2..1f6e9e7d8 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -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, From 022d24cb79589f3a6933c1a0b2103c87c21731ca Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 4 May 2026 09:03:15 +0200 Subject: [PATCH 14/17] Fold legacy quit-alt1 into the multi-key quit binding Now that quit accepts multiple keys, the historical quit-alt1 field is redundant: existing configs that set it should keep working without the user having to migrate, but the lazygit code shouldn't have to register the alt binding separately. Add a merge step that runs after the user config is loaded (and from NewDummyAppConfig, which the cheatsheet generator and integration tests go through) folding the alt value into the main key list. Mark QuitAlt1 deprecated so it disappears from the generated Config.md example, while staying in the JSON schema with a description so editors can still steer users toward the new form. Note that instead of marking the alt config as deprecated, we could have added a migrator that changes users' config files and gets rid of the alt config for good. I decided not to do that, because this would render the config file invalid for older versions of lazygit, which would then refuse to start; and that's annoying when bisecting bugs. We'll keep the deprecated configs in the code for a year or so, and then add the migrator. The next commit will fold the remaining ~15 -alt-style fields the same way; the helper is shaped to keep that mechanical. --- docs-master/Config.md | 3 +- docs-master/keybindings/Keybindings_en.md | 2 +- docs-master/keybindings/Keybindings_ja.md | 2 +- docs-master/keybindings/Keybindings_ko.md | 2 +- docs-master/keybindings/Keybindings_nl.md | 2 +- docs-master/keybindings/Keybindings_pl.md | 2 +- docs-master/keybindings/Keybindings_pt.md | 2 +- docs-master/keybindings/Keybindings_ru.md | 2 +- docs-master/keybindings/Keybindings_zh-CN.md | 2 +- docs-master/keybindings/Keybindings_zh-TW.md | 2 +- pkg/config/app_config.go | 1 + pkg/config/dummies.go | 4 +- pkg/config/keybinding.go | 6 +++ pkg/config/keybinding_test.go | 53 ++++++++++++++++++++ pkg/config/user_config.go | 11 +++- pkg/gui/controllers/global_controller.go | 4 -- pkg/jsonschema/generate.go | 1 + schema-master/config.json | 6 ++- 18 files changed, 89 insertions(+), 18 deletions(-) diff --git a/docs-master/Config.md b/docs-master/Config.md index 4e9a4617a..dd0a7dd11 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -597,8 +597,7 @@ promptToReturnFromSubprocess: true # for the syntax. keybinding: universal: - quit: q - quit-alt1: + quit: [q, ] suspendApp: return: quitWithoutChangingDirectory: Q diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index 74dbcc97d..8191c6b8b 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | Quit | | +| `` q, `` | Quit | | | `` `` | Suspend the application | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | Undo | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index f06f1a0bf..0d51ebe7f 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | フィルターオプションを表示 | コミットログのフィルタリングオプションを表示し、フィルタに一致するコミットのみを表示します。 | | `` W `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 | | `` `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 | -| `` q `` | 終了 | | +| `` q, `` | 終了 | | | `` `` | Suspend the application | | | `` `` | 空白表示の切り替え | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | 元に戻す | 最後のgitコマンドを元に戻すために実行するgitコマンドを決定するためにreflogが使用されます。これにはワーキングツリーへの変更は含まれません。コミットのみが考慮されます。 | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index 2b96d0aa8..d183f82de 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | 종료 | | +| `` q, `` | 종료 | | | `` `` | Suspend the application | | | `` `` | 공백문자를 Diff 뷰에서 표시 여부 전환 | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | 되돌리기 (reflog) (실험적) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index f048e2a2c..8b01ad9da 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | Quit | | +| `` q, `` | Quit | | | `` `` | Suspend the application | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | Ongedaan maken (via reflog) (experimenteel) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index fcde7bfb4..36d3c58a2 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. | | `` W `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. | | `` `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. | -| `` q `` | Wyjdź | | +| `` q, `` | Wyjdź | | | `` `` | Suspend the application | | | `` `` | Przełącz białe znaki | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | Cofnij | Dziennik reflog zostanie użyty do określenia, jakie polecenie git należy uruchomić, aby cofnąć ostatnie polecenie git. Nie obejmuje to zmian w drzewie roboczym; brane są pod uwagę tylko commity. | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 1aacc5722..17835d1a4 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Ver opções de filtro | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | Sair | | +| `` q, `` | Sair | | | `` `` | Suspender a aplicação | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | Desfazer | O reflog será usado para determinar qual comando git para executar para desfazer o último comando git. Isto não inclui mudanças na árvore de trabalho; apenas compromissos são tidos em consideração. | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index 0dcb6753e..538a05ef0 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | Выйти | | +| `` q, `` | Выйти | | | `` `` | Suspend the application | | | `` `` | Переключить отображение изменении пробелов в просмотрщике сравнении | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | Отменить (через reflog) (экспериментальный) | Журнал ссылок (reflog) будет использоваться для определения того, какую команду git запустить, чтобы отменить последнюю команду git. Сюда не входят изменения в рабочем дереве; учитываются только коммиты. | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index d78572f1b..b144b08cd 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 | | `` W `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 | | `` `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 | -| `` q `` | 退出 | | +| `` q, `` | 退出 | | | `` `` | 挂起应用程序 | | | `` `` | 切换是否在差异视图中显示空白字符差异 | 切换是否在差异视图中显示空白字符更改。

默认值可在配置文件中通过键 'git.ignoreWhitespaceInDiffView' 更改。 | | `` z `` | 撤销 | Reflog将用于确定运行哪个git命令来撤消最后一个git命令。这并不包括对工作树的更改,只考虑提交。 | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index 70294eab9..5e7892bd9 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -28,7 +28,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. | | `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` q `` | 結束 | | +| `` q, `` | 結束 | | | `` `` | Suspend the application | | | `` `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | | `` z `` | 復原 | 將使用 reflog 確任 git 指令以復原。這不包括工作區更改;只考慮提交。 | diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 27ee38c0b..e7267158a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -203,6 +203,7 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig, isGuiInitialize } } + base.Keybinding.MergeLegacyAltKeybindings() return base, nil } diff --git a/pkg/config/dummies.go b/pkg/config/dummies.go index 06c8755a6..5bc349fa0 100644 --- a/pkg/config/dummies.go +++ b/pkg/config/dummies.go @@ -6,11 +6,13 @@ import ( // NewDummyAppConfig creates a new dummy AppConfig for testing func NewDummyAppConfig() *AppConfig { + userConfig := GetDefaultConfig() + userConfig.Keybinding.MergeLegacyAltKeybindings() appConfig := &AppConfig{ name: "lazygit", version: "unversioned", debug: false, - userConfig: GetDefaultConfig(), + userConfig: userConfig, appState: &AppState{}, } _ = yaml.Unmarshal([]byte{}, appConfig.appState) diff --git a/pkg/config/keybinding.go b/pkg/config/keybinding.go index f552707e5..905bc2bd7 100644 --- a/pkg/config/keybinding.go +++ b/pkg/config/keybinding.go @@ -84,3 +84,9 @@ func (Keybinding) JSONSchema() *jsonschema.Schema { }, } } + +// mergeLegacyAlt folds a deprecated `*Alt*` field into the corresponding +// multi-key main field. +func mergeLegacyAlt(main *Keybinding, alt Keybinding) { + *main = lo.Union(*main, alt) +} diff --git a/pkg/config/keybinding_test.go b/pkg/config/keybinding_test.go index a0bff786c..be9f15acb 100644 --- a/pkg/config/keybinding_test.go +++ b/pkg/config/keybinding_test.go @@ -135,6 +135,59 @@ func TestKeybindingMarshalJSON(t *testing.T) { } } +func TestMergeLegacyAltKeybindings(t *testing.T) { + scenarios := []struct { + name string + quit Keybinding + quitAlt1 Keybinding + expected Keybinding + }{ + { + name: "alt is folded into main", + quit: Keybinding{"q"}, + quitAlt1: Keybinding{""}, + expected: Keybinding{"q", ""}, + }, + { + name: "alt is not appended if already present", + quit: Keybinding{"q", ""}, + quitAlt1: Keybinding{""}, + expected: Keybinding{"q", ""}, + }, + { + name: "empty alt is ignored", + quit: Keybinding{"q"}, + quitAlt1: nil, + expected: Keybinding{"q"}, + }, + { + name: "user-supplied multi-key main is preserved", + quit: Keybinding{"q", ""}, + quitAlt1: Keybinding{""}, + expected: Keybinding{"q", "", ""}, + }, + { + name: "multi-key alt is folded element by element", + quit: Keybinding{"q"}, + quitAlt1: Keybinding{"", ""}, + expected: Keybinding{"q", "", ""}, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + cfg := KeybindingConfig{ + Universal: KeybindingUniversalConfig{ + Quit: s.quit, + QuitAlt1: s.quitAlt1, + }, + } + cfg.MergeLegacyAltKeybindings() + assert.Equal(t, s.expected, cfg.Universal.Quit) + }) + } +} + func TestKeybindingYAMLRoundTrip(t *testing.T) { scenarios := []Keybinding{ {"q"}, diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 6461ece75..a5525804d 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -423,7 +423,8 @@ type KeybindingConfig struct { // damn looks like we have some inconsistencies here with -alt and -alt1 type KeybindingUniversalConfig struct { - Quit Keybinding `yaml:"quit"` + Quit Keybinding `yaml:"quit"` + // Deprecated: add the key to `quit` instead. QuitAlt1 Keybinding `yaml:"quit-alt1"` SuspendApp Keybinding `yaml:"suspendApp"` Return Keybinding `yaml:"return"` @@ -769,6 +770,14 @@ type IconProperties struct { Color string `yaml:"color"` } +// MergeLegacyAltKeybindings folds deprecated `*Alt*` fields into their +// corresponding multi-key main field. New code should treat the main field +// as the single source of truth; the alt fields will be removed in a future +// release. +func (c *KeybindingConfig) MergeLegacyAltKeybindings() { + mergeLegacyAlt(&c.Universal.Quit, c.Universal.QuitAlt1) +} + func GetDefaultConfig() *UserConfig { // This is only for tests; we don't want to use the test runner's host platform in that case, // but always use the fallback bindings diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index 5528e10e7..8e5013a55 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -111,10 +111,6 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type Description: self.c.Tr.Quit, Handler: self.quit, }, - { - Keys: opts.GetKeys(opts.Config.Universal.QuitAlt1), - Handler: self.quit, - }, { Keys: opts.GetKeys(opts.Config.Universal.QuitWithoutChangingDirectory), Handler: self.quitWithoutChangingDirectory, diff --git a/pkg/jsonschema/generate.go b/pkg/jsonschema/generate.go index 414756b50..dc5045025 100644 --- a/pkg/jsonschema/generate.go +++ b/pkg/jsonschema/generate.go @@ -60,6 +60,7 @@ func customReflect(v *config.UserConfig) *jsonschema.Schema { schema := r.Reflect(v) inlineKeybindingRefs(schema) defaultConfig := config.GetDefaultConfig() + defaultConfig.Keybinding.MergeLegacyAltKeybindings() userConfigSchema := schema.Definitions["UserConfig"] defaultValue := reflect.ValueOf(defaultConfig).Elem() diff --git a/schema-master/config.json b/schema-master/config.json index 1f6e9e7d8..a33e20f2d 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -2125,7 +2125,10 @@ "type": "array" } ], - "default": "q" + "default": [ + "q", + "\u003cctrl+c\u003e" + ] }, "quit-alt1": { "oneOf": [ @@ -2139,6 +2142,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `quit` instead.", "default": "\u003cctrl+c\u003e" }, "suspendApp": { From 2ba401909d16be289a625a9c3992a2fae50967f8 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 25 May 2026 12:10:31 +0200 Subject: [PATCH 15/17] Use a dedicated keybinding for hunk navigation in the main view Previously the patch_explorer and merge_conflicts controllers reused Universal.PrevBlock/NextBlock for moving between hunks (or conflicts) in the main view, sharing keys with the global side-window cycle. The two operations are conceptually distinct: cycling side windows is a global navigation gesture, while next/prev hunk acts on the diff in the main view. Tying them together also blocks adding / as side- window-cycle keys, because already means "toggle panel" in the staging view. Add Main.PrevHunk/NextHunk to the existing KeybindingMainConfig (which already groups bindings for the main view across staging, patch building, and merge conflicts) and switch both controllers to it. The defaults match the active key set those controllers had before (//h/l), so the user-visible behavior is unchanged. --- docs-master/Config.md | 2 ++ docs-master/keybindings/Keybindings_en.md | 12 +++---- docs-master/keybindings/Keybindings_ja.md | 12 +++---- docs-master/keybindings/Keybindings_ko.md | 12 +++---- docs-master/keybindings/Keybindings_nl.md | 12 +++---- docs-master/keybindings/Keybindings_pl.md | 12 +++---- docs-master/keybindings/Keybindings_pt.md | 12 +++---- docs-master/keybindings/Keybindings_ru.md | 12 +++---- docs-master/keybindings/Keybindings_zh-CN.md | 12 +++---- docs-master/keybindings/Keybindings_zh-TW.md | 12 +++---- pkg/config/user_config.go | 4 +++ .../controllers/merge_conflicts_controller.go | 12 ++----- .../controllers/patch_explorer_controller.go | 12 ++----- schema-master/config.json | 34 +++++++++++++++++++ 14 files changed, 98 insertions(+), 74 deletions(-) diff --git a/docs-master/Config.md b/docs-master/Config.md index dd0a7dd11..90ddde045 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -780,6 +780,8 @@ keybinding: commitFiles: checkoutCommitFile: c main: + prevHunk: [, h] + nextHunk: [, l] toggleSelectHunk: a pickBothHunks: b editSelectHunk: E diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index 8191c6b8b..fafa7312d 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -207,8 +207,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Pick all hunks | | | `` `` | Previous hunk | | | `` `` | Next hunk | | -| `` `` | Previous conflict | | -| `` `` | Next conflict | | +| `` , h `` | Previous conflict | | +| `` , l `` | Next conflict | | | `` z `` | Undo | Undo last merge conflict resolution. | | `` e `` | Edit file | Open file in external editor. | | `` o `` | Open file | Open file in default application. | @@ -229,8 +229,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Go to previous hunk | | -| `` `` | Go to next hunk | | +| `` , h `` | Go to previous hunk | | +| `` , l `` | Go to next hunk | | | `` v `` | Toggle range select | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Copy selected text to clipboard | | @@ -245,8 +245,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Go to previous hunk | | -| `` `` | Go to next hunk | | +| `` , h `` | Go to previous hunk | | +| `` , l `` | Go to next hunk | | | `` v `` | Toggle range select | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Copy selected text to clipboard | | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index 0d51ebe7f..4b5bfc9f3 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -248,8 +248,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 前のハンクに移動 | | -| `` `` | 次のハンクに移動 | | +| `` , h `` | 前のハンクに移動 | | +| `` , l `` | 次のハンクに移動 | | | `` v `` | 範囲選択を切り替え | | | `` a `` | ハンクの選択を切り替える | Toggle line-by-line vs. hunk selection mode. | | `` `` | 選択したテキストをクリップボードにコピー | | @@ -270,8 +270,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 前のハンクに移動 | | -| `` `` | 次のハンクに移動 | | +| `` , h `` | 前のハンクに移動 | | +| `` , l `` | 次のハンクに移動 | | | `` v `` | 範囲選択を切り替え | | | `` a `` | ハンクの選択を切り替える | Toggle line-by-line vs. hunk selection mode. | | `` `` | 選択したテキストをクリップボードにコピー | | @@ -290,8 +290,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | すべてのハンクを選択 | | | `` `` | 前のハンク | | | `` `` | 次のハンク | | -| `` `` | 前のコンフリクト | | -| `` `` | 次のコンフリクト | | +| `` , h `` | 前のコンフリクト | | +| `` , l `` | 次のコンフリクト | | | `` z `` | 元に戻す | 最後のマージコンフリクト解決を元に戻します。 | | `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 | | `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index d183f82de..157984a9c 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -146,8 +146,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Pick all hunks | | | `` `` | 이전 hunk를 선택 | | | `` `` | 다음 hunk를 선택 | | -| `` `` | 이전 충돌을 선택 | | -| `` `` | 다음 충돌을 선택 | | +| `` , h `` | 이전 충돌을 선택 | | +| `` , l `` | 다음 충돌을 선택 | | | `` z `` | 되돌리기 | Undo last merge conflict resolution. | | `` e `` | 파일 편집 | Open file in external editor. | | `` o `` | 파일 닫기 | Open file in default application. | @@ -168,8 +168,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 이전 hunk를 선택 | | -| `` `` | 다음 hunk를 선택 | | +| `` , h `` | 이전 hunk를 선택 | | +| `` , l `` | 다음 hunk를 선택 | | | `` v `` | 드래그 선택 전환 | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | 선택한 텍스트를 클립보드에 복사 | | @@ -184,8 +184,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 이전 hunk를 선택 | | -| `` `` | 다음 hunk를 선택 | | +| `` , h `` | 이전 hunk를 선택 | | +| `` , l `` | 다음 hunk를 선택 | | | `` v `` | 드래그 선택 전환 | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | 선택한 텍스트를 클립보드에 복사 | | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index 8b01ad9da..ca3449cf9 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -215,8 +215,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Kies beide stukken | | | `` `` | Selecteer bovenste hunk | | | `` `` | Selecteer onderste hunk | | -| `` `` | Selecteer voorgaand conflict | | -| `` `` | Selecteer volgende conflict | | +| `` , h `` | Selecteer voorgaand conflict | | +| `` , l `` | Selecteer volgende conflict | | | `` z `` | Ongedaan maken | Undo last merge conflict resolution. | | `` e `` | Verander bestand | Open file in external editor. | | `` o `` | Open bestand | Open file in default application. | @@ -237,8 +237,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Selecteer de vorige hunk | | -| `` `` | Selecteer de volgende hunk | | +| `` , h `` | Selecteer de vorige hunk | | +| `` , l `` | Selecteer de volgende hunk | | | `` v `` | Toggle drag selecteer | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Copy selected text to clipboard | | @@ -312,8 +312,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Selecteer de vorige hunk | | -| `` `` | Selecteer de volgende hunk | | +| `` , h `` | Selecteer de vorige hunk | | +| `` , l `` | Selecteer de volgende hunk | | | `` v `` | Toggle drag selecteer | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Copy selected text to clipboard | | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index 36d3c58a2..69e60b78d 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -115,8 +115,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Idź do poprzedniego fragmentu | | -| `` `` | Idź do następnego fragmentu | | +| `` , h `` | Idź do poprzedniego fragmentu | | +| `` , l `` | Idź do następnego fragmentu | | | `` v `` | Przełącz zaznaczenie zakresu | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Kopiuj zaznaczony tekst do schowka | | @@ -191,8 +191,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Wybierz wszystkie fragmenty | | | `` `` | Poprzedni fragment | | | `` `` | Następny fragment | | -| `` `` | Poprzedni konflikt | | -| `` `` | Następny konflikt | | +| `` , h `` | Poprzedni konflikt | | +| `` , l `` | Następny konflikt | | | `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. | | `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. | | `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. | @@ -203,8 +203,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Idź do poprzedniego fragmentu | | -| `` `` | Idź do następnego fragmentu | | +| `` , h `` | Idź do poprzedniego fragmentu | | +| `` , l `` | Idź do następnego fragmentu | | | `` v `` | Przełącz zaznaczenie zakresu | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Kopiuj zaznaczony tekst do schowka | | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 17835d1a4..0152530f0 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -241,8 +241,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Ir para o local anterior | | -| `` `` | Ir para o próximo trecho | | +| `` , h `` | Ir para o local anterior | | +| `` , l `` | Ir para o próximo trecho | | | `` v `` | Toggle range select | | | `` a `` | Toggle hunk selection | Ativa/desativa modo linha por linha vs. modo de seleção por partes. | | `` `` | Copiar texto selecionado para área de transferência | | @@ -275,8 +275,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Pegar todos os pedaços | | | `` `` | Trecho anterior | | | `` `` | Próximo trecho | | -| `` `` | Conflito anterior | | -| `` `` | Próximo conflito | | +| `` , h `` | Conflito anterior | | +| `` , l `` | Próximo conflito | | | `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. | | `` e `` | Editar arquivo | Abrir arquivo no editor externo. | | `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. | @@ -287,8 +287,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Ir para o local anterior | | -| `` `` | Ir para o próximo trecho | | +| `` , h `` | Ir para o local anterior | | +| `` , l `` | Ir para o próximo trecho | | | `` v `` | Toggle range select | | | `` a `` | Toggle hunk selection | Ativa/desativa modo linha por linha vs. modo de seleção por partes. | | `` `` | Copiar texto selecionado para área de transferência | | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index 538a05ef0..697912e5a 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -80,8 +80,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Выбрать предыдущую часть | | -| `` `` | Выбрать следующую часть | | +| `` , h `` | Выбрать предыдущую часть | | +| `` , l `` | Выбрать следующую часть | | | `` v `` | Переключить выборку перетаскивания | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Скопировать выделенный текст в буфер обмена | | @@ -116,8 +116,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | Выбрать все части | | | `` `` | Выбрать предыдущую часть | | | `` `` | Выбрать следующую часть | | -| `` `` | Выбрать предыдущий конфликт | | -| `` `` | Выбрать следующий конфликт | | +| `` , h `` | Выбрать предыдущий конфликт | | +| `` , l `` | Выбрать следующий конфликт | | | `` z `` | Отменить | Undo last merge conflict resolution. | | `` e `` | Редактировать файл | Open file in external editor. | | `` o `` | Открыть файл | Open file in default application. | @@ -128,8 +128,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | Выбрать предыдущую часть | | -| `` `` | Выбрать следующую часть | | +| `` , h `` | Выбрать предыдущую часть | | +| `` , l `` | Выбрать следующую часть | | | `` v `` | Переключить выборку перетаскивания | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | Скопировать выделенный текст в буфер обмена | | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index b144b08cd..fcd78596a 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -252,8 +252,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 选择上一个区块 | | -| `` `` | 选择下一个区块 | | +| `` , h `` | 选择上一个区块 | | +| `` , l `` | 选择下一个区块 | | | `` v `` | 切换拖动选择 | | | `` a `` | 切换代码块选择 | 切换逐行选择与代码块选择模式。 | | `` `` | 复制选中文本到剪贴板 | | @@ -296,8 +296,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | 选中所有区块 | | | `` `` | 选择顶部块 | | | `` `` | 选择底部块 | | -| `` `` | 选择上一个冲突 | | -| `` `` | 选择下一个冲突 | | +| `` , h `` | 选择上一个冲突 | | +| `` , l `` | 选择下一个冲突 | | | `` z `` | 撤销 | 撤消上次合并冲突解决 | | `` e `` | 编辑文件 | 使用外部编辑器打开文件 | | `` o `` | 打开文件 | 使用默认程序打开该文件 | @@ -308,8 +308,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 选择上一个区块 | | -| `` `` | 选择下一个区块 | | +| `` , h `` | 选择上一个区块 | | +| `` , l `` | 选择下一个区块 | | | `` v `` | 切换拖动选择 | | | `` a `` | 切换代码块选择 | 切换逐行选择与代码块选择模式。 | | `` `` | 复制选中文本到剪贴板 | | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index 5e7892bd9..2c2456e4a 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -62,8 +62,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 選擇上一段 | | -| `` `` | 選擇下一段 | | +| `` , h `` | 選擇上一段 | | +| `` , l `` | 選擇下一段 | | | `` v `` | 切換拖曳選擇 | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | 複製所選文本至剪貼簿 | | @@ -92,8 +92,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` b `` | 挑選所有程式碼片段 | | | `` `` | 選擇上一段 | | | `` `` | 選擇下一段 | | -| `` `` | 選擇上一個衝突 | | -| `` `` | 選擇下一個衝突 | | +| `` , h `` | 選擇上一個衝突 | | +| `` , l `` | 選擇下一個衝突 | | | `` z `` | 復原 | Undo last merge conflict resolution. | | `` e `` | 編輯檔案 | 使用外部編輯器開啟 | | `` o `` | 開啟檔案 | 使用預設軟體開啟 | @@ -104,8 +104,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| -| `` `` | 選擇上一段 | | -| `` `` | 選擇下一段 | | +| `` , h `` | 選擇上一段 | | +| `` , l `` | 選擇下一段 | | | `` v `` | 切換拖曳選擇 | | | `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. | | `` `` | 複製所選文本至剪貼簿 | | diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index a5525804d..6956d4366 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -607,6 +607,8 @@ type KeybindingCommitFilesConfig struct { } type KeybindingMainConfig struct { + PrevHunk Keybinding `yaml:"prevHunk"` + NextHunk Keybinding `yaml:"nextHunk"` ToggleSelectHunk Keybinding `yaml:"toggleSelectHunk"` PickBothHunks Keybinding `yaml:"pickBothHunks"` EditSelectHunk Keybinding `yaml:"editSelectHunk"` @@ -1088,6 +1090,8 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig { CheckoutCommitFile: Keybinding{"c"}, }, Main: KeybindingMainConfig{ + PrevHunk: Keybinding{"", "h"}, + NextHunk: Keybinding{"", "l"}, ToggleSelectHunk: Keybinding{"a"}, PickBothHunks: Keybinding{"b"}, EditSelectHunk: Keybinding{"E"}, diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index a539e710f..322d1cd39 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -52,13 +52,13 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) DisplayOnScreen: true, }, { - Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), + Keys: opts.GetKeys(opts.Config.Main.PrevHunk), Handler: self.withRenderAndFocus(self.PrevConflict), Description: self.c.Tr.PrevConflict, DisplayOnScreen: true, }, { - Keys: opts.GetKeys(opts.Config.Universal.NextBlock), + Keys: opts.GetKeys(opts.Config.Main.NextHunk), Handler: self.withRenderAndFocus(self.NextConflict), Description: self.c.Tr.NextConflict, DisplayOnScreen: true, @@ -83,14 +83,6 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, - { - Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), - Handler: self.withRenderAndFocus(self.PrevConflict), - }, - { - Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), - Handler: self.withRenderAndFocus(self.NextConflict), - }, { Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.withRenderAndFocus(self.PrevConflictHunk), diff --git a/pkg/gui/controllers/patch_explorer_controller.go b/pkg/gui/controllers/patch_explorer_controller.go index 14bce304e..6f7e766af 100644 --- a/pkg/gui/controllers/patch_explorer_controller.go +++ b/pkg/gui/controllers/patch_explorer_controller.go @@ -72,23 +72,15 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) Description: self.c.Tr.RangeSelectDown, }, { - Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), + Keys: opts.GetKeys(opts.Config.Main.PrevHunk), Handler: self.withRenderAndFocus(self.HandlePrevHunk), Description: self.c.Tr.PrevHunk, }, { - Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), - Handler: self.withRenderAndFocus(self.HandlePrevHunk), - }, - { - Keys: opts.GetKeys(opts.Config.Universal.NextBlock), + Keys: opts.GetKeys(opts.Config.Main.NextHunk), Handler: self.withRenderAndFocus(self.HandleNextHunk), Description: self.c.Tr.NextHunk, }, - { - Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), - Handler: self.withRenderAndFocus(self.HandleNextHunk), - }, { Keys: opts.GetKeys(opts.Config.Universal.ToggleRangeSelect), Handler: self.withRenderAndFocus(self.HandleToggleSelectRange), diff --git a/schema-master/config.json b/schema-master/config.json index a33e20f2d..b879ba5c5 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -1921,6 +1921,40 @@ }, "KeybindingMainConfig": { "properties": { + "prevHunk": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "default": [ + "\u003cleft\u003e", + "h" + ] + }, + "nextHunk": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "default": [ + "\u003cright\u003e", + "l" + ] + }, "toggleSelectHunk": { "oneOf": [ { From 3a3625d85580789fac3b770f6883e0f8035c6247 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 10 May 2026 09:09:57 +0200 Subject: [PATCH 16/17] Fold remaining alt bindings into their main fields Convert the remaining *Alt/*Alt[12] sibling fields (PrevItem/NextItem, GotoTop/GotoBottom, PrevBlock/NextBlock, ScrollUpMain/ScrollDownMain, OptionMenu, ConfirmInEditor, DiffingMenu) so the merge mechanism folds their values into the corresponding main multi-key binding at config load. The redundant alt-only Binding registrations across the various controllers and the global keybindings file are gone: the merged main field already carries every key, so the for-loop in SetKeybinding registers them all. --- docs-master/Config.md | 34 +--- docs-master/keybindings/Keybindings_en.md | 15 +- docs-master/keybindings/Keybindings_ja.md | 15 +- docs-master/keybindings/Keybindings_ko.md | 15 +- docs-master/keybindings/Keybindings_nl.md | 15 +- docs-master/keybindings/Keybindings_pl.md | 15 +- docs-master/keybindings/Keybindings_pt.md | 15 +- docs-master/keybindings/Keybindings_ru.md | 15 +- docs-master/keybindings/Keybindings_zh-CN.md | 15 +- docs-master/keybindings/Keybindings_zh-TW.md | 15 +- pkg/config/user_config.go | 186 ++++++++++-------- pkg/gui/command_log_panel.go | 5 +- .../commit_description_controller.go | 30 +-- pkg/gui/controllers/global_controller.go | 7 - pkg/gui/controllers/list_controller.go | 8 +- .../controllers/merge_conflicts_controller.go | 8 - .../controllers/patch_explorer_controller.go | 20 -- pkg/gui/controllers/side_window_controller.go | 4 - .../controllers/view_selection_controller.go | 8 +- pkg/gui/keybindings.go | 62 ------ pkg/gui/menu_panel.go | 4 + pkg/i18n/english.go | 2 - schema-master/config.json | 68 ++++++- 23 files changed, 254 insertions(+), 327 deletions(-) diff --git a/docs-master/Config.md b/docs-master/Config.md index 90ddde045..882baec63 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -602,27 +602,19 @@ keybinding: return: quitWithoutChangingDirectory: Q togglePanel: - prevItem: - nextItem: - prevItem-alt: k - nextItem-alt: j + prevItem: [, k] + nextItem: [, j] prevPage: ',' nextPage: . scrollLeft: H scrollRight: L - gotoTop: < - gotoBottom: '>' - gotoTop-alt: - gotoBottom-alt: + gotoTop: [<, ] + gotoBottom: ['>', ] toggleRangeSelect: v rangeSelectDown: rangeSelectUp: - prevBlock: - nextBlock: - prevBlock-alt: h - nextBlock-alt: l - nextBlock-alt2: - prevBlock-alt2: + prevBlock: [, h, ] + nextBlock: [, l, ] jumpToBlock: - "1" - "2" @@ -653,18 +645,13 @@ keybinding: confirmSuggestion: # on Mac - confirmInEditor: - confirmInEditor-alt: + confirmInEditor: [, ] remove: d new: "n" edit: e openFile: o - scrollUpMain: - scrollDownMain: - scrollUpMain-alt1: K - scrollDownMain-alt1: J - scrollUpMain-alt2: - scrollDownMain-alt2: + scrollUpMain: [, K, ] + scrollDownMain: [, J, ] executeShellCommand: ':' createRebaseOptionsMenu: m @@ -683,8 +670,7 @@ keybinding: undo: z redo: Z filteringMenu: - diffingMenu: W - diffingMenu-alt: + diffingMenu: [W, ] copyToClipboard: openRecentRepos: submitEditorText: diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index fafa7312d..71ecdae5b 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Switch to a recent repo | | -| `` (fn+up/shift+k) `` | Scroll up main window | | -| `` (fn+down/shift+j) `` | Scroll down main window | | +| `` , K, (fn+up/shift+k) `` | Scroll up main window | | +| `` , J, (fn+down/shift+j) `` | Scroll down main window | | | `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Cancel | | | `` ? `` | Open keybindings menu | | | `` `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | Quit | | | `` `` | Suspend the application | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | Previous page | | | `` . `` | Next page | | -| `` < () `` | Scroll to top | | -| `` > () `` | Scroll to bottom | | +| `` <, `` | Scroll to top | | +| `` >, `` | Scroll to bottom | | | `` v `` | Toggle range select | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -205,8 +204,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Pick hunk | | | `` b `` | Pick all hunks | | -| `` `` | Previous hunk | | -| `` `` | Next hunk | | +| `` , k `` | Previous hunk | | +| `` , j `` | Next hunk | | | `` , h `` | Previous conflict | | | `` , l `` | Next conflict | | | `` z `` | Undo | Undo last merge conflict resolution. | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index 4b5bfc9f3..5a958f80e 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 最近のリポジトリをチェックアウト | | -| `` (fn+up/shift+k) `` | メインウィンドウを上にスクロール | | -| `` (fn+down/shift+j) `` | メインウィンドウを下にスクロール | | +| `` , K, (fn+up/shift+k) `` | メインウィンドウを上にスクロール | | +| `` , J, (fn+down/shift+j) `` | メインウィンドウを下にスクロール | | | `` @ `` | コマンドログオプションを表示 | コマンドログのオプションを表示します(例:コマンドログの表示/非表示、コマンドログへのフォーカスなど)。 | | `` P `` | プッシュ | 現在のブランチを対応するアップストリームブランチにプッシュします。アップストリームが設定されていない場合、アップストリームブランチの設定を求められます。 | | `` p `` | プル | 現在のブランチのリモートから変更をプルします。アップストリームが設定されていない場合、アップストリームブランチの設定を求められます。 | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | キャンセル | | | `` ? `` | キーバインディングメニューを開く | | | `` `` | フィルターオプションを表示 | コミットログのフィルタリングオプションを表示し、フィルタに一致するコミットのみを表示します。 | -| `` W `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 | -| `` `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 | +| `` W, `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 | | `` q, `` | 終了 | | | `` `` | Suspend the application | | | `` `` | 空白表示の切り替え | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | 前のページ | | | `` . `` | 次のページ | | -| `` < () `` | 先頭にスクロール | | -| `` > () `` | 末尾にスクロール | | +| `` <, `` | 先頭にスクロール | | +| `` >, `` | 末尾にスクロール | | | `` v `` | 範囲選択を切り替え | | | `` `` | 範囲選択を下に | | | `` `` | 範囲選択を上に | | @@ -288,8 +287,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | ハンクを選択 | | | `` b `` | すべてのハンクを選択 | | -| `` `` | 前のハンク | | -| `` `` | 次のハンク | | +| `` , k `` | 前のハンク | | +| `` , j `` | 次のハンク | | | `` , h `` | 前のコンフリクト | | | `` , l `` | 次のコンフリクト | | | `` z `` | 元に戻す | 最後のマージコンフリクト解決を元に戻します。 | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index 157984a9c..d6121452b 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 최근에 사용한 저장소로 전환 | | -| `` (fn+up/shift+k) `` | 메인 패널을 위로 스크롤 | | -| `` (fn+down/shift+j) `` | 메인 패널을 아래로로 스크롤 | | +| `` , K, (fn+up/shift+k) `` | 메인 패널을 위로 스크롤 | | +| `` , J, (fn+down/shift+j) `` | 메인 패널을 아래로로 스크롤 | | | `` @ `` | 명령어 로그 메뉴 열기 | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | 푸시 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` p `` | 업데이트 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | 취소 | | | `` ? `` | 매뉴 열기 | | | `` `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | 종료 | | | `` `` | Suspend the application | | | `` `` | 공백문자를 Diff 뷰에서 표시 여부 전환 | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | 이전 페이지 | | | `` . `` | 다음 페이지 | | -| `` < () `` | 맨 위로 스크롤 | | -| `` > () `` | 맨 아래로 스크롤 | | +| `` <, `` | 맨 위로 스크롤 | | +| `` >, `` | 맨 아래로 스크롤 | | | `` v `` | 드래그 선택 전환 | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -144,8 +143,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Pick hunk | | | `` b `` | Pick all hunks | | -| `` `` | 이전 hunk를 선택 | | -| `` `` | 다음 hunk를 선택 | | +| `` , k `` | 이전 hunk를 선택 | | +| `` , j `` | 다음 hunk를 선택 | | | `` , h `` | 이전 충돌을 선택 | | | `` , l `` | 다음 충돌을 선택 | | | `` z `` | 되돌리기 | Undo last merge conflict resolution. | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index ca3449cf9..23a08aae4 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Wissel naar een recente repo | | -| `` (fn+up/shift+k) `` | Scroll naar beneden vanaf hoofdpaneel | | -| `` (fn+down/shift+j) `` | Scroll naar beneden vanaf hoofdpaneel | | +| `` , K, (fn+up/shift+k) `` | Scroll naar beneden vanaf hoofdpaneel | | +| `` , J, (fn+down/shift+j) `` | Scroll naar beneden vanaf hoofdpaneel | | | `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Annuleren | | | `` ? `` | Open menu | | | `` `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | Quit | | | `` `` | Suspend the application | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | Vorige pagina | | | `` . `` | Volgende pagina | | -| `` < () `` | Scroll naar boven | | -| `` > () `` | Scroll naar beneden | | +| `` <, `` | Scroll naar boven | | +| `` >, `` | Scroll naar beneden | | | `` v `` | Toggle drag selecteer | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -213,8 +212,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Kies stuk | | | `` b `` | Kies beide stukken | | -| `` `` | Selecteer bovenste hunk | | -| `` `` | Selecteer onderste hunk | | +| `` , k `` | Selecteer bovenste hunk | | +| `` , j `` | Selecteer onderste hunk | | | `` , h `` | Selecteer voorgaand conflict | | | `` , l `` | Selecteer volgende conflict | | | `` z `` | Ongedaan maken | Undo last merge conflict resolution. | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index 69e60b78d..b233fd6d4 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Przełącz na ostatnie repozytorium | | -| `` (fn+up/shift+k) `` | Przewiń główne okno w górę | | -| `` (fn+down/shift+j) `` | Przewiń główne okno w dół | | +| `` , K, (fn+up/shift+k) `` | Przewiń główne okno w górę | | +| `` , J, (fn+down/shift+j) `` | Przewiń główne okno w dół | | | `` @ `` | Pokaż opcje dziennika poleceń | Pokaż opcje dla dziennika poleceń, np. pokazywanie/ukrywanie dziennika poleceń i skupienie na dzienniku poleceń. | | `` P `` | Wypchnij | Wypchnij bieżącą gałąź do jej gałęzi nadrzędnej. Jeśli nie skonfigurowano gałęzi nadrzędnej, zostaniesz poproszony o skonfigurowanie gałęzi nadrzędnej. | | `` p `` | Pociągnij | Pociągnij zmiany z zdalnego dla bieżącej gałęzi. Jeśli nie skonfigurowano gałęzi nadrzędnej, zostaniesz poproszony o skonfigurowanie gałęzi nadrzędnej. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Anuluj | | | `` ? `` | Otwórz menu przypisań klawiszy | | | `` `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. | -| `` W `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. | -| `` `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. | +| `` W, `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. | | `` q, `` | Wyjdź | | | `` `` | Suspend the application | | | `` `` | Przełącz białe znaki | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | Poprzednia strona | | | `` . `` | Następna strona | | -| `` < () `` | Przewiń do góry | | -| `` > () `` | Przewiń do dołu | | +| `` <, `` | Przewiń do góry | | +| `` >, `` | Przewiń do dołu | | | `` v `` | Przełącz zaznaczenie zakresu | | | `` `` | Zaznacz zakres w dół | | | `` `` | Zaznacz zakres w górę | | @@ -189,8 +188,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Wybierz fragment | | | `` b `` | Wybierz wszystkie fragmenty | | -| `` `` | Poprzedni fragment | | -| `` `` | Następny fragment | | +| `` , k `` | Poprzedni fragment | | +| `` , j `` | Następny fragment | | | `` , h `` | Poprzedni konflikt | | | `` , l `` | Następny konflikt | | | `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 0152530f0..22d5cbb55 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Mudar para um repositório recente | | -| `` (fn+up/shift+k) `` | Rolar janela principal para cima | | -| `` (fn+down/shift+j) `` | Rolar a janela principal para baixo | | +| `` , K, (fn+up/shift+k) `` | Rolar janela principal para cima | | +| `` , J, (fn+down/shift+j) `` | Rolar a janela principal para baixo | | | `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | Empurre (Push) | Faça push do branch atual para o seu branch upstream. Se nenhum upstream estiver configurado, você será solicitado a configurar um branch a montante. | | `` p `` | Puxar (Pull) | Puxe alterações do controle remoto para o ramo atual. Se nenhum upstream estiver configurado, será solicitado configurar um ramo a montante. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Cancelar | | | `` ? `` | Abrir o menu de atalhos do teclado | | | `` `` | Ver opções de filtro | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | Sair | | | `` `` | Suspender a aplicação | | | `` `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | Aba anterior | | | `` . `` | Próxima aba | | -| `` < () `` | Voltar ao topo | | -| `` > () `` | Ir para o final | | +| `` <, `` | Voltar ao topo | | +| `` >, `` | Ir para o final | | | `` v `` | Toggle range select | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -273,8 +272,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Escolha o local | | | `` b `` | Pegar todos os pedaços | | -| `` `` | Trecho anterior | | -| `` `` | Próximo trecho | | +| `` , k `` | Trecho anterior | | +| `` , j `` | Próximo trecho | | | `` , h `` | Conflito anterior | | | `` , l `` | Próximo conflito | | | `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index 697912e5a..3b81d2433 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Переключиться на последний репозиторий | | -| `` (fn+up/shift+k) `` | Прокрутить вверх главную панель | | -| `` (fn+down/shift+j) `` | Прокрутить вниз главную панель | | +| `` , K, (fn+up/shift+k) `` | Прокрутить вверх главную панель | | +| `` , J, (fn+down/shift+j) `` | Прокрутить вниз главную панель | | | `` @ `` | Открыть меню журнала команд | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | Отправить изменения | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` p `` | Получить и слить изменения | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | Отменить | | | `` ? `` | Открыть меню | | | `` `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | Выйти | | | `` `` | Suspend the application | | | `` `` | Переключить отображение изменении пробелов в просмотрщике сравнении | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | Предыдущая страница | | | `` . `` | Следующая страница | | -| `` < () `` | Пролистать наверх | | -| `` > () `` | Прокрутить вниз | | +| `` <, `` | Пролистать наверх | | +| `` >, `` | Прокрутить вниз | | | `` v `` | Переключить выборку перетаскивания | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -114,8 +113,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | Выбрать эту часть | | | `` b `` | Выбрать все части | | -| `` `` | Выбрать предыдущую часть | | -| `` `` | Выбрать следующую часть | | +| `` , k `` | Выбрать предыдущую часть | | +| `` , j `` | Выбрать следующую часть | | | `` , h `` | Выбрать предыдущий конфликт | | | `` , l `` | Выбрать следующий конфликт | | | `` z `` | Отменить | Undo last merge conflict resolution. | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index fcd78596a..76e378695 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 切换到最近的仓库 | | -| `` (fn+up/shift+k) `` | 向上滚动主面板 | | -| `` (fn+down/shift+j) `` | 向下滚动主面板 | | +| `` , K, (fn+up/shift+k) `` | 向上滚动主面板 | | +| `` , J, (fn+down/shift+j) `` | 向下滚动主面板 | | | `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 | | `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,您可以在弹窗中配置上游分支。 | | `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游未配置,您可以在弹窗中配置上游分支。 | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | 取消 | | | `` ? `` | 打开菜单 | | | `` `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 | -| `` W `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 | -| `` `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 | +| `` W, `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 | | `` q, `` | 退出 | | | `` `` | 挂起应用程序 | | | `` `` | 切换是否在差异视图中显示空白字符差异 | 切换是否在差异视图中显示空白字符更改。

默认值可在配置文件中通过键 'git.ignoreWhitespaceInDiffView' 更改。 | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | 上一页 | | | `` . `` | 下一页 | | -| `` < () `` | 滚动到顶部 | | -| `` > () `` | 滚动到底部 | | +| `` <, `` | 滚动到顶部 | | +| `` >, `` | 滚动到底部 | | | `` v `` | 切换拖动选择 | | | `` `` | 向下扩展选择范围 | | | `` `` | 向上扩展选择范围 | | @@ -294,8 +293,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | 选中区块 | | | `` b `` | 选中所有区块 | | -| `` `` | 选择顶部块 | | -| `` `` | 选择底部块 | | +| `` , k `` | 选择顶部块 | | +| `` , j `` | 选择底部块 | | | `` , h `` | 选择上一个冲突 | | | `` , l `` | 选择下一个冲突 | | | `` z `` | 撤销 | 撤消上次合并冲突解决 | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index 2c2456e4a..6ebfa5c68 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -7,8 +7,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 切換到最近使用的版本庫 | | -| `` (fn+up/shift+k) `` | 向上捲動主面板 | | -| `` (fn+down/shift+j) `` | 向下捲動主面板 | | +| `` , K, (fn+up/shift+k) `` | 向上捲動主面板 | | +| `` , J, (fn+down/shift+j) `` | 向下捲動主面板 | | | `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. | | `` P `` | 推送 | 推送到遠端。如果沒有設定遠端,會開啟設定視窗。 | | `` p `` | 拉取 | 從遠端同步當前分支。如果沒有設定遠端,會開啟設定視窗。 | @@ -26,8 +26,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` `` | 取消 | | | `` ? `` | 開啟選單 | | | `` `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. | -| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | -| `` `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | +| `` W, `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. | | `` q, `` | 結束 | | | `` `` | Suspend the application | | | `` `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view.

The default can be changed in the config file with the key 'git.ignoreWhitespaceInDiffView'. | @@ -40,8 +39,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` , `` | 上一頁 | | | `` . `` | 下一頁 | | -| `` < () `` | 捲動到頂部 | | -| `` > () `` | 捲動到底部 | | +| `` <, `` | 捲動到頂部 | | +| `` >, `` | 捲動到底部 | | | `` v `` | 切換拖曳選擇 | | | `` `` | Range select down | | | `` `` | Range select up | | @@ -90,8 +89,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct |-----|--------|-------------| | `` `` | 挑選程式碼片段 | | | `` b `` | 挑選所有程式碼片段 | | -| `` `` | 選擇上一段 | | -| `` `` | 選擇下一段 | | +| `` , k `` | 選擇上一段 | | +| `` , j `` | 選擇下一段 | | | `` , h `` | 選擇上一個衝突 | | | `` , l `` | 選擇下一個衝突 | | | `` z `` | 復原 | Undo last merge conflict resolution. | diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 6956d4366..0b2dcac0c 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -425,85 +425,99 @@ type KeybindingConfig struct { type KeybindingUniversalConfig struct { Quit Keybinding `yaml:"quit"` // Deprecated: add the key to `quit` instead. - QuitAlt1 Keybinding `yaml:"quit-alt1"` - SuspendApp Keybinding `yaml:"suspendApp"` - Return Keybinding `yaml:"return"` - QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"` - TogglePanel Keybinding `yaml:"togglePanel"` - PrevItem Keybinding `yaml:"prevItem"` - NextItem Keybinding `yaml:"nextItem"` - PrevItemAlt Keybinding `yaml:"prevItem-alt"` - NextItemAlt Keybinding `yaml:"nextItem-alt"` - PrevPage Keybinding `yaml:"prevPage"` - NextPage Keybinding `yaml:"nextPage"` - ScrollLeft Keybinding `yaml:"scrollLeft"` - ScrollRight Keybinding `yaml:"scrollRight"` - GotoTop Keybinding `yaml:"gotoTop"` - GotoBottom Keybinding `yaml:"gotoBottom"` - GotoTopAlt Keybinding `yaml:"gotoTop-alt"` - GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"` - ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"` - RangeSelectDown Keybinding `yaml:"rangeSelectDown"` - RangeSelectUp Keybinding `yaml:"rangeSelectUp"` - PrevBlock Keybinding `yaml:"prevBlock"` - NextBlock Keybinding `yaml:"nextBlock"` - PrevBlockAlt Keybinding `yaml:"prevBlock-alt"` - NextBlockAlt Keybinding `yaml:"nextBlock-alt"` - NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"` - PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"` - JumpToBlock []Keybinding `yaml:"jumpToBlock"` - FocusMainView Keybinding `yaml:"focusMainView"` - NextMatch Keybinding `yaml:"nextMatch"` - PrevMatch Keybinding `yaml:"prevMatch"` - StartSearch Keybinding `yaml:"startSearch"` - MoveWordLeft Keybinding `yaml:"moveWordLeft"` // on Mac - MoveWordRight Keybinding `yaml:"moveWordRight"` // on Mac - BackspaceWord Keybinding `yaml:"backspaceWord"` // on Mac - ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // on Mac - OptionMenu Keybinding `yaml:"optionMenu"` - Select Keybinding `yaml:"select"` - GoInto Keybinding `yaml:"goInto"` - Confirm Keybinding `yaml:"confirm"` - ConfirmMenu Keybinding `yaml:"confirmMenu"` - ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"` - ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // on Mac - ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"` - Remove Keybinding `yaml:"remove"` - New Keybinding `yaml:"new"` - Edit Keybinding `yaml:"edit"` - OpenFile Keybinding `yaml:"openFile"` - ScrollUpMain Keybinding `yaml:"scrollUpMain"` - ScrollDownMain Keybinding `yaml:"scrollDownMain"` - ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"` - ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"` - ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"` - ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"` - ExecuteShellCommand Keybinding `yaml:"executeShellCommand"` - CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"` - Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons - Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons - Refresh Keybinding `yaml:"refresh"` - CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"` - NextTab Keybinding `yaml:"nextTab"` - PrevTab Keybinding `yaml:"prevTab"` - NextScreenMode Keybinding `yaml:"nextScreenMode"` - PrevScreenMode Keybinding `yaml:"prevScreenMode"` - CyclePagers Keybinding `yaml:"cyclePagers"` - Undo Keybinding `yaml:"undo"` - Redo Keybinding `yaml:"redo"` - FilteringMenu Keybinding `yaml:"filteringMenu"` - DiffingMenu Keybinding `yaml:"diffingMenu"` - DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"` - CopyToClipboard Keybinding `yaml:"copyToClipboard"` - OpenRecentRepos Keybinding `yaml:"openRecentRepos"` - SubmitEditorText Keybinding `yaml:"submitEditorText"` - ExtrasMenu Keybinding `yaml:"extrasMenu"` - ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"` - IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"` - DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"` - IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"` - DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"` - OpenDiffTool Keybinding `yaml:"openDiffTool"` + QuitAlt1 Keybinding `yaml:"quit-alt1"` + SuspendApp Keybinding `yaml:"suspendApp"` + Return Keybinding `yaml:"return"` + QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"` + TogglePanel Keybinding `yaml:"togglePanel"` + PrevItem Keybinding `yaml:"prevItem"` + NextItem Keybinding `yaml:"nextItem"` + // Deprecated: add the key to `prevItem` instead. + PrevItemAlt Keybinding `yaml:"prevItem-alt"` + // Deprecated: add the key to `nextItem` instead. + NextItemAlt Keybinding `yaml:"nextItem-alt"` + PrevPage Keybinding `yaml:"prevPage"` + NextPage Keybinding `yaml:"nextPage"` + ScrollLeft Keybinding `yaml:"scrollLeft"` + ScrollRight Keybinding `yaml:"scrollRight"` + GotoTop Keybinding `yaml:"gotoTop"` + GotoBottom Keybinding `yaml:"gotoBottom"` + // Deprecated: add the key to `gotoTop` instead. + GotoTopAlt Keybinding `yaml:"gotoTop-alt"` + // Deprecated: add the key to `gotoBottom` instead. + GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"` + ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"` + RangeSelectDown Keybinding `yaml:"rangeSelectDown"` + RangeSelectUp Keybinding `yaml:"rangeSelectUp"` + PrevBlock Keybinding `yaml:"prevBlock"` + NextBlock Keybinding `yaml:"nextBlock"` + // Deprecated: add the key to `prevBlock` instead. + PrevBlockAlt Keybinding `yaml:"prevBlock-alt"` + // Deprecated: add the key to `nextBlock` instead. + NextBlockAlt Keybinding `yaml:"nextBlock-alt"` + // Deprecated: add the key to `nextBlock` instead. + NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"` + // Deprecated: add the key to `prevBlock` instead. + PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"` + JumpToBlock []Keybinding `yaml:"jumpToBlock"` + FocusMainView Keybinding `yaml:"focusMainView"` + NextMatch Keybinding `yaml:"nextMatch"` + PrevMatch Keybinding `yaml:"prevMatch"` + StartSearch Keybinding `yaml:"startSearch"` + MoveWordLeft Keybinding `yaml:"moveWordLeft"` // on Mac + MoveWordRight Keybinding `yaml:"moveWordRight"` // on Mac + BackspaceWord Keybinding `yaml:"backspaceWord"` // on Mac + ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // on Mac + OptionMenu Keybinding `yaml:"optionMenu"` + Select Keybinding `yaml:"select"` + GoInto Keybinding `yaml:"goInto"` + Confirm Keybinding `yaml:"confirm"` + ConfirmMenu Keybinding `yaml:"confirmMenu"` + ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"` + ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // on Mac + // Deprecated: add the key to `confirmInEditor` instead. + ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"` + Remove Keybinding `yaml:"remove"` + New Keybinding `yaml:"new"` + Edit Keybinding `yaml:"edit"` + OpenFile Keybinding `yaml:"openFile"` + ScrollUpMain Keybinding `yaml:"scrollUpMain"` + ScrollDownMain Keybinding `yaml:"scrollDownMain"` + // Deprecated: add the key to `scrollUpMain` instead. + ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"` + // Deprecated: add the key to `scrollDownMain` instead. + ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"` + // Deprecated: add the key to `scrollUpMain` instead. + ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"` + // Deprecated: add the key to `scrollDownMain` instead. + ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"` + ExecuteShellCommand Keybinding `yaml:"executeShellCommand"` + CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"` + Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons + Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons + Refresh Keybinding `yaml:"refresh"` + CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"` + NextTab Keybinding `yaml:"nextTab"` + PrevTab Keybinding `yaml:"prevTab"` + NextScreenMode Keybinding `yaml:"nextScreenMode"` + PrevScreenMode Keybinding `yaml:"prevScreenMode"` + CyclePagers Keybinding `yaml:"cyclePagers"` + Undo Keybinding `yaml:"undo"` + Redo Keybinding `yaml:"redo"` + FilteringMenu Keybinding `yaml:"filteringMenu"` + DiffingMenu Keybinding `yaml:"diffingMenu"` + // Deprecated: add the key to `diffingMenu` instead. + DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"` + CopyToClipboard Keybinding `yaml:"copyToClipboard"` + OpenRecentRepos Keybinding `yaml:"openRecentRepos"` + SubmitEditorText Keybinding `yaml:"submitEditorText"` + ExtrasMenu Keybinding `yaml:"extrasMenu"` + ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"` + IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"` + DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"` + IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"` + DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"` + OpenDiffTool Keybinding `yaml:"openDiffTool"` } type KeybindingStatusConfig struct { @@ -778,6 +792,20 @@ type IconProperties struct { // release. func (c *KeybindingConfig) MergeLegacyAltKeybindings() { mergeLegacyAlt(&c.Universal.Quit, c.Universal.QuitAlt1) + mergeLegacyAlt(&c.Universal.PrevItem, c.Universal.PrevItemAlt) + mergeLegacyAlt(&c.Universal.NextItem, c.Universal.NextItemAlt) + mergeLegacyAlt(&c.Universal.GotoTop, c.Universal.GotoTopAlt) + mergeLegacyAlt(&c.Universal.GotoBottom, c.Universal.GotoBottomAlt) + mergeLegacyAlt(&c.Universal.PrevBlock, c.Universal.PrevBlockAlt) + mergeLegacyAlt(&c.Universal.NextBlock, c.Universal.NextBlockAlt) + mergeLegacyAlt(&c.Universal.PrevBlock, c.Universal.PrevBlockAlt2) + mergeLegacyAlt(&c.Universal.NextBlock, c.Universal.NextBlockAlt2) + mergeLegacyAlt(&c.Universal.ConfirmInEditor, c.Universal.ConfirmInEditorAlt) + mergeLegacyAlt(&c.Universal.ScrollUpMain, c.Universal.ScrollUpMainAlt1) + mergeLegacyAlt(&c.Universal.ScrollUpMain, c.Universal.ScrollUpMainAlt2) + mergeLegacyAlt(&c.Universal.ScrollDownMain, c.Universal.ScrollDownMainAlt1) + mergeLegacyAlt(&c.Universal.ScrollDownMain, c.Universal.ScrollDownMainAlt2) + mergeLegacyAlt(&c.Universal.DiffingMenu, c.Universal.DiffingMenuAlt) } func GetDefaultConfig() *UserConfig { diff --git a/pkg/gui/command_log_panel.go b/pkg/gui/command_log_panel.go index 3381f371a..8f2e06b98 100644 --- a/pkg/gui/command_log_panel.go +++ b/pkg/gui/command_log_panel.go @@ -136,9 +136,8 @@ func (gui *Gui) getRandomTip() string { config.Universal.NextPage, ), fmt.Sprintf( - "You can jump to the top/bottom of a panel using '%s (or %s)' and '%s (or %s)'", - config.Universal.GotoTop, config.Universal.GotoTopAlt, - config.Universal.GotoBottom, config.Universal.GotoBottomAlt, + "You can jump to the top/bottom of a panel using '%s' and '%s'", + config.Universal.GotoTop, config.Universal.GotoBottom, ), fmt.Sprintf( "To collapse/expand a directory, press '%s'", diff --git a/pkg/gui/controllers/commit_description_controller.go b/pkg/gui/controllers/commit_description_controller.go index 755fddb56..41ec54103 100644 --- a/pkg/gui/controllers/commit_description_controller.go +++ b/pkg/gui/controllers/commit_description_controller.go @@ -37,10 +37,6 @@ func (self *CommitDescriptionController) GetKeybindings(opts types.KeybindingsOp Keys: opts.GetKeys(opts.Config.Universal.ConfirmInEditor), Handler: self.confirm, }, - { - Keys: opts.GetKeys(opts.Config.Universal.ConfirmInEditorAlt), - Handler: self.confirm, - }, { Keys: opts.GetKeys(opts.Config.CommitMessage.CommitMenu), Handler: self.openCommitMenu, @@ -68,26 +64,12 @@ func (self *CommitDescriptionController) GetMouseKeybindings(opts types.Keybindi func (self *CommitDescriptionController) GetOnFocus() func(types.OnFocusOpts) { return func(types.OnFocusOpts) { footer := "" - mainDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor) > 0 - altDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt) > 0 - if !mainDisabled || !altDisabled { - if mainDisabled { - footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter, - map[string]string{ - "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(), - }) - } else if altDisabled { - footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter, - map[string]string{ - "confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(), - }) - } else { - footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooterTwoBindings, - map[string]string{ - "confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(), - "confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(), - }) - } + keys := self.c.UserConfig().Keybinding.Universal.ConfirmInEditor + if len(keys) > 0 { + footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter, + map[string]string{ + "confirmInEditorKeybinding": keys.String(), + }) } self.c.Views().CommitDescription.Footer = footer } diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index 8e5013a55..1043ee88f 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -99,13 +99,6 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type Tooltip: self.c.Tr.ViewDiffingOptionsTooltip, OpensMenu: true, }, - { - Keys: opts.GetKeys(opts.Config.Universal.DiffingMenuAlt), - Handler: opts.Guards.NoPopupPanel(self.createDiffingMenu), - Description: self.c.Tr.ViewDiffingOptions, - Tooltip: self.c.Tr.ViewDiffingOptionsTooltip, - OpensMenu: true, - }, { Keys: opts.GetKeys(opts.Config.Universal.Quit), Description: self.c.Tr.Quit, diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index 854e14ffa..b2d45679b 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -271,16 +271,12 @@ func (self *ListController) isFocused() bool { func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.HandlePrevLine}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.HandlePrevLine}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.HandleNextLine}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.HandleNextLine}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: self.HandlePrevPage, Description: self.c.Tr.PrevPage}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.HandleNextPage, Description: self.c.Tr.NextPage}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: self.HandleGotoTop}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: self.HandleGotoBottom}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight}, } diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index 322d1cd39..e1e3f8e2c 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -83,14 +83,6 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) Description: self.c.Tr.OpenFile, Tooltip: self.c.Tr.OpenFileTooltip, }, - { - Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), - Handler: self.withRenderAndFocus(self.PrevConflictHunk), - }, - { - Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), - Handler: self.withRenderAndFocus(self.NextConflictHunk), - }, { Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.withRenderAndFocus(self.HandleScrollLeft), diff --git a/pkg/gui/controllers/patch_explorer_controller.go b/pkg/gui/controllers/patch_explorer_controller.go index 6f7e766af..aa5fd54bb 100644 --- a/pkg/gui/controllers/patch_explorer_controller.go +++ b/pkg/gui/controllers/patch_explorer_controller.go @@ -39,21 +39,11 @@ func (self *PatchExplorerController) Context() types.Context { func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - { - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), - Handler: self.withRenderAndFocus(self.HandlePrevLine), - }, { Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.withRenderAndFocus(self.HandlePrevLine), }, - { - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), - Handler: self.withRenderAndFocus(self.HandleNextLine), - }, { Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItem), @@ -123,16 +113,6 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) Description: self.c.Tr.GotoBottom, Handler: self.withRenderAndFocus(self.HandleGotoBottom), }, - { - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), - Handler: self.withRenderAndFocus(self.HandleGotoTop), - }, - { - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), - Handler: self.withRenderAndFocus(self.HandleGotoBottom), - }, { Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), diff --git a/pkg/gui/controllers/side_window_controller.go b/pkg/gui/controllers/side_window_controller.go index f09a5bbdb..67fc9f946 100644 --- a/pkg/gui/controllers/side_window_controller.go +++ b/pkg/gui/controllers/side_window_controller.go @@ -37,10 +37,6 @@ func (self *SideWindowController) GetKeybindings(opts types.KeybindingsOpts) []* return []*types.Binding{ {Keys: opts.GetKeys(opts.Config.Universal.PrevBlock), Handler: self.previousSideWindow}, {Keys: opts.GetKeys(opts.Config.Universal.NextBlock), Handler: self.nextSideWindow}, - {Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt), Handler: self.previousSideWindow}, - {Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt), Handler: self.nextSideWindow}, - {Keys: opts.GetKeys(opts.Config.Universal.PrevBlockAlt2), Handler: self.previousSideWindow}, - {Keys: opts.GetKeys(opts.Config.Universal.NextBlockAlt2), Handler: self.nextSideWindow}, } } diff --git a/pkg/gui/controllers/view_selection_controller.go b/pkg/gui/controllers/view_selection_controller.go index 710fd37cb..31cbd3695 100644 --- a/pkg/gui/controllers/view_selection_controller.go +++ b/pkg/gui/controllers/view_selection_controller.go @@ -37,15 +37,11 @@ func (self *ViewSelectionController) Context() types.Context { func (self *ViewSelectionController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItem), Handler: self.handlePrevLine}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), Handler: self.handlePrevLine}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: self.handleNextLine}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), Handler: self.handleNextLine}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.PrevPage), Handler: self.handlePrevPage, Description: self.c.Tr.PrevPage}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop, Alternative: ""}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: ""}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), Handler: self.handleGotoTop}, - {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), Handler: self.handleGotoBottom}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom}, } } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 7bab622b7..22d76f01b 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -99,26 +99,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Alternative: "fn+down/shift+j", Description: gui.c.Tr.ScrollDownMainWindow, }, - { - ViewName: "", - Keys: opts.GetKeys(opts.Config.Universal.ScrollUpMainAlt1), - Handler: gui.scrollUpMain, - }, - { - ViewName: "", - Keys: opts.GetKeys(opts.Config.Universal.ScrollDownMainAlt1), - Handler: gui.scrollDownMain, - }, - { - ViewName: "", - Keys: opts.GetKeys(opts.Config.Universal.ScrollUpMainAlt2), - Handler: gui.scrollUpMain, - }, - { - ViewName: "", - Keys: opts.GetKeys(opts.Config.Universal.ScrollDownMainAlt2), - Handler: gui.scrollDownMain, - }, { ViewName: "files", Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), @@ -228,16 +208,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: gui.scrollDownConfirmationPanel, }, - { - ViewName: "confirmation", - Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), - Handler: gui.scrollUpConfirmationPanel, - }, - { - ViewName: "confirmation", - Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), - Handler: gui.scrollDownConfirmationPanel, - }, { ViewName: "confirmation", Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelUp)}, @@ -263,21 +233,11 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: gui.goToConfirmationPanelTop, }, - { - ViewName: "confirmation", - Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), - Handler: gui.goToConfirmationPanelTop, - }, { ViewName: "confirmation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: gui.goToConfirmationPanelBottom, }, - { - ViewName: "confirmation", - Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), - Handler: gui.goToConfirmationPanelBottom, - }, { ViewName: "submodules", Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), @@ -295,12 +255,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Keys: []gocui.Key{gocui.NewKeyName(gocui.MouseWheelDown)}, Handler: gui.scrollDownExtra, }, - { - ViewName: "extras", - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.PrevItemAlt), - Handler: gui.scrollUpExtra, - }, { ViewName: "extras", Tag: "navigation", @@ -313,12 +267,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Keys: opts.GetKeys(opts.Config.Universal.NextItem), Handler: gui.scrollDownExtra, }, - { - ViewName: "extras", - Tag: "navigation", - Keys: opts.GetKeys(opts.Config.Universal.NextItemAlt), - Handler: gui.scrollDownExtra, - }, { ViewName: "extras", Keys: opts.GetKeys(opts.Config.Universal.NextPage), @@ -334,21 +282,11 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: gui.goToExtrasPanelTop, }, - { - ViewName: "extras", - Keys: opts.GetKeys(opts.Config.Universal.GotoTopAlt), - Handler: gui.goToExtrasPanelTop, - }, { ViewName: "extras", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: gui.goToExtrasPanelBottom, }, - { - ViewName: "extras", - Keys: opts.GetKeys(opts.Config.Universal.GotoBottomAlt), - Handler: gui.goToExtrasPanelBottom, - }, { ViewName: "extras", Tag: "navigation", diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 336f7601b..23016b9a5 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -27,6 +27,10 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error { maxColumnSize := 1 + // Only the primary key of each navigation binding is reserved as + // essential; alternates (e.g. the historical j/k that lived under + // `*Alt` fields) stay available to be reused by menu items, which + // take precedence over the inherited list bindings. essentialKeys := []gocui.Key{ config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu)[0], config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.Return)[0], diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index ea8e42da4..769248375 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -337,7 +337,6 @@ type TranslationSet struct { CommitDescriptionTitle string CommitDescriptionSubTitle string CommitDescriptionFooter string - CommitDescriptionFooterTwoBindings string CommitHooksDisabledSubTitle string LocalBranchesTitle string SearchTitle string @@ -1456,7 +1455,6 @@ func EnglishTranslationSet() *TranslationSet { CommitDescriptionTitle: "Commit description", CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus, {{.commitMenuKeybinding}} to open menu", CommitDescriptionFooter: "Press {{.confirmInEditorKeybinding}} to submit", - CommitDescriptionFooterTwoBindings: "Press {{.confirmInEditorKeybinding1}} or {{.confirmInEditorKeybinding2}} to submit", CommitHooksDisabledSubTitle: "(hooks disabled)", LocalBranchesTitle: "Local branches", SearchTitle: "Search", diff --git a/schema-master/config.json b/schema-master/config.json index b879ba5c5..84fd2220e 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -2247,7 +2247,10 @@ "type": "array" } ], - "default": "\u003cup\u003e" + "default": [ + "\u003cup\u003e", + "k" + ] }, "nextItem": { "oneOf": [ @@ -2261,7 +2264,10 @@ "type": "array" } ], - "default": "\u003cdown\u003e" + "default": [ + "\u003cdown\u003e", + "j" + ] }, "prevItem-alt": { "oneOf": [ @@ -2275,6 +2281,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `prevItem` instead.", "default": "k" }, "nextItem-alt": { @@ -2289,6 +2296,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `nextItem` instead.", "default": "j" }, "prevPage": { @@ -2359,7 +2367,10 @@ "type": "array" } ], - "default": "\u003c" + "default": [ + "\u003c", + "\u003chome\u003e" + ] }, "gotoBottom": { "oneOf": [ @@ -2373,7 +2384,10 @@ "type": "array" } ], - "default": "\u003e" + "default": [ + "\u003e", + "\u003cend\u003e" + ] }, "gotoTop-alt": { "oneOf": [ @@ -2387,6 +2401,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `gotoTop` instead.", "default": "\u003chome\u003e" }, "gotoBottom-alt": { @@ -2401,6 +2416,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `gotoBottom` instead.", "default": "\u003cend\u003e" }, "toggleRangeSelect": { @@ -2457,7 +2473,11 @@ "type": "array" } ], - "default": "\u003cleft\u003e" + "default": [ + "\u003cleft\u003e", + "h", + "\u003cbacktab\u003e" + ] }, "nextBlock": { "oneOf": [ @@ -2471,7 +2491,11 @@ "type": "array" } ], - "default": "\u003cright\u003e" + "default": [ + "\u003cright\u003e", + "l", + "\u003ctab\u003e" + ] }, "prevBlock-alt": { "oneOf": [ @@ -2485,6 +2509,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `prevBlock` instead.", "default": "h" }, "nextBlock-alt": { @@ -2499,6 +2524,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `nextBlock` instead.", "default": "l" }, "nextBlock-alt2": { @@ -2513,6 +2539,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `nextBlock` instead.", "default": "\u003ctab\u003e" }, "prevBlock-alt2": { @@ -2527,6 +2554,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `prevBlock` instead.", "default": "\u003cbacktab\u003e" }, "jumpToBlock": { @@ -2765,7 +2793,10 @@ } ], "description": "\u003cmeta+enter\u003e on Mac", - "default": "\u003cctrl+enter\u003e" + "default": [ + "\u003cctrl+enter\u003e", + "\u003cctrl+s\u003e" + ] }, "confirmInEditor-alt": { "oneOf": [ @@ -2779,6 +2810,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `confirmInEditor` instead.", "default": "\u003cctrl+s\u003e" }, "remove": { @@ -2849,7 +2881,11 @@ "type": "array" } ], - "default": "\u003cpgup\u003e" + "default": [ + "\u003cpgup\u003e", + "K", + "\u003cctrl+u\u003e" + ] }, "scrollDownMain": { "oneOf": [ @@ -2863,7 +2899,11 @@ "type": "array" } ], - "default": "\u003cpgdown\u003e" + "default": [ + "\u003cpgdown\u003e", + "J", + "\u003cctrl+d\u003e" + ] }, "scrollUpMain-alt1": { "oneOf": [ @@ -2877,6 +2917,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `scrollUpMain` instead.", "default": "K" }, "scrollDownMain-alt1": { @@ -2891,6 +2932,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `scrollDownMain` instead.", "default": "J" }, "scrollUpMain-alt2": { @@ -2905,6 +2947,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `scrollUpMain` instead.", "default": "\u003cctrl+u\u003e" }, "scrollDownMain-alt2": { @@ -2919,6 +2962,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `scrollDownMain` instead.", "default": "\u003cctrl+d\u003e" }, "executeShellCommand": { @@ -3131,7 +3175,10 @@ "type": "array" } ], - "default": "W" + "default": [ + "W", + "\u003cctrl+e\u003e" + ] }, "diffingMenu-alt": { "oneOf": [ @@ -3145,6 +3192,7 @@ "type": "array" } ], + "description": "Deprecated: add the key to `diffingMenu` instead.", "default": "\u003cctrl+e\u003e" }, "copyToClipboard": { From d0d58233fffe9ff18621664b53a0e05ee604df9e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 17 May 2026 15:40:13 +0200 Subject: [PATCH 17/17] If a menu entry has multiple keybindings, list them in a tooltip We append them with a blank line to an existing tooltip if the item already has one, or create a new tooltip if not. --- pkg/gui/controllers/options_menu_action.go | 14 +++++++++++++- pkg/i18n/english.go | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/gui/controllers/options_menu_action.go b/pkg/gui/controllers/options_menu_action.go index e49c02386..c92fdd589 100644 --- a/pkg/gui/controllers/options_menu_action.go +++ b/pkg/gui/controllers/options_menu_action.go @@ -1,6 +1,10 @@ package controllers import ( + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" @@ -23,6 +27,14 @@ func (self *OptionsMenuAction) Call() error { if binding.GetDisabledReason != nil { disabledReason = binding.GetDisabledReason() } + tooltip := binding.Tooltip + if len(binding.Keys) > 1 { + if tooltip != "" { + tooltip += "\n\n" + } + keyLabels := lo.Map(binding.Keys, func(k gocui.Key, _ int) string { return config.LabelForKey(k) }) + tooltip += self.c.Tr.KeybindingsTooltip + strings.Join(keyLabels, ", ") + } return &types.MenuItem{ OpensMenu: binding.OpensMenu, Label: binding.GetDescription(), @@ -34,7 +46,7 @@ func (self *OptionsMenuAction) Call() error { return self.c.IGuiCommon.CallKeybindingHandler(binding) }, Keys: binding.Keys, - Tooltip: binding.Tooltip, + Tooltip: tooltip, DisabledReason: disabledReason, Section: section, } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 769248375..ee5f4ceec 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -616,6 +616,7 @@ type TranslationSet struct { KeybindingsMenuSectionLocal string KeybindingsMenuSectionGlobal string KeybindingsMenuSectionNavigation string + KeybindingsTooltip string RenameBranch string Upstream string BranchUpstreamOptionsTitle string @@ -1475,6 +1476,7 @@ func EnglishTranslationSet() *TranslationSet { KeybindingsMenuSectionLocal: "Local", KeybindingsMenuSectionGlobal: "Global", KeybindingsMenuSectionNavigation: "Navigation", + KeybindingsTooltip: "Keybindings: ", RebasingTitle: "Rebase '{{.checkedOutBranch}}'", RebasingFromBaseCommitTitle: "Rebase '{{.checkedOutBranch}}' from marked base", SimpleRebase: "Simple rebase onto '{{.ref}}'",