key_sequences.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package tea
  2. import (
  3. "bytes"
  4. "sort"
  5. "unicode/utf8"
  6. )
  7. // extSequences is used by the map-based algorithm below. It contains
  8. // the sequences plus their alternatives with an escape character
  9. // prefixed, plus the control chars, plus the space.
  10. // It does not contain the NUL character, which is handled specially
  11. // by detectOneMsg.
  12. var extSequences = func() map[string]Key {
  13. s := map[string]Key{}
  14. for seq, key := range sequences {
  15. key := key
  16. s[seq] = key
  17. if !key.Alt {
  18. key.Alt = true
  19. s["\x1b"+seq] = key
  20. }
  21. }
  22. for i := keyNUL + 1; i <= keyDEL; i++ {
  23. if i == keyESC {
  24. continue
  25. }
  26. s[string([]byte{byte(i)})] = Key{Type: i}
  27. s[string([]byte{'\x1b', byte(i)})] = Key{Type: i, Alt: true}
  28. if i == keyUS {
  29. i = keyDEL - 1
  30. }
  31. }
  32. s[" "] = Key{Type: KeySpace, Runes: spaceRunes}
  33. s["\x1b "] = Key{Type: KeySpace, Alt: true, Runes: spaceRunes}
  34. s["\x1b\x1b"] = Key{Type: KeyEscape, Alt: true}
  35. return s
  36. }()
  37. // seqLengths is the sizes of valid sequences, starting with the
  38. // largest size.
  39. var seqLengths = func() []int {
  40. sizes := map[int]struct{}{}
  41. for seq := range extSequences {
  42. sizes[len(seq)] = struct{}{}
  43. }
  44. lsizes := make([]int, 0, len(sizes))
  45. for sz := range sizes {
  46. lsizes = append(lsizes, sz)
  47. }
  48. sort.Slice(lsizes, func(i, j int) bool { return lsizes[i] > lsizes[j] })
  49. return lsizes
  50. }()
  51. // detectSequence uses a longest prefix match over the input
  52. // sequence and a hash map.
  53. func detectSequence(input []byte) (hasSeq bool, width int, msg Msg) {
  54. seqs := extSequences
  55. for _, sz := range seqLengths {
  56. if sz > len(input) {
  57. continue
  58. }
  59. prefix := input[:sz]
  60. key, ok := seqs[string(prefix)]
  61. if ok {
  62. return true, sz, KeyMsg(key)
  63. }
  64. }
  65. // Is this an unknown CSI sequence?
  66. if loc := unknownCSIRe.FindIndex(input); loc != nil {
  67. return true, loc[1], unknownCSISequenceMsg(input[:loc[1]])
  68. }
  69. return false, 0, nil
  70. }
  71. // detectBracketedPaste detects an input pasted while bracketed
  72. // paste mode was enabled.
  73. //
  74. // Note: this function is a no-op if bracketed paste was not enabled
  75. // on the terminal, since in that case we'd never see this
  76. // particular escape sequence.
  77. func detectBracketedPaste(input []byte) (hasBp bool, width int, msg Msg) {
  78. // Detect the start sequence.
  79. const bpStart = "\x1b[200~"
  80. if len(input) < len(bpStart) || string(input[:len(bpStart)]) != bpStart {
  81. return false, 0, nil
  82. }
  83. // Skip over the start sequence.
  84. input = input[len(bpStart):]
  85. // If we saw the start sequence, then we must have an end sequence
  86. // as well. Find it.
  87. const bpEnd = "\x1b[201~"
  88. idx := bytes.Index(input, []byte(bpEnd))
  89. inputLen := len(bpStart) + idx + len(bpEnd)
  90. if idx == -1 {
  91. // We have encountered the end of the input buffer without seeing
  92. // the marker for the end of the bracketed paste.
  93. // Tell the outer loop we have done a short read and we want more.
  94. return true, 0, nil
  95. }
  96. // The paste is everything in-between.
  97. paste := input[:idx]
  98. // All there is in-between is runes, not to be interpreted further.
  99. k := Key{Type: KeyRunes, Paste: true}
  100. for len(paste) > 0 {
  101. r, w := utf8.DecodeRune(paste)
  102. if r != utf8.RuneError {
  103. k.Runes = append(k.Runes, r)
  104. }
  105. paste = paste[w:]
  106. }
  107. return true, inputLen, KeyMsg(k)
  108. }