github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/ui/key.go (about) 1 package ui 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "src.elv.sh/pkg/parse" 9 "src.elv.sh/pkg/persistent/hash" 10 ) 11 12 // Key represents a single keyboard input, typically assembled from a escape 13 // sequence. 14 type Key struct { 15 Rune rune 16 Mod Mod 17 } 18 19 // K constructs a new Key. 20 func K(r rune, mods ...Mod) Key { 21 var mod Mod 22 for _, m := range mods { 23 mod |= m 24 } 25 return Key{r, mod} 26 } 27 28 // Default is used in the key binding table to indicate a default binding. 29 var Default = Key{DefaultBindingRune, 0} 30 31 // Mod represents a modifier key. 32 type Mod byte 33 34 // Values for Mod. 35 const ( 36 // Shift is the shift modifier. It is only applied to special keys (e.g. 37 // Shift-F1). For instance 'A' and '@' which are typically entered with the 38 // shift key pressed, are not considered to be shift-modified. 39 Shift Mod = 1 << iota 40 // Alt is the alt modifier, traditionally known as the meta modifier. 41 Alt 42 Ctrl 43 ) 44 45 const functionKeyOffset = 1000 46 47 // Special negative runes to represent function keys, used in the Rune field 48 // of the Key struct. This also has a few function names that are aliases for 49 // simple runes. See keyNames below for mapping these values to strings. 50 const ( 51 // DefaultBindingRune is a special value to represent a default binding. 52 DefaultBindingRune rune = iota - functionKeyOffset 53 54 F1 55 F2 56 F3 57 F4 58 F5 59 F6 60 F7 61 F8 62 F9 63 F10 64 F11 65 F12 66 67 Up 68 Down 69 Right 70 Left 71 72 Home 73 Insert 74 Delete 75 End 76 PageUp 77 PageDown 78 79 // Function key names that are aliases for their ASCII representation. 80 Tab = '\t' 81 Enter = '\n' 82 Backspace = 0x7f 83 ) 84 85 // keyNames maps runes, whether simple or function, to symbolic key names. 86 var keyNames = map[rune]string{ 87 DefaultBindingRune: "Default", 88 F1: "F1", 89 F2: "F2", 90 F3: "F3", 91 F4: "F4", 92 F5: "F5", 93 F6: "F6", 94 F7: "F7", 95 F8: "F8", 96 F9: "F9", 97 F10: "F10", 98 F11: "F11", 99 F12: "F12", 100 Up: "Up", 101 Down: "Down", 102 Right: "Right", 103 Left: "Left", 104 Home: "Home", 105 Insert: "Insert", 106 Delete: "Delete", 107 End: "End", 108 PageUp: "PageUp", 109 PageDown: "PageDown", 110 Tab: "Tab", 111 Enter: "Enter", 112 Backspace: "Backspace", 113 } 114 115 func (k Key) Kind() string { 116 return "edit:key" 117 } 118 119 func (k Key) Equal(other interface{}) bool { 120 return k == other 121 } 122 123 func (k Key) Hash() uint32 { 124 return hash.DJB(uint32(k.Rune), uint32(k.Mod)) 125 } 126 127 func (k Key) Repr(int) string { 128 return "(edit:key " + parse.Quote(k.String()) + ")" 129 } 130 131 func (k Key) String() string { 132 var b bytes.Buffer 133 134 if k.Mod&Ctrl != 0 { 135 b.WriteString("Ctrl-") 136 } 137 if k.Mod&Alt != 0 { 138 b.WriteString("Alt-") 139 } 140 if k.Mod&Shift != 0 { 141 b.WriteString("Shift-") 142 } 143 144 if name, ok := keyNames[k.Rune]; ok { 145 b.WriteString(name) 146 } else { 147 if k.Rune >= 0 { 148 b.WriteRune(k.Rune) 149 } else { 150 fmt.Fprintf(&b, "(bad function key %d)", k.Rune) 151 } 152 } 153 154 return b.String() 155 } 156 157 // modifierByName maps a name to an modifier. It is used for parsing keys where 158 // the modifier string is first turned to lower case, so that all of C, c, 159 // CTRL, Ctrl and ctrl can represent the Ctrl modifier. 160 var modifierByName = map[string]Mod{ 161 "S": Shift, "Shift": Shift, 162 "A": Alt, "Alt": Alt, 163 "M": Alt, "Meta": Alt, 164 "C": Ctrl, "Ctrl": Ctrl, 165 } 166 167 // ParseKey parses a symbolic key. The syntax is: 168 // 169 // Key = { Mod ('+' | '-') } BareKey 170 // 171 // BareKey = FunctionKeyName | SingleRune 172 func ParseKey(s string) (Key, error) { 173 var k Key 174 175 // Parse modifiers. 176 for { 177 i := strings.IndexAny(s, "+-") 178 if i == -1 { 179 break 180 } 181 modname := s[:i] 182 if mod, ok := modifierByName[modname]; ok { 183 k.Mod |= mod 184 s = s[i+1:] 185 } else { 186 return Key{}, fmt.Errorf("bad modifier: %s", parse.Quote(modname)) 187 } 188 } 189 190 if len(s) == 1 { 191 k.Rune = rune(s[0]) 192 if k.Rune < 0x20 { 193 if k.Mod&Ctrl != 0 { 194 return Key{}, fmt.Errorf("Ctrl modifier with literal control char: %q", k.Rune) 195 } 196 // Convert literal control char to the equivalent canonical form; 197 // e.g., "\e" to Ctrl-'[' and "\t" to Ctrl-I. 198 k.Mod |= Ctrl 199 k.Rune += 0x40 200 } 201 // TODO(xiaq): The following assumptions about keys with Ctrl are not 202 // checked with all terminals. 203 if k.Mod&Ctrl != 0 { 204 // Keys with Ctrl as one of the modifiers and a single ASCII letter 205 // as the base rune do not distinguish between cases. So we 206 // normalize the base rune to upper case. 207 if 'a' <= k.Rune && k.Rune <= 'z' { 208 k.Rune += 'A' - 'a' 209 } 210 // Normalize Ctrl-I to Tab, Ctrl-J to Enter, and Ctrl-? to Backspace. 211 if k.Rune == 'I' { 212 k.Mod &= ^Ctrl 213 k.Rune = Tab 214 } else if k.Rune == 'J' { 215 k.Mod &= ^Ctrl 216 k.Rune = Enter 217 } 218 } 219 return k, nil 220 } 221 222 // Is this is a symbolic key name, such as `Enter`, we recognize? 223 for r, name := range keyNames { 224 if s == name { 225 k.Rune = r 226 return k, nil 227 } 228 } 229 230 return Key{}, fmt.Errorf("bad key: %s", parse.Quote(s)) 231 } 232 233 // Keys implements sort.Interface. 234 type Keys []Key 235 236 func (ks Keys) Len() int { return len(ks) } 237 func (ks Keys) Swap(i, j int) { ks[i], ks[j] = ks[j], ks[i] } 238 func (ks Keys) Less(i, j int) bool { 239 return ks[i].Mod < ks[j].Mod || 240 (ks[i].Mod == ks[j].Mod && ks[i].Rune < ks[j].Rune) 241 }