key.go 5.4 KB

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