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.
This commit is contained in:
parent
7110853eb5
commit
faea88d48e
4 changed files with 174 additions and 204 deletions
|
@ -41,14 +41,6 @@ type Document struct {
|
||||||
Error error
|
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.
|
// Node represents a parsed node of the document. It's an empty interface and can be ignored.
|
||||||
type Node interface{}
|
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")
|
return "", fmt.Errorf("could not write output: parse was not called")
|
||||||
}
|
}
|
||||||
w.Before(d)
|
w.Before(d)
|
||||||
w.WriteNodes(d.Nodes...)
|
WriteNodes(w, d.Nodes...)
|
||||||
w.After(d)
|
w.After(d)
|
||||||
return w.String(), err
|
return w.String(), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,87 +63,29 @@ func (w *HTMLWriter) emptyClone() *HTMLWriter {
|
||||||
|
|
||||||
func (w *HTMLWriter) nodesAsString(nodes ...Node) string {
|
func (w *HTMLWriter) nodesAsString(nodes ...Node) string {
|
||||||
tmp := w.emptyClone()
|
tmp := w.emptyClone()
|
||||||
tmp.WriteNodes(nodes...)
|
WriteNodes(tmp, nodes...)
|
||||||
return tmp.String()
|
return tmp.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) Before(d *Document) {
|
func (w *HTMLWriter) Before(d *Document) {
|
||||||
w.document = d
|
w.document = d
|
||||||
w.log = d.Log
|
w.log = d.Log
|
||||||
w.writeOutline(d)
|
w.WriteOutline(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) After(d *Document) {
|
func (w *HTMLWriter) After(d *Document) {
|
||||||
w.writeFootnotes(d)
|
w.WriteFootnotes(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) WriteNodes(ns ...Node) {
|
func (w *HTMLWriter) WriteComment(Comment) {}
|
||||||
for _, n := range ns {
|
func (w *HTMLWriter) WritePropertyDrawer(PropertyDrawer) {}
|
||||||
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
|
|
||||||
|
|
||||||
case FootnoteDefinition:
|
func (w *HTMLWriter) WriteBlock(b Block) {
|
||||||
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) {
|
|
||||||
content := ""
|
content := ""
|
||||||
if isRawTextBlock(b.Name) {
|
if isRawTextBlock(b.Name) {
|
||||||
exportWriter := w.emptyClone()
|
exportWriter := w.emptyClone()
|
||||||
exportWriter.htmlEscape = false
|
exportWriter.htmlEscape = false
|
||||||
exportWriter.WriteNodes(b.Children...)
|
WriteNodes(exportWriter, b.Children...)
|
||||||
content = strings.TrimRightFunc(exportWriter.String(), unicode.IsSpace)
|
content = strings.TrimRightFunc(exportWriter.String(), unicode.IsSpace)
|
||||||
} else {
|
} else {
|
||||||
content = w.nodesAsString(b.Children...)
|
content = w.nodesAsString(b.Children...)
|
||||||
|
@ -170,30 +112,32 @@ func (w *HTMLWriter) writeBlock(b Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeDrawer(d Drawer) {
|
func (w *HTMLWriter) WriteDrawer(d Drawer) {
|
||||||
w.WriteNodes(d.Children...)
|
WriteNodes(w, d.Children...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeKeyword(k Keyword) {
|
func (w *HTMLWriter) WriteKeyword(k Keyword) {
|
||||||
if k.Key == "HTML" {
|
if k.Key == "HTML" {
|
||||||
w.WriteString(k.Value + "\n")
|
w.WriteString(k.Value + "\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeInclude(i Include) {
|
func (w *HTMLWriter) WriteInclude(i Include) {
|
||||||
w.WriteNodes(i.Resolve())
|
WriteNodes(w, i.Resolve())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *HTMLWriter) WriteFootnoteDefinition(FootnoteDefinition) {}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeFootnoteDefinition(f FootnoteDefinition) {
|
func (w *HTMLWriter) writeFootnoteDefinition(f FootnoteDefinition) {
|
||||||
n := f.Name
|
n := f.Name
|
||||||
w.WriteString(`<div class="footnote-definition">` + "\n")
|
w.WriteString(`<div class="footnote-definition">` + "\n")
|
||||||
w.WriteString(fmt.Sprintf(`<sup id="footnote-%s"><a href="#footnote-reference-%s">%s</a></sup>`, n, n, n) + "\n")
|
w.WriteString(fmt.Sprintf(`<sup id="footnote-%s"><a href="#footnote-reference-%s">%s</a></sup>`, n, n, n) + "\n")
|
||||||
w.WriteString(`<div class="footnote-body">` + "\n")
|
w.WriteString(`<div class="footnote-body">` + "\n")
|
||||||
w.WriteNodes(f.Children...)
|
WriteNodes(w, f.Children...)
|
||||||
w.WriteString("</div>\n</div>\n")
|
w.WriteString("</div>\n</div>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeFootnotes(d *Document) {
|
func (w *HTMLWriter) WriteFootnotes(d *Document) {
|
||||||
if !w.document.GetOption("f") || len(d.Footnotes.Definitions) == 0 {
|
if !w.document.GetOption("f") || len(d.Footnotes.Definitions) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -206,7 +150,7 @@ func (w *HTMLWriter) writeFootnotes(d *Document) {
|
||||||
w.WriteString("</div>\n</div>\n")
|
w.WriteString("</div>\n</div>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeOutline(d *Document) {
|
func (w *HTMLWriter) WriteOutline(d *Document) {
|
||||||
if w.document.GetOption("toc") && len(d.Outline.Children) != 0 {
|
if w.document.GetOption("toc") && len(d.Outline.Children) != 0 {
|
||||||
w.WriteString("<nav>\n<ul>\n")
|
w.WriteString("<nav>\n<ul>\n")
|
||||||
for _, section := range d.Outline.Children {
|
for _, section := range d.Outline.Children {
|
||||||
|
@ -232,7 +176,7 @@ func (w *HTMLWriter) writeSection(section *Section) {
|
||||||
w.WriteString("</li>\n")
|
w.WriteString("</li>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeHeadline(h Headline) {
|
func (w *HTMLWriter) WriteHeadline(h Headline) {
|
||||||
for _, excludeTag := range strings.Fields(w.document.Get("EXCLUDE_TAGS")) {
|
for _, excludeTag := range strings.Fields(w.document.Get("EXCLUDE_TAGS")) {
|
||||||
for _, tag := range h.Tags {
|
for _, tag := range h.Tags {
|
||||||
if excludeTag == tag {
|
if excludeTag == tag {
|
||||||
|
@ -249,7 +193,7 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
|
||||||
w.WriteString(fmt.Sprintf(`<span class="priority">[%s]</span>`, h.Priority) + "\n")
|
w.WriteString(fmt.Sprintf(`<span class="priority">[%s]</span>`, h.Priority) + "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteNodes(h.Title...)
|
WriteNodes(w, h.Title...)
|
||||||
if w.document.GetOption("tags") && len(h.Tags) != 0 {
|
if w.document.GetOption("tags") && len(h.Tags) != 0 {
|
||||||
tags := make([]string, len(h.Tags))
|
tags := make([]string, len(h.Tags))
|
||||||
for i, tag := range h.Tags {
|
for i, tag := range h.Tags {
|
||||||
|
@ -259,10 +203,10 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
|
||||||
w.WriteString(fmt.Sprintf(`<span class="tags">%s</span>`, strings.Join(tags, " ")))
|
w.WriteString(fmt.Sprintf(`<span class="tags">%s</span>`, strings.Join(tags, " ")))
|
||||||
}
|
}
|
||||||
w.WriteString(fmt.Sprintf("\n</h%d>\n", h.Lvl))
|
w.WriteString(fmt.Sprintf("\n</h%d>\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 {
|
if !w.htmlEscape {
|
||||||
w.WriteString(t.Content)
|
w.WriteString(t.Content)
|
||||||
} else if !w.document.GetOption("e") || t.IsRaw {
|
} 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]
|
tags, ok := emphasisTags[e.Kind]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("bad emphasis %#v", e))
|
panic(fmt.Sprintf("bad emphasis %#v", e))
|
||||||
}
|
}
|
||||||
w.WriteString(tags[0])
|
w.WriteString(tags[0])
|
||||||
w.WriteNodes(e.Content...)
|
WriteNodes(w, e.Content...)
|
||||||
w.WriteString(tags[1])
|
w.WriteString(tags[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeStatisticToken(s StatisticToken) {
|
func (w *HTMLWriter) WriteStatisticToken(s StatisticToken) {
|
||||||
w.WriteString(fmt.Sprintf(`<code class="statistic">[%s]</code>`, s.Content))
|
w.WriteString(fmt.Sprintf(`<code class="statistic">[%s]</code>`, s.Content))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeLineBreak(l LineBreak) {
|
func (w *HTMLWriter) WriteLineBreak(l LineBreak) {
|
||||||
w.WriteString(strings.Repeat("\n", l.Count))
|
w.WriteString(strings.Repeat("\n", l.Count))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
|
func (w *HTMLWriter) WriteExplicitLineBreak(l ExplicitLineBreak) {
|
||||||
w.WriteString("<br>\n")
|
w.WriteString("<br>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeFootnoteLink(l FootnoteLink) {
|
func (w *HTMLWriter) WriteFootnoteLink(l FootnoteLink) {
|
||||||
if !w.document.GetOption("f") {
|
if !w.document.GetOption("f") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -302,7 +246,7 @@ func (w *HTMLWriter) writeFootnoteLink(l FootnoteLink) {
|
||||||
w.WriteString(fmt.Sprintf(`<sup class="footnote-reference"><a id="footnote-reference-%s" href="#footnote-%s">%s</a></sup>`, n, n, n))
|
w.WriteString(fmt.Sprintf(`<sup class="footnote-reference"><a id="footnote-reference-%s" href="#footnote-%s">%s</a></sup>`, n, n, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeRegularLink(l RegularLink) {
|
func (w *HTMLWriter) WriteRegularLink(l RegularLink) {
|
||||||
url := html.EscapeString(l.URL)
|
url := html.EscapeString(l.URL)
|
||||||
if l.Protocol == "file" {
|
if l.Protocol == "file" {
|
||||||
url = url[len("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]
|
tags, ok := listTags[l.Kind]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("bad list kind %#v", l))
|
panic(fmt.Sprintf("bad list kind %#v", l))
|
||||||
}
|
}
|
||||||
w.WriteString(tags[0] + "\n")
|
w.WriteString(tags[0] + "\n")
|
||||||
w.WriteNodes(l.Items...)
|
WriteNodes(w, l.Items...)
|
||||||
w.WriteString(tags[1] + "\n")
|
w.WriteString(tags[1] + "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeListItem(li ListItem) {
|
func (w *HTMLWriter) WriteListItem(li ListItem) {
|
||||||
if li.Status != "" {
|
if li.Status != "" {
|
||||||
w.WriteString(fmt.Sprintf("<li class=\"%s\">\n", listItemStatuses[li.Status]))
|
w.WriteString(fmt.Sprintf("<li class=\"%s\">\n", listItemStatuses[li.Status]))
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("<li>\n")
|
w.WriteString("<li>\n")
|
||||||
}
|
}
|
||||||
w.WriteNodes(li.Children...)
|
WriteNodes(w, li.Children...)
|
||||||
w.WriteString("</li>\n")
|
w.WriteString("</li>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
func (w *HTMLWriter) WriteDescriptiveListItem(di DescriptiveListItem) {
|
||||||
if di.Status != "" {
|
if di.Status != "" {
|
||||||
w.WriteString(fmt.Sprintf("<dt class=\"%s\">\n", listItemStatuses[di.Status]))
|
w.WriteString(fmt.Sprintf("<dt class=\"%s\">\n", listItemStatuses[di.Status]))
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,16 +293,16 @@ func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(di.Term) != 0 {
|
if len(di.Term) != 0 {
|
||||||
w.WriteNodes(di.Term...)
|
WriteNodes(w, di.Term...)
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("?")
|
w.WriteString("?")
|
||||||
}
|
}
|
||||||
w.WriteString("<dd>\n")
|
w.WriteString("<dd>\n")
|
||||||
w.WriteNodes(di.Details...)
|
WriteNodes(w, di.Details...)
|
||||||
w.WriteString("<dd>\n")
|
w.WriteString("<dd>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeParagraph(p Paragraph) {
|
func (w *HTMLWriter) WriteParagraph(p Paragraph) {
|
||||||
if len(p.Children) == 0 {
|
if len(p.Children) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -366,26 +310,26 @@ func (w *HTMLWriter) writeParagraph(p Paragraph) {
|
||||||
if _, ok := p.Children[0].(LineBreak); !ok {
|
if _, ok := p.Children[0].(LineBreak); !ok {
|
||||||
w.WriteString("\n")
|
w.WriteString("\n")
|
||||||
}
|
}
|
||||||
w.WriteNodes(p.Children...)
|
WriteNodes(w, p.Children...)
|
||||||
w.WriteString("\n</p>\n")
|
w.WriteString("\n</p>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeExample(e Example) {
|
func (w *HTMLWriter) WriteExample(e Example) {
|
||||||
w.WriteString(`<pre class="example">` + "\n")
|
w.WriteString(`<pre class="example">` + "\n")
|
||||||
if len(e.Children) != 0 {
|
if len(e.Children) != 0 {
|
||||||
for _, n := range e.Children {
|
for _, n := range e.Children {
|
||||||
w.WriteNodes(n)
|
WriteNodes(w, n)
|
||||||
w.WriteString("\n")
|
w.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.WriteString("</pre>\n")
|
w.WriteString("</pre>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeHorizontalRule(h HorizontalRule) {
|
func (w *HTMLWriter) WriteHorizontalRule(h HorizontalRule) {
|
||||||
w.WriteString("<hr>\n")
|
w.WriteString("<hr>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeNodeWithMeta(n NodeWithMeta) {
|
func (w *HTMLWriter) WriteNodeWithMeta(n NodeWithMeta) {
|
||||||
out := w.nodesAsString(n.Node)
|
out := w.nodesAsString(n.Node)
|
||||||
if p, ok := n.Node.(Paragraph); ok {
|
if p, ok := n.Node.(Paragraph); ok {
|
||||||
if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
|
if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
|
||||||
|
@ -408,7 +352,7 @@ func (w *HTMLWriter) writeNodeWithMeta(n NodeWithMeta) {
|
||||||
w.WriteString(out)
|
w.WriteString(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeTable(t Table) {
|
func (w *HTMLWriter) WriteTable(t Table) {
|
||||||
w.WriteString("<table>\n")
|
w.WriteString("<table>\n")
|
||||||
beforeFirstContentRow := true
|
beforeFirstContentRow := true
|
||||||
for i, row := range t.Rows {
|
for i, row := range t.Rows {
|
||||||
|
@ -439,7 +383,7 @@ func (w *HTMLWriter) writeTableColumns(columns []Column, tag string) {
|
||||||
} else {
|
} else {
|
||||||
w.WriteString(fmt.Sprintf(`<%s class="align-%s">`, tag, column.Align))
|
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(fmt.Sprintf("</%s>\n", tag))
|
||||||
}
|
}
|
||||||
w.WriteString("</tr>\n")
|
w.WriteString("</tr>\n")
|
||||||
|
|
|
@ -44,72 +44,11 @@ func (w *OrgWriter) emptyClone() *OrgWriter {
|
||||||
|
|
||||||
func (w *OrgWriter) nodesAsString(nodes ...Node) string {
|
func (w *OrgWriter) nodesAsString(nodes ...Node) string {
|
||||||
tmp := w.emptyClone()
|
tmp := w.emptyClone()
|
||||||
tmp.WriteNodes(nodes...)
|
WriteNodes(tmp, nodes...)
|
||||||
return tmp.String()
|
return tmp.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) WriteNodes(ns ...Node) {
|
func (w *OrgWriter) WriteHeadline(h Headline) {
|
||||||
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) {
|
|
||||||
tmp := w.emptyClone()
|
tmp := w.emptyClone()
|
||||||
tmp.WriteString(strings.Repeat("*", h.Lvl))
|
tmp.WriteString(strings.Repeat("*", h.Lvl))
|
||||||
if h.Status != "" {
|
if h.Status != "" {
|
||||||
|
@ -119,7 +58,7 @@ func (w *OrgWriter) writeHeadline(h Headline) {
|
||||||
tmp.WriteString(" [#" + h.Priority + "]")
|
tmp.WriteString(" [#" + h.Priority + "]")
|
||||||
}
|
}
|
||||||
tmp.WriteString(" ")
|
tmp.WriteString(" ")
|
||||||
tmp.WriteNodes(h.Title...)
|
WriteNodes(tmp, h.Title...)
|
||||||
hString := tmp.String()
|
hString := tmp.String()
|
||||||
if len(h.Tags) != 0 {
|
if len(h.Tags) != 0 {
|
||||||
tString := ":" + strings.Join(h.Tags, ":") + ":"
|
tString := ":" + strings.Join(h.Tags, ":") + ":"
|
||||||
|
@ -136,12 +75,12 @@ func (w *OrgWriter) writeHeadline(h Headline) {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
}
|
}
|
||||||
if h.Properties != nil {
|
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)
|
w.WriteString(w.indent + "#+BEGIN_" + b.Name)
|
||||||
if len(b.Parameters) != 0 {
|
if len(b.Parameters) != 0 {
|
||||||
w.WriteString(" " + strings.Join(b.Parameters, " "))
|
w.WriteString(" " + strings.Join(b.Parameters, " "))
|
||||||
|
@ -150,20 +89,20 @@ func (w *OrgWriter) writeBlock(b Block) {
|
||||||
if isRawTextBlock(b.Name) {
|
if isRawTextBlock(b.Name) {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
}
|
}
|
||||||
w.WriteNodes(b.Children...)
|
WriteNodes(w, b.Children...)
|
||||||
if !isRawTextBlock(b.Name) {
|
if !isRawTextBlock(b.Name) {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
}
|
}
|
||||||
w.WriteString("#+END_" + b.Name + "\n")
|
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.WriteString(w.indent + ":" + d.Name + ":\n")
|
||||||
w.WriteNodes(d.Children...)
|
WriteNodes(w, d.Children...)
|
||||||
w.WriteString(w.indent + ":END:\n")
|
w.WriteString(w.indent + ":END:\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) writePropertyDrawer(d PropertyDrawer) {
|
func (w *OrgWriter) WritePropertyDrawer(d PropertyDrawer) {
|
||||||
w.WriteString(":PROPERTIES:\n")
|
w.WriteString(":PROPERTIES:\n")
|
||||||
for _, kvPair := range d.Properties {
|
for _, kvPair := range d.Properties {
|
||||||
k, v := kvPair[0], kvPair[1]
|
k, v := kvPair[0], kvPair[1]
|
||||||
|
@ -175,7 +114,7 @@ func (w *OrgWriter) writePropertyDrawer(d PropertyDrawer) {
|
||||||
w.WriteString(":END:\n")
|
w.WriteString(":END:\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
content := w.nodesAsString(f.Children...)
|
content := w.nodesAsString(f.Children...)
|
||||||
if content != "" && !unicode.IsSpace(rune(content[0])) {
|
if content != "" && !unicode.IsSpace(rune(content[0])) {
|
||||||
|
@ -184,7 +123,7 @@ func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) {
|
||||||
w.WriteString(content)
|
w.WriteString(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) writeParagraph(p Paragraph) {
|
func (w *OrgWriter) WriteParagraph(p Paragraph) {
|
||||||
content := w.nodesAsString(p.Children...)
|
content := w.nodesAsString(p.Children...)
|
||||||
if len(content) > 0 && content[0] != '\n' {
|
if len(content) > 0 && content[0] != '\n' {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
|
@ -192,7 +131,7 @@ func (w *OrgWriter) writeParagraph(p Paragraph) {
|
||||||
w.WriteString(content + "\n")
|
w.WriteString(content + "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) writeExample(e Example) {
|
func (w *OrgWriter) WriteExample(e Example) {
|
||||||
for _, n := range e.Children {
|
for _, n := range e.Children {
|
||||||
w.WriteString(w.indent + ":")
|
w.WriteString(w.indent + ":")
|
||||||
if content := w.nodesAsString(n); content != "" {
|
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 + ":")
|
w.WriteString(w.indent + "#+" + k.Key + ":")
|
||||||
if k.Value != "" {
|
if k.Value != "" {
|
||||||
w.WriteString(" " + k.Value)
|
w.WriteString(" " + k.Value)
|
||||||
|
@ -210,29 +149,33 @@ func (w *OrgWriter) writeKeyword(k Keyword) {
|
||||||
w.WriteString("\n")
|
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 {
|
for _, ns := range n.Meta.Caption {
|
||||||
w.WriteString("#+CAPTION: ")
|
w.WriteString("#+CAPTION: ")
|
||||||
w.WriteNodes(ns...)
|
WriteNodes(w, ns...)
|
||||||
w.WriteString("\n")
|
w.WriteString("\n")
|
||||||
}
|
}
|
||||||
for _, attributes := range n.Meta.HTMLAttributes {
|
for _, attributes := range n.Meta.HTMLAttributes {
|
||||||
w.WriteString("#+ATTR_HTML: ")
|
w.WriteString("#+ATTR_HTML: ")
|
||||||
w.WriteString(strings.Join(attributes, " ") + "\n")
|
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")
|
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 := w.emptyClone()
|
||||||
liWriter.indent = w.indent + strings.Repeat(" ", len(li.Bullet)+1)
|
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)
|
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
|
||||||
w.WriteString(w.indent + li.Bullet)
|
w.WriteString(w.indent + li.Bullet)
|
||||||
if li.Status != "" {
|
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)
|
w.WriteString(w.indent + di.Bullet)
|
||||||
if di.Status != "" {
|
if di.Status != "" {
|
||||||
w.WriteString(fmt.Sprintf(" [%s]", di.Status))
|
w.WriteString(fmt.Sprintf(" [%s]", di.Status))
|
||||||
|
@ -258,7 +201,7 @@ func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
||||||
}
|
}
|
||||||
diWriter := w.emptyClone()
|
diWriter := w.emptyClone()
|
||||||
diWriter.indent = indent
|
diWriter.indent = indent
|
||||||
diWriter.WriteNodes(di.Details...)
|
WriteNodes(diWriter, di.Details...)
|
||||||
details := strings.TrimPrefix(diWriter.String(), diWriter.indent)
|
details := strings.TrimPrefix(diWriter.String(), diWriter.indent)
|
||||||
if len(details) > 0 && details[0] == '\n' {
|
if len(details) > 0 && details[0] == '\n' {
|
||||||
w.WriteString(details)
|
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 {
|
for _, row := range t.Rows {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
if len(row.Columns) == 0 {
|
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")
|
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]
|
borders, ok := emphasisOrgBorders[e.Kind]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("bad emphasis %#v", e))
|
panic(fmt.Sprintf("bad emphasis %#v", e))
|
||||||
}
|
}
|
||||||
w.WriteString(borders[0])
|
w.WriteString(borders[0])
|
||||||
w.WriteNodes(e.Content...)
|
WriteNodes(w, e.Content...)
|
||||||
w.WriteString(borders[1])
|
w.WriteString(borders[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) writeStatisticToken(s StatisticToken) {
|
func (w *OrgWriter) WriteStatisticToken(s StatisticToken) {
|
||||||
w.WriteString(fmt.Sprintf("[%s]", s.Content))
|
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))
|
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)
|
w.WriteString(`\\` + "\n" + w.indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
if l.Definition != nil {
|
||||||
w.WriteString(":")
|
w.WriteString(":")
|
||||||
w.WriteNodes(l.Definition.Children[0].(Paragraph).Children...)
|
WriteNodes(w, l.Definition.Children[0].(Paragraph).Children...)
|
||||||
}
|
}
|
||||||
w.WriteString("]")
|
w.WriteString("]")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) writeRegularLink(l RegularLink) {
|
func (w *OrgWriter) WriteRegularLink(l RegularLink) {
|
||||||
if l.AutoLink {
|
if l.AutoLink {
|
||||||
w.WriteString(l.URL)
|
w.WriteString(l.URL)
|
||||||
} else if l.Description == nil {
|
} else if l.Description == nil {
|
||||||
w.WriteString(fmt.Sprintf("[[%s]]", l.URL))
|
w.WriteString(fmt.Sprintf("[[%s]]", l.URL))
|
||||||
} else {
|
} else {
|
||||||
descriptionWriter := w.emptyClone()
|
descriptionWriter := w.emptyClone()
|
||||||
descriptionWriter.WriteNodes(l.Description...)
|
WriteNodes(descriptionWriter, l.Description...)
|
||||||
description := descriptionWriter.String()
|
description := descriptionWriter.String()
|
||||||
w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, description))
|
w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, description))
|
||||||
}
|
}
|
||||||
|
|
91
org/writer.go
Normal file
91
org/writer.go
Normal file
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue