You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
4.7 KiB

  1. package text
  2. import (
  3. "bytes"
  4. "github.com/yuin/goldmark/util"
  5. )
  6. var space = []byte(" ")
  7. // A Segment struct holds information about source potisions.
  8. type Segment struct {
  9. // Start is a start position of the segment.
  10. Start int
  11. // Stop is a stop position of the segment.
  12. // This value should be excluded.
  13. Stop int
  14. // Padding is a padding length of the segment.
  15. Padding int
  16. }
  17. // NewSegment return a new Segment.
  18. func NewSegment(start, stop int) Segment {
  19. return Segment{
  20. Start: start,
  21. Stop: stop,
  22. Padding: 0,
  23. }
  24. }
  25. // NewSegmentPadding returns a new Segment with the given padding.
  26. func NewSegmentPadding(start, stop, n int) Segment {
  27. return Segment{
  28. Start: start,
  29. Stop: stop,
  30. Padding: n,
  31. }
  32. }
  33. // Value returns a value of the segment.
  34. func (t *Segment) Value(buffer []byte) []byte {
  35. if t.Padding == 0 {
  36. return buffer[t.Start:t.Stop]
  37. }
  38. result := make([]byte, 0, t.Padding+t.Stop-t.Start+1)
  39. result = append(result, bytes.Repeat(space, t.Padding)...)
  40. return append(result, buffer[t.Start:t.Stop]...)
  41. }
  42. // Len returns a length of the segment.
  43. func (t *Segment) Len() int {
  44. return t.Stop - t.Start + t.Padding
  45. }
  46. // Between returns a segment between this segment and the given segment.
  47. func (t *Segment) Between(other Segment) Segment {
  48. if t.Stop != other.Stop {
  49. panic("invalid state")
  50. }
  51. return NewSegmentPadding(
  52. t.Start,
  53. other.Start,
  54. t.Padding-other.Padding,
  55. )
  56. }
  57. // IsEmpty returns true if this segment is empty, otherwise false.
  58. func (t *Segment) IsEmpty() bool {
  59. return t.Start >= t.Stop && t.Padding == 0
  60. }
  61. // TrimRightSpace returns a new segment by slicing off all trailing
  62. // space characters.
  63. func (t *Segment) TrimRightSpace(buffer []byte) Segment {
  64. v := buffer[t.Start:t.Stop]
  65. l := util.TrimRightSpaceLength(v)
  66. if l == len(v) {
  67. return NewSegment(t.Start, t.Start)
  68. }
  69. return NewSegmentPadding(t.Start, t.Stop-l, t.Padding)
  70. }
  71. // TrimLeftSpace returns a new segment by slicing off all leading
  72. // space characters including padding.
  73. func (t *Segment) TrimLeftSpace(buffer []byte) Segment {
  74. v := buffer[t.Start:t.Stop]
  75. l := util.TrimLeftSpaceLength(v)
  76. return NewSegment(t.Start+l, t.Stop)
  77. }
  78. // TrimLeftSpaceWidth returns a new segment by slicing off leading space
  79. // characters until the given width.
  80. func (t *Segment) TrimLeftSpaceWidth(width int, buffer []byte) Segment {
  81. padding := t.Padding
  82. for ; width > 0; width-- {
  83. if padding == 0 {
  84. break
  85. }
  86. padding--
  87. }
  88. if width == 0 {
  89. return NewSegmentPadding(t.Start, t.Stop, padding)
  90. }
  91. text := buffer[t.Start:t.Stop]
  92. start := t.Start
  93. for _, c := range text {
  94. if start >= t.Stop-1 || width <= 0 {
  95. break
  96. }
  97. if c == ' ' {
  98. width--
  99. } else if c == '\t' {
  100. width -= 4
  101. } else {
  102. break
  103. }
  104. start++
  105. }
  106. if width < 0 {
  107. padding = width * -1
  108. }
  109. return NewSegmentPadding(start, t.Stop, padding)
  110. }
  111. // WithStart returns a new Segment with same value except Start.
  112. func (t *Segment) WithStart(v int) Segment {
  113. return NewSegmentPadding(v, t.Stop, t.Padding)
  114. }
  115. // WithStop returns a new Segment with same value except Stop.
  116. func (t *Segment) WithStop(v int) Segment {
  117. return NewSegmentPadding(t.Start, v, t.Padding)
  118. }
  119. // ConcatPadding concats the padding to the given slice.
  120. func (t *Segment) ConcatPadding(v []byte) []byte {
  121. if t.Padding > 0 {
  122. return append(v, bytes.Repeat(space, t.Padding)...)
  123. }
  124. return v
  125. }
  126. // Segments is a collection of the Segment.
  127. type Segments struct {
  128. values []Segment
  129. }
  130. // NewSegments return a new Segments.
  131. func NewSegments() *Segments {
  132. return &Segments{
  133. values: nil,
  134. }
  135. }
  136. // Append appends the given segment after the tail of the collection.
  137. func (s *Segments) Append(t Segment) {
  138. if s.values == nil {
  139. s.values = make([]Segment, 0, 20)
  140. }
  141. s.values = append(s.values, t)
  142. }
  143. // AppendAll appends all elements of given segments after the tail of the collection.
  144. func (s *Segments) AppendAll(t []Segment) {
  145. if s.values == nil {
  146. s.values = make([]Segment, 0, 20)
  147. }
  148. s.values = append(s.values, t...)
  149. }
  150. // Len returns the length of the collection.
  151. func (s *Segments) Len() int {
  152. if s.values == nil {
  153. return 0
  154. }
  155. return len(s.values)
  156. }
  157. // At returns a segment at the given index.
  158. func (s *Segments) At(i int) Segment {
  159. return s.values[i]
  160. }
  161. // Set sets the given Segment.
  162. func (s *Segments) Set(i int, v Segment) {
  163. s.values[i] = v
  164. }
  165. // SetSliced replace the collection with a subsliced value.
  166. func (s *Segments) SetSliced(lo, hi int) {
  167. s.values = s.values[lo:hi]
  168. }
  169. // Sliced returns a subslice of the collection.
  170. func (s *Segments) Sliced(lo, hi int) []Segment {
  171. return s.values[lo:hi]
  172. }
  173. // Clear delete all element of the collction.
  174. func (s *Segments) Clear() {
  175. s.values = nil
  176. }
  177. // Unshift insert the given Segment to head of the collection.
  178. func (s *Segments) Unshift(v Segment) {
  179. s.values = append(s.values[0:1], s.values[0:]...)
  180. s.values[0] = v
  181. }