gtsocial-umbx

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

code_span.go (2178B)


      1 package parser
      2 
      3 import (
      4 	"github.com/yuin/goldmark/ast"
      5 	"github.com/yuin/goldmark/text"
      6 )
      7 
      8 type codeSpanParser struct {
      9 }
     10 
     11 var defaultCodeSpanParser = &codeSpanParser{}
     12 
     13 // NewCodeSpanParser return a new InlineParser that parses inline codes
     14 // surrounded by '`' .
     15 func NewCodeSpanParser() InlineParser {
     16 	return defaultCodeSpanParser
     17 }
     18 
     19 func (s *codeSpanParser) Trigger() []byte {
     20 	return []byte{'`'}
     21 }
     22 
     23 func (s *codeSpanParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node {
     24 	line, startSegment := block.PeekLine()
     25 	opener := 0
     26 	for ; opener < len(line) && line[opener] == '`'; opener++ {
     27 	}
     28 	block.Advance(opener)
     29 	l, pos := block.Position()
     30 	node := ast.NewCodeSpan()
     31 	for {
     32 		line, segment := block.PeekLine()
     33 		if line == nil {
     34 			block.SetPosition(l, pos)
     35 			return ast.NewTextSegment(startSegment.WithStop(startSegment.Start + opener))
     36 		}
     37 		for i := 0; i < len(line); i++ {
     38 			c := line[i]
     39 			if c == '`' {
     40 				oldi := i
     41 				for ; i < len(line) && line[i] == '`'; i++ {
     42 				}
     43 				closure := i - oldi
     44 				if closure == opener && (i >= len(line) || line[i] != '`') {
     45 					segment = segment.WithStop(segment.Start + i - closure)
     46 					if !segment.IsEmpty() {
     47 						node.AppendChild(node, ast.NewRawTextSegment(segment))
     48 					}
     49 					block.Advance(i)
     50 					goto end
     51 				}
     52 			}
     53 		}
     54 		node.AppendChild(node, ast.NewRawTextSegment(segment))
     55 		block.AdvanceLine()
     56 	}
     57 end:
     58 	if !node.IsBlank(block.Source()) {
     59 		// trim first halfspace and last halfspace
     60 		segment := node.FirstChild().(*ast.Text).Segment
     61 		shouldTrimmed := true
     62 		if !(!segment.IsEmpty() && isSpaceOrNewline(block.Source()[segment.Start])) {
     63 			shouldTrimmed = false
     64 		}
     65 		segment = node.LastChild().(*ast.Text).Segment
     66 		if !(!segment.IsEmpty() && isSpaceOrNewline(block.Source()[segment.Stop-1])) {
     67 			shouldTrimmed = false
     68 		}
     69 		if shouldTrimmed {
     70 			t := node.FirstChild().(*ast.Text)
     71 			segment := t.Segment
     72 			t.Segment = segment.WithStart(segment.Start + 1)
     73 			t = node.LastChild().(*ast.Text)
     74 			segment = node.LastChild().(*ast.Text).Segment
     75 			t.Segment = segment.WithStop(segment.Stop - 1)
     76 		}
     77 
     78 	}
     79 	return node
     80 }
     81 
     82 func isSpaceOrNewline(c byte) bool {
     83 	return c == ' ' || c == '\n'
     84 }