Add image/link text render and blockquote support
This commit is contained in:
parent
85b0ef51b3
commit
49725d712a
1 changed files with 83 additions and 38 deletions
|
@ -9,21 +9,19 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
lineBreak = []byte{'\n'}
|
||||
space = []byte{' '}
|
||||
linkPrefix = []byte("=> ")
|
||||
lineBreak = []byte{'\n'}
|
||||
lineBreakByte byte = 0x0a
|
||||
space = []byte{' '}
|
||||
linkPrefix = []byte("=> ")
|
||||
quotePrefix = []byte("> ")
|
||||
)
|
||||
|
||||
// Renderer implements markdown.Renderer.
|
||||
type Renderer struct {
|
||||
LinkStack []ast.Node
|
||||
}
|
||||
type Renderer struct{}
|
||||
|
||||
// NewRenderer returns a new Renderer.
|
||||
func NewRenderer() Renderer {
|
||||
return Renderer{
|
||||
LinkStack: nil,
|
||||
}
|
||||
return Renderer{}
|
||||
}
|
||||
|
||||
func (r Renderer) link(w io.Writer, node *ast.Link, entering bool) {
|
||||
|
@ -37,6 +35,24 @@ func (r Renderer) link(w io.Writer, node *ast.Link, entering bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r Renderer) linkText(w io.Writer, node *ast.Link) {
|
||||
for _, text := range node.Children {
|
||||
// TODO: Renderer.linkText: link can contain subblocks
|
||||
if l := text.AsLeaf(); l != nil {
|
||||
w.Write(l.Literal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r Renderer) imageText(w io.Writer, node *ast.Image) {
|
||||
for _, text := range node.Children {
|
||||
// TODO: Renderer.imageText: link can contain subblocks
|
||||
if l := text.AsLeaf(); l != nil {
|
||||
w.Write(l.Literal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r Renderer) image(w io.Writer, node *ast.Image, entering bool) {
|
||||
if entering {
|
||||
w.Write(linkPrefix)
|
||||
|
@ -53,11 +69,34 @@ func (r Renderer) image(w io.Writer, node *ast.Image, entering bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r Renderer) citation(w io.Writer, node *ast.Citation) {}
|
||||
func (r Renderer) blockquote(w io.Writer, node *ast.BlockQuote, entering bool) {
|
||||
// TODO: Renderer.blockquote: needs support for subnode rendering;
|
||||
// ideally to be merged with paragraph
|
||||
if entering {
|
||||
w.Write(quotePrefix)
|
||||
if para, ok := node.Children[0].(*ast.Paragraph); ok {
|
||||
for _, subnode := range para.Children {
|
||||
if l := subnode.AsLeaf(); l != nil {
|
||||
// TODO: Renderer.blockquote: rendering by byte is asking
|
||||
// for optimizations
|
||||
for _, b := range l.Literal {
|
||||
w.Write([]byte{b})
|
||||
if b == lineBreakByte {
|
||||
w.Write(quotePrefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.Write(lineBreak)
|
||||
w.Write(lineBreak)
|
||||
}
|
||||
}
|
||||
|
||||
func (r Renderer) heading(w io.Writer, node *ast.Heading, entering bool) {
|
||||
if entering {
|
||||
// prepend headings with the relevant number of #-s
|
||||
// pad headings with the relevant number of #-s
|
||||
heading := make([]byte, node.Level+1)
|
||||
heading[len(heading)-1] = ' '
|
||||
for i := 0; i < len(heading)-1; i++ {
|
||||
|
@ -75,34 +114,44 @@ func (r Renderer) heading(w io.Writer, node *ast.Heading, entering bool) {
|
|||
|
||||
func (r Renderer) paragraph(w io.Writer, node *ast.Paragraph, entering bool) {
|
||||
if entering {
|
||||
if r.LinkStack != nil {
|
||||
panic("link stack not empty")
|
||||
}
|
||||
r.LinkStack = make([]ast.Node, 0, len(node.Children))
|
||||
linkStack := make([]ast.Node, 0, len(node.Children))
|
||||
onlyElement := len(node.Children) == 1
|
||||
for _, child := range node.Children {
|
||||
// only render links text in the paragraph if they're
|
||||
// combined with some other text on page
|
||||
if link, ok := child.(*ast.Link); ok {
|
||||
r.LinkStack = append(r.LinkStack, link)
|
||||
if !(len(link.Children) > 1) && !onlyElement {
|
||||
r.linkText(w, link)
|
||||
}
|
||||
linkStack = append(linkStack, link)
|
||||
}
|
||||
if image, ok := child.(*ast.Image); ok {
|
||||
r.LinkStack = append(r.LinkStack, image)
|
||||
if !(len(image.Children) > 1) && !onlyElement {
|
||||
r.imageText(w, image)
|
||||
}
|
||||
linkStack = append(linkStack, image)
|
||||
}
|
||||
if text, ok := child.(*ast.Text); ok {
|
||||
r.text(w, text)
|
||||
}
|
||||
}
|
||||
// render a links block after paragraph
|
||||
if len(linkStack) > 0 {
|
||||
w.Write(lineBreak)
|
||||
w.Write(lineBreak)
|
||||
for _, link := range linkStack {
|
||||
if link, ok := link.(*ast.Link); ok {
|
||||
r.link(w, link, true)
|
||||
}
|
||||
if image, ok := link.(*ast.Image); ok {
|
||||
r.image(w, image, true)
|
||||
}
|
||||
w.Write(lineBreak)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.Write(lineBreak)
|
||||
w.Write(lineBreak)
|
||||
for _, link := range r.LinkStack {
|
||||
if link, ok := link.(*ast.Link); ok {
|
||||
r.link(w, link, true)
|
||||
}
|
||||
if image, ok := link.(*ast.Image); ok {
|
||||
r.image(w, image, true)
|
||||
}
|
||||
w.Write(lineBreak)
|
||||
}
|
||||
r.LinkStack = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,21 +174,17 @@ func (r Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Walk
|
|||
// despite most of the subroutines here accepting entering, most of
|
||||
// them don't really need an extra pass
|
||||
switch node := node.(type) {
|
||||
case *ast.Link:
|
||||
// TODO: shouldn't be here at all
|
||||
r.link(w, node, entering)
|
||||
case *ast.Image:
|
||||
// TODO: neither this
|
||||
r.image(w, node, entering)
|
||||
case *ast.Citation:
|
||||
// TODO: neither this
|
||||
r.citation(w, node)
|
||||
case *ast.BlockQuote:
|
||||
r.blockquote(w, node, entering)
|
||||
case *ast.Heading:
|
||||
r.heading(w, node, entering)
|
||||
case *ast.Paragraph:
|
||||
r.paragraph(w, node, entering)
|
||||
// blockquote wraps paragraphs which makes for an extra render
|
||||
if _, parentIsBlockQuote := node.Parent.(*ast.BlockQuote); !parentIsBlockQuote {
|
||||
r.paragraph(w, node, entering)
|
||||
}
|
||||
case *ast.Code:
|
||||
// TODO: likely not even this
|
||||
// TODO: *ast.Code render is likely to be merged into paragraph
|
||||
r.code(w, node, entering)
|
||||
}
|
||||
return ast.GoToNext
|
||||
|
|
Loading…
Reference in a new issue