You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lazydocker/pkg/gui/keybindings.go

594 lines
15 KiB
Go

package gui
import (
"fmt"
"github.com/jesseduffield/gocui"
)
// Binding - a keybinding mapping a key and modifier to a handler. The keypress
// is only handled if the given view has focus, or handled globally if the view
// is ""
type Binding struct {
ViewName string
Handler func(*gocui.Gui, *gocui.View) error
Key interface{} // FIXME: find out how to get `gocui.Key | rune`
Modifier gocui.Modifier
Description string
}
// GetDisplayStrings returns the display string of a file
func (b *Binding) GetDisplayStrings(isFocused bool) []string {
return []string{b.GetKey(), b.Description}
}
// GetKey is a function.
func (b *Binding) GetKey() string {
key := 0
switch b.Key.(type) {
case rune:
key = int(b.Key.(rune))
case gocui.Key:
key = int(b.Key.(gocui.Key))
}
// special keys
switch key {
case 27:
return "esc"
case 13:
return "enter"
case 32:
return "space"
case 65514:
return "►"
case 65515:
return "◄"
case 65517:
return "▲"
case 65516:
return "▼"
case 65508:
return "PgUp"
case 65507:
return "PgDn"
}
return fmt.Sprintf("%c", key)
}
// GetInitialKeybindings is a function.
func (gui *Gui) GetInitialKeybindings() []*Binding {
bindings := []*Binding{
{
ViewName: "",
Key: 'q',
Modifier: gocui.ModNone,
Handler: gui.quit,
},
{
ViewName: "",
Key: gocui.KeyCtrlC,
Modifier: gocui.ModNone,
Handler: gui.quit,
},
{
ViewName: "",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
Handler: gui.quit,
},
{
ViewName: "",
Key: gocui.KeyPgup,
Modifier: gocui.ModNone,
Handler: gui.scrollUpMain,
},
{
ViewName: "",
Key: gocui.KeyPgdn,
Modifier: gocui.ModNone,
Handler: gui.scrollDownMain,
},
{
ViewName: "",
Key: gocui.KeyCtrlU,
Modifier: gocui.ModNone,
Handler: gui.scrollUpMain,
},
{
ViewName: "",
Key: gocui.KeyCtrlD,
Modifier: gocui.ModNone,
Handler: gui.scrollDownMain,
},
{
ViewName: "",
Key: gocui.KeyEnd,
Modifier: gocui.ModNone,
Handler: gui.autoScrollMain,
},
{
ViewName: "",
Key: 'x',
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
},
{
ViewName: "",
Key: '?',
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
},
{
ViewName: "",
Key: 'X',
Modifier: gocui.ModNone,
Handler: gui.handleCustomCommand,
},
{
ViewName: "project",
Key: 'e',
Modifier: gocui.ModNone,
Handler: gui.handleEditConfig,
Description: gui.Tr.EditConfig,
},
{
ViewName: "project",
Key: 'o',
Modifier: gocui.ModNone,
Handler: gui.handleOpenConfig,
Description: gui.Tr.OpenConfig,
},
{
ViewName: "project",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleProjectPrevContext,
Description: gui.Tr.PreviousContext,
},
{
ViewName: "project",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleProjectNextContext,
Description: gui.Tr.NextContext,
},
{
ViewName: "project",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleProjectClick,
},
{
ViewName: "project",
Key: 'm',
Modifier: gocui.ModNone,
Handler: gui.handleViewAllLogs,
Description: gui.Tr.ViewLogs,
},
{
ViewName: "project",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleProjectSelect,
},
{
ViewName: "menu",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
},
{
ViewName: "menu",
Key: 'q',
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
},
{
ViewName: "information",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleDonate,
},
{
ViewName: "containers",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleContainersPrevContext,
Description: gui.Tr.PreviousContext,
},
{
ViewName: "containers",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleContainersNextContext,
Description: gui.Tr.NextContext,
},
{
ViewName: "containers",
Key: 'd',
Modifier: gocui.ModNone,
Handler: gui.handleContainersRemoveMenu,
Description: gui.Tr.Remove,
},
{
ViewName: "containers",
Key: 'e',
Modifier: gocui.ModNone,
Handler: gui.handleHideStoppedContainers,
Description: gui.Tr.HideStopped,
},
{
ViewName: "containers",
Key: 'p',
Modifier: gocui.ModNone,
Handler: gui.handleContainerPause,
Description: gui.Tr.Pause,
},
{
ViewName: "containers",
Key: 's',
Modifier: gocui.ModNone,
Handler: gui.handleContainerStop,
Description: gui.Tr.Stop,
},
{
ViewName: "containers",
Key: 'r',
Modifier: gocui.ModNone,
Handler: gui.handleContainerRestart,
Description: gui.Tr.Restart,
},
{
ViewName: "containers",
Key: 'a',
Modifier: gocui.ModNone,
Handler: gui.handleContainerAttach,
Description: gui.Tr.Attach,
},
{
ViewName: "containers",
Key: 'm',
Modifier: gocui.ModNone,
Handler: gui.handleContainerViewLogs,
Description: gui.Tr.ViewLogs,
},
{
ViewName: "containers",
Key: 'E',
Modifier: gocui.ModNone,
Handler: gui.handleContainersExecShell,
Description: gui.Tr.ExecShell,
},
{
ViewName: "containers",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleContainersCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "containers",
Key: 'b',
Modifier: gocui.ModNone,
Handler: gui.handleContainersBulkCommand,
Description: gui.Tr.ViewBulkCommands,
},
{
ViewName: "containers",
Key: 'w',
Modifier: gocui.ModNone,
Handler: gui.handleContainersOpenInBrowserCommand,
Description: gui.Tr.OpenInBrowser,
},
{
ViewName: "services",
Key: 'd',
Modifier: gocui.ModNone,
Handler: gui.handleServiceRemoveMenu,
Description: gui.Tr.RemoveService,
},
{
ViewName: "services",
Key: 's',
Modifier: gocui.ModNone,
Handler: gui.handleServiceStop,
Description: gui.Tr.Stop,
},
{
ViewName: "services",
Key: 'p',
Modifier: gocui.ModNone,
Handler: gui.handleServicePause,
Description: gui.Tr.Pause,
},
{
ViewName: "services",
Key: 'r',
Modifier: gocui.ModNone,
Handler: gui.handleServiceRestart,
Description: gui.Tr.Restart,
},
{
ViewName: "services",
Key: 'S',
Modifier: gocui.ModNone,
Handler: gui.handleServiceStart,
Description: gui.Tr.Start,
},
{
ViewName: "services",
Key: 'a',
Modifier: gocui.ModNone,
Handler: gui.handleServiceAttach,
Description: gui.Tr.Attach,
},
{
ViewName: "services",
Key: 'm',
Modifier: gocui.ModNone,
Handler: gui.handleServiceRenderLogsToMain,
Description: gui.Tr.ViewLogs,
},
{
ViewName: "services",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleServicesPrevContext,
Description: gui.Tr.PreviousContext,
},
{
ViewName: "services",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleServicesNextContext,
Description: gui.Tr.NextContext,
},
{
ViewName: "services",
Key: 'R',
Modifier: gocui.ModNone,
Handler: gui.handleServiceRestartMenu,
Description: gui.Tr.ViewRestartOptions,
},
{
ViewName: "services",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleServicesCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "services",
Key: 'b',
Modifier: gocui.ModNone,
Handler: gui.handleServicesBulkCommand,
Description: gui.Tr.ViewBulkCommands,
},
{
ViewName: "services",
Key: 'E',
Modifier: gocui.ModNone,
Handler: gui.handleServicesExecShell,
Description: gui.Tr.ExecShell,
},
{
ViewName: "services",
Key: 'w',
Modifier: gocui.ModNone,
Handler: gui.handleServicesOpenInBrowserCommand,
Description: gui.Tr.OpenInBrowser,
},
{
ViewName: "images",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleImagesPrevContext,
Description: gui.Tr.PreviousContext,
},
{
ViewName: "images",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleImagesNextContext,
Description: gui.Tr.NextContext,
},
{
ViewName: "images",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleImagesCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "images",
Key: 'd',
Modifier: gocui.ModNone,
Handler: gui.handleImagesRemoveMenu,
Description: gui.Tr.RemoveImage,
},
{
ViewName: "images",
Key: 'b',
Modifier: gocui.ModNone,
Handler: gui.handleImagesBulkCommand,
Description: gui.Tr.ViewBulkCommands,
},
{
ViewName: "volumes",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesPrevContext,
Description: gui.Tr.PreviousContext,
},
{
ViewName: "volumes",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesNextContext,
Description: gui.Tr.NextContext,
},
{
ViewName: "volumes",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "volumes",
Key: 'd',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesRemoveMenu,
Description: gui.Tr.RemoveVolume,
},
{
ViewName: "volumes",
Key: 'b',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesBulkCommand,
Description: gui.Tr.ViewBulkCommands,
},
{
ViewName: "main",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
Handler: gui.handleExitMain,
Description: gui.Tr.Return,
},
{
ViewName: "main",
Key: gocui.KeyArrowLeft,
Modifier: gocui.ModNone,
Handler: gui.scrollLeftMain,
},
{
ViewName: "main",
Key: gocui.KeyArrowRight,
Modifier: gocui.ModNone,
Handler: gui.scrollRightMain,
},
{
ViewName: "main",
Key: 'h',
Modifier: gocui.ModNone,
Handler: gui.scrollLeftMain,
},
{
ViewName: "main",
Key: 'l',
Modifier: gocui.ModNone,
Handler: gui.scrollRightMain,
},
{
ViewName: "",
Key: 'J',
Modifier: gocui.ModNone,
Handler: gui.scrollDownMain,
},
{
ViewName: "",
Key: 'K',
Modifier: gocui.ModNone,
Handler: gui.scrollUpMain,
},
{
ViewName: "",
Key: 'H',
Modifier: gocui.ModNone,
Handler: gui.scrollLeftMain,
},
{
ViewName: "",
Key: 'L',
Modifier: gocui.ModNone,
Handler: gui.scrollRightMain,
},
{
ViewName: "",
Key: '+',
Handler: wrappedHandler(gui.nextScreenMode),
Description: gui.Tr.LcNextScreenMode,
},
{
ViewName: "",
Key: '_',
Handler: wrappedHandler(gui.prevScreenMode),
Description: gui.Tr.LcPrevScreenMode,
},
}
// TODO: add more views here
for _, viewName := range []string{"project", "services", "containers", "images", "volumes", "menu"} {
bindings = append(bindings, []*Binding{
{ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: viewName, Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: viewName, Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: viewName, Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: viewName, Key: gocui.KeyBacktab, Modifier: gocui.ModNone, Handler: gui.previousView},
}...)
}
panelMap := map[string]struct {
onKeyUpPress func(*gocui.Gui, *gocui.View) error
onKeyDownPress func(*gocui.Gui, *gocui.View) error
onClick func(*gocui.Gui, *gocui.View) error
}{
"menu": {onKeyUpPress: gui.handleMenuPrevLine, onKeyDownPress: gui.handleMenuNextLine, onClick: gui.handleMenuClick},
"services": {onKeyUpPress: gui.handleServicesPrevLine, onKeyDownPress: gui.handleServicesNextLine, onClick: gui.handleServicesClick},
"containers": {onKeyUpPress: gui.handleContainersPrevLine, onKeyDownPress: gui.handleContainersNextLine, onClick: gui.handleContainersClick},
"images": {onKeyUpPress: gui.handleImagesPrevLine, onKeyDownPress: gui.handleImagesNextLine, onClick: gui.handleImagesClick},
"volumes": {onKeyUpPress: gui.handleVolumesPrevLine, onKeyDownPress: gui.handleVolumesNextLine, onClick: gui.handleVolumesClick},
"main": {onKeyUpPress: gui.scrollUpMain, onKeyDownPress: gui.scrollDownMain, onClick: gui.handleMainClick},
}
for viewName, functions := range panelMap {
bindings = append(bindings, []*Binding{
{ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: functions.onKeyUpPress},
{ViewName: viewName, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: functions.onKeyUpPress},
{ViewName: viewName, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: functions.onKeyUpPress},
{ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: functions.onKeyDownPress},
{ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: functions.onKeyDownPress},
{ViewName: viewName, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: functions.onKeyDownPress},
{ViewName: viewName, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: functions.onClick},
}...)
}
for _, viewName := range []string{"project", "services", "containers", "images", "volumes"} {
bindings = append(bindings, &Binding{
ViewName: viewName,
Key: gocui.KeyEnter,
Modifier: gocui.ModNone,
Handler: gui.handleEnterMain,
Description: gui.Tr.FocusMain,
})
}
return bindings
}
func (gui *Gui) keybindings(g *gocui.Gui) error {
bindings := gui.GetInitialKeybindings()
for _, binding := range bindings {
if err := g.SetKeybinding(binding.ViewName, nil, binding.Key, binding.Modifier, binding.Handler); err != nil {
return err
}
}
if err := g.SetTabClickBinding("main", gui.onMainTabClick); err != nil {
return err
}
return nil
}
func wrappedHandler(f func() error) func(*gocui.Gui, *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error {
return f()
}
}