diff --git a/ast/ast.go b/ast/ast.go
index c5edfe5..4f1d885 100644
--- a/ast/ast.go
+++ b/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
diff --git a/extension/_test/footnote.txt b/extension/_test/footnote.txt
index 4a04a74..34cb5c0 100644
--- a/extension/_test/footnote.txt
+++ b/extension/_test/footnote.txt
@@ -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
+//- - - - - - - - -//
+
This is text with footnotes.
diff --git a/extension/ast/footnote.go b/extension/ast/footnote.go
index 291e6b3..835f847 100644
--- a/extension/ast/footnote.go
+++ b/extension/ast/footnote.go
@@ -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.
@@ -87,7 +90,8 @@ func (n *Footnote) Kind() gast.NodeKind {
// NewFootnote returns a new Footnote node.
func NewFootnote(ref []byte) *Footnote {
return &Footnote{
- Ref: ref,
+ 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,
+ }
}
diff --git a/extension/footnote.go b/extension/footnote.go
index 2fbcbb5..31efddc 100644
--- a/extension/footnote.go
+++ b/extension/footnote.go
@@ -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,14 +181,29 @@ 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
- container.AppendChild(container, ast.NewFootnoteBackLink(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)
diff --git a/parser/attribute.go b/parser/attribute.go
index f417d2b..ea8c064 100644
--- a/parser/attribute.go
+++ b/parser/attribute.go
@@ -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 == ':') {