Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 41 additions & 11 deletions link.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ import (
"golang.org/x/text/cases"
)

type RefStyle int

const (
NoRef RefStyle = iota
Full
Collpased
Shortcut
)

// Note: Link and Image are the same underlying struct by design,
// so that code can safely convert between *Link and *Image.

Expand All @@ -24,6 +33,9 @@ type Link struct {
URL string
Title string
TitleChar byte // ', " or )

Label string
RefStyle RefStyle
}

// An Image is an [Inline] representing an [image] (<a> tag).
Expand All @@ -34,6 +46,9 @@ type Image struct {
URL string
Title string
TitleChar byte

Label string
RefStyle RefStyle
}

func (*Link) Inline() {}
Expand All @@ -57,14 +72,25 @@ func (x *Link) printMarkdown(p *printer) {
for _, c := range x.Inner {
c.printMarkdown(p)
}
p.WriteString("](")
u := mdLinkEscaper.Replace(x.URL)
if u == "" || strings.ContainsAny(u, " ") {
u = "<" + u + ">"
p.WriteByte(']')
switch x.RefStyle {
case NoRef:
p.WriteByte('(')
u := mdLinkEscaper.Replace(x.URL)
if u == "" || strings.ContainsAny(u, " ") {
u = "<" + u + ">"
}
p.WriteString(u)
printLinkTitleMarkdown(p, x.Title, x.TitleChar)
p.WriteByte(')')
case Full:
p.WriteByte('[')
p.WriteString(x.Label)
p.WriteByte(']')
case Collpased:
p.WriteString("[]")
case Shortcut:
}
p.WriteString(u)
printLinkTitleMarkdown(p, x.Title, x.TitleChar)
p.WriteByte(')')
}

func printLinkTitleMarkdown(p *printer, title string, titleChar byte) {
Expand Down Expand Up @@ -193,8 +219,9 @@ func parseLinkClose(p *parser, s string, start int, open *openPlain) (*Link, int
if !ok {
break
}
if link, ok := p.links[normalizeLabel(label)]; ok {
return &Link{URL: link.URL, Title: link.Title}, i, true
label = normalizeLabel(label)
if link, ok := p.links[label]; ok {
return &Link{URL: link.URL, Title: link.Title, Label: label, RefStyle: Full}, i, true
}
// Note: Could break here, but CommonMark dingus does not
// fall back to trying Text for [Text][Label] when Label is unknown.
Expand All @@ -205,12 +232,15 @@ func parseLinkClose(p *parser, s string, start int, open *openPlain) (*Link, int

// Collapsed or shortcut reference link: [Text][] or [Text].
end := i + 1
refStyle := Shortcut
if strings.HasPrefix(s[end:], "[]") {
end += 2
refStyle = Collpased
}

if link, ok := p.links[normalizeLabel(s[open.i:i])]; ok {
return &Link{URL: link.URL, Title: link.Title}, end, true
label := normalizeLabel(s[open.i:i])
if link, ok := p.links[label]; ok {
return &Link{URL: link.URL, Title: link.Title, Label: label, RefStyle: refStyle}, end, true
}
return nil, 0, false
}
Expand Down
6 changes: 6 additions & 0 deletions md_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.29/57": true, // setext heading
"TestToHTML/spec0.29/63": true, // setext heading
"TestToHTML/spec0.29/65": true, // newline in heading
"TestToHTML/spec0.29/163": true, // escaped bracket in label
"TestToHTML/spec0.29/171": true, // link ref def
"TestToHTML/spec0.29/208": true, // weird list
"TestToHTML/spec0.29/227": true, // weird list
Expand All @@ -58,6 +59,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.29/331": true, // backtick spaces
"TestToHTML/spec0.29/349": true, // backticks
"TestToHTML/spec0.29/502": true, // escape quotes
"TestToHTML/spec0.29/545": true, // escaped bracket in label

"TestToHTML/spec0.30/26": true, // escape plain
"TestToHTML/spec0.30/37": true, // escape plain
Expand All @@ -72,6 +74,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.30/87": true, // setext heading
"TestToHTML/spec0.30/93": true, // setext heading
"TestToHTML/spec0.30/95": true, // newline in heading
"TestToHTML/spec0.30/194": true, // escaped bracket in label
"TestToHTML/spec0.30/202": true, // link ref def
"TestToHTML/spec0.30/238": true, // weird list
"TestToHTML/spec0.30/257": true, // weird list
Expand All @@ -81,6 +84,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.30/331": true, // backtick spaces
"TestToHTML/spec0.30/349": true, // backticks
"TestToHTML/spec0.30/505": true, // escape quotes
"TestToHTML/spec0.30/548": true, // escaped bracket in label

"TestToHTML/spec0.31.2/26": true, // escape plain
"TestToHTML/spec0.31.2/37": true, // escape plain
Expand All @@ -95,6 +99,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.31.2/87": true, // setext heading
"TestToHTML/spec0.31.2/93": true, // setext heading
"TestToHTML/spec0.31.2/95": true, // newline in heading
"TestToHTML/spec0.31.2/194": true, // escaped bracket in label
"TestToHTML/spec0.31.2/202": true, // link ref def
"TestToHTML/spec0.31.2/238": true, // weird list
"TestToHTML/spec0.31.2/257": true, // weird list
Expand All @@ -104,6 +109,7 @@ var roundTripFailures = map[string]bool{
"TestToHTML/spec0.31.2/331": true, // backtick spaces
"TestToHTML/spec0.31.2/349": true, // backticks
"TestToHTML/spec0.31.2/506": true, // escape quotes
"TestToHTML/spec0.31.2/549": true, // escaped bracket in label

"TestToHTML/table/gfm200": true, // table
"TestToHTML/table/2": true, // table
Expand Down
12 changes: 12 additions & 0 deletions testdata/linkref_fmt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@ A document.
[r1]: u1 (title1)
[r2]: u2 "title2"
[r3]: u3 'title3'
-- reflink-full --
[Foo bar][baz]

[baz]: u1
-- reflink-collapsed --
[Foo bar][]

[foo bar]: u1
-- reflink-shortcut --
[Foo bar]

[foo bar]: u1