gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }