diff --git a/org/block.go b/org/block.go
index 9668f3b..6ba264f 100644
--- a/org/block.go
+++ b/org/block.go
@@ -27,7 +27,7 @@ func lexBlock(line string) (token, bool) {
func isRawTextBlock(name string) bool { return name == "SRC" || name == "EXAMPLE" || name == "EXPORT" }
func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) {
- t, start, lines := d.tokens[i], i, []string{}
+ t, start := d.tokens[i], i
name, parameters := t.content, strings.Fields(t.matches[3])
trim := trimIndentUpTo(d.tokens[i].lvl)
stop := func(d *Document, i int) bool {
@@ -35,11 +35,12 @@ func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) {
}
block, consumed, i := Block{name, parameters, nil}, 0, i+1
if isRawTextBlock(name) {
+ rawText := ""
for ; !stop(d, i); i++ {
- lines = append(lines, trim(d.tokens[i].matches[0]))
+ rawText += trim(d.tokens[i].matches[0]) + "\n"
}
consumed = i - start
- block.Children = []Node{Text{strings.Join(lines, "\n")}}
+ block.Children = d.parseRawInline(rawText)
} else {
consumed, block.Children = d.parseMany(i, stop)
consumed++ // line with BEGIN
diff --git a/org/example.go b/org/example.go
index 9d716f3..9e737cb 100644
--- a/org/example.go
+++ b/org/example.go
@@ -20,7 +20,7 @@ func lexExample(line string) (token, bool) {
func (d *Document) parseExample(i int, parentStop stopFn) (int, Node) {
example, start := Example{}, i
for ; !parentStop(d, i) && d.tokens[i].kind == "example"; i++ {
- example.Children = append(example.Children, Text{d.tokens[i].content})
+ example.Children = append(example.Children, Text{d.tokens[i].content, true})
}
return i - start, example
}
diff --git a/org/html.go b/org/html.go
index d562345..e34f5d0 100644
--- a/org/html.go
+++ b/org/html.go
@@ -4,6 +4,7 @@ import (
"fmt"
"html"
"strings"
+ "unicode"
h "golang.org/x/net/html"
"golang.org/x/net/html/atom"
@@ -13,6 +14,7 @@ type HTMLWriter struct {
stringBuilder
HighlightCodeBlock func(source, lang string) string
FootnotesHeadingTitle string
+ htmlEscape bool
}
var emphasisTags = map[string][]string{
@@ -34,6 +36,7 @@ var listTags = map[string][]string{
func NewHTMLWriter() *HTMLWriter {
return &HTMLWriter{
+ htmlEscape: true,
FootnotesHeadingTitle: "Footnotes",
HighlightCodeBlock: func(source, lang string) string {
return fmt.Sprintf("%s\n
\n%s\n
\n", ``, html.EscapeString(source))
@@ -117,31 +120,34 @@ func (w *HTMLWriter) writeNodes(ns ...Node) {
}
func (w *HTMLWriter) writeBlock(b Block) {
+ content := ""
+ if isRawTextBlock(b.Name) {
+ exportWriter := w.emptyClone()
+ exportWriter.htmlEscape = false
+ exportWriter.writeNodes(b.Children...)
+ content = strings.TrimRightFunc(exportWriter.String(), unicode.IsSpace)
+ } else {
+ content = w.nodesAsString(b.Children...)
+ }
switch name := b.Name; {
case name == "SRC":
- source, lang := b.Children[0].(Text).Content, "text"
+ lang := "text"
if len(b.Parameters) >= 1 {
lang = strings.ToLower(b.Parameters[0])
}
- w.WriteString(w.HighlightCodeBlock(source, lang) + "\n")
+ w.WriteString(w.HighlightCodeBlock(content, lang) + "\n")
case name == "EXAMPLE":
- w.WriteString(`
` + "\n")
- w.writeNodes(b.Children...)
- w.WriteString("\n
\n")
+ w.WriteString(`
` + "\n" + content + "\n
\n")
case name == "EXPORT" && len(b.Parameters) >= 1 && strings.ToLower(b.Parameters[0]) == "html":
- w.WriteString(b.Children[0].(Text).Content + "\n")
+ w.WriteString(content + "\n")
case name == "QUOTE":
- w.WriteString("
\n")
- w.writeNodes(b.Children...)
- w.WriteString("
\n")
+ w.WriteString("
\n" + content + "
\n")
case name == "CENTER":
w.WriteString(`
` + "\n")
- w.writeNodes(b.Children...)
- w.WriteString("
\n")
+ w.WriteString(content + "
\n")
default:
w.WriteString(fmt.Sprintf(``, strings.ToLower(b.Name)) + "\n")
- w.writeNodes(b.Children...)
- w.WriteString("
\n")
+ w.WriteString(content + "\n")
}
}
@@ -205,7 +211,13 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
}
func (w *HTMLWriter) writeText(t Text) {
- w.WriteString(html.EscapeString(htmlEntityReplacer.Replace(t.Content)))
+ if !w.htmlEscape {
+ w.WriteString(t.Content)
+ } else if t.IsRaw {
+ w.WriteString(html.EscapeString(t.Content))
+ } else {
+ w.WriteString(html.EscapeString(htmlEntityReplacer.Replace(t.Content)))
+ }
}
func (w *HTMLWriter) writeEmphasis(e Emphasis) {
@@ -219,7 +231,7 @@ func (w *HTMLWriter) writeEmphasis(e Emphasis) {
}
func (w *HTMLWriter) writeLineBreak(l LineBreak) {
- w.WriteString("\n")
+ w.WriteString(strings.Repeat("\n", l.Count))
}
func (w *HTMLWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
@@ -298,7 +310,7 @@ func (w *HTMLWriter) writeExample(e Example) {
w.WriteString("\n")
}
}
- w.WriteString("\n\n")
+ w.WriteString("\n")
}
func (w *HTMLWriter) writeHorizontalRule(h HorizontalRule) {
diff --git a/org/inline.go b/org/inline.go
index e11fd45..52f2ff7 100644
--- a/org/inline.go
+++ b/org/inline.go
@@ -7,7 +7,10 @@ import (
"unicode"
)
-type Text struct{ Content string }
+type Text struct {
+ Content string
+ IsRaw bool
+}
type LineBreak struct{ Count int }
type ExplicitLineBreak struct{}
@@ -46,8 +49,10 @@ func (d *Document) parseInline(input string) (nodes []Node) {
consumed, node = d.parseSubOrSuperScript(input, current)
case '_':
consumed, node = d.parseSubScriptOrEmphasis(input, current)
- case '*', '/', '=', '~', '+':
- consumed, node = d.parseEmphasis(input, current)
+ case '*', '/', '+':
+ consumed, node = d.parseEmphasis(input, current, false)
+ case '=', '~':
+ consumed, node = d.parseEmphasis(input, current, true)
case '[':
consumed, node = d.parseRegularLinkOrFootnoteReference(input, current)
case '\\':
@@ -60,7 +65,7 @@ func (d *Document) parseInline(input string) (nodes []Node) {
}
if consumed != 0 {
if current > previous {
- nodes = append(nodes, Text{input[previous:current]})
+ nodes = append(nodes, Text{input[previous:current], false})
}
if node != nil {
nodes = append(nodes, node)
@@ -73,7 +78,28 @@ func (d *Document) parseInline(input string) (nodes []Node) {
}
if previous < len(input) {
- nodes = append(nodes, Text{input[previous:]})
+ nodes = append(nodes, Text{input[previous:], false})
+ }
+ return nodes
+}
+
+func (d *Document) parseRawInline(input string) (nodes []Node) {
+ previous, current := 0, 0
+ for current < len(input) {
+ if input[current] == '\n' {
+ consumed, node := d.parseLineBreak(input, current)
+ if current > previous {
+ nodes = append(nodes, Text{input[previous:current], true})
+ }
+ nodes = append(nodes, node)
+ current += consumed
+ previous = current
+ } else {
+ current++
+ }
+ }
+ if previous < len(input) {
+ nodes = append(nodes, Text{input[previous:], true})
}
return nodes
}
@@ -102,7 +128,7 @@ func (d *Document) parseExplicitLineBreak(input string, start int) (int, Node) {
func (d *Document) parseSubOrSuperScript(input string, start int) (int, Node) {
if m := subScriptSuperScriptRegexp.FindStringSubmatch(input[start:]); m != nil {
- return len(m[2]) + 3, Emphasis{m[1] + "{}", []Node{Text{m[2]}}}
+ return len(m[2]) + 3, Emphasis{m[1] + "{}", []Node{Text{m[2], false}}}
}
return 0, nil
}
@@ -111,7 +137,7 @@ func (d *Document) parseSubScriptOrEmphasis(input string, start int) (int, Node)
if consumed, node := d.parseSubOrSuperScript(input, start); consumed != 0 {
return consumed, node
}
- return d.parseEmphasis(input, start)
+ return d.parseEmphasis(input, start, false)
}
func (d *Document) parseRegularLinkOrFootnoteReference(input string, start int) (int, Node) {
@@ -180,7 +206,7 @@ func (d *Document) parseRegularLink(input string, start int) (int, Node) {
return consumed, RegularLink{protocol, description, link, false}
}
-func (d *Document) parseEmphasis(input string, start int) (int, Node) {
+func (d *Document) parseEmphasis(input string, start int, isRaw bool) (int, Node) {
marker, i := input[start], start
if !hasValidPreAndBorderChars(input, i) {
return 0, nil
@@ -191,6 +217,9 @@ func (d *Document) parseEmphasis(input string, start int) (int, Node) {
}
if input[i] == marker && i != start+1 && hasValidPostAndBorderChars(input, i) {
+ if isRaw {
+ return i + 1 - start, Emphasis{input[start : start+1], d.parseRawInline(input[start+1 : i])}
+ }
return i + 1 - start, Emphasis{input[start : start+1], d.parseInline(input[start+1 : i])}
}
}
diff --git a/org/keyword.go b/org/keyword.go
index c972430..cf1121c 100644
--- a/org/keyword.go
+++ b/org/keyword.go
@@ -117,7 +117,7 @@ func (d *Document) newInclude(k Keyword) (int, Node) {
if err != nil {
panic(fmt.Sprintf("bad include '#+INCLUDE: %s': %s", k.Value, err))
}
- return Block{strings.ToUpper(kind), []string{lang}, []Node{Text{string(bs)}}}
+ return Block{strings.ToUpper(kind), []string{lang}, d.parseRawInline(string(bs))}
}
}
return 1, Include{k, resolve}
diff --git a/org/org.go b/org/org.go
index e70162a..116038d 100644
--- a/org/org.go
+++ b/org/org.go
@@ -140,16 +140,9 @@ func (w *OrgWriter) writeBlock(b Block) {
if len(b.Parameters) != 0 {
w.WriteString(" " + strings.Join(b.Parameters, " "))
}
- w.WriteString("\n")
-
- if isRawTextBlock(b.Name) {
- for _, line := range strings.Split(b.Children[0].(Text).Content, "\n") {
- w.WriteString(w.indent + line + "\n")
- }
- } else {
- w.writeNodes(b.Children...)
- }
- w.WriteString(w.indent + "#+END_" + b.Name + "\n")
+ w.WriteString("\n" + w.indent)
+ w.writeNodes(b.Children...)
+ w.WriteString("#+END_" + b.Name + "\n")
}
func (w *OrgWriter) writeDrawer(d Drawer) {
diff --git a/org/testdata/blocks.html b/org/testdata/blocks.html
index 5160801..d6d5ebd 100644
--- a/org/testdata/blocks.html
+++ b/org/testdata/blocks.html
@@ -34,7 +34,6 @@ note that /inline/ *markup* ignored
examples like this
are also supported
note that /inline/ *markup* ignored
-
diff --git a/org/testdata/lists.html b/org/testdata/lists.html
index e93a7bf..4d93680 100644
--- a/org/testdata/lists.html
+++ b/org/testdata/lists.html
@@ -88,7 +88,6 @@ unordered list item 4
with an example
that spans multiple lines
-
diff --git a/org/testdata/misc.html b/org/testdata/misc.html
index 550e903..9da1979 100644
--- a/org/testdata/misc.html
+++ b/org/testdata/misc.html
@@ -57,7 +57,6 @@ Still outside the drawer
This is inside the drawer
:END:
Still outside the drawer
-
@@ -79,7 +78,6 @@ lines.
Paragraphs can contain inline markup like emphasis strong and links example.com and stuff.
-
@@ -87,7 +85,7 @@ example block
language: go
-go: "1.x"
+go: "1.x"
script:
- make test
- make generate-gh-pages
@@ -100,7 +98,6 @@ deploy:
verbose: true
on:
branch: master
-
@@ -270,3 +267,89 @@ Bar
Bar paragraph
+
+DONE
+#86: Multiple hyphens not converted to dashes
+
+
+just like #46
+
+
+-
+
+--
-> – (en dash)
+
+
+-
+
+---
-> — (em dash)
+
+
+
+
+also, consecutive dashes inside
+
+
+
+DONE
+#87: Markup in footnotes is rendered literally
+
+
+footnotes can contain markup - and other elements and stuff
+
+
diff --git a/org/testdata/misc.org b/org/testdata/misc.org
index 643a862..a871ff7 100644
--- a/org/testdata/misc.org
+++ b/org/testdata/misc.org
@@ -82,3 +82,33 @@ just a space as title...
Foo paragraph.
**** Bar
Bar paragraph
+*** DONE [[https://github.com/chaseadamsio/goorgeous/issues/86][#86]]: Multiple hyphens not converted to dashes
+just like #46
+- =--= -> -- (en dash)
+- =---= -> --- (em dash)
+
+also, consecutive dashes inside
+- inline code =--= =---= and verbatim ~--~ ~---~
+- src/example/export blocks should not be converted!
+ #+BEGIN_SRC sh
+ --, ---
+ #+END_SRC
+
+ #+BEGIN_EXAMPLE
+ --, ---
+ #+END_EXAMPLE
+
+ #+BEGIN_EXPORT html
+ --, ---
+ #+END_EXPORT
+
+ : --, ---
+
+*** DONE [[https://github.com/chaseadamsio/goorgeous/issues/87][#87]]: Markup in footnotes is rendered literally
+footnotes can contain *markup* - and other elements and stuff [fn:2:that also goes for *inline* footnote /definitions/]
+
+* Footnotes
+
+[fn:1] a footnote /with/ *markup*
+- and a *list*
+- because that's possible