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 }