Add lossless inline-definition-footnote rendering for the OrgWriter

This commit is contained in:
Niklas Fasching 2018-12-02 17:24:10 +01:00
parent fc982125c9
commit a570fc736f
6 changed files with 49 additions and 29 deletions

View file

@ -14,6 +14,7 @@ type Footnotes struct {
type FootnoteDefinition struct { type FootnoteDefinition struct {
Name string Name string
Children []Node Children []Node
Inline bool
} }
var footnoteDefinitionRegexp = regexp.MustCompile(`^\[fn:([\w-]+)\]\s+(.+)`) var footnoteDefinitionRegexp = regexp.MustCompile(`^\[fn:([\w-]+)\]\s+(.+)`)
@ -33,6 +34,6 @@ func (d *Document) parseFootnoteDefinition(i int, parentStop stopFn) (int, Node)
d.tokens[i].kind == "headline" || d.tokens[i].kind == "footnoteDefinition" d.tokens[i].kind == "headline" || d.tokens[i].kind == "footnoteDefinition"
} }
consumed, nodes := d.parseMany(i, stop) consumed, nodes := d.parseMany(i, stop)
d.Footnotes.Definitions[name] = FootnoteDefinition{name, nodes} d.Footnotes.Definitions[name] = FootnoteDefinition{name, nodes, false}
return consumed, nil return consumed, nil
} }

View file

@ -44,19 +44,8 @@ func (w *HTMLWriter) emptyClone() *HTMLWriter {
} }
func (w *HTMLWriter) before(d *Document) {} func (w *HTMLWriter) before(d *Document) {}
func (w *HTMLWriter) after(d *Document) { func (w *HTMLWriter) after(d *Document) {
fs := d.Footnotes w.writeFootnotes(d)
if len(fs.Definitions) == 0 {
return
}
w.WriteString(`<div id="footnotes">` + "\n")
w.WriteString(`<h1 class="footnotes-title">` + fs.Title + `</h1>` + "\n")
w.WriteString(`<div class="footnote-definitions">` + "\n")
for _, name := range fs.Order {
w.writeNodes(fs.Definitions[name])
}
w.WriteString("</div>\n</div>\n")
} }
func (w *HTMLWriter) writeNodes(ns ...Node) { func (w *HTMLWriter) writeNodes(ns ...Node) {
@ -141,6 +130,19 @@ func (w *HTMLWriter) writeFootnoteDefinition(f FootnoteDefinition) {
w.WriteString("</div>\n") w.WriteString("</div>\n")
} }
func (w *HTMLWriter) writeFootnotes(d *Document) {
fs := d.Footnotes
if len(fs.Definitions) == 0 {
return
}
w.WriteString(`<div id="footnotes">` + "\n")
w.WriteString(`<h1 class="footnotes-title">` + fs.Title + `</h1>` + "\n")
w.WriteString(`<div class="footnote-definitions">` + "\n")
for _, name := range fs.Order {
w.writeNodes(fs.Definitions[name])
}
w.WriteString("</div>\n</div>\n")
}
func (w *HTMLWriter) writeHeadline(h Headline) { func (w *HTMLWriter) writeHeadline(h Headline) {
w.WriteString(fmt.Sprintf("<h%d>", h.Lvl)) w.WriteString(fmt.Sprintf("<h%d>", h.Lvl))
w.writeNodes(h.Title...) w.writeNodes(h.Title...)

View file

@ -15,7 +15,10 @@ type Emphasis struct {
Content []Node Content []Node
} }
type FootnoteLink struct{ Name string } type FootnoteLink struct {
Name string
Definition *FootnoteDefinition
}
type RegularLink struct { type RegularLink struct {
Protocol string Protocol string
@ -104,7 +107,7 @@ func (d *Document) parseRegularLinkOrFootnoteReference(input string, start int)
func (d *Document) parseFootnoteReference(input string, start int) (int, Node) { func (d *Document) parseFootnoteReference(input string, start int) (int, Node) {
if m := footnoteRegexp.FindStringSubmatch(input[start:]); m != nil { if m := footnoteRegexp.FindStringSubmatch(input[start:]); m != nil {
name, definition := m[1], m[3] name, definition := m[1], m[3]
seen := false seen, link := false, FootnoteLink{name, nil}
for _, otherName := range d.Footnotes.Order { for _, otherName := range d.Footnotes.Order {
if name == otherName { if name == otherName {
seen = true seen = true
@ -114,9 +117,10 @@ func (d *Document) parseFootnoteReference(input string, start int) (int, Node) {
d.Footnotes.Order = append(d.Footnotes.Order, name) d.Footnotes.Order = append(d.Footnotes.Order, name)
} }
if definition != "" { if definition != "" {
d.Footnotes.Definitions[name] = FootnoteDefinition{name, d.parseInline(definition)} link.Definition = &FootnoteDefinition{name, d.parseInline(definition), true}
d.Footnotes.Definitions[name] = *link.Definition
} }
return len(m[0]), FootnoteLink{name} return len(m[0]), link
} }
return 0, nil return 0, nil
} }

View file

@ -33,14 +33,7 @@ func NewOrgWriter() *OrgWriter {
func (w *OrgWriter) before(d *Document) {} func (w *OrgWriter) before(d *Document) {}
func (w *OrgWriter) after(d *Document) { func (w *OrgWriter) after(d *Document) {
fs := d.Footnotes w.writeFootnotes(d)
if len(fs.Definitions) == 0 {
return
}
w.WriteString("* " + fs.Title + "\n")
for _, name := range fs.Order {
w.writeNodes(fs.Definitions[name])
}
} }
func (w *OrgWriter) emptyClone() *OrgWriter { func (w *OrgWriter) emptyClone() *OrgWriter {
@ -146,6 +139,19 @@ func (w *OrgWriter) writeBlock(b Block) {
w.WriteString(w.indent + "#+END_" + b.Name + "\n") w.WriteString(w.indent + "#+END_" + b.Name + "\n")
} }
func (w *OrgWriter) writeFootnotes(d *Document) {
fs := d.Footnotes
if len(fs.Definitions) == 0 {
return
}
w.WriteString("* " + fs.Title + "\n")
for _, name := range fs.Order {
if fnDefinition := fs.Definitions[name]; !fnDefinition.Inline {
w.writeNodes(fnDefinition)
}
}
}
func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) { func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) {
w.WriteString(fmt.Sprintf("[fn:%s] ", f.Name)) w.WriteString(fmt.Sprintf("[fn:%s] ", f.Name))
w.writeNodes(f.Children...) w.writeNodes(f.Children...)
@ -228,7 +234,12 @@ func (w *OrgWriter) writeLinebreak(l Linebreak) {
} }
func (w *OrgWriter) writeFootnoteLink(l FootnoteLink) { func (w *OrgWriter) writeFootnoteLink(l FootnoteLink) {
w.WriteString("[fn:" + l.Name + "]") w.WriteString("[fn:" + l.Name)
if l.Definition != nil {
w.WriteString(":")
w.writeNodes(l.Definition.Children...)
}
w.WriteString("]")
} }
func (w *OrgWriter) writeRegularLink(l RegularLink) { func (w *OrgWriter) writeRegularLink(l RegularLink) {

View file

@ -65,7 +65,7 @@
<ul> <ul>
<li>normal footnote reference <sup class="footnote-reference"><a href="#footnote-1">1</a></sup></li> <li>normal footnote reference <sup class="footnote-reference"><a href="#footnote-1">1</a></sup></li>
<li>further references to the same footnote should not <sup class="footnote-reference"><a href="#footnote-1">1</a></sup> render duplicates in the footnote list</li> <li>further references to the same footnote should not <sup class="footnote-reference"><a href="#footnote-1">1</a></sup> render duplicates in the footnote list</li>
<li>also inline footnotes are supported via <code class="verbatim">fn:2:inline definition</code>. But we won&#39;t test that because it would cause the output to look different from the input </li> <li>inline footnotes are also supported via <sup class="footnote-reference"><a href="#footnote-2">2</a></sup>. </li>
</ul> </ul>
<div id="footnotes"> <div id="footnotes">
<h1 class="footnotes-title">Footnotes</h1> <h1 class="footnotes-title">Footnotes</h1>
@ -74,5 +74,8 @@
<sup id="footnote-1">1</sup> <sup id="footnote-1">1</sup>
<p>Foobar</p> <p>Foobar</p>
</div> </div>
<div class="footnote-definition">
<sup id="footnote-2">2</sup>
the inline footnote definition</div>
</div> </div>
</div> </div>

View file

@ -53,8 +53,7 @@ this one is cheating a little as tags are ALWAYS printed right aligned to a give
** Footnotes ** Footnotes
- normal footnote reference [fn:1] - normal footnote reference [fn:1]
- further references to the same footnote should not [fn:1] render duplicates in the footnote list - further references to the same footnote should not [fn:1] render duplicates in the footnote list
- also inline footnotes are supported via =fn:2:inline definition=. But we won't test that because it would - inline footnotes are also supported via [fn:2:the inline footnote definition].
cause the output to look different from the input
* Footnotes * Footnotes
[fn:1] Foobar [fn:1] Foobar