mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 08:32:25 -05:00 
			
		
		
		
	* add minify dependency specifically for markdown * rearrange markdown formatting * update markdown tests
		
			
				
	
	
		
			164 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package buffer
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| )
 | |
| 
 | |
| var nullBuffer = []byte{0}
 | |
| 
 | |
| // Lexer is a buffered reader that allows peeking forward and shifting, taking an io.Reader.
 | |
| // It keeps data in-memory until Free, taking a byte length, is called to move beyond the data.
 | |
| type Lexer struct {
 | |
| 	buf   []byte
 | |
| 	pos   int // index in buf
 | |
| 	start int // index in buf
 | |
| 	err   error
 | |
| 
 | |
| 	restore func()
 | |
| }
 | |
| 
 | |
| // NewLexer returns a new Lexer for a given io.Reader, and uses ioutil.ReadAll to read it into a byte slice.
 | |
| // If the io.Reader implements Bytes, that is used instead.
 | |
| // It will append a NULL at the end of the buffer.
 | |
| func NewLexer(r io.Reader) *Lexer {
 | |
| 	var b []byte
 | |
| 	if r != nil {
 | |
| 		if buffer, ok := r.(interface {
 | |
| 			Bytes() []byte
 | |
| 		}); ok {
 | |
| 			b = buffer.Bytes()
 | |
| 		} else {
 | |
| 			var err error
 | |
| 			b, err = ioutil.ReadAll(r)
 | |
| 			if err != nil {
 | |
| 				return &Lexer{
 | |
| 					buf: nullBuffer,
 | |
| 					err: err,
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return NewLexerBytes(b)
 | |
| }
 | |
| 
 | |
| // NewLexerBytes returns a new Lexer for a given byte slice, and appends NULL at the end.
 | |
| // To avoid reallocation, make sure the capacity has room for one more byte.
 | |
| func NewLexerBytes(b []byte) *Lexer {
 | |
| 	z := &Lexer{
 | |
| 		buf: b,
 | |
| 	}
 | |
| 
 | |
| 	n := len(b)
 | |
| 	if n == 0 {
 | |
| 		z.buf = nullBuffer
 | |
| 	} else {
 | |
| 		// Append NULL to buffer, but try to avoid reallocation
 | |
| 		if cap(b) > n {
 | |
| 			// Overwrite next byte but restore when done
 | |
| 			b = b[:n+1]
 | |
| 			c := b[n]
 | |
| 			b[n] = 0
 | |
| 
 | |
| 			z.buf = b
 | |
| 			z.restore = func() {
 | |
| 				b[n] = c
 | |
| 			}
 | |
| 		} else {
 | |
| 			z.buf = append(b, 0)
 | |
| 		}
 | |
| 	}
 | |
| 	return z
 | |
| }
 | |
| 
 | |
| // Restore restores the replaced byte past the end of the buffer by NULL.
 | |
| func (z *Lexer) Restore() {
 | |
| 	if z.restore != nil {
 | |
| 		z.restore()
 | |
| 		z.restore = nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Err returns the error returned from io.Reader or io.EOF when the end has been reached.
 | |
| func (z *Lexer) Err() error {
 | |
| 	return z.PeekErr(0)
 | |
| }
 | |
| 
 | |
| // PeekErr returns the error at position pos. When pos is zero, this is the same as calling Err().
 | |
| func (z *Lexer) PeekErr(pos int) error {
 | |
| 	if z.err != nil {
 | |
| 		return z.err
 | |
| 	} else if z.pos+pos >= len(z.buf)-1 {
 | |
| 		return io.EOF
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Peek returns the ith byte relative to the end position.
 | |
| // Peek returns 0 when an error has occurred, Err returns the error.
 | |
| func (z *Lexer) Peek(pos int) byte {
 | |
| 	pos += z.pos
 | |
| 	return z.buf[pos]
 | |
| }
 | |
| 
 | |
| // PeekRune returns the rune and rune length of the ith byte relative to the end position.
 | |
| func (z *Lexer) PeekRune(pos int) (rune, int) {
 | |
| 	// from unicode/utf8
 | |
| 	c := z.Peek(pos)
 | |
| 	if c < 0xC0 || z.Peek(pos+1) == 0 {
 | |
| 		return rune(c), 1
 | |
| 	} else if c < 0xE0 || z.Peek(pos+2) == 0 {
 | |
| 		return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2
 | |
| 	} else if c < 0xF0 || z.Peek(pos+3) == 0 {
 | |
| 		return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3
 | |
| 	}
 | |
| 	return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4
 | |
| }
 | |
| 
 | |
| // Move advances the position.
 | |
| func (z *Lexer) Move(n int) {
 | |
| 	z.pos += n
 | |
| }
 | |
| 
 | |
| // Pos returns a mark to which can be rewinded.
 | |
| func (z *Lexer) Pos() int {
 | |
| 	return z.pos - z.start
 | |
| }
 | |
| 
 | |
| // Rewind rewinds the position to the given position.
 | |
| func (z *Lexer) Rewind(pos int) {
 | |
| 	z.pos = z.start + pos
 | |
| }
 | |
| 
 | |
| // Lexeme returns the bytes of the current selection.
 | |
| func (z *Lexer) Lexeme() []byte {
 | |
| 	return z.buf[z.start:z.pos:z.pos]
 | |
| }
 | |
| 
 | |
| // Skip collapses the position to the end of the selection.
 | |
| func (z *Lexer) Skip() {
 | |
| 	z.start = z.pos
 | |
| }
 | |
| 
 | |
| // Shift returns the bytes of the current selection and collapses the position to the end of the selection.
 | |
| func (z *Lexer) Shift() []byte {
 | |
| 	b := z.buf[z.start:z.pos:z.pos]
 | |
| 	z.start = z.pos
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // Offset returns the character position in the buffer.
 | |
| func (z *Lexer) Offset() int {
 | |
| 	return z.pos
 | |
| }
 | |
| 
 | |
| // Bytes returns the underlying buffer.
 | |
| func (z *Lexer) Bytes() []byte {
 | |
| 	return z.buf[: len(z.buf)-1 : len(z.buf)-1]
 | |
| }
 | |
| 
 | |
| // Reset resets position to the underlying buffer.
 | |
| func (z *Lexer) Reset() {
 | |
| 	z.start = 0
 | |
| 	z.pos = 0
 | |
| }
 |