From 5e9380dc6312a02108b022fe50f981b9bf6fc1e1 Mon Sep 17 00:00:00 2001
From: cxsu <imcxsu@gmail.com>
Date: Sun, 27 Dec 2020 14:56:03 +0900
Subject: [PATCH 1/3] Update gocui module

---
 go.mod                                        |   5 +-
 go.sum                                        |  17 +-
 runtime/ui/app.go                             |   7 +-
 runtime/ui/controller.go                      |   2 +-
 runtime/ui/key/binding.go                     |  15 +-
 runtime/ui/key/key.go                         | 186 ++++++++++++++++++
 .../layout/compound/layer_details_column.go   |  10 +-
 runtime/ui/layout/layout.go                   |   2 +-
 runtime/ui/layout/manager.go                  |   2 +-
 runtime/ui/layout/manager_test.go             |   2 +-
 runtime/ui/view/cursor.go                     |   2 +-
 runtime/ui/view/debug.go                      |   7 +-
 runtime/ui/view/details.go                    |   2 +-
 runtime/ui/view/filetree.go                   |   9 +-
 runtime/ui/view/filter.go                     |   9 +-
 runtime/ui/view/layer.go                      |   2 +-
 runtime/ui/view/status.go                     |   7 +-
 runtime/ui/view/views.go                      |   2 +-
 utils/view.go                                 |   2 +-
 19 files changed, 237 insertions(+), 53 deletions(-)
 create mode 100644 runtime/ui/key/key.go

diff --git a/go.mod b/go.mod
index c86e6a9..16dd5e0 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.13
 require (
 	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
+	github.com/awesome-gocui/gocui v0.6.0
 	github.com/cespare/xxhash v1.1.0
 	github.com/docker/cli v0.0.0-20190906153656-016a3232168d
 	github.com/docker/distribution v2.7.1+incompatible // indirect
@@ -17,17 +18,14 @@ require (
 	github.com/google/go-cmp v0.3.0 // indirect
 	github.com/google/uuid v1.1.1
 	github.com/gorilla/mux v1.7.2 // indirect
-	github.com/jroimartin/gocui v0.4.0
 	github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
 	github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b
 	github.com/lunixbochs/vtclean v1.0.0
 	github.com/magiconair/properties v1.8.1 // indirect
 	github.com/mattn/go-colorable v0.1.2 // indirect
 	github.com/mattn/go-isatty v0.0.9 // indirect
-	github.com/mattn/go-runewidth v0.0.4 // indirect
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/morikuni/aec v1.0.0 // indirect
-	github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 // indirect
 	github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
 	github.com/opencontainers/image-spec v1.0.1 // indirect
 	github.com/pelletier/go-toml v1.4.0 // indirect
@@ -40,7 +38,6 @@ require (
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/spf13/viper v1.4.0
 	github.com/stretchr/testify v1.4.0 // indirect
-	github.com/wagoodman/keybinding v0.0.0-20181213133715-6a824da6df05
 	golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
 	golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
 	golang.org/x/text v0.3.2 // indirect
diff --git a/go.sum b/go.sum
index 7d64d3a..bbe2939 100644
--- a/go.sum
+++ b/go.sum
@@ -10,6 +10,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/awesome-gocui/gocui v0.6.0 h1:hhDJiQC12tEsJNJ+iZBBVaSSLFYo9llFuYpQlL5JZVI=
+github.com/awesome-gocui/gocui v0.6.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA=
+github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0=
+github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -47,6 +51,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -64,7 +70,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golangci/golangci-lint v1.32.0 h1:3wL5pvhTpRvlvtosoZecS+hu40IAiJl1qlZQuXIFBAg=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -83,8 +88,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jroimartin/gocui v0.4.0 h1:52jnalstgmc25FmtGcWqa0tcbMEWS6RpFLsOIO+I+E8=
-github.com/jroimartin/gocui v0.4.0/go.mod h1:7i7bbj99OgFHzo7kB2zPb8pXLqMBSQegY7azfqXMkyY=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -113,8 +116,6 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
 github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
-github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
-github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@@ -126,10 +127,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
 github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed h1:bAVGG6B+R5qpSylrrA+BAMrzYkdAoiTaKPVxRB+4cyM=
-github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
-github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 h1:hhGN4SFXgXo61Q4Sjj/X9sBjyeSa2kdpaOzCO+8EVQw=
-github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -197,8 +194,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/wagoodman/keybinding v0.0.0-20181213133715-6a824da6df05 h1:YMcRwVDe8DLDZ/vrhuImCfqjjG/+gZs6SF61DDQkL/8=
-github.com/wagoodman/keybinding v0.0.0-20181213133715-6a824da6df05/go.mod h1:gXFkc2sM2o06uzn5Lgo6Ql76uweGdxNfeAlFyKiHAdk=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
diff --git a/runtime/ui/app.go b/runtime/ui/app.go
index 91317f4..036429f 100644
--- a/runtime/ui/app.go
+++ b/runtime/ui/app.go
@@ -1,13 +1,14 @@
 package ui
 
 import (
+	"sync"
+
 	"github.com/wagoodman/dive/dive/image"
 	"github.com/wagoodman/dive/runtime/ui/key"
 	"github.com/wagoodman/dive/runtime/ui/layout"
 	"github.com/wagoodman/dive/runtime/ui/layout/compound"
-	"sync"
 
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/dive/filetree"
 )
@@ -130,7 +131,7 @@ func (a *app) quit() error {
 func Run(imageName string, analysis *image.AnalysisResult, treeStack filetree.Comparer) error {
 	var err error
 
-	g, err := gocui.NewGui(gocui.OutputNormal)
+	g, err := gocui.NewGui(gocui.OutputNormal, true)
 	if err != nil {
 		return err
 	}
diff --git a/runtime/ui/controller.go b/runtime/ui/controller.go
index 6d9d5a7..964fb83 100644
--- a/runtime/ui/controller.go
+++ b/runtime/ui/controller.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/dive/filetree"
 	"github.com/wagoodman/dive/dive/image"
diff --git a/runtime/ui/key/binding.go b/runtime/ui/key/binding.go
index 76ffa31..916c747 100644
--- a/runtime/ui/key/binding.go
+++ b/runtime/ui/key/binding.go
@@ -2,11 +2,12 @@ package key
 
 import (
 	"fmt"
-	"github.com/jroimartin/gocui"
+
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 	"github.com/wagoodman/dive/runtime/ui/format"
-	"github.com/wagoodman/keybinding"
+	// "github.com/wagoodman/keybinding"
 )
 
 type BindingInfo struct {
@@ -19,7 +20,7 @@ type BindingInfo struct {
 }
 
 type Binding struct {
-	key         []keybinding.Key
+	key         []Key
 	displayName string
 	selectedFn  func() bool
 	actionFn    func() error
@@ -52,11 +53,11 @@ func GenerateBindings(gui *gocui.Gui, influence string, infos []BindingInfo) ([]
 }
 
 func NewBinding(gui *gocui.Gui, influence string, key gocui.Key, mod gocui.Modifier, displayName string, actionFn func() error) (*Binding, error) {
-	return newBinding(gui, influence, []keybinding.Key{{Value: key, Modifier: mod}}, displayName, actionFn)
+	return newBinding(gui, influence, []Key{{Value: key, Modifier: mod}}, displayName, actionFn)
 }
 
 func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string, displayName string, actionFn func() error) (*Binding, error) {
-	var parsedKeys []keybinding.Key
+	var parsedKeys []Key
 	for _, configKey := range configKeys {
 		bindStr := viper.GetString(configKey)
 		if bindStr == "" {
@@ -65,7 +66,7 @@ func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string,
 		}
 		logrus.Debugf("parsing keybinding '%s' --> '%s'", configKey, bindStr)
 
-		keys, err := keybinding.ParseAll(bindStr)
+		keys, err := ParseAll(bindStr)
 		if err != nil {
 			return nil, err
 		}
@@ -82,7 +83,7 @@ func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string,
 	return newBinding(gui, influence, parsedKeys, displayName, actionFn)
 }
 
-func newBinding(gui *gocui.Gui, influence string, keys []keybinding.Key, displayName string, actionFn func() error) (*Binding, error) {
+func newBinding(gui *gocui.Gui, influence string, keys []Key, displayName string, actionFn func() error) (*Binding, error) {
 	binding := &Binding{
 		key:         keys,
 		displayName: displayName,
diff --git a/runtime/ui/key/key.go b/runtime/ui/key/key.go
new file mode 100644
index 0000000..dc12619
--- /dev/null
+++ b/runtime/ui/key/key.go
@@ -0,0 +1,186 @@
+package key
+
+import (
+	"fmt"
+	"strings"
+	"unicode"
+
+	"github.com/awesome-gocui/gocui"
+)
+
+var translate = map[string]string{
+	"/":        "Slash",
+	"\\":       "Backslash",
+	"[":        "LsqBracket",
+	"]":        "RsqBracket",
+	"_":        "Underscore",
+	"escape":   "Esc",
+	"~":        "Tilde",
+	"pageup":   "Pgup",
+	"pagedown": "Pgdn",
+	"pgup":     "Pgup",
+	"pgdown":   "Pgdn",
+	"up":       "ArrowUp",
+	"down":     "ArrowDown",
+	"right":    "ArrowRight",
+	"left":     "ArrowLeft",
+	"ctl":      "Ctrl",
+}
+
+var display = map[string]string{
+	"Slash":      "/",
+	"Backslash":  "\\",
+	"LsqBracket": "[",
+	"RsqBracket": "]",
+	"Underscore": "_",
+	"Tilde":      "~",
+	"Ctrl":       "^",
+}
+
+var supportedKeybindings = map[string]gocui.Key{
+	"KeyF1":             gocui.KeyF1,
+	"KeyF2":             gocui.KeyF2,
+	"KeyF3":             gocui.KeyF3,
+	"KeyF4":             gocui.KeyF4,
+	"KeyF5":             gocui.KeyF5,
+	"KeyF6":             gocui.KeyF6,
+	"KeyF7":             gocui.KeyF7,
+	"KeyF8":             gocui.KeyF8,
+	"KeyF9":             gocui.KeyF9,
+	"KeyF10":            gocui.KeyF10,
+	"KeyF11":            gocui.KeyF11,
+	"KeyF12":            gocui.KeyF12,
+	"KeyInsert":         gocui.KeyInsert,
+	"KeyDelete":         gocui.KeyDelete,
+	"KeyHome":           gocui.KeyHome,
+	"KeyEnd":            gocui.KeyEnd,
+	"KeyPgup":           gocui.KeyPgup,
+	"KeyPgdn":           gocui.KeyPgdn,
+	"KeyArrowUp":        gocui.KeyArrowUp,
+	"KeyArrowDown":      gocui.KeyArrowDown,
+	"KeyArrowLeft":      gocui.KeyArrowLeft,
+	"KeyArrowRight":     gocui.KeyArrowRight,
+	"KeyCtrlTilde":      gocui.KeyCtrlTilde,
+	"KeyCtrl2":          gocui.KeyCtrl2,
+	"KeyCtrlSpace":      gocui.KeyCtrlSpace,
+	"KeyCtrlA":          gocui.KeyCtrlA,
+	"KeyCtrlB":          gocui.KeyCtrlB,
+	"KeyCtrlC":          gocui.KeyCtrlC,
+	"KeyCtrlD":          gocui.KeyCtrlD,
+	"KeyCtrlE":          gocui.KeyCtrlE,
+	"KeyCtrlF":          gocui.KeyCtrlF,
+	"KeyCtrlG":          gocui.KeyCtrlG,
+	"KeyBackspace":      gocui.KeyBackspace,
+	"KeyCtrlH":          gocui.KeyCtrlH,
+	"KeyTab":            gocui.KeyTab,
+	"KeyCtrlI":          gocui.KeyCtrlI,
+	"KeyCtrlJ":          gocui.KeyCtrlJ,
+	"KeyCtrlK":          gocui.KeyCtrlK,
+	"KeyCtrlL":          gocui.KeyCtrlL,
+	"KeyEnter":          gocui.KeyEnter,
+	"KeyCtrlM":          gocui.KeyCtrlM,
+	"KeyCtrlN":          gocui.KeyCtrlN,
+	"KeyCtrlO":          gocui.KeyCtrlO,
+	"KeyCtrlP":          gocui.KeyCtrlP,
+	"KeyCtrlQ":          gocui.KeyCtrlQ,
+	"KeyCtrlR":          gocui.KeyCtrlR,
+	"KeyCtrlS":          gocui.KeyCtrlS,
+	"KeyCtrlT":          gocui.KeyCtrlT,
+	"KeyCtrlU":          gocui.KeyCtrlU,
+	"KeyCtrlV":          gocui.KeyCtrlV,
+	"KeyCtrlW":          gocui.KeyCtrlW,
+	"KeyCtrlX":          gocui.KeyCtrlX,
+	"KeyCtrlY":          gocui.KeyCtrlY,
+	"KeyCtrlZ":          gocui.KeyCtrlZ,
+	"KeyEsc":            gocui.KeyEsc,
+	"KeyCtrlLsqBracket": gocui.KeyCtrlLsqBracket,
+	"KeyCtrl3":          gocui.KeyCtrl3,
+	"KeyCtrl4":          gocui.KeyCtrl4,
+	"KeyCtrlBackslash":  gocui.KeyCtrlBackslash,
+	"KeyCtrl5":          gocui.KeyCtrl5,
+	"KeyCtrlRsqBracket": gocui.KeyCtrlRsqBracket,
+	"KeyCtrl6":          gocui.KeyCtrl6,
+	"KeyCtrl7":          gocui.KeyCtrl7,
+	"KeyCtrlSlash":      gocui.KeyCtrlSlash,
+	"KeyCtrlUnderscore": gocui.KeyCtrlUnderscore,
+	"KeySpace":          gocui.KeySpace,
+	"KeyBackspace2":     gocui.KeyBackspace2,
+	"KeyCtrl8":          gocui.KeyCtrl8,
+}
+
+type Key struct {
+	Value    gocui.Key
+	Modifier gocui.Modifier
+	Tokens   []string
+}
+
+func Parse(input string) (Key, error) {
+	f := func(c rune) bool { return unicode.IsSpace(c) || c == '+' }
+	tokens := strings.FieldsFunc(input, f)
+	var normalizedTokens []string
+	var modifier = gocui.ModNone
+
+	for _, token := range tokens {
+		normalized := strings.ToLower(token)
+
+		if value, exists := translate[normalized]; exists {
+			normalized = value
+		} else {
+			normalized = strings.Title(normalized)
+		}
+
+		if normalized == "Alt" {
+			modifier = gocui.ModAlt
+			continue
+		}
+
+		if len(normalized) == 1 {
+			normalizedTokens = append(normalizedTokens, strings.ToUpper(normalized))
+			continue
+		}
+
+		normalizedTokens = append(normalizedTokens, normalized)
+	}
+
+	lookup := "Key" + strings.Join(normalizedTokens, "")
+
+	if key, exists := supportedKeybindings[lookup]; exists {
+		return Key{key, modifier, normalizedTokens}, nil
+	}
+
+	if modifier != gocui.ModNone {
+		return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s (+%+v)", lookup, modifier)
+	}
+	return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s", lookup)
+}
+
+func ParseAll(input string) ([]Key, error) {
+	ret := make([]Key, 0)
+	for _, value := range strings.Split(input, ",") {
+		key, err := Parse(value)
+		if err != nil {
+			return nil, fmt.Errorf("could not parse keybinding '%s' from request '%s': %+v", value, input, err)
+		}
+		ret = append(ret, key)
+	}
+	if len(ret) == 0 {
+		return nil, fmt.Errorf("must have at least one keybinding")
+	}
+	return ret, nil
+}
+
+func (key Key) String() string {
+	displayTokens := make([]string, 0)
+	prefix := ""
+	for _, token := range key.Tokens {
+		if token == "Ctrl" {
+			prefix = "^"
+			continue
+		}
+		if value, exists := display[token]; exists {
+			token = value
+		}
+		displayTokens = append(displayTokens, token)
+	}
+	return prefix + strings.Join(displayTokens, "+")
+}
diff --git a/runtime/ui/layout/compound/layer_details_column.go b/runtime/ui/layout/compound/layer_details_column.go
index 1941edf..3981442 100644
--- a/runtime/ui/layout/compound/layer_details_column.go
+++ b/runtime/ui/layout/compound/layer_details_column.go
@@ -1,7 +1,7 @@
 package compound
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/runtime/ui/view"
 	"github.com/wagoodman/dive/utils"
@@ -56,10 +56,10 @@ func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, max
 	}
 
 	// note: maxY needs to account for the (invisible) border, thus a +1
-	header, headerErr := g.SetView(cl.layer.Name()+"header", minX, minY, maxX, minY+layerHeaderHeight+1)
+	header, headerErr := g.SetView(cl.layer.Name()+"header", minX, minY, maxX, minY+layerHeaderHeight+1, 0)
 
 	// we are going to overlap the view over the (invisible) border (so minY will be one less than expected)
-	main, viewErr := g.SetView(cl.layer.Name(), minX, minY+layerHeaderHeight, maxX, minY+layerHeaderHeight+layersHeight)
+	main, viewErr := g.SetView(cl.layer.Name(), minX, minY+layerHeaderHeight, maxX, minY+layerHeaderHeight+layersHeight, 0)
 
 	if utils.IsNewView(viewErr, headerErr) {
 		err := cl.layer.Setup(main, header)
@@ -103,8 +103,8 @@ func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, max
 
 	}
 
-	header, headerErr = g.SetView(cl.details.Name()+"header", minX, detailsMinY, maxX, detailsMinY+detailsHeaderHeight)
-	main, viewErr = g.SetView(cl.details.Name(), minX, detailsMinY+detailsHeaderHeight, maxX, maxY)
+	header, headerErr = g.SetView(cl.details.Name()+"header", minX, detailsMinY, maxX, detailsMinY+detailsHeaderHeight, 0)
+	main, viewErr = g.SetView(cl.details.Name(), minX, detailsMinY+detailsHeaderHeight, maxX, maxY, 0)
 
 	if utils.IsNewView(viewErr, headerErr) {
 		err := cl.details.Setup(main, header)
diff --git a/runtime/ui/layout/layout.go b/runtime/ui/layout/layout.go
index abc0dbb..226b45c 100644
--- a/runtime/ui/layout/layout.go
+++ b/runtime/ui/layout/layout.go
@@ -1,6 +1,6 @@
 package layout
 
-import "github.com/jroimartin/gocui"
+import "github.com/awesome-gocui/gocui"
 
 type Layout interface {
 	Name() string
diff --git a/runtime/ui/layout/manager.go b/runtime/ui/layout/manager.go
index 460cbea..2f679cd 100644
--- a/runtime/ui/layout/manager.go
+++ b/runtime/ui/layout/manager.go
@@ -1,7 +1,7 @@
 package layout
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 )
 
diff --git a/runtime/ui/layout/manager_test.go b/runtime/ui/layout/manager_test.go
index 06c1a93..a3e6962 100644
--- a/runtime/ui/layout/manager_test.go
+++ b/runtime/ui/layout/manager_test.go
@@ -1,7 +1,7 @@
 package layout
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"testing"
 )
 
diff --git a/runtime/ui/view/cursor.go b/runtime/ui/view/cursor.go
index 7cd5bcf..a2b6b89 100644
--- a/runtime/ui/view/cursor.go
+++ b/runtime/ui/view/cursor.go
@@ -2,7 +2,7 @@ package view
 
 import (
 	"errors"
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 )
 
 // CursorDown moves the cursor down in the currently selected gocui pane, scrolling the screen as needed.
diff --git a/runtime/ui/view/debug.go b/runtime/ui/view/debug.go
index aab9d06..cb45676 100644
--- a/runtime/ui/view/debug.go
+++ b/runtime/ui/view/debug.go
@@ -2,7 +2,8 @@ package view
 
 import (
 	"fmt"
-	"github.com/jroimartin/gocui"
+
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/runtime/ui/format"
 	"github.com/wagoodman/dive/utils"
@@ -103,10 +104,10 @@ func (v *Debug) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
 	// header
 	headerSize := 1
 	// note: maxY needs to account for the (invisible) border, thus a +1
-	header, headerErr := g.SetView(v.Name()+"header", minX, minY, maxX, minY+headerSize+1)
+	header, headerErr := g.SetView(v.Name()+"header", minX, minY, maxX, minY+headerSize+1, 0)
 	// we are going to overlap the view over the (invisible) border (so minY will be one less than expected).
 	// additionally, maxY will be bumped by one to include the border
-	view, viewErr := g.SetView(v.Name(), minX, minY+headerSize, maxX, maxY+1)
+	view, viewErr := g.SetView(v.Name(), minX, minY+headerSize, maxX, maxY+1, 0)
 	if utils.IsNewView(viewErr, headerErr) {
 		err := v.Setup(view, header)
 		if err != nil {
diff --git a/runtime/ui/view/details.go b/runtime/ui/view/details.go
index 02262d1..5f21730 100644
--- a/runtime/ui/view/details.go
+++ b/runtime/ui/view/details.go
@@ -10,8 +10,8 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/awesome-gocui/gocui"
 	"github.com/dustin/go-humanize"
-	"github.com/jroimartin/gocui"
 )
 
 // Details holds the UI objects and data models for populating the lower-left pane. Specifically the pane that
diff --git a/runtime/ui/view/filetree.go b/runtime/ui/view/filetree.go
index 97e6f7b..b9ff8db 100644
--- a/runtime/ui/view/filetree.go
+++ b/runtime/ui/view/filetree.go
@@ -2,7 +2,9 @@ package view
 
 import (
 	"fmt"
-	"github.com/jroimartin/gocui"
+	"regexp"
+
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 	"github.com/wagoodman/dive/dive/filetree"
@@ -10,7 +12,6 @@ import (
 	"github.com/wagoodman/dive/runtime/ui/key"
 	"github.com/wagoodman/dive/runtime/ui/viewmodel"
 	"github.com/wagoodman/dive/utils"
-	"regexp"
 )
 
 type ViewOptionChangeListener func() error
@@ -409,10 +410,10 @@ func (v *FileTree) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
 	// header + attribute header
 	headerSize := 1 + attributeRowSize
 	// note: maxY needs to account for the (invisible) border, thus a +1
-	header, headerErr := g.SetView(v.Name()+"header", minX, minY, maxX, minY+headerSize+1)
+	header, headerErr := g.SetView(v.Name()+"header", minX, minY, maxX, minY+headerSize+1, 0)
 	// we are going to overlap the view over the (invisible) border (so minY will be one less than expected).
 	// additionally, maxY will be bumped by one to include the border
-	view, viewErr := g.SetView(v.Name(), minX, minY+headerSize, maxX, maxY+1)
+	view, viewErr := g.SetView(v.Name(), minX, minY+headerSize, maxX, maxY+1, 0)
 	if utils.IsNewView(viewErr, headerErr) {
 		err := v.Setup(view, header)
 		if err != nil {
diff --git a/runtime/ui/view/filter.go b/runtime/ui/view/filter.go
index e8f911b..5fdf915 100644
--- a/runtime/ui/view/filter.go
+++ b/runtime/ui/view/filter.go
@@ -2,11 +2,12 @@ package view
 
 import (
 	"fmt"
-	"github.com/jroimartin/gocui"
+	"strings"
+
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/runtime/ui/format"
 	"github.com/wagoodman/dive/utils"
-	"strings"
 )
 
 type FilterEditListener func(string) error
@@ -172,8 +173,8 @@ func (v *Filter) OnLayoutChange() error {
 func (v *Filter) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
 	logrus.Tracef("view.Layout(minX: %d, minY: %d, maxX: %d, maxY: %d) %s", minX, minY, maxX, maxY, v.Name())
 
-	label, labelErr := g.SetView(v.Name()+"label", minX, minY, len(v.labelStr), maxY)
-	view, viewErr := g.SetView(v.Name(), minX+(len(v.labelStr)-1), minY, maxX, maxY)
+	label, labelErr := g.SetView(v.Name()+"label", minX, minY, len(v.labelStr), maxY, 0)
+	view, viewErr := g.SetView(v.Name(), minX+(len(v.labelStr)-1), minY, maxX, maxY, 0)
 
 	if utils.IsNewView(viewErr, labelErr) {
 		err := v.Setup(view, label)
diff --git a/runtime/ui/view/layer.go b/runtime/ui/view/layer.go
index 601cd78..c1f9d0c 100644
--- a/runtime/ui/view/layer.go
+++ b/runtime/ui/view/layer.go
@@ -2,7 +2,7 @@ package view
 
 import (
 	"fmt"
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 	"github.com/wagoodman/dive/dive/image"
diff --git a/runtime/ui/view/status.go b/runtime/ui/view/status.go
index 87a4b46..9706280 100644
--- a/runtime/ui/view/status.go
+++ b/runtime/ui/view/status.go
@@ -2,13 +2,14 @@ package view
 
 import (
 	"fmt"
+	"strings"
+
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/runtime/ui/format"
 	"github.com/wagoodman/dive/runtime/ui/key"
 	"github.com/wagoodman/dive/utils"
-	"strings"
 
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 )
 
 // Status holds the UI objects and data models for populating the bottom-most pane. Specifically the panel
@@ -113,7 +114,7 @@ func (v *Status) KeyHelp() string {
 func (v *Status) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
 	logrus.Tracef("view.Layout(minX: %d, minY: %d, maxX: %d, maxY: %d) %s", minX, minY, maxX, maxY, v.Name())
 
-	view, viewErr := g.SetView(v.Name(), minX, minY, maxX, maxY)
+	view, viewErr := g.SetView(v.Name(), minX, minY, maxX, maxY, 0)
 	if utils.IsNewView(viewErr) {
 		err := v.Setup(view)
 		if err != nil {
diff --git a/runtime/ui/view/views.go b/runtime/ui/view/views.go
index e336635..b1b72b8 100644
--- a/runtime/ui/view/views.go
+++ b/runtime/ui/view/views.go
@@ -1,7 +1,7 @@
 package view
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/wagoodman/dive/dive/filetree"
 	"github.com/wagoodman/dive/dive/image"
 )
diff --git a/utils/view.go b/utils/view.go
index 270da4b..a65ce79 100644
--- a/utils/view.go
+++ b/utils/view.go
@@ -1,7 +1,7 @@
 package utils
 
 import (
-	"github.com/jroimartin/gocui"
+	"github.com/awesome-gocui/gocui"
 	"github.com/sirupsen/logrus"
 )
 

From b310bdb2d6ae34d86929e2b555b5df35356c399f Mon Sep 17 00:00:00 2001
From: cxsu <imcxsu@gmail.com>
Date: Sun, 27 Dec 2020 20:28:29 +0900
Subject: [PATCH 2/3] Add module awesome-gocui/keybinding

---
 go.mod                    |   1 +
 go.sum                    |   3 +
 runtime/ui/key/binding.go |  12 +--
 runtime/ui/key/key.go     | 186 --------------------------------------
 4 files changed, 10 insertions(+), 192 deletions(-)
 delete mode 100644 runtime/ui/key/key.go

diff --git a/go.mod b/go.mod
index 16dd5e0..f2ca464 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
 	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/awesome-gocui/gocui v0.6.0
+	github.com/awesome-gocui/keybinding v1.0.0
 	github.com/cespare/xxhash v1.1.0
 	github.com/docker/cli v0.0.0-20190906153656-016a3232168d
 	github.com/docker/distribution v2.7.1+incompatible // indirect
diff --git a/go.sum b/go.sum
index bbe2939..e6023a3 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,11 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/awesome-gocui/gocui v0.5.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA=
 github.com/awesome-gocui/gocui v0.6.0 h1:hhDJiQC12tEsJNJ+iZBBVaSSLFYo9llFuYpQlL5JZVI=
 github.com/awesome-gocui/gocui v0.6.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA=
+github.com/awesome-gocui/keybinding v1.0.0 h1:CrnjCfEhWpjcqIQUan9IllaXeRGELdwfjeUmY7ljbng=
+github.com/awesome-gocui/keybinding v1.0.0/go.mod h1:z0TyCwIhaT97yU+becTse8Dqh2CvYT0FLw0R0uTk0ag=
 github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0=
 github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
diff --git a/runtime/ui/key/binding.go b/runtime/ui/key/binding.go
index 916c747..14566a7 100644
--- a/runtime/ui/key/binding.go
+++ b/runtime/ui/key/binding.go
@@ -4,10 +4,10 @@ import (
 	"fmt"
 
 	"github.com/awesome-gocui/gocui"
+	"github.com/awesome-gocui/keybinding"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 	"github.com/wagoodman/dive/runtime/ui/format"
-	// "github.com/wagoodman/keybinding"
 )
 
 type BindingInfo struct {
@@ -20,7 +20,7 @@ type BindingInfo struct {
 }
 
 type Binding struct {
-	key         []Key
+	key         []keybinding.Key
 	displayName string
 	selectedFn  func() bool
 	actionFn    func() error
@@ -53,11 +53,11 @@ func GenerateBindings(gui *gocui.Gui, influence string, infos []BindingInfo) ([]
 }
 
 func NewBinding(gui *gocui.Gui, influence string, key gocui.Key, mod gocui.Modifier, displayName string, actionFn func() error) (*Binding, error) {
-	return newBinding(gui, influence, []Key{{Value: key, Modifier: mod}}, displayName, actionFn)
+	return newBinding(gui, influence, []keybinding.Key{{Value: key, Modifier: mod}}, displayName, actionFn)
 }
 
 func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string, displayName string, actionFn func() error) (*Binding, error) {
-	var parsedKeys []Key
+	var parsedKeys []keybinding.Key
 	for _, configKey := range configKeys {
 		bindStr := viper.GetString(configKey)
 		if bindStr == "" {
@@ -66,7 +66,7 @@ func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string,
 		}
 		logrus.Debugf("parsing keybinding '%s' --> '%s'", configKey, bindStr)
 
-		keys, err := ParseAll(bindStr)
+		keys, err := keybinding.ParseAll(bindStr)
 		if err != nil {
 			return nil, err
 		}
@@ -83,7 +83,7 @@ func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string,
 	return newBinding(gui, influence, parsedKeys, displayName, actionFn)
 }
 
-func newBinding(gui *gocui.Gui, influence string, keys []Key, displayName string, actionFn func() error) (*Binding, error) {
+func newBinding(gui *gocui.Gui, influence string, keys []keybinding.Key, displayName string, actionFn func() error) (*Binding, error) {
 	binding := &Binding{
 		key:         keys,
 		displayName: displayName,
diff --git a/runtime/ui/key/key.go b/runtime/ui/key/key.go
deleted file mode 100644
index dc12619..0000000
--- a/runtime/ui/key/key.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package key
-
-import (
-	"fmt"
-	"strings"
-	"unicode"
-
-	"github.com/awesome-gocui/gocui"
-)
-
-var translate = map[string]string{
-	"/":        "Slash",
-	"\\":       "Backslash",
-	"[":        "LsqBracket",
-	"]":        "RsqBracket",
-	"_":        "Underscore",
-	"escape":   "Esc",
-	"~":        "Tilde",
-	"pageup":   "Pgup",
-	"pagedown": "Pgdn",
-	"pgup":     "Pgup",
-	"pgdown":   "Pgdn",
-	"up":       "ArrowUp",
-	"down":     "ArrowDown",
-	"right":    "ArrowRight",
-	"left":     "ArrowLeft",
-	"ctl":      "Ctrl",
-}
-
-var display = map[string]string{
-	"Slash":      "/",
-	"Backslash":  "\\",
-	"LsqBracket": "[",
-	"RsqBracket": "]",
-	"Underscore": "_",
-	"Tilde":      "~",
-	"Ctrl":       "^",
-}
-
-var supportedKeybindings = map[string]gocui.Key{
-	"KeyF1":             gocui.KeyF1,
-	"KeyF2":             gocui.KeyF2,
-	"KeyF3":             gocui.KeyF3,
-	"KeyF4":             gocui.KeyF4,
-	"KeyF5":             gocui.KeyF5,
-	"KeyF6":             gocui.KeyF6,
-	"KeyF7":             gocui.KeyF7,
-	"KeyF8":             gocui.KeyF8,
-	"KeyF9":             gocui.KeyF9,
-	"KeyF10":            gocui.KeyF10,
-	"KeyF11":            gocui.KeyF11,
-	"KeyF12":            gocui.KeyF12,
-	"KeyInsert":         gocui.KeyInsert,
-	"KeyDelete":         gocui.KeyDelete,
-	"KeyHome":           gocui.KeyHome,
-	"KeyEnd":            gocui.KeyEnd,
-	"KeyPgup":           gocui.KeyPgup,
-	"KeyPgdn":           gocui.KeyPgdn,
-	"KeyArrowUp":        gocui.KeyArrowUp,
-	"KeyArrowDown":      gocui.KeyArrowDown,
-	"KeyArrowLeft":      gocui.KeyArrowLeft,
-	"KeyArrowRight":     gocui.KeyArrowRight,
-	"KeyCtrlTilde":      gocui.KeyCtrlTilde,
-	"KeyCtrl2":          gocui.KeyCtrl2,
-	"KeyCtrlSpace":      gocui.KeyCtrlSpace,
-	"KeyCtrlA":          gocui.KeyCtrlA,
-	"KeyCtrlB":          gocui.KeyCtrlB,
-	"KeyCtrlC":          gocui.KeyCtrlC,
-	"KeyCtrlD":          gocui.KeyCtrlD,
-	"KeyCtrlE":          gocui.KeyCtrlE,
-	"KeyCtrlF":          gocui.KeyCtrlF,
-	"KeyCtrlG":          gocui.KeyCtrlG,
-	"KeyBackspace":      gocui.KeyBackspace,
-	"KeyCtrlH":          gocui.KeyCtrlH,
-	"KeyTab":            gocui.KeyTab,
-	"KeyCtrlI":          gocui.KeyCtrlI,
-	"KeyCtrlJ":          gocui.KeyCtrlJ,
-	"KeyCtrlK":          gocui.KeyCtrlK,
-	"KeyCtrlL":          gocui.KeyCtrlL,
-	"KeyEnter":          gocui.KeyEnter,
-	"KeyCtrlM":          gocui.KeyCtrlM,
-	"KeyCtrlN":          gocui.KeyCtrlN,
-	"KeyCtrlO":          gocui.KeyCtrlO,
-	"KeyCtrlP":          gocui.KeyCtrlP,
-	"KeyCtrlQ":          gocui.KeyCtrlQ,
-	"KeyCtrlR":          gocui.KeyCtrlR,
-	"KeyCtrlS":          gocui.KeyCtrlS,
-	"KeyCtrlT":          gocui.KeyCtrlT,
-	"KeyCtrlU":          gocui.KeyCtrlU,
-	"KeyCtrlV":          gocui.KeyCtrlV,
-	"KeyCtrlW":          gocui.KeyCtrlW,
-	"KeyCtrlX":          gocui.KeyCtrlX,
-	"KeyCtrlY":          gocui.KeyCtrlY,
-	"KeyCtrlZ":          gocui.KeyCtrlZ,
-	"KeyEsc":            gocui.KeyEsc,
-	"KeyCtrlLsqBracket": gocui.KeyCtrlLsqBracket,
-	"KeyCtrl3":          gocui.KeyCtrl3,
-	"KeyCtrl4":          gocui.KeyCtrl4,
-	"KeyCtrlBackslash":  gocui.KeyCtrlBackslash,
-	"KeyCtrl5":          gocui.KeyCtrl5,
-	"KeyCtrlRsqBracket": gocui.KeyCtrlRsqBracket,
-	"KeyCtrl6":          gocui.KeyCtrl6,
-	"KeyCtrl7":          gocui.KeyCtrl7,
-	"KeyCtrlSlash":      gocui.KeyCtrlSlash,
-	"KeyCtrlUnderscore": gocui.KeyCtrlUnderscore,
-	"KeySpace":          gocui.KeySpace,
-	"KeyBackspace2":     gocui.KeyBackspace2,
-	"KeyCtrl8":          gocui.KeyCtrl8,
-}
-
-type Key struct {
-	Value    gocui.Key
-	Modifier gocui.Modifier
-	Tokens   []string
-}
-
-func Parse(input string) (Key, error) {
-	f := func(c rune) bool { return unicode.IsSpace(c) || c == '+' }
-	tokens := strings.FieldsFunc(input, f)
-	var normalizedTokens []string
-	var modifier = gocui.ModNone
-
-	for _, token := range tokens {
-		normalized := strings.ToLower(token)
-
-		if value, exists := translate[normalized]; exists {
-			normalized = value
-		} else {
-			normalized = strings.Title(normalized)
-		}
-
-		if normalized == "Alt" {
-			modifier = gocui.ModAlt
-			continue
-		}
-
-		if len(normalized) == 1 {
-			normalizedTokens = append(normalizedTokens, strings.ToUpper(normalized))
-			continue
-		}
-
-		normalizedTokens = append(normalizedTokens, normalized)
-	}
-
-	lookup := "Key" + strings.Join(normalizedTokens, "")
-
-	if key, exists := supportedKeybindings[lookup]; exists {
-		return Key{key, modifier, normalizedTokens}, nil
-	}
-
-	if modifier != gocui.ModNone {
-		return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s (+%+v)", lookup, modifier)
-	}
-	return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s", lookup)
-}
-
-func ParseAll(input string) ([]Key, error) {
-	ret := make([]Key, 0)
-	for _, value := range strings.Split(input, ",") {
-		key, err := Parse(value)
-		if err != nil {
-			return nil, fmt.Errorf("could not parse keybinding '%s' from request '%s': %+v", value, input, err)
-		}
-		ret = append(ret, key)
-	}
-	if len(ret) == 0 {
-		return nil, fmt.Errorf("must have at least one keybinding")
-	}
-	return ret, nil
-}
-
-func (key Key) String() string {
-	displayTokens := make([]string, 0)
-	prefix := ""
-	for _, token := range key.Tokens {
-		if token == "Ctrl" {
-			prefix = "^"
-			continue
-		}
-		if value, exists := display[token]; exists {
-			token = value
-		}
-		displayTokens = append(displayTokens, token)
-	}
-	return prefix + strings.Join(displayTokens, "+")
-}

From d4a9c0807956450e990405c136cdf868a2d160d7 Mon Sep 17 00:00:00 2001
From: cxsu <imcxsu@gmail.com>
Date: Sun, 27 Dec 2020 21:55:27 +0900
Subject: [PATCH 3/3] Fix detail wrap option

---
 runtime/ui/view/details.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/runtime/ui/view/details.go b/runtime/ui/view/details.go
index 5f21730..43ea329 100644
--- a/runtime/ui/view/details.go
+++ b/runtime/ui/view/details.go
@@ -2,13 +2,14 @@ package view
 
 import (
 	"fmt"
+	"strconv"
+	"strings"
+
 	"github.com/sirupsen/logrus"
 	"github.com/wagoodman/dive/dive/filetree"
 	"github.com/wagoodman/dive/dive/image"
 	"github.com/wagoodman/dive/runtime/ui/format"
 	"github.com/wagoodman/dive/runtime/ui/key"
-	"strconv"
-	"strings"
 
 	"github.com/awesome-gocui/gocui"
 	"github.com/dustin/go-humanize"
@@ -55,7 +56,7 @@ func (v *Details) Setup(view *gocui.View, header *gocui.View) error {
 	// set controller options
 	v.view = view
 	v.view.Editable = false
-	v.view.Wrap = true
+	v.view.Wrap = false
 	v.view.Highlight = false
 	v.view.Frame = false