package parser import ( "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" ) type codeSpanParser struct { } var defaultCodeSpanParser = &codeSpanParser{} // NewCodeSpanParser return a new InlineParser that parses inline codes // surrounded by '`' . func NewCodeSpanParser() InlineParser { return defaultCodeSpanParser } func (s *codeSpanParser) Trigger() []byte { return []byte{'`'} } func (s *codeSpanParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { line, startSegment := block.PeekLine() opener := 0 for ; opener < len(line) && line[opener] == '`'; opener++ { } block.Advance(opener) l, pos := block.Position() node := ast.NewCodeSpan() for { line, segment := block.PeekLine() if line == nil { block.SetPosition(l, pos) return ast.NewTextSegment(startSegment.WithStop(startSegment.Start + opener)) } for i := 0; i < len(line); i++ { c := line[i] if c == '`' { oldi := i for ; i < len(line) && line[i] == '`'; i++ { } closure := i - oldi if closure == opener && (i >= len(line) || line[i] != '`') { segment = segment.WithStop(segment.Start + i - closure) if !segment.IsEmpty() { node.AppendChild(node, ast.NewRawTextSegment(segment)) } block.Advance(i) goto end } } } if !util.IsBlank(line) { node.AppendChild(node, ast.NewRawTextSegment(segment)) } block.AdvanceLine() } end: if !node.IsBlank(block.Source()) { // trim first halfspace and last halfspace segment := node.FirstChild().(*ast.Text).Segment shouldTrimmed := true if !(!segment.IsEmpty() && block.Source()[segment.Start] == ' ') { shouldTrimmed = false } segment = node.LastChild().(*ast.Text).Segment if !(!segment.IsEmpty() && block.Source()[segment.Stop-1] == ' ') { shouldTrimmed = false } if shouldTrimmed { t := node.FirstChild().(*ast.Text) segment := t.Segment t.Segment = segment.WithStart(segment.Start + 1) t = node.LastChild().(*ast.Text) segment = node.LastChild().(*ast.Text).Segment t.Segment = segment.WithStop(segment.Stop - 1) } } return node }