1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-14 11:23:09 +02:00
lazygit/pkg/gui/keybindings.go

409 lines
11 KiB
Go
Raw Normal View History

package gui
2018-08-08 11:18:41 +02:00
import (
2019-12-05 05:16:47 +02:00
"log"
2020-08-12 11:19:32 +02:00
2020-01-07 12:42:33 +02:00
"github.com/jesseduffield/gocui"
2022-02-13 01:39:14 +02:00
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
2022-01-28 11:44:36 +02:00
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
2018-08-08 11:18:41 +02:00
func (gui *Gui) noPopupPanel(f func() error) func() error {
return func() error {
2023-03-21 11:57:52 +02:00
if gui.helpers.Confirmation.IsPopupPanelFocused() {
return nil
}
return f()
}
}
func (gui *Gui) outsideFilterMode(f func() error) func() error {
return func() error {
if !gui.validateNotInFilterMode() {
return nil
}
return f()
}
}
2023-03-23 13:32:41 +02:00
func (gui *Gui) validateNotInFilterMode() bool {
if gui.State.Modes.Filtering.Active() {
_ = gui.c.Confirm(types.ConfirmOpts{
Title: gui.c.Tr.MustExitFilterModeTitle,
Prompt: gui.c.Tr.MustExitFilterModePrompt,
HandleConfirm: gui.helpers.Mode.ExitFilterMode,
})
return false
}
return true
}
2022-02-13 01:39:14 +02:00
// only to be called from the cheatsheet generate script. This mutates the Gui struct.
func (self *Gui) GetCheatsheetKeybindings() []*types.Binding {
self.g = &gocui.Gui{}
if err := self.createAllViews(); err != nil {
panic(err)
}
// need to instantiate views
2022-02-13 01:39:14 +02:00
self.helpers = helpers.NewStubHelpers()
self.State = &GuiRepoState{}
self.State.Contexts = self.contextTree()
self.State.ContextMgr = NewContextMgr(self, self.State.Contexts)
self.resetHelpersAndControllers()
2022-02-13 01:39:14 +02:00
bindings, _ := self.GetInitialKeybindings()
return bindings
}
2023-03-21 11:57:52 +02:00
func (self *Gui) keybindingOpts() types.KeybindingsOpts {
2022-02-06 06:54:26 +02:00
config := self.c.UserConfig.Keybinding
guards := types.KeybindingGuards{
2022-02-06 06:54:26 +02:00
OutsideFilterMode: self.outsideFilterMode,
NoPopupPanel: self.noPopupPanel,
}
2023-03-21 11:57:52 +02:00
return types.KeybindingsOpts{
GetKey: keybindings.GetKey,
2022-02-06 06:54:26 +02:00
Config: config,
Guards: guards,
}
2023-03-21 11:57:52 +02:00
}
// renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually.
func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) {
opts := self.c.KeybindingsOpts()
2020-10-03 06:54:55 +02:00
2022-01-28 11:44:36 +02:00
bindings := []*types.Binding{
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.OpenRecentRepos),
Handler: self.helpers.Repos.CreateRecentReposMenu,
2022-02-06 06:54:26 +02:00
Description: self.c.Tr.SwitchRepo,
},
2019-11-16 03:41:04 +02:00
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollUpMain),
Handler: self.scrollUpMain,
Alternative: "fn+up/shift+k",
Description: self.c.Tr.ScrollUpMainPanel,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollDownMain),
Handler: self.scrollDownMain,
Alternative: "fn+down/shift+j",
Description: self.c.Tr.ScrollDownMainPanel,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt1),
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpMain,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt1),
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownMain,
2019-11-16 03:41:04 +02:00
},
{
2018-09-01 12:10:03 +02:00
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt2),
2018-09-01 12:10:03 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpMain,
2019-11-16 03:41:04 +02:00
},
{
2018-09-01 12:10:03 +02:00
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt2),
2018-09-01 12:10:03 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownMain,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "files",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyFileNameToClipboard,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "localBranches",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyBranchNameToClipboard,
2023-02-07 14:10:55 +02:00
},
{
ViewName: "remoteBranches",
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyBranchNameToClipboard,
2020-04-15 12:30:24 +02:00
},
{
ViewName: "commits",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyCommitShaToClipboard,
2020-04-15 12:30:24 +02:00
},
{
ViewName: "commits",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Commits.ResetCherryPick),
Handler: self.helpers.CherryPick.Reset,
Description: self.c.Tr.ResetCherryPick,
2022-01-19 09:32:27 +02:00
},
{
ViewName: "reflogCommits",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyCommitShaToClipboard,
2020-09-19 12:55:52 +02:00
},
2020-08-22 00:49:02 +02:00
{
ViewName: "subCommits",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyCommitShaToClipboard,
},
2019-11-16 03:41:04 +02:00
{
ViewName: "information",
2019-02-25 13:11:35 +02:00
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.handleInfoClick,
2019-11-16 03:41:04 +02:00
},
{
ViewName: "commitFiles",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopyCommitFileNameToClipboard,
},
{
ViewName: "",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.ExtrasMenu),
Handler: self.handleCreateExtrasMenuPanel,
Description: self.c.Tr.OpenExtrasMenu,
OpensMenu: true,
},
2019-11-10 07:50:36 +02:00
{
ViewName: "secondary",
Key: gocui.MouseWheelUp,
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpSecondary,
2019-11-10 07:50:36 +02:00
},
{
ViewName: "secondary",
Key: gocui.MouseWheelDown,
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownSecondary,
2019-11-10 07:50:36 +02:00
},
2019-11-16 03:41:04 +02:00
{
ViewName: "main",
Key: gocui.MouseWheelDown,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownMain,
Description: self.c.Tr.ScrollDown,
2019-11-16 03:41:04 +02:00
Alternative: "fn+up",
},
{
ViewName: "main",
Key: gocui.MouseWheelUp,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpMain,
Description: self.c.Tr.ScrollUp,
2019-11-16 03:41:04 +02:00
Alternative: "fn+down",
},
{
ViewName: "secondary",
Key: gocui.MouseWheelUp,
Modifier: gocui.ModNone,
Handler: self.scrollUpSecondary,
2019-11-16 03:41:04 +02:00
},
2020-03-26 12:39:59 +02:00
{
ViewName: "confirmation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.PrevItem),
2020-03-26 12:39:59 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpConfirmationPanel,
2020-03-26 12:39:59 +02:00
},
{
ViewName: "confirmation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.NextItem),
2020-03-26 12:39:59 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownConfirmationPanel,
2020-03-26 12:39:59 +02:00
},
{
ViewName: "confirmation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.PrevItemAlt),
2020-03-26 12:39:59 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpConfirmationPanel,
2020-03-26 12:39:59 +02:00
},
{
ViewName: "confirmation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.NextItemAlt),
2020-03-26 12:39:59 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownConfirmationPanel,
2020-03-26 12:39:59 +02:00
},
2020-09-30 00:27:23 +02:00
{
ViewName: "submodules",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.CopySubmoduleNameToClipboard,
2020-09-30 00:27:23 +02:00
},
2021-04-11 03:43:07 +02:00
{
ViewName: "extras",
Key: gocui.MouseWheelUp,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpExtra,
2021-04-11 03:43:07 +02:00
},
{
ViewName: "extras",
Key: gocui.MouseWheelDown,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownExtra,
2021-04-11 03:43:07 +02:00
},
2021-04-11 07:01:49 +02:00
{
ViewName: "extras",
Tag: "navigation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.PrevItemAlt),
2021-04-11 07:01:49 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpExtra,
2021-04-11 07:01:49 +02:00
},
{
ViewName: "extras",
Tag: "navigation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.PrevItem),
2021-04-11 07:01:49 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollUpExtra,
2021-04-11 07:01:49 +02:00
},
{
ViewName: "extras",
Tag: "navigation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.NextItem),
2021-04-11 07:01:49 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownExtra,
2021-04-11 07:01:49 +02:00
},
{
ViewName: "extras",
Tag: "navigation",
2022-02-06 06:54:26 +02:00
Key: opts.GetKey(opts.Config.Universal.NextItemAlt),
2021-04-11 07:01:49 +02:00
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.scrollDownExtra,
2021-04-11 07:01:49 +02:00
},
{
ViewName: "extras",
Tag: "navigation",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
2022-02-06 06:54:26 +02:00
Handler: self.handleFocusCommandLog,
2021-04-11 07:01:49 +02:00
},
2018-08-08 11:18:41 +02:00
}
2022-02-05 05:42:56 +02:00
mouseKeybindings := []*gocui.ViewMouseBinding{}
2022-02-06 06:54:26 +02:00
for _, c := range self.State.Contexts.Flatten() {
2022-02-05 05:42:56 +02:00
viewName := c.GetViewName()
2022-02-06 06:54:26 +02:00
for _, binding := range c.GetKeybindings(opts) {
2022-02-05 05:42:56 +02:00
// TODO: move all mouse keybindings into the mouse keybindings approach below
binding.ViewName = viewName
bindings = append(bindings, binding)
}
2022-01-28 11:44:36 +02:00
2022-02-27 02:42:22 +02:00
mouseKeybindings = append(mouseKeybindings, c.GetMouseKeybindings(opts)...)
2022-01-28 11:44:36 +02:00
}
bindings = append(bindings, []*types.Binding{
{
ViewName: "",
Key: opts.GetKey(opts.Config.Universal.NextTab),
Handler: self.handleNextTab,
Description: self.c.Tr.NextTab,
Tag: "navigation",
},
{
ViewName: "",
Key: opts.GetKey(opts.Config.Universal.PrevTab),
Handler: self.handlePrevTab,
Description: self.c.Tr.PrevTab,
Tag: "navigation",
},
}...)
2020-10-01 23:32:48 +02:00
2022-02-05 05:42:56 +02:00
return bindings, mouseKeybindings
2018-08-28 20:07:13 +02:00
}
2023-03-23 13:21:42 +02:00
func (self *Gui) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, []*gocui.ViewMouseBinding) {
bindings, mouseBindings := self.GetInitialKeybindings()
customBindings, err := self.CustomCommandsClient.GetCustomCommandKeybindings()
if err != nil {
log.Fatal(err)
}
2023-03-23 13:21:42 +02:00
// prepending because we want to give our custom keybindings precedence over default keybindings
bindings = append(customBindings, bindings...)
2023-03-23 13:21:42 +02:00
return bindings, mouseBindings
}
func (gui *Gui) resetKeybindings() error {
gui.g.DeleteAllKeybindings()
bindings, mouseBindings := gui.GetInitialKeybindingsWithCustomCommands()
2018-08-28 20:07:13 +02:00
2018-08-08 11:18:41 +02:00
for _, binding := range bindings {
2022-01-29 10:09:20 +02:00
if err := gui.SetKeybinding(binding); err != nil {
2018-08-08 11:18:41 +02:00
return err
}
}
2019-11-13 14:18:31 +02:00
2022-02-05 05:42:56 +02:00
for _, binding := range mouseBindings {
if err := gui.SetMouseKeybinding(binding); err != nil {
return err
}
}
for _, values := range gui.viewTabMap() {
for _, value := range values {
viewName := value.ViewName
tabClickCallback := func(tabIndex int) error {
return gui.onViewTabClick(gui.helpers.Window.WindowForView(viewName), tabIndex)
}
2020-01-09 12:34:17 +02:00
if err := gui.g.SetTabClickBinding(viewName, tabClickCallback); err != nil {
return err
}
2020-01-09 12:34:17 +02:00
}
2019-11-13 14:18:31 +02:00
}
return nil
}
2022-01-29 10:09:20 +02:00
func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error {
return f()
}
}
func (gui *Gui) SetKeybinding(binding *types.Binding) error {
handler := binding.Handler
2022-02-05 05:42:56 +02:00
// TODO: move all mouse-ey stuff into new mouse approach
if gocui.IsMouseKey(binding.Key) {
2022-01-29 10:09:20 +02:00
handler = func() error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused
2023-03-21 11:57:52 +02:00
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName {
2022-01-29 10:09:20 +02:00
return nil
}
return binding.Handler()
}
}
return gui.g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, gui.wrappedHandler(handler))
2022-01-29 10:09:20 +02:00
}
2022-02-05 05:42:56 +02:00
// warning: mutates the binding
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
baseHandler := binding.Handler
newHandler := func(opts gocui.ViewMouseBindingOpts) error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused
2023-03-21 11:57:52 +02:00
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName {
2022-02-05 05:42:56 +02:00
return nil
}
return baseHandler(opts)
2022-01-30 11:34:59 +02:00
}
2022-02-05 05:42:56 +02:00
binding.Handler = newHandler
return gui.g.SetViewClickBinding(binding)
2022-01-29 10:09:20 +02:00
}