Fix multiline emphasis

I didn't have a test case for this and broke it when i introduced Line nodes to
support printing back to org mode. Oops
This commit is contained in:
Niklas Fasching 2018-12-10 17:14:13 +01:00
parent 6de03e0d13
commit 6637e63892
9 changed files with 104 additions and 71 deletions

View file

@ -24,31 +24,30 @@ func lexBlock(line string) (token, bool) {
return nilToken, false
}
func isRawTextBlock(name string) bool { return name == "SRC" || name == "EXAMPLE" }
func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) {
t, start, nodes := d.tokens[i], i, []Node{}
t, start, lines := d.tokens[i], i, []string{}
name, parameters := t.content, strings.Fields(t.matches[3])
trim := trimIndentUpTo(d.tokens[i].lvl)
stop := func(d *Document, i int) bool {
return parentStop(d, i) || (d.tokens[i].kind == "endBlock" && d.tokens[i].content == name)
}
if name == "SRC" || name == "EXAMPLE" {
for i++; !stop(d, i); i++ {
nodes = append(nodes, Line{[]Node{Text{trim(d.tokens[i].matches[0])}}})
block, consumed, i := Block{name, parameters, nil}, 0, i+1
if isRawTextBlock(name) {
for ; !stop(d, i); i++ {
lines = append(lines, trim(d.tokens[i].matches[0]))
}
consumed = i - start
block.Children = []Node{Text{strings.Join(lines, "\n")}}
} else {
for i++; !stop(d, i); {
consumed, node := d.parseParagraph(i, stop)
if consumed == 0 {
break
}
i += consumed
nodes = append(nodes, node)
}
consumed, block.Children = d.parseMany(i, stop)
consumed++ // line with BEGIN
}
if parentStop(d, i) {
return 0, nil
}
return i + 1 - start, Block{name, parameters, nodes}
return consumed + 1, block
}
func trimIndentUpTo(max int) func(string) string {

View file

@ -86,15 +86,14 @@ func (w *HTMLWriter) writeNodes(ns ...Node) {
w.writeParagraph(n)
case HorizontalRule:
w.writeHorizontalRule(n)
case Line:
w.writeLine(n)
case Text:
w.writeText(n)
case Emphasis:
w.writeEmphasis(n)
case Linebreak:
w.writeLinebreak(n)
case ExplicitLineBreak:
w.writeExplicitLineBreak(n)
case LineBreak:
w.writeLineBreak(n)
case RegularLink:
w.writeRegularLink(n)
case FootnoteLink:
@ -110,18 +109,15 @@ func (w *HTMLWriter) writeNodes(ns ...Node) {
func (w *HTMLWriter) writeBlock(b Block) {
switch b.Name {
case "SRC":
lines, lang := []string{}, "text"
source, lang := b.Children[0].(Text).Content, "text"
if len(b.Parameters) >= 1 {
lang = b.Parameters[0]
}
for _, n := range b.Children {
lines = append(lines, n.(Line).Children[0].(Text).Content)
}
w.WriteString(w.HighlightCodeBlock(strings.Join(lines, "\n"), lang) + "\n")
w.WriteString(w.HighlightCodeBlock(source, lang) + "\n")
case "EXAMPLE":
w.WriteString(`<pre class="example">` + "\n")
w.writeNodes(b.Children...)
w.WriteString("</pre>\n")
w.WriteString("\n</pre>\n")
case "QUOTE":
w.WriteString("<blockquote>\n")
w.writeNodes(b.Children...)
@ -134,7 +130,6 @@ func (w *HTMLWriter) writeBlock(b Block) {
w.WriteString(fmt.Sprintf(`<div class="%s-block">`, strings.ToLower(b.Name)) + "\n")
w.writeNodes(b.Children...)
w.WriteString("</div>\n")
}
}
@ -182,7 +177,11 @@ func (w *HTMLWriter) writeEmphasis(e Emphasis) {
w.WriteString(tags[1])
}
func (w *HTMLWriter) writeLinebreak(l Linebreak) {
func (w *HTMLWriter) writeLineBreak(l LineBreak) {
w.WriteString("\n")
}
func (w *HTMLWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
w.WriteString("<br>\n")
}
@ -228,20 +227,16 @@ func (w *HTMLWriter) writeListItem(li ListItem) {
w.WriteString("</li>\n")
}
func (w *HTMLWriter) writeLine(l Line) {
if len(l.Children) != 0 {
w.writeNodes(l.Children...)
w.WriteString("\n")
}
}
func (w *HTMLWriter) writeParagraph(p Paragraph) {
if len(p.Children) == 1 && p.Children[0].(Line).Children == nil {
if isEmptyLineParagraph(p) {
return
}
w.WriteString("<p>\n")
w.WriteString("<p>")
if _, ok := p.Children[0].(LineBreak); !ok {
w.WriteString("\n")
}
w.writeNodes(p.Children...)
w.WriteString("</p>\n")
w.WriteString("\n</p>\n")
}
func (w *HTMLWriter) writeHorizontalRule(h HorizontalRule) {

View file

@ -9,7 +9,8 @@ import (
type Text struct{ Content string }
type Linebreak struct{}
type LineBreak struct{ Count int }
type ExplicitLineBreak struct{}
type Emphasis struct {
Kind string
@ -51,6 +52,8 @@ func (d *Document) parseInline(input string) (nodes []Node) {
consumed, node = d.parseRegularLinkOrFootnoteReference(input, current)
case '\\':
consumed, node = d.parseExplicitLineBreak(input, current)
case '\n':
consumed, node = d.parseLineBreak(input, current)
case ':':
rewind, consumed, node = d.parseAutoLink(input, current)
current -= rewind
@ -75,13 +78,20 @@ func (d *Document) parseInline(input string) (nodes []Node) {
return nodes
}
func (d *Document) parseLineBreak(input string, start int) (int, Node) {
i := start
for ; input[i] == '\n'; i++ {
}
return i - start, LineBreak{i - start}
}
func (d *Document) parseExplicitLineBreak(input string, start int) (int, Node) {
if start == 0 || input[start-1] == '\n' || start+1 >= len(input) || input[start+1] != '\\' {
return 0, nil
}
for i := start + 1; ; i++ {
for i := start + 2; ; i++ {
if i == len(input)-1 || input[i] == '\n' {
return i + 1 - start, Linebreak{}
return i + 1 - start, ExplicitLineBreak{}
}
if !unicode.IsSpace(rune(input[i])) {
break
@ -118,8 +128,7 @@ func (d *Document) parseFootnoteReference(input string, start int) (int, Node) {
name, definition := m[1], m[3]
link := FootnoteLink{name, nil}
if definition != "" {
paragraph := Paragraph{[]Node{Line{d.parseInline(definition)}}}
link.Definition = &FootnoteDefinition{name, []Node{paragraph}, true}
link.Definition = &FootnoteDefinition{name, []Node{Paragraph{d.parseInline(definition)}}, true}
d.Footnotes.add(name, link.Definition)
}
return len(m[0]), link

View file

@ -66,7 +66,7 @@ func (d *Document) parseAffiliated(i int, stop stopFn) (int, Node) {
consumed, node := 0, (Node)(nil)
if t := d.tokens[i]; t.kind == "text" {
if nodes := d.parseInline(t.content); len(nodes) == 1 && isImageOrVideoLink(nodes[0]) {
consumed, node = 1, Line{nodes[:1]}
consumed, node = 1, Paragraph{nodes[:1]}
}
} else {
consumed, node = d.parseOne(i, stop)

View file

@ -76,15 +76,14 @@ func (w *OrgWriter) writeNodes(ns ...Node) {
w.writeParagraph(n)
case HorizontalRule:
w.writeHorizontalRule(n)
case Line:
w.writeLine(n)
case Text:
w.writeText(n)
case Emphasis:
w.writeEmphasis(n)
case Linebreak:
w.writeLinebreak(n)
case LineBreak:
w.writeLineBreak(n)
case ExplicitLineBreak:
w.writeExplicitLineBreak(n)
case RegularLink:
w.writeRegularLink(n)
case FootnoteLink:
@ -133,7 +132,14 @@ func (w *OrgWriter) writeBlock(b Block) {
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")
}
@ -160,6 +166,7 @@ func (w *OrgWriter) writeFootnoteDefinition(f FootnoteDefinition) {
func (w *OrgWriter) writeParagraph(p Paragraph) {
w.writeNodes(p.Children...)
w.WriteString("\n")
}
func (w *OrgWriter) writeKeyword(k Keyword) {
@ -221,14 +228,6 @@ func (w *OrgWriter) writeHorizontalRule(hr HorizontalRule) {
w.WriteString(w.indent + "-----\n")
}
func (w *OrgWriter) writeLine(l Line) {
if len(l.Children) != 0 {
w.WriteString(w.indent)
w.writeNodes(l.Children...)
}
w.WriteString("\n")
}
func (w *OrgWriter) writeText(t Text) { w.WriteString(t.Content) }
func (w *OrgWriter) writeEmphasis(e Emphasis) {
@ -241,16 +240,19 @@ func (w *OrgWriter) writeEmphasis(e Emphasis) {
w.WriteString(borders[1])
}
func (w *OrgWriter) writeLinebreak(l Linebreak) {
w.WriteString(`\\`)
func (w *OrgWriter) writeLineBreak(l LineBreak) {
w.WriteString(strings.Repeat("\n"+w.indent, l.Count))
}
func (w *OrgWriter) writeExplicitLineBreak(l ExplicitLineBreak) {
w.WriteString(`\\` + "\n" + w.indent)
}
func (w *OrgWriter) writeFootnoteLink(l FootnoteLink) {
w.WriteString("[fn:" + l.Name)
if l.Definition != nil {
w.WriteString(":")
line := l.Definition.Children[0].(Paragraph).Children[0].(Line)
w.writeNodes(line.Children...)
w.writeNodes(l.Definition.Children[0].(Paragraph).Children...)
}
w.WriteString("]")
}

View file

@ -2,9 +2,9 @@ package org
import (
"regexp"
"strings"
)
type Line struct{ Children []Node }
type Paragraph struct{ Children []Node }
type HorizontalRule struct{}
@ -26,16 +26,16 @@ func lexHorizontalRule(line string) (token, bool) {
}
func (d *Document) parseParagraph(i int, parentStop stopFn) (int, Node) {
lines, start := []Node{Line{d.parseInline(d.tokens[i].content)}}, i
lines, start := []string{d.tokens[i].content}, i
i++
stop := func(d *Document, i int) bool {
return parentStop(d, i) || d.tokens[i].kind != "text" || d.tokens[i].content == ""
}
for ; !stop(d, i); i++ {
lines = append(lines, Line{d.parseInline(d.tokens[i].content)})
lines = append(lines, d.tokens[i].content)
}
consumed := i - start
return consumed, Paragraph{lines}
return consumed, Paragraph{d.parseInline(strings.Join(lines, "\n"))}
}
func (d *Document) parseHorizontalRule(i int, parentStop stopFn) (int, Node) {

View file

@ -106,7 +106,6 @@ unordered list item 4
<li>
<p>
<em>emphasis</em> and a hard line break <br>
see?
</p>
</li>
@ -147,6 +146,25 @@ links with slashes do not become <em>emphasis</em>: <a href="https://somelinksho
</li>
<li>
<p>
<code class="verbatim">multiline emphasis is
supported - and respects MaxEmphasisNewLines (default: 1)</code>
<em>so this
is emphasized</em>
</p>
<p>
/but
this
is
not emphasized/
</p>
</li>
<li>
<p>
empty emphasis markers like ++ // __ and so on are ignored
</p>
</li>
<li>
<p>
subscript<sub>sub</sub> and superscript<sup>super</sup>
</p>
</li>
@ -204,7 +222,9 @@ captioned soure block
</p>
</div>
<div class="captioned">
<p>
<video src="my-video.mp4" title="my-video.mp4">my-video.mp4</video>
</p>
<p class="caption">
captioned link (video in this case)
</p>
@ -258,7 +278,7 @@ either <code>this</code> or <code>that</code> foo.
either <code>this</code>
or <code>that</code> foo.
</p>
<h3><a href="https://github.com/chaseadamsio/goorgeous/issues/50">#50</a>: Linebreaks in lists are preserved</h3>
<h3><a href="https://github.com/chaseadamsio/goorgeous/issues/50">#50</a>: LineBreaks in lists are preserved</h3>
<ul>
<li>
<p>

View file

@ -54,6 +54,16 @@ this one is cheating a little as tags are ALWAYS printed right aligned to a give
- links with slashes do not become /emphasis/: [[https://somelinkshouldntrenderaccidentalemphasis.com]]/ /emphasis/
- _underlined_ *bold* =verbatim= ~code~ +strikethrough+
- *bold string with an *asterisk inside*
- =multiline emphasis is
supported - and respects MaxEmphasisNewLines (default: 1)=
/so this
is emphasized/
/but
this
is
not emphasized/
- empty emphasis markers like ++ // __ and so on are ignored
- subscript_{sub} and superscript^{super}
- links
1. regular link [[https://example.com]] link without description
@ -121,7 +131,7 @@ crazy ain't it?
either ~this~ or ~that~ foo.
either ~this~
or ~that~ foo.
*** DONE [[https://github.com/chaseadamsio/goorgeous/issues/50][#50]]: Linebreaks in lists are preserved
*** DONE [[https://github.com/chaseadamsio/goorgeous/issues/50][#50]]: LineBreaks in lists are preserved
- this list item
has
multiple

View file

@ -12,10 +12,8 @@ func isSecondBlankLine(d *Document, i int) bool {
}
func isEmptyLineParagraph(n Node) bool {
if p, _ := n.(Paragraph); len(p.Children) == 1 {
return len(p.Children[0].(Line).Children) == 0
}
return false
p, ok := n.(Paragraph)
return ok && len(p.Children) == 0
}
func isImageOrVideoLink(n Node) bool {