Add direct link to a footnote from it's referer

Some renderers might not care to have an explicit list of footnotes at
the end of the document, instead they're interested in the content of
the footnote at the location of a referer. Make their lives easier by
providing such a link
This commit is contained in:
Vytautas Šaltenis 2016-09-17 19:31:29 +03:00
parent b91b5719eb
commit 8a11177489
3 changed files with 17 additions and 7 deletions

View File

@ -297,6 +297,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) {
txtE := i txtE := i
i++ i++
var footnoteNode *Node
// skip any amount of whitespace or newline // skip any amount of whitespace or newline
// (this is much more lax than original markdown syntax) // (this is much more lax than original markdown syntax)
@ -476,6 +477,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) {
} }
} }
footnoteNode = NewNode(Item)
if t == linkInlineFootnote { if t == linkInlineFootnote {
// create a new reference // create a new reference
noteID = len(p.notes) + 1 noteID = len(p.notes) + 1
@ -497,6 +499,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) {
hasBlock: false, hasBlock: false,
link: fragment, link: fragment,
title: id, title: id,
footnote: footnoteNode,
} }
p.notes = append(p.notes, ref) p.notes = append(p.notes, ref)
@ -512,6 +515,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) {
if t == linkDeferredFootnote { if t == linkDeferredFootnote {
lr.noteID = len(p.notes) + 1 lr.noteID = len(p.notes) + 1
lr.footnote = footnoteNode
p.notes = append(p.notes, lr) p.notes = append(p.notes, lr)
} }
@ -570,6 +574,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) {
linkNode.Destination = link linkNode.Destination = link
linkNode.Title = title linkNode.Title = title
linkNode.NoteID = noteID linkNode.NoteID = noteID
linkNode.Footnote = footnoteNode
if t == linkInlineFootnote { if t == linkInlineFootnote {
i++ i++
} }

View File

@ -213,14 +213,16 @@ func (p *parser) finalize(block *Node) {
} }
func (p *parser) addChild(node NodeType, offset uint32) *Node { func (p *parser) addChild(node NodeType, offset uint32) *Node {
for !p.tip.canContain(node) { return p.addExistingChild(NewNode(node), offset)
}
func (p *parser) addExistingChild(node *Node, offset uint32) *Node {
for !p.tip.canContain(node.Type) {
p.finalize(p.tip) p.finalize(p.tip)
} }
newNode := NewNode(node) p.tip.AppendChild(node)
newNode.content = []byte{} p.tip = node
p.tip.AppendChild(newNode) return node
p.tip = newNode
return newNode
} }
func (p *parser) closeUnmatchedBlocks() { func (p *parser) closeUnmatchedBlocks() {
@ -419,7 +421,8 @@ func (p *parser) parseRefsToAST() {
// the fixed initial set. // the fixed initial set.
for i := 0; i < len(p.notes); i++ { for i := 0; i < len(p.notes); i++ {
ref := p.notes[i] ref := p.notes[i]
block := p.addBlock(Item, nil) p.addExistingChild(ref.footnote, 0)
block := ref.footnote
block.ListFlags = flags | ListTypeOrdered block.ListFlags = flags | ListTypeOrdered
block.RefLink = ref.link block.RefLink = ref.link
if ref.hasBlock { if ref.hasBlock {
@ -570,6 +573,7 @@ type reference struct {
title []byte title []byte
noteID int // 0 if not a footnote ref noteID int // 0 if not a footnote ref
hasBlock bool hasBlock bool
footnote *Node // a link to the Item node within a list of footnotes
text []byte // only gets populated by refOverride feature with Reference.Text text []byte // only gets populated by refOverride feature with Reference.Text
} }

View File

@ -84,6 +84,7 @@ type LinkData struct {
Destination []byte // Destination is what goes into a href Destination []byte // Destination is what goes into a href
Title []byte // Title is the tooltip thing that goes in a title attribute Title []byte // Title is the tooltip thing that goes in a title attribute
NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote
Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
} }
// CodeBlockData contains fields relevant to a CodeBlock node type. // CodeBlockData contains fields relevant to a CodeBlock node type.