func (r *blockReader ) ReadRune () (rune , int , error ) {
return readRuneReader (r )
}
func (r *blockReader ) PrecendingCharacter () rune {
if r .pos .Padding != 0 {
return rune (' ' )
}
if r .segments .Len () < 1 {
return rune ('\n' )
}
firstSegment := r .segments .At (0 )
if r .line == 0 && r .pos .Start <= firstSegment .Start {
return rune ('\n' )
}
l := len (r .source )
i := r .pos .Start - 1
for ; i < l && i >= 0 ; i -- {
if utf8 .RuneStart (r .source [i ]) {
break
}
}
if i < 0 || i >= l {
return rune ('\n' )
}
rn , _ := utf8 .DecodeRune (r .source [i :])
return rn
}
func (r *blockReader ) LineOffset () int {
if r .lineOffset < 0 {
v := 0
for i := r .head ; i < r .pos .Start ; i ++ {
if r .source [i ] == '\t' {
v += util .TabWidth (v )
} else {
v ++
}
}
r .lineOffset = v - r .pos .Padding
}
return r .lineOffset
}
func (r *blockReader ) Peek () byte {
if r .line < r .segmentsLength && r .pos .Start >= 0 && r .pos .Start < r .last {
if r .pos .Padding != 0 {
return space [0 ]
}
return r .source [r .pos .Start ]
}
return EOF
}
func (r *blockReader ) PeekLine () ([]byte , Segment ) {
if r .line < r .segmentsLength && r .pos .Start >= 0 && r .pos .Start < r .last {
return r .pos .Value (r .source ), r .pos
}
return nil , r .pos
}
func (r *blockReader ) Advance (n int ) {
r .lineOffset = -1
if n < r .pos .Stop -r .pos .Start && r .pos .Padding == 0 {
r .pos .Start += n
return
}
for ; n > 0 ; n -- {
if r .pos .Padding != 0 {
r .pos .Padding --
continue
}
if r .pos .Start >= r .pos .Stop -1 && r .pos .Stop < r .last {
r .AdvanceLine ()
continue
}
r .pos .Start ++
}
}
func (r *blockReader ) AdvanceAndSetPadding (n , padding int ) {
r .Advance (n )
if padding > r .pos .Padding {
r .SetPadding (padding )
}
}
func (r *blockReader ) AdvanceLine () {
r .SetPosition (r .line +1 , NewSegment (invalidValue , invalidValue ))
r .head = r .pos .Start
}
func (r *blockReader ) Position () (int , Segment ) {
return r .line , r .pos
}
func (r *blockReader ) SetPosition (line int , pos Segment ) {
r .lineOffset = -1
r .line = line
if pos .Start == invalidValue {
if r .line < r .segmentsLength {
s := r .segments .At (line )
r .head = s .Start
r .pos = s
}
} else {
r .pos = pos
if r .line < r .segmentsLength {
s := r .segments .At (line )
r .head = s .Start
}
}
}
func (r *blockReader ) SetPadding (v int ) {
r .lineOffset = -1
r .pos .Padding = v
}
func (r *blockReader ) SkipSpaces () (Segment , int , bool ) {
return skipSpacesReader (r )
}
func (r *blockReader ) SkipBlankLines () (Segment , int , bool ) {
return skipBlankLinesReader (r )
}
func (r *blockReader ) Match (reg *regexp .Regexp ) bool {
return matchReader (r , reg )
}
func (r *blockReader ) FindSubMatch (reg *regexp .Regexp ) [][]byte {
return findSubMatchReader (r , reg )
}
func skipBlankLinesReader (r Reader ) (Segment , int , bool ) {
lines := 0
for {
line , seg := r .PeekLine ()
if line == nil {
return seg , lines , false
}
if util .IsBlank (line ) {
lines ++
r .AdvanceLine ()
} else {
return seg , lines , true
}
}
}
func skipSpacesReader (r Reader ) (Segment , int , bool ) {
chars := 0
for {
line , segment := r .PeekLine ()
if line == nil {
return segment , chars , false
}
for i , c := range line {
if util .IsSpace (c ) {
chars ++
r .Advance (1 )
continue
}
return segment .WithStart (segment .Start + i + 1 ), chars , true
}
}
}
func matchReader (r Reader , reg *regexp .Regexp ) bool {
oldline , oldseg := r .Position ()
match := reg .FindReaderSubmatchIndex (r )
r .SetPosition (oldline , oldseg )
if match == nil {
return false
}
r .Advance (match [1 ] - match [0 ])
return true
}
func findSubMatchReader (r Reader , reg *regexp .Regexp ) [][]byte {
oldline , oldseg := r .Position ()
match := reg .FindReaderSubmatchIndex (r )
r .SetPosition (oldline , oldseg )
if match == nil {
return nil
}
runes := make ([]rune , 0 , match [1 ]-match [0 ])
for i := 0 ; i < match [1 ]; {
r , size , _ := readRuneReader (r )
i += size
runes = append (runes , r )
}
result := [][]byte {}
for i := 0 ; i < len (match ); i += 2 {
result = append (result , []byte (string (runes [match [i ]:match [i +1 ]])))
}
r .SetPosition (oldline , oldseg )
r .Advance (match [1 ] - match [0 ])
return result
}
func readRuneReader (r Reader ) (rune , int , error ) {
line , _ := r .PeekLine ()
if line == nil {
return 0 , 0 , io .EOF
}
rn , size := utf8 .DecodeRune (line )
if rn == utf8 .RuneError {
return 0 , 0 , io .EOF
}
r .Advance (size )
return rn , size , nil