4
0

segment.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package codec
  2. import (
  3. "fmt"
  4. )
  5. // EncodedSegment represents a portion of text that is encoded in some way.
  6. type EncodedSegment struct {
  7. // predecessors are all of the segments from the previous decoding pass
  8. predecessors []*EncodedSegment
  9. // original start/end indices before decoding
  10. original startEnd
  11. // encoded start/end indices relative to the previous decoding pass.
  12. // If it's a top level segment, original and encoded will be the
  13. // same.
  14. encoded startEnd
  15. // decoded start/end indices in this pass after decoding
  16. decoded startEnd
  17. // decodedValue contains the decoded string for this segment
  18. decodedValue string
  19. // encodings is the encodings that make up this segment. encodingKind
  20. // can be or'd together to hold multiple encodings
  21. encodings encodingKind
  22. // depth is how many decoding passes it took to decode this segment
  23. depth int
  24. }
  25. // Tags returns additional meta data tags related to the types of segments
  26. func Tags(segments []*EncodedSegment) []string {
  27. // Return an empty list if we don't have any segments
  28. if len(segments) == 0 {
  29. return []string{}
  30. }
  31. // Since decoding is done in passes, the depth of all the segments
  32. // should be the same
  33. depth := segments[0].depth
  34. // Collect the encodings from the segments
  35. encodings := segments[0].encodings
  36. for i := 1; i < len(segments); i++ {
  37. encodings |= segments[i].encodings
  38. }
  39. kinds := encodings.kinds()
  40. tags := make([]string, len(kinds)+1)
  41. tags[len(tags)-1] = fmt.Sprintf("decode-depth:%d", depth)
  42. for i, kind := range kinds {
  43. tags[i] = fmt.Sprintf("decoded:%s", kind)
  44. }
  45. return tags
  46. }
  47. // CurrentLine returns from the start of the line containing the segments
  48. // to the end of the line where the segment ends.
  49. func CurrentLine(segments []*EncodedSegment, currentRaw string) string {
  50. // Return the whole thing if no segments are provided
  51. if len(segments) == 0 {
  52. return currentRaw
  53. }
  54. start := 0
  55. end := len(currentRaw)
  56. // Merge the ranges together into a single decoded value
  57. decoded := segments[0].decoded
  58. for i := 1; i < len(segments); i++ {
  59. decoded = decoded.merge(segments[i].decoded)
  60. }
  61. // Find the start of the range
  62. for i := decoded.start; i > -1; i-- {
  63. c := currentRaw[i]
  64. if c == '\n' {
  65. start = i
  66. break
  67. }
  68. }
  69. // Find the end of the range
  70. for i := decoded.end; i < end; i++ {
  71. c := currentRaw[i]
  72. if c == '\n' {
  73. end = i
  74. break
  75. }
  76. }
  77. return currentRaw[start:end]
  78. }
  79. // AdjustMatchIndex maps a match index from the current decode pass back to
  80. // its location in the original text
  81. func AdjustMatchIndex(segments []*EncodedSegment, matchIndex []int) []int {
  82. // Don't adjust if we're not provided any segments
  83. if len(segments) == 0 {
  84. return matchIndex
  85. }
  86. // Map the match to the location in the original text
  87. match := startEnd{matchIndex[0], matchIndex[1]}
  88. // Map the match to its orignal location
  89. adjusted := toOriginal(segments, match)
  90. // Return the adjusted match index
  91. return []int{
  92. adjusted.start,
  93. adjusted.end,
  94. }
  95. }
  96. // SegmentsWithDecodedOverlap the segments where the start and end overlap its
  97. // decoded range
  98. func SegmentsWithDecodedOverlap(segments []*EncodedSegment, start, end int) []*EncodedSegment {
  99. se := startEnd{start, end}
  100. overlaps := []*EncodedSegment{}
  101. for _, segment := range segments {
  102. if segment.decoded.overlaps(se) {
  103. overlaps = append(overlaps, segment)
  104. }
  105. }
  106. return overlaps
  107. }
  108. // toOriginal maps a start/end to its start/end in the original text
  109. // the provided start/end should be relative to the segment's decoded value
  110. func toOriginal(predecessors []*EncodedSegment, decoded startEnd) startEnd {
  111. if len(predecessors) == 0 {
  112. return decoded
  113. }
  114. // Map the decoded value one level up where it was encoded
  115. encoded := startEnd{}
  116. for _, p := range predecessors {
  117. if !p.decoded.overlaps(decoded) {
  118. continue // Not in scope
  119. }
  120. // If fully contained, return the segments original start/end
  121. if p.decoded.contains(decoded) {
  122. return p.original
  123. }
  124. // Map the value to be relative to the predecessors's decoded values
  125. if encoded.end == 0 {
  126. encoded = p.encoded.add(p.decoded.overflow(decoded))
  127. } else {
  128. encoded = encoded.merge(p.encoded.add(p.decoded.overflow(decoded)))
  129. }
  130. }
  131. // Should only get here if the thing passed in wasn't in a decoded
  132. // value. This shouldn't be the case
  133. if encoded.end == 0 {
  134. return decoded
  135. }
  136. // Climb up another level
  137. // (NOTE: each segment references all the predecessors)
  138. return toOriginal(predecessors[0].predecessors, encoded)
  139. }