mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Fixes #50
This commit is contained in:
parent
ea2c6c34ce
commit
171dbc66a8
5 changed files with 92 additions and 11 deletions
36
ast/ast.go
36
ast/ast.go
|
|
@ -98,6 +98,9 @@ type Node interface {
|
|||
// RemoveChildren removes all children from this node.
|
||||
RemoveChildren(self Node)
|
||||
|
||||
// SortChildren sorts childrens by comparator.
|
||||
SortChildren(comparator func(n1, n2 Node) int)
|
||||
|
||||
// ReplaceChild replace a node v1 with a node insertee.
|
||||
// If v1 is not children of this node, ReplaceChild append a insetee to the
|
||||
// tail of the children.
|
||||
|
|
@ -243,6 +246,39 @@ func (n *BaseNode) RemoveChildren(self Node) {
|
|||
n.childCount = 0
|
||||
}
|
||||
|
||||
// SortChildren implements Node.SortChildren
|
||||
func (n *BaseNode) SortChildren(comparator func(n1, n2 Node) int) {
|
||||
var sorted Node
|
||||
current := n.firstChild
|
||||
for current != nil {
|
||||
next := current.NextSibling()
|
||||
if sorted == nil || comparator(sorted, current) >= 0 {
|
||||
current.SetNextSibling(sorted)
|
||||
if sorted != nil {
|
||||
sorted.SetPreviousSibling(current)
|
||||
}
|
||||
sorted = current
|
||||
sorted.SetPreviousSibling(nil)
|
||||
} else {
|
||||
c := sorted
|
||||
for c.NextSibling() != nil && comparator(c.NextSibling(), current) < 0 {
|
||||
c = c.NextSibling()
|
||||
}
|
||||
current.SetNextSibling(c.NextSibling())
|
||||
current.SetPreviousSibling(c)
|
||||
if c.NextSibling() != nil {
|
||||
c.NextSibling().SetPreviousSibling(current)
|
||||
}
|
||||
c.SetNextSibling(current)
|
||||
}
|
||||
current = next
|
||||
}
|
||||
n.firstChild = sorted
|
||||
for c := n.firstChild; c != nil; c = c.NextSibling() {
|
||||
n.lastChild = c
|
||||
}
|
||||
}
|
||||
|
||||
// FirstChild implements Node.FirstChild .
|
||||
func (n *BaseNode) FirstChild() Node {
|
||||
return n.firstChild
|
||||
|
|
|
|||
|
|
@ -22,11 +22,28 @@ That's some text with a footnote.[^1]
|
|||
//- - - - - - - - -//
|
||||
[^000]:0 [^]:
|
||||
//- - - - - - - - -//
|
||||
//= = = = = = = = = = = = = = = = = = = = = = = =//
|
||||
|
||||
4
|
||||
//- - - - - - - - -//
|
||||
This[^3] is[^1] text with footnotes[^2].
|
||||
|
||||
[^1]: Footnote one
|
||||
[^2]: Footnote two
|
||||
[^3]: Footnote three
|
||||
//- - - - - - - - -//
|
||||
<p>This<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> is<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> text with footnotes<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
|
||||
<section class="footnotes" role="doc-endnotes">
|
||||
<hr>
|
||||
<ol>
|
||||
<li id="fn:1" role="doc-endnote">
|
||||
<p>0 [^]: <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||||
<p>Footnote three <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||||
</li>
|
||||
<li id="fn:2" role="doc-endnote">
|
||||
<p>Footnote one <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||||
</li>
|
||||
<li id="fn:3" role="doc-endnote">
|
||||
<p>Footnote two <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ type Footnote struct {
|
|||
|
||||
// Dump implements Node.Dump.
|
||||
func (n *Footnote) Dump(source []byte, level int) {
|
||||
gast.DumpHelper(n, source, level, nil, nil)
|
||||
m := map[string]string{}
|
||||
m["Index"] = fmt.Sprintf("%v", n.Index)
|
||||
m["Ref"] = fmt.Sprintf("%s", n.Ref)
|
||||
gast.DumpHelper(n, source, level, m, nil)
|
||||
}
|
||||
|
||||
// KindFootnote is a NodeKind of the Footnote node.
|
||||
|
|
@ -88,6 +91,7 @@ func (n *Footnote) Kind() gast.NodeKind {
|
|||
func NewFootnote(ref []byte) *Footnote {
|
||||
return &Footnote{
|
||||
Ref: ref,
|
||||
Index: -1,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,11 +99,14 @@ func NewFootnote(ref []byte) *Footnote {
|
|||
// (PHP Markdown Extra) text.
|
||||
type FootnoteList struct {
|
||||
gast.BaseBlock
|
||||
Count int
|
||||
}
|
||||
|
||||
// Dump implements Node.Dump.
|
||||
func (n *FootnoteList) Dump(source []byte, level int) {
|
||||
gast.DumpHelper(n, source, level, nil, nil)
|
||||
m := map[string]string{}
|
||||
m["Count"] = fmt.Sprintf("%v", n.Count)
|
||||
gast.DumpHelper(n, source, level, m, nil)
|
||||
}
|
||||
|
||||
// KindFootnoteList is a NodeKind of the FootnoteList node.
|
||||
|
|
@ -112,5 +119,7 @@ func (n *FootnoteList) Kind() gast.NodeKind {
|
|||
|
||||
// NewFootnoteList returns a new FootnoteList node.
|
||||
func NewFootnoteList() *FootnoteList {
|
||||
return &FootnoteList{}
|
||||
return &FootnoteList{
|
||||
Count: 0,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,9 +91,6 @@ func (b *footnoteBlockParser) Close(node gast.Node, reader text.Reader, pc parse
|
|||
node.Parent().InsertBefore(node.Parent(), node, list)
|
||||
}
|
||||
node.Parent().RemoveChild(node.Parent(), node)
|
||||
n := node.(*ast.Footnote)
|
||||
index := list.ChildCount() + 1
|
||||
n.Index = index
|
||||
list.AppendChild(list, node)
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +147,10 @@ func (s *footnoteParser) Parse(parent gast.Node, block text.Reader, pc parser.Co
|
|||
for def := list.FirstChild(); def != nil; def = def.NextSibling() {
|
||||
d := def.(*ast.Footnote)
|
||||
if bytes.Equal(d.Ref, value) {
|
||||
if d.Index < 0 {
|
||||
list.Count += 1
|
||||
d.Index = list.Count
|
||||
}
|
||||
index = d.Index
|
||||
break
|
||||
}
|
||||
|
|
@ -180,15 +181,30 @@ func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Read
|
|||
return
|
||||
}
|
||||
pc.Set(footnoteListKey, nil)
|
||||
|
||||
for footnote := list.FirstChild(); footnote != nil; footnote = footnote.NextSibling() {
|
||||
for footnote := list.FirstChild(); footnote != nil; {
|
||||
var container gast.Node = footnote
|
||||
next := footnote.NextSibling()
|
||||
if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) {
|
||||
container = fc
|
||||
}
|
||||
index := footnote.(*ast.Footnote).Index
|
||||
if index < 0 {
|
||||
list.RemoveChild(list, footnote)
|
||||
} else {
|
||||
container.AppendChild(container, ast.NewFootnoteBackLink(index))
|
||||
}
|
||||
footnote = next
|
||||
}
|
||||
list.SortChildren(func(n1, n2 gast.Node) int {
|
||||
if n1.(*ast.Footnote).Index < n2.(*ast.Footnote).Index {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})
|
||||
if list.Count <= 0 {
|
||||
list.Parent().RemoveChild(list.Parent(), list)
|
||||
return
|
||||
}
|
||||
|
||||
node.AppendChild(node, list)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ func parseAttribute(reader text.Reader) (Attribute, bool) {
|
|||
return Attribute{Name: name, Value: line[0:i]}, true
|
||||
}
|
||||
line, _ := reader.PeekLine()
|
||||
if len(line) == 0 {
|
||||
return Attribute{}, false
|
||||
}
|
||||
c = line[0]
|
||||
if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
c == '_' || c == ':') {
|
||||
|
|
|
|||
Loading…
Reference in a new issue