1package text 2 3import ( 4 "bytes" 5 "github.com/yuin/goldmark/util" 6) 7 8var space = []byte(" ") 9 10// A Segment struct holds information about source positions. 11type 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. 24func 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. 33func 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. 42func (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. 52func (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. 57func (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. 69func (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. 75func (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. 86func (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. 94func (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. 127func (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. 132func (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. 137func (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. 145type Segments struct { 146 values []Segment 147} 148 149// NewSegments return a new Segments. 150func NewSegments() *Segments { 151 return &Segments{ 152 values: nil, 153 } 154} 155 156// Append appends the given segment after the tail of the collection. 157func (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. 165func (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. 173func (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. 181func (s *Segments) At(i int) Segment { 182 return s.values[i] 183} 184 185// Set sets the given Segment. 186func (s *Segments) Set(i int, v Segment) { 187 s.values[i] = v 188} 189 190// SetSliced replace the collection with a subsliced value. 191func (s *Segments) SetSliced(lo, hi int) { 192 s.values = s.values[lo:hi] 193} 194 195// Sliced returns a subslice of the collection. 196func (s *Segments) Sliced(lo, hi int) []Segment { 197 return s.values[lo:hi] 198} 199 200// Clear delete all element of the collection. 201func (s *Segments) Clear() { 202 s.values = nil 203} 204 205// Unshift insert the given Segment to head of the collection. 206func (s *Segments) Unshift(v Segment) { 207 s.values = append(s.values[0:1], s.values[0:]...) 208 s.values[0] = v 209} 210