Keep line breaks in blockquotes

This makes the renderer preserve existing line breaks in blockquotes,
provided they do not split paragraphs. Some clients/sites may use this
to form semantic around line breaks (for instance, for poems).

See #5.
This commit is contained in:
Timur Demin 2021-08-13 09:49:06 +05:00
parent 35977a721c
commit 36922b6e95
No known key found for this signature in database
GPG key ID: 9EDF3F9D9286FA20

View file

@ -18,6 +18,7 @@
package gemini
import (
"bytes"
"fmt"
"io"
"regexp"
@ -32,6 +33,7 @@ var (
lineBreak = []byte{'\n'}
space = []byte{' '}
linkPrefix = []byte("=> ")
quoteBrPrefix = []byte("\n> ")
quotePrefix = []byte("> ")
itemPrefix = []byte("* ")
itemIndent = []byte{'\t'}
@ -89,8 +91,7 @@ func (r Renderer) blockquote(w io.Writer, node *ast.BlockQuote, entering bool) {
if node := node.AsContainer(); node != nil {
for _, child := range node.Children {
w.Write(quotePrefix)
// assume children would be paragraphs
r.text(w, child)
r.blockquoteText(w, child)
// double linebreak to ensure Gemini clients don't merge
// quotes; gomarkdown assumes separate blockquotes are
// paragraphs of the same blockquote while we don't
@ -260,6 +261,21 @@ func (r Renderer) text(w io.Writer, node ast.Node) {
}
}
// TODO: this really should've been unified with text(), but having two
// extra params for prefix/line breaks is not neat
func (r Renderer) blockquoteText(w io.Writer, node ast.Node) {
if node := node.AsLeaf(); node != nil {
// pad every line break with blockquote symbol
w.Write([]byte(bytes.ReplaceAll(node.Literal, lineBreak, quoteBrPrefix)))
return
}
if node := node.AsContainer(); node != nil {
for _, child := range node.Children {
r.blockquoteText(w, child)
}
}
}
func extractText(node ast.Node) string {
if node := node.AsLeaf(); node != nil {
return strings.ReplaceAll(string(node.Literal), "\n", " ")