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