Skip to content
quarry Artifact [b98e5cc473]
Login

Artifact [b98e5cc473]

Artifact b98e5cc473d176f4b5baeabae25552017ec309c17147f6e27fa9fb8186f3334f:


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
}