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