187 lines
5.0 KiB
Go
187 lines
5.0 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/jroimartin/gocui"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
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
|
|
input string
|
|
}
|
|
|
|
func getKeybinding(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, input}, nil
|
|
}
|
|
|
|
if modifier != gocui.ModNone {
|
|
return Key{0, modifier, normalizedTokens, input}, fmt.Errorf("unsupported keybinding: %s (+%+v)", lookup, modifier)
|
|
}
|
|
return Key{0, modifier, normalizedTokens, input}, fmt.Errorf("unsupported keybinding: %s", lookup)
|
|
}
|
|
|
|
func getKeybindings(input string) []Key {
|
|
ret := make([]Key, 0)
|
|
for _, value := range strings.Split(input, ",") {
|
|
key, err := getKeybinding(value)
|
|
if err != nil {
|
|
panic(fmt.Errorf("could not parse keybinding '%s' from request '%s': %+v", value, input, err))
|
|
}
|
|
ret = append(ret, key)
|
|
}
|
|
if len(ret) == 0 {
|
|
panic(fmt.Errorf("must have at least one keybinding"))
|
|
}
|
|
return ret
|
|
}
|
|
|
|
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, "+")
|
|
}
|