key_sequences.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package tea
  2. import "sort"
  3. // extSequences is used by the map-based algorithm below. It contains
  4. // the sequences plus their alternatives with an escape character
  5. // prefixed, plus the control chars, plus the space.
  6. // It does not contain the NUL character, which is handled specially
  7. // by detectOneMsg.
  8. var extSequences = func() map[string]Key {
  9. s := map[string]Key{}
  10. for seq, key := range sequences {
  11. key := key
  12. s[seq] = key
  13. if !key.Alt {
  14. key.Alt = true
  15. s["\x1b"+seq] = key
  16. }
  17. }
  18. for i := keyNUL + 1; i <= keyDEL; i++ {
  19. if i == keyESC {
  20. continue
  21. }
  22. s[string([]byte{byte(i)})] = Key{Type: i}
  23. s[string([]byte{'\x1b', byte(i)})] = Key{Type: i, Alt: true}
  24. if i == keyUS {
  25. i = keyDEL - 1
  26. }
  27. }
  28. s[" "] = Key{Type: KeySpace, Runes: spaceRunes}
  29. s["\x1b "] = Key{Type: KeySpace, Alt: true, Runes: spaceRunes}
  30. s["\x1b\x1b"] = Key{Type: KeyEscape, Alt: true}
  31. return s
  32. }()
  33. // seqLengths is the sizes of valid sequences, starting with the
  34. // largest size.
  35. var seqLengths = func() []int {
  36. sizes := map[int]struct{}{}
  37. for seq := range extSequences {
  38. sizes[len(seq)] = struct{}{}
  39. }
  40. lsizes := make([]int, 0, len(sizes))
  41. for sz := range sizes {
  42. lsizes = append(lsizes, sz)
  43. }
  44. sort.Slice(lsizes, func(i, j int) bool { return lsizes[i] > lsizes[j] })
  45. return lsizes
  46. }()
  47. // detectSequence uses a longest prefix match over the input
  48. // sequence and a hash map.
  49. func detectSequence(input []byte) (hasSeq bool, width int, msg Msg) {
  50. seqs := extSequences
  51. for _, sz := range seqLengths {
  52. if sz > len(input) {
  53. continue
  54. }
  55. prefix := input[:sz]
  56. key, ok := seqs[string(prefix)]
  57. if ok {
  58. return true, sz, KeyMsg(key)
  59. }
  60. }
  61. // Is this an unknown CSI sequence?
  62. if loc := unknownCSIRe.FindIndex(input); loc != nil {
  63. return true, loc[1], unknownCSISequenceMsg(input[:loc[1]])
  64. }
  65. return false, 0, nil
  66. }