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