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 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
|
||||||
|
|
|
||||||
|
|
@ -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">↩︎</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>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 == ':') {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue