From faea88d48e957ad97a1ddaf781ae86c6f251931b Mon Sep 17 00:00:00 2001
From: Niklas Fasching
Date: Fri, 4 Jan 2019 20:05:20 +0100
Subject: [PATCH] Refactor Writer Interface
The existing approach made it hard to extend existing writers.
With this change, replacing individual methods of a writer is possible by
embedding it.
Sharing the WriteNodes function also removes some unnecesseray duplication, so
win win.
---
org/document.go | 10 +---
org/html_writer.go | 142 ++++++++++++++-------------------------------
org/org_writer.go | 135 +++++++++++++-----------------------------
org/writer.go | 91 +++++++++++++++++++++++++++++
4 files changed, 174 insertions(+), 204 deletions(-)
create mode 100644 org/writer.go
diff --git a/org/document.go b/org/document.go
index 657919f..8c89a23 100644
--- a/org/document.go
+++ b/org/document.go
@@ -41,14 +41,6 @@ type Document struct {
Error error
}
-// Writer is the interface that is used to export a parsed document into a new format. See Document.Write().
-type Writer interface {
- Before(*Document) // Before is called before any nodes are passed to the writer.
- After(*Document) // After is called after all nodes have been passed to the writer.
- WriteNodes(...Node) // WriteNodes is called with the nodes of the parsed document.
- String() string // String is called at the very end to retrieve the final output.
-}
-
// Node represents a parsed node of the document. It's an empty interface and can be ignored.
type Node interface{}
@@ -105,7 +97,7 @@ func (d *Document) Write(w Writer) (out string, err error) {
return "", fmt.Errorf("could not write output: parse was not called")
}
w.Before(d)
- w.WriteNodes(d.Nodes...)
+ WriteNodes(w, d.Nodes...)
w.After(d)
return w.String(), err
}
diff --git a/org/html_writer.go b/org/html_writer.go
index 75320ed..e9ef2b0 100644
--- a/org/html_writer.go
+++ b/org/html_writer.go
@@ -63,87 +63,29 @@ func (w *HTMLWriter) emptyClone() *HTMLWriter {
func (w *HTMLWriter) nodesAsString(nodes ...Node) string {
tmp := w.emptyClone()
- tmp.WriteNodes(nodes...)
+ WriteNodes(tmp, nodes...)
return tmp.String()
}
func (w *HTMLWriter) Before(d *Document) {
w.document = d
w.log = d.Log
- w.writeOutline(d)
+ w.WriteOutline(d)
}
func (w *HTMLWriter) After(d *Document) {
- w.writeFootnotes(d)
+ w.WriteFootnotes(d)
}
-func (w *HTMLWriter) WriteNodes(ns ...Node) {
- for _, n := range ns {
- switch n := n.(type) {
- case Keyword:
- w.writeKeyword(n)
- case Include:
- w.writeInclude(n)
- case Comment:
- continue
- case NodeWithMeta:
- w.writeNodeWithMeta(n)
- case Headline:
- w.writeHeadline(n)
- case Block:
- w.writeBlock(n)
- case Drawer:
- w.writeDrawer(n)
- case PropertyDrawer:
- continue
+func (w *HTMLWriter) WriteComment(Comment) {}
+func (w *HTMLWriter) WritePropertyDrawer(PropertyDrawer) {}
- case FootnoteDefinition:
- continue
-
- case List:
- w.writeList(n)
- case ListItem:
- w.writeListItem(n)
- case DescriptiveListItem:
- w.writeDescriptiveListItem(n)
-
- case Table:
- w.writeTable(n)
-
- case Paragraph:
- w.writeParagraph(n)
- case Example:
- w.writeExample(n)
- case HorizontalRule:
- w.writeHorizontalRule(n)
- case Text:
- w.writeText(n)
- case Emphasis:
- w.writeEmphasis(n)
- case StatisticToken:
- w.writeStatisticToken(n)
- case ExplicitLineBreak:
- w.writeExplicitLineBreak(n)
- case LineBreak:
- w.writeLineBreak(n)
- case RegularLink:
- w.writeRegularLink(n)
- case FootnoteLink:
- w.writeFootnoteLink(n)
- default:
- if n != nil {
- panic(fmt.Sprintf("bad node %#v", n))
- }
- }
- }
-}
-
-func (w *HTMLWriter) writeBlock(b Block) {
+func (w *HTMLWriter) WriteBlock(b Block) {
content := ""
if isRawTextBlock(b.Name) {
exportWriter := w.emptyClone()
exportWriter.htmlEscape = false
- exportWriter.WriteNodes(b.Children...)
+ WriteNodes(exportWriter, b.Children...)
content = strings.TrimRightFunc(exportWriter.String(), unicode.IsSpace)
} else {
content = w.nodesAsString(b.Children...)
@@ -170,30 +112,32 @@ func (w *HTMLWriter) writeBlock(b Block) {
}
}
-func (w *HTMLWriter) writeDrawer(d Drawer) {
- w.WriteNodes(d.Children...)
+func (w *HTMLWriter) WriteDrawer(d Drawer) {
+ WriteNodes(w, d.Children...)
}
-func (w *HTMLWriter) writeKeyword(k Keyword) {
+func (w *HTMLWriter) WriteKeyword(k Keyword) {
if k.Key == "HTML" {
w.WriteString(k.Value + "\n")
}
}
-func (w *HTMLWriter) writeInclude(i Include) {
- w.WriteNodes(i.Resolve())
+func (w *HTMLWriter) WriteInclude(i Include) {
+ WriteNodes(w, i.Resolve())
}
+func (w *HTMLWriter) WriteFootnoteDefinition(FootnoteDefinition) {}
+
func (w *HTMLWriter) writeFootnoteDefinition(f FootnoteDefinition) {
n := f.Name
w.WriteString(`\n")
}
-func (w *HTMLWriter) writeFootnotes(d *Document) {
+func (w *HTMLWriter) WriteFootnotes(d *Document) {
if !w.document.GetOption("f") || len(d.Footnotes.Definitions) == 0 {
return
}
@@ -206,7 +150,7 @@ func (w *HTMLWriter) writeFootnotes(d *Document) {
w.WriteString("\n\n")
}
-func (w *HTMLWriter) writeOutline(d *Document) {
+func (w *HTMLWriter) WriteOutline(d *Document) {
if w.document.GetOption("toc") && len(d.Outline.Children) != 0 {
w.WriteString("\n\n")
for _, section := range d.Outline.Children {
@@ -232,7 +176,7 @@ func (w *HTMLWriter) writeSection(section *Section) {
w.WriteString("\n")
}
-func (w *HTMLWriter) writeHeadline(h Headline) {
+func (w *HTMLWriter) WriteHeadline(h Headline) {
for _, excludeTag := range strings.Fields(w.document.Get("EXCLUDE_TAGS")) {
for _, tag := range h.Tags {
if excludeTag == tag {
@@ -249,7 +193,7 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
w.WriteString(fmt.Sprintf(`[%s] `, h.Priority) + "\n")
}
- w.WriteNodes(h.Title...)
+ WriteNodes(w, h.Title...)
if w.document.GetOption("tags") && len(h.Tags) != 0 {
tags := make([]string, len(h.Tags))
for i, tag := range h.Tags {
@@ -259,10 +203,10 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
w.WriteString(fmt.Sprintf(`%s `, strings.Join(tags, " ")))
}
w.WriteString(fmt.Sprintf("\n\n", h.Lvl))
- w.WriteNodes(h.Children...)
+ WriteNodes(w, h.Children...)
}
-func (w *HTMLWriter) writeText(t Text) {
+func (w *HTMLWriter) WriteText(t Text) {
if !w.htmlEscape {
w.WriteString(t.Content)
} else if !w.document.GetOption("e") || t.IsRaw {
@@ -272,29 +216,29 @@ func (w *HTMLWriter) writeText(t Text) {
}
}
-func (w *HTMLWriter) writeEmphasis(e Emphasis) {
+func (w *HTMLWriter) WriteEmphasis(e Emphasis) {
tags, ok := emphasisTags[e.Kind]
if !ok {
panic(fmt.Sprintf("bad emphasis %#v", e))
}
w.WriteString(tags[0])
- w.WriteNodes(e.Content...)
+ WriteNodes(w, e.Content...)
w.WriteString(tags[1])
}
-func (w *HTMLWriter) writeStatisticToken(s StatisticToken) {
+func (w *HTMLWriter) WriteStatisticToken(s StatisticToken) {
w.WriteString(fmt.Sprintf(`[%s]
`, s.Content))
}
-func (w *HTMLWriter) writeLineBreak(l LineBreak) {
+func (w *HTMLWriter) WriteLineBreak(l LineBreak) {
w.WriteString(strings.Repeat("\n", l.Count))
}
-func (w *HTMLWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
+func (w *HTMLWriter) WriteExplicitLineBreak(l ExplicitLineBreak) {
w.WriteString(" \n")
}
-func (w *HTMLWriter) writeFootnoteLink(l FootnoteLink) {
+func (w *HTMLWriter) WriteFootnoteLink(l FootnoteLink) {
if !w.document.GetOption("f") {
return
}
@@ -302,7 +246,7 @@ func (w *HTMLWriter) writeFootnoteLink(l FootnoteLink) {
w.WriteString(fmt.Sprintf(``, n, n, n))
}
-func (w *HTMLWriter) writeRegularLink(l RegularLink) {
+func (w *HTMLWriter) WriteRegularLink(l RegularLink) {
url := html.EscapeString(l.URL)
if l.Protocol == "file" {
url = url[len("file:"):]
@@ -321,27 +265,27 @@ func (w *HTMLWriter) writeRegularLink(l RegularLink) {
}
}
-func (w *HTMLWriter) writeList(l List) {
+func (w *HTMLWriter) WriteList(l List) {
tags, ok := listTags[l.Kind]
if !ok {
panic(fmt.Sprintf("bad list kind %#v", l))
}
w.WriteString(tags[0] + "\n")
- w.WriteNodes(l.Items...)
+ WriteNodes(w, l.Items...)
w.WriteString(tags[1] + "\n")
}
-func (w *HTMLWriter) writeListItem(li ListItem) {
+func (w *HTMLWriter) WriteListItem(li ListItem) {
if li.Status != "" {
w.WriteString(fmt.Sprintf("\n", listItemStatuses[li.Status]))
} else {
w.WriteString(" \n")
}
- w.WriteNodes(li.Children...)
+ WriteNodes(w, li.Children...)
w.WriteString(" \n")
}
-func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
+func (w *HTMLWriter) WriteDescriptiveListItem(di DescriptiveListItem) {
if di.Status != "" {
w.WriteString(fmt.Sprintf("\n", listItemStatuses[di.Status]))
} else {
@@ -349,16 +293,16 @@ func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
}
if len(di.Term) != 0 {
- w.WriteNodes(di.Term...)
+ WriteNodes(w, di.Term...)
} else {
w.WriteString("?")
}
w.WriteString(" \n")
- w.WriteNodes(di.Details...)
+ WriteNodes(w, di.Details...)
w.WriteString("\n")
}
-func (w *HTMLWriter) writeParagraph(p Paragraph) {
+func (w *HTMLWriter) WriteParagraph(p Paragraph) {
if len(p.Children) == 0 {
return
}
@@ -366,26 +310,26 @@ func (w *HTMLWriter) writeParagraph(p Paragraph) {
if _, ok := p.Children[0].(LineBreak); !ok {
w.WriteString("\n")
}
- w.WriteNodes(p.Children...)
+ WriteNodes(w, p.Children...)
w.WriteString("\n
\n")
}
-func (w *HTMLWriter) writeExample(e Example) {
+func (w *HTMLWriter) WriteExample(e Example) {
w.WriteString(`` + "\n")
if len(e.Children) != 0 {
for _, n := range e.Children {
- w.WriteNodes(n)
+ WriteNodes(w, n)
w.WriteString("\n")
}
}
w.WriteString(" \n")
}
-func (w *HTMLWriter) writeHorizontalRule(h HorizontalRule) {
+func (w *HTMLWriter) WriteHorizontalRule(h HorizontalRule) {
w.WriteString(" \n")
}
-func (w *HTMLWriter) writeNodeWithMeta(n NodeWithMeta) {
+func (w *HTMLWriter) WriteNodeWithMeta(n NodeWithMeta) {
out := w.nodesAsString(n.Node)
if p, ok := n.Node.(Paragraph); ok {
if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
@@ -408,7 +352,7 @@ func (w *HTMLWriter) writeNodeWithMeta(n NodeWithMeta) {
w.WriteString(out)
}
-func (w *HTMLWriter) writeTable(t Table) {
+func (w *HTMLWriter) WriteTable(t Table) {
w.WriteString("\n")
beforeFirstContentRow := true
for i, row := range t.Rows {
@@ -439,7 +383,7 @@ func (w *HTMLWriter) writeTableColumns(columns []Column, tag string) {
} else {
w.WriteString(fmt.Sprintf(`<%s class="align-%s">`, tag, column.Align))
}
- w.WriteNodes(column.Children...)
+ WriteNodes(w, column.Children...)
w.WriteString(fmt.Sprintf("%s>\n", tag))
}
w.WriteString("\n")
diff --git a/org/org_writer.go b/org/org_writer.go
index e624ce4..b57f561 100644
--- a/org/org_writer.go
+++ b/org/org_writer.go
@@ -44,72 +44,11 @@ func (w *OrgWriter) emptyClone() *OrgWriter {
func (w *OrgWriter) nodesAsString(nodes ...Node) string {
tmp := w.emptyClone()
- tmp.WriteNodes(nodes...)
+ WriteNodes(tmp, nodes...)
return tmp.String()
}
-func (w *OrgWriter) WriteNodes(ns ...Node) {
- for _, n := range ns {
- switch n := n.(type) {
- case Comment:
- w.writeComment(n)
- case Keyword:
- w.writeKeyword(n)
- case Include:
- w.writeKeyword(n.Keyword)
- case NodeWithMeta:
- w.writeNodeWithMeta(n)
- case Headline:
- w.writeHeadline(n)
- case Block:
- w.writeBlock(n)
- case Drawer:
- w.writeDrawer(n)
- case PropertyDrawer:
- w.writePropertyDrawer(n)
-
- case FootnoteDefinition:
- w.writeFootnoteDefinition(n)
-
- case List:
- w.writeList(n)
- case ListItem:
- w.writeListItem(n)
- case DescriptiveListItem:
- w.writeDescriptiveListItem(n)
-
- case Table:
- w.writeTable(n)
-
- case Paragraph:
- w.writeParagraph(n)
- case Example:
- w.writeExample(n)
- case HorizontalRule:
- w.writeHorizontalRule(n)
- case Text:
- w.writeText(n)
- case Emphasis:
- w.writeEmphasis(n)
- case StatisticToken:
- w.writeStatisticToken(n)
- case LineBreak:
- w.writeLineBreak(n)
- case ExplicitLineBreak:
- w.writeExplicitLineBreak(n)
- case RegularLink:
- w.writeRegularLink(n)
- case FootnoteLink:
- w.writeFootnoteLink(n)
- default:
- if n != nil {
- panic(fmt.Sprintf("bad node %#v", n))
- }
- }
- }
-}
-
-func (w *OrgWriter) writeHeadline(h Headline) {
+func (w *OrgWriter) WriteHeadline(h Headline) {
tmp := w.emptyClone()
tmp.WriteString(strings.Repeat("*", h.Lvl))
if h.Status != "" {
@@ -119,7 +58,7 @@ func (w *OrgWriter) writeHeadline(h Headline) {
tmp.WriteString(" [#" + h.Priority + "]")
}
tmp.WriteString(" ")
- tmp.WriteNodes(h.Title...)
+ WriteNodes(tmp, h.Title...)
hString := tmp.String()
if len(h.Tags) != 0 {
tString := ":" + strings.Join(h.Tags, ":") + ":"
@@ -136,12 +75,12 @@ func (w *OrgWriter) writeHeadline(h Headline) {
w.WriteString(w.indent)
}
if h.Properties != nil {
- w.WriteNodes(*h.Properties)
+ WriteNodes(w, *h.Properties)
}
- w.WriteNodes(h.Children...)
+ WriteNodes(w, h.Children...)
}
-func (w *OrgWriter) writeBlock(b Block) {
+func (w *OrgWriter) WriteBlock(b Block) {
w.WriteString(w.indent + "#+BEGIN_" + b.Name)
if len(b.Parameters) != 0 {
w.WriteString(" " + strings.Join(b.Parameters, " "))
@@ -150,20 +89,20 @@ func (w *OrgWriter) writeBlock(b Block) {
if isRawTextBlock(b.Name) {
w.WriteString(w.indent)
}
- w.WriteNodes(b.Children...)
+ WriteNodes(w, b.Children...)
if !isRawTextBlock(b.Name) {
w.WriteString(w.indent)
}
w.WriteString("#+END_" + b.Name + "\n")
}
-func (w *OrgWriter) writeDrawer(d Drawer) {
+func (w *OrgWriter) WriteDrawer(d Drawer) {
w.WriteString(w.indent + ":" + d.Name + ":\n")
- w.WriteNodes(d.Children...)
+ WriteNodes(w, d.Children...)
w.WriteString(w.indent + ":END:\n")
}
-func (w *OrgWriter) writePropertyDrawer(d PropertyDrawer) {
+func (w *OrgWriter) WritePropertyDrawer(d PropertyDrawer) {
w.WriteString(":PROPERTIES:\n")
for _, kvPair := range d.Properties {
k, v := kvPair[0], kvPair[1]
@@ -175,7 +114,7 @@ func (w *OrgWriter) writePropertyDrawer(d PropertyDrawer) {
w.WriteString(":END:\n")
}
-func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) {
+func (w *OrgWriter) WriteFootnoteDefinition(f FootnoteDefinition) {
w.WriteString(fmt.Sprintf("[fn:%s]", f.Name))
content := w.nodesAsString(f.Children...)
if content != "" && !unicode.IsSpace(rune(content[0])) {
@@ -184,7 +123,7 @@ func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) {
w.WriteString(content)
}
-func (w *OrgWriter) writeParagraph(p Paragraph) {
+func (w *OrgWriter) WriteParagraph(p Paragraph) {
content := w.nodesAsString(p.Children...)
if len(content) > 0 && content[0] != '\n' {
w.WriteString(w.indent)
@@ -192,7 +131,7 @@ func (w *OrgWriter) writeParagraph(p Paragraph) {
w.WriteString(content + "\n")
}
-func (w *OrgWriter) writeExample(e Example) {
+func (w *OrgWriter) WriteExample(e Example) {
for _, n := range e.Children {
w.WriteString(w.indent + ":")
if content := w.nodesAsString(n); content != "" {
@@ -202,7 +141,7 @@ func (w *OrgWriter) writeExample(e Example) {
}
}
-func (w *OrgWriter) writeKeyword(k Keyword) {
+func (w *OrgWriter) WriteKeyword(k Keyword) {
w.WriteString(w.indent + "#+" + k.Key + ":")
if k.Value != "" {
w.WriteString(" " + k.Value)
@@ -210,29 +149,33 @@ func (w *OrgWriter) writeKeyword(k Keyword) {
w.WriteString("\n")
}
-func (w *OrgWriter) writeNodeWithMeta(n NodeWithMeta) {
+func (w *OrgWriter) WriteInclude(i Include) {
+ w.WriteKeyword(i.Keyword)
+}
+
+func (w *OrgWriter) WriteNodeWithMeta(n NodeWithMeta) {
for _, ns := range n.Meta.Caption {
w.WriteString("#+CAPTION: ")
- w.WriteNodes(ns...)
+ WriteNodes(w, ns...)
w.WriteString("\n")
}
for _, attributes := range n.Meta.HTMLAttributes {
w.WriteString("#+ATTR_HTML: ")
w.WriteString(strings.Join(attributes, " ") + "\n")
}
- w.WriteNodes(n.Node)
+ WriteNodes(w, n.Node)
}
-func (w *OrgWriter) writeComment(c Comment) {
+func (w *OrgWriter) WriteComment(c Comment) {
w.WriteString(w.indent + "#" + c.Content + "\n")
}
-func (w *OrgWriter) writeList(l List) { w.WriteNodes(l.Items...) }
+func (w *OrgWriter) WriteList(l List) { WriteNodes(w, l.Items...) }
-func (w *OrgWriter) writeListItem(li ListItem) {
+func (w *OrgWriter) WriteListItem(li ListItem) {
liWriter := w.emptyClone()
liWriter.indent = w.indent + strings.Repeat(" ", len(li.Bullet)+1)
- liWriter.WriteNodes(li.Children...)
+ WriteNodes(liWriter, li.Children...)
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
w.WriteString(w.indent + li.Bullet)
if li.Status != "" {
@@ -245,7 +188,7 @@ func (w *OrgWriter) writeListItem(li ListItem) {
}
}
-func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
+func (w *OrgWriter) WriteDescriptiveListItem(di DescriptiveListItem) {
w.WriteString(w.indent + di.Bullet)
if di.Status != "" {
w.WriteString(fmt.Sprintf(" [%s]", di.Status))
@@ -258,7 +201,7 @@ func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
}
diWriter := w.emptyClone()
diWriter.indent = indent
- diWriter.WriteNodes(di.Details...)
+ WriteNodes(diWriter, di.Details...)
details := strings.TrimPrefix(diWriter.String(), diWriter.indent)
if len(details) > 0 && details[0] == '\n' {
w.WriteString(details)
@@ -267,7 +210,7 @@ func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
}
}
-func (w *OrgWriter) writeTable(t Table) {
+func (w *OrgWriter) WriteTable(t Table) {
for _, row := range t.Rows {
w.WriteString(w.indent)
if len(row.Columns) == 0 {
@@ -309,51 +252,51 @@ func (w *OrgWriter) writeTable(t Table) {
}
}
-func (w *OrgWriter) writeHorizontalRule(hr HorizontalRule) {
+func (w *OrgWriter) WriteHorizontalRule(hr HorizontalRule) {
w.WriteString(w.indent + "-----\n")
}
-func (w *OrgWriter) writeText(t Text) { w.WriteString(t.Content) }
+func (w *OrgWriter) WriteText(t Text) { w.WriteString(t.Content) }
-func (w *OrgWriter) writeEmphasis(e Emphasis) {
+func (w *OrgWriter) WriteEmphasis(e Emphasis) {
borders, ok := emphasisOrgBorders[e.Kind]
if !ok {
panic(fmt.Sprintf("bad emphasis %#v", e))
}
w.WriteString(borders[0])
- w.WriteNodes(e.Content...)
+ WriteNodes(w, e.Content...)
w.WriteString(borders[1])
}
-func (w *OrgWriter) writeStatisticToken(s StatisticToken) {
+func (w *OrgWriter) WriteStatisticToken(s StatisticToken) {
w.WriteString(fmt.Sprintf("[%s]", s.Content))
}
-func (w *OrgWriter) writeLineBreak(l LineBreak) {
+func (w *OrgWriter) WriteLineBreak(l LineBreak) {
w.WriteString(strings.Repeat("\n"+w.indent, l.Count))
}
-func (w *OrgWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
+func (w *OrgWriter) WriteExplicitLineBreak(l ExplicitLineBreak) {
w.WriteString(`\\` + "\n" + w.indent)
}
-func (w *OrgWriter) writeFootnoteLink(l FootnoteLink) {
+func (w *OrgWriter) WriteFootnoteLink(l FootnoteLink) {
w.WriteString("[fn:" + l.Name)
if l.Definition != nil {
w.WriteString(":")
- w.WriteNodes(l.Definition.Children[0].(Paragraph).Children...)
+ WriteNodes(w, l.Definition.Children[0].(Paragraph).Children...)
}
w.WriteString("]")
}
-func (w *OrgWriter) writeRegularLink(l RegularLink) {
+func (w *OrgWriter) WriteRegularLink(l RegularLink) {
if l.AutoLink {
w.WriteString(l.URL)
} else if l.Description == nil {
w.WriteString(fmt.Sprintf("[[%s]]", l.URL))
} else {
descriptionWriter := w.emptyClone()
- descriptionWriter.WriteNodes(l.Description...)
+ WriteNodes(descriptionWriter, l.Description...)
description := descriptionWriter.String()
w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, description))
}
diff --git a/org/writer.go b/org/writer.go
new file mode 100644
index 0000000..855d61a
--- /dev/null
+++ b/org/writer.go
@@ -0,0 +1,91 @@
+package org
+
+import "fmt"
+
+// Writer is the interface that is used to export a parsed document into a new format. See Document.Write().
+type Writer interface {
+ Before(*Document) // Before is called before any nodes are passed to the writer.
+ After(*Document) // After is called after all nodes have been passed to the writer.
+ String() string // String is called at the very end to retrieve the final output.
+
+ WriteKeyword(Keyword)
+ WriteInclude(Include)
+ WriteComment(Comment)
+ WriteNodeWithMeta(NodeWithMeta)
+ WriteHeadline(Headline)
+ WriteBlock(Block)
+ WriteExample(Example)
+ WriteDrawer(Drawer)
+ WritePropertyDrawer(PropertyDrawer)
+ WriteList(List)
+ WriteListItem(ListItem)
+ WriteDescriptiveListItem(DescriptiveListItem)
+ WriteTable(Table)
+ WriteHorizontalRule(HorizontalRule)
+ WriteParagraph(Paragraph)
+ WriteText(Text)
+ WriteEmphasis(Emphasis)
+ WriteStatisticToken(StatisticToken)
+ WriteExplicitLineBreak(ExplicitLineBreak)
+ WriteLineBreak(LineBreak)
+ WriteRegularLink(RegularLink)
+ WriteFootnoteLink(FootnoteLink)
+ WriteFootnoteDefinition(FootnoteDefinition)
+}
+
+func WriteNodes(w Writer, nodes ...Node) {
+ for _, n := range nodes {
+ switch n := n.(type) {
+ case Keyword:
+ w.WriteKeyword(n)
+ case Include:
+ w.WriteInclude(n)
+ case Comment:
+ w.WriteComment(n)
+ case NodeWithMeta:
+ w.WriteNodeWithMeta(n)
+ case Headline:
+ w.WriteHeadline(n)
+ case Block:
+ w.WriteBlock(n)
+ case Example:
+ w.WriteExample(n)
+ case Drawer:
+ w.WriteDrawer(n)
+ case PropertyDrawer:
+ w.WritePropertyDrawer(n)
+ case List:
+ w.WriteList(n)
+ case ListItem:
+ w.WriteListItem(n)
+ case DescriptiveListItem:
+ w.WriteDescriptiveListItem(n)
+ case Table:
+ w.WriteTable(n)
+ case HorizontalRule:
+ w.WriteHorizontalRule(n)
+ case Paragraph:
+ w.WriteParagraph(n)
+ case Text:
+ w.WriteText(n)
+ case Emphasis:
+ w.WriteEmphasis(n)
+ case StatisticToken:
+ w.WriteStatisticToken(n)
+ case ExplicitLineBreak:
+ w.WriteExplicitLineBreak(n)
+ case LineBreak:
+ w.WriteLineBreak(n)
+ case RegularLink:
+ w.WriteRegularLink(n)
+ case FootnoteLink:
+ w.WriteFootnoteLink(n)
+ case FootnoteDefinition:
+ w.WriteFootnoteDefinition(n)
+ default:
+ if n != nil {
+ panic(fmt.Sprintf("bad node %#v", n))
+ }
+ }
+ }
+}