This commit is contained in:
yuin 2019-12-05 13:39:55 +09:00
parent ea2c6c34ce
commit 171dbc66a8
5 changed files with 92 additions and 11 deletions

View file

@ -98,6 +98,9 @@ type Node interface {
// RemoveChildren removes all children from this node. // RemoveChildren removes all children from this node.
RemoveChildren(self 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. // ReplaceChild replace a node v1 with a node insertee.
// If v1 is not children of this node, ReplaceChild append a insetee to the // If v1 is not children of this node, ReplaceChild append a insetee to the
// tail of the children. // tail of the children.
@ -243,6 +246,39 @@ func (n *BaseNode) RemoveChildren(self Node) {
n.childCount = 0 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 . // FirstChild implements Node.FirstChild .
func (n *BaseNode) FirstChild() Node { func (n *BaseNode) FirstChild() Node {
return n.firstChild return n.firstChild

View file

@ -22,11 +22,28 @@ That's some text with a footnote.[^1]
//- - - - - - - - -// //- - - - - - - - -//
[^000]:0 [^]: [^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"> <section class="footnotes" role="doc-endnotes">
<hr> <hr>
<ol> <ol>
<li id="fn:1" role="doc-endnote"> <li id="fn:1" role="doc-endnote">
<p>0 [^]: <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> <p>Footnote three <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Footnote one <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Footnote two <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li> </li>
</ol> </ol>
</section> </section>

View file

@ -73,7 +73,10 @@ type Footnote struct {
// Dump implements Node.Dump. // Dump implements Node.Dump.
func (n *Footnote) Dump(source []byte, level int) { 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. // KindFootnote is a NodeKind of the Footnote node.
@ -88,6 +91,7 @@ func (n *Footnote) Kind() gast.NodeKind {
func NewFootnote(ref []byte) *Footnote { func NewFootnote(ref []byte) *Footnote {
return &Footnote{ return &Footnote{
Ref: ref, Ref: ref,
Index: -1,
} }
} }
@ -95,11 +99,14 @@ func NewFootnote(ref []byte) *Footnote {
// (PHP Markdown Extra) text. // (PHP Markdown Extra) text.
type FootnoteList struct { type FootnoteList struct {
gast.BaseBlock gast.BaseBlock
Count int
} }
// Dump implements Node.Dump. // Dump implements Node.Dump.
func (n *FootnoteList) Dump(source []byte, level int) { 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. // KindFootnoteList is a NodeKind of the FootnoteList node.
@ -112,5 +119,7 @@ func (n *FootnoteList) Kind() gast.NodeKind {
// NewFootnoteList returns a new FootnoteList node. // NewFootnoteList returns a new FootnoteList node.
func NewFootnoteList() *FootnoteList { func NewFootnoteList() *FootnoteList {
return &FootnoteList{} return &FootnoteList{
Count: 0,
}
} }

View file

@ -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().InsertBefore(node.Parent(), node, list)
} }
node.Parent().RemoveChild(node.Parent(), node) node.Parent().RemoveChild(node.Parent(), node)
n := node.(*ast.Footnote)
index := list.ChildCount() + 1
n.Index = index
list.AppendChild(list, node) 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() { for def := list.FirstChild(); def != nil; def = def.NextSibling() {
d := def.(*ast.Footnote) d := def.(*ast.Footnote)
if bytes.Equal(d.Ref, value) { if bytes.Equal(d.Ref, value) {
if d.Index < 0 {
list.Count += 1
d.Index = list.Count
}
index = d.Index index = d.Index
break break
} }
@ -180,15 +181,30 @@ func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Read
return return
} }
pc.Set(footnoteListKey, nil) pc.Set(footnoteListKey, nil)
for footnote := list.FirstChild(); footnote != nil; {
for footnote := list.FirstChild(); footnote != nil; footnote = footnote.NextSibling() {
var container gast.Node = footnote var container gast.Node = footnote
next := footnote.NextSibling()
if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) { if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) {
container = fc container = fc
} }
index := footnote.(*ast.Footnote).Index index := footnote.(*ast.Footnote).Index
if index < 0 {
list.RemoveChild(list, footnote)
} else {
container.AppendChild(container, ast.NewFootnoteBackLink(index)) 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) node.AppendChild(node, list)
} }

View file

@ -99,6 +99,9 @@ func parseAttribute(reader text.Reader) (Attribute, bool) {
return Attribute{Name: name, Value: line[0:i]}, true return Attribute{Name: name, Value: line[0:i]}, true
} }
line, _ := reader.PeekLine() line, _ := reader.PeekLine()
if len(line) == 0 {
return Attribute{}, false
}
c = line[0] c = line[0]
if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
c == '_' || c == ':') { c == '_' || c == ':') {