package markup
import (
"bytes"
gast "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
)
// spacedLink accepts "[label] (url)" — a space between the bracket and
// the parenthesis — as the link it was meant to be. CommonMark makes
// that a literal "[label]" followed by an autolinked URL, which reads
// as a rendering bug to anyone who typed it. The label may not hold
// brackets; the URL may not hold spaces or parentheses; anything else
// falls through to the standard parsers untouched. Runs before
// goldmark's own link parser, which handles the no-space form.
type spacedLink struct{}
func (spacedLink) Trigger() []byte { return []byte{'['} }
func (spacedLink) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
line, seg := block.PeekLine()
close := bytes.IndexByte(line, ']')
if close <= 1 || bytes.IndexByte(line[1:close], '[') >= 0 {
return nil
}
i := close + 1
spaces := 0
for i < len(line) && (line[i] == ' ' || line[i] == '\t') {
i++
spaces++
}
if spaces == 0 || i >= len(line) || line[i] != '(' {
return nil
}
end := bytes.IndexByte(line[i:], ')')
if end <= 1 {
return nil
}
dest := line[i+1 : i+end]
if bytes.ContainsAny(dest, " \t(") {
return nil
}
if !bytes.HasPrefix(dest, []byte("http://")) && !bytes.HasPrefix(dest, []byte("https://")) &&
!bytes.HasPrefix(dest, []byte("/")) && !bytes.HasPrefix(dest, []byte("#")) {
dest = append([]byte("http://"), dest...)
}
link := gast.NewLink()
link.Destination = dest
link.AppendChild(link, gast.NewTextSegment(text.NewSegment(seg.Start+1, seg.Start+close)))
block.Advance(i + end + 1)
return link
}