|
| 1 | +package keybinding |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "github.com/jroimartin/gocui" |
| 6 | + "strings" |
| 7 | + "unicode" |
| 8 | +) |
| 9 | + |
| 10 | +var translate = map[string]string{ |
| 11 | + "/": "Slash", |
| 12 | + "\\": "Backslash", |
| 13 | + "[": "LsqBracket", |
| 14 | + "]": "RsqBracket", |
| 15 | + "_": "Underscore", |
| 16 | + "escape": "Esc", |
| 17 | + "~": "Tilde", |
| 18 | + "pageup": "Pgup", |
| 19 | + "pagedown": "Pgdn", |
| 20 | + "pgup": "Pgup", |
| 21 | + "pgdown": "Pgdn", |
| 22 | + "up": "ArrowUp", |
| 23 | + "down": "ArrowDown", |
| 24 | + "right": "ArrowRight", |
| 25 | + "left": "ArrowLeft", |
| 26 | + "ctl": "Ctrl", |
| 27 | +} |
| 28 | + |
| 29 | +var display = map[string]string{ |
| 30 | + "Slash": "/", |
| 31 | + "Backslash": "\\", |
| 32 | + "LsqBracket": "[", |
| 33 | + "RsqBracket": "]", |
| 34 | + "Underscore": "_", |
| 35 | + "Tilde": "~", |
| 36 | + "Ctrl": "^", |
| 37 | +} |
| 38 | + |
| 39 | +var supportedKeybindings = map[string]gocui.Key{ |
| 40 | + "KeyF1": gocui.KeyF1, |
| 41 | + "KeyF2": gocui.KeyF2, |
| 42 | + "KeyF3": gocui.KeyF3, |
| 43 | + "KeyF4": gocui.KeyF4, |
| 44 | + "KeyF5": gocui.KeyF5, |
| 45 | + "KeyF6": gocui.KeyF6, |
| 46 | + "KeyF7": gocui.KeyF7, |
| 47 | + "KeyF8": gocui.KeyF8, |
| 48 | + "KeyF9": gocui.KeyF9, |
| 49 | + "KeyF10": gocui.KeyF10, |
| 50 | + "KeyF11": gocui.KeyF11, |
| 51 | + "KeyF12": gocui.KeyF12, |
| 52 | + "KeyInsert": gocui.KeyInsert, |
| 53 | + "KeyDelete": gocui.KeyDelete, |
| 54 | + "KeyHome": gocui.KeyHome, |
| 55 | + "KeyEnd": gocui.KeyEnd, |
| 56 | + "KeyPgup": gocui.KeyPgup, |
| 57 | + "KeyPgdn": gocui.KeyPgdn, |
| 58 | + "KeyArrowUp": gocui.KeyArrowUp, |
| 59 | + "KeyArrowDown": gocui.KeyArrowDown, |
| 60 | + "KeyArrowLeft": gocui.KeyArrowLeft, |
| 61 | + "KeyArrowRight": gocui.KeyArrowRight, |
| 62 | + "KeyCtrlTilde": gocui.KeyCtrlTilde, |
| 63 | + "KeyCtrl2": gocui.KeyCtrl2, |
| 64 | + "KeyCtrlSpace": gocui.KeyCtrlSpace, |
| 65 | + "KeyCtrlA": gocui.KeyCtrlA, |
| 66 | + "KeyCtrlB": gocui.KeyCtrlB, |
| 67 | + "KeyCtrlC": gocui.KeyCtrlC, |
| 68 | + "KeyCtrlD": gocui.KeyCtrlD, |
| 69 | + "KeyCtrlE": gocui.KeyCtrlE, |
| 70 | + "KeyCtrlF": gocui.KeyCtrlF, |
| 71 | + "KeyCtrlG": gocui.KeyCtrlG, |
| 72 | + "KeyBackspace": gocui.KeyBackspace, |
| 73 | + "KeyCtrlH": gocui.KeyCtrlH, |
| 74 | + "KeyTab": gocui.KeyTab, |
| 75 | + "KeyCtrlI": gocui.KeyCtrlI, |
| 76 | + "KeyCtrlJ": gocui.KeyCtrlJ, |
| 77 | + "KeyCtrlK": gocui.KeyCtrlK, |
| 78 | + "KeyCtrlL": gocui.KeyCtrlL, |
| 79 | + "KeyEnter": gocui.KeyEnter, |
| 80 | + "KeyCtrlM": gocui.KeyCtrlM, |
| 81 | + "KeyCtrlN": gocui.KeyCtrlN, |
| 82 | + "KeyCtrlO": gocui.KeyCtrlO, |
| 83 | + "KeyCtrlP": gocui.KeyCtrlP, |
| 84 | + "KeyCtrlQ": gocui.KeyCtrlQ, |
| 85 | + "KeyCtrlR": gocui.KeyCtrlR, |
| 86 | + "KeyCtrlS": gocui.KeyCtrlS, |
| 87 | + "KeyCtrlT": gocui.KeyCtrlT, |
| 88 | + "KeyCtrlU": gocui.KeyCtrlU, |
| 89 | + "KeyCtrlV": gocui.KeyCtrlV, |
| 90 | + "KeyCtrlW": gocui.KeyCtrlW, |
| 91 | + "KeyCtrlX": gocui.KeyCtrlX, |
| 92 | + "KeyCtrlY": gocui.KeyCtrlY, |
| 93 | + "KeyCtrlZ": gocui.KeyCtrlZ, |
| 94 | + "KeyEsc": gocui.KeyEsc, |
| 95 | + "KeyCtrlLsqBracket": gocui.KeyCtrlLsqBracket, |
| 96 | + "KeyCtrl3": gocui.KeyCtrl3, |
| 97 | + "KeyCtrl4": gocui.KeyCtrl4, |
| 98 | + "KeyCtrlBackslash": gocui.KeyCtrlBackslash, |
| 99 | + "KeyCtrl5": gocui.KeyCtrl5, |
| 100 | + "KeyCtrlRsqBracket": gocui.KeyCtrlRsqBracket, |
| 101 | + "KeyCtrl6": gocui.KeyCtrl6, |
| 102 | + "KeyCtrl7": gocui.KeyCtrl7, |
| 103 | + "KeyCtrlSlash": gocui.KeyCtrlSlash, |
| 104 | + "KeyCtrlUnderscore": gocui.KeyCtrlUnderscore, |
| 105 | + "KeySpace": gocui.KeySpace, |
| 106 | + "KeyBackspace2": gocui.KeyBackspace2, |
| 107 | + "KeyCtrl8": gocui.KeyCtrl8, |
| 108 | +} |
| 109 | + |
| 110 | +type Key struct { |
| 111 | + Value gocui.Key |
| 112 | + Modifier gocui.Modifier |
| 113 | + Tokens []string |
| 114 | +} |
| 115 | + |
| 116 | +func Parse(input string) (Key, error) { |
| 117 | + f := func(c rune) bool { return unicode.IsSpace(c) || c == '+' } |
| 118 | + tokens := strings.FieldsFunc(input, f) |
| 119 | + var normalizedTokens []string |
| 120 | + var modifier = gocui.ModNone |
| 121 | + |
| 122 | + for _, token := range tokens { |
| 123 | + normalized := strings.ToLower(token) |
| 124 | + |
| 125 | + if value, exists := translate[normalized]; exists { |
| 126 | + normalized = value |
| 127 | + } else { |
| 128 | + normalized = strings.Title(normalized) |
| 129 | + } |
| 130 | + |
| 131 | + if normalized == "Alt" { |
| 132 | + modifier = gocui.ModAlt |
| 133 | + continue |
| 134 | + } |
| 135 | + |
| 136 | + if len(normalized) == 1 { |
| 137 | + normalizedTokens = append(normalizedTokens, strings.ToUpper(normalized)) |
| 138 | + continue |
| 139 | + } |
| 140 | + |
| 141 | + normalizedTokens = append(normalizedTokens, normalized) |
| 142 | + } |
| 143 | + |
| 144 | + lookup := "Key" + strings.Join(normalizedTokens, "") |
| 145 | + |
| 146 | + if key, exists := supportedKeybindings[lookup]; exists { |
| 147 | + return Key{key, modifier, normalizedTokens}, nil |
| 148 | + } |
| 149 | + |
| 150 | + if modifier != gocui.ModNone { |
| 151 | + return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s (+%+v)", lookup, modifier) |
| 152 | + } |
| 153 | + return Key{0, modifier, normalizedTokens}, fmt.Errorf("unsupported keybinding: %s", lookup) |
| 154 | +} |
| 155 | + |
| 156 | +func ParseAll(input string) ([]Key, error) { |
| 157 | + ret := make([]Key, 0) |
| 158 | + for _, value := range strings.Split(input, ",") { |
| 159 | + key, err := Parse(value) |
| 160 | + if err != nil { |
| 161 | + return nil, fmt.Errorf("could not parse keybinding '%s' from request '%s': %+v", value, input, err) |
| 162 | + } |
| 163 | + ret = append(ret, key) |
| 164 | + } |
| 165 | + if len(ret) == 0 { |
| 166 | + return nil, fmt.Errorf("must have at least one keybinding") |
| 167 | + } |
| 168 | + return ret, nil |
| 169 | +} |
| 170 | + |
| 171 | +func (key Key) String() string { |
| 172 | + displayTokens := make([]string, 0) |
| 173 | + prefix := "" |
| 174 | + for _, token := range key.Tokens { |
| 175 | + if token == "Ctrl" { |
| 176 | + prefix = "^" |
| 177 | + continue |
| 178 | + } |
| 179 | + if value, exists := display[token]; exists { |
| 180 | + token = value |
| 181 | + } |
| 182 | + displayTokens = append(displayTokens, token) |
| 183 | + } |
| 184 | + return prefix + strings.Join(displayTokens, "+") |
| 185 | +} |
0 commit comments