package bfg import ( "fmt" "io" "strings" bf "github.com/russross/blackfriday/v2") type Link struct { URL []byte Description []byte} type GeminiRenderer struct { footLinks []Link footLinksOffset int inLink bool isVerbatim bool isQuoting bool} func NewGeminiRenderer() *GeminiRenderer { return &GeminiRenderer{}} func (r *GeminiRenderer) nl(w io.Writer) { w.Write([]byte{'\n'})} func (r *GeminiRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus { switch node.Type { case bf.Text: if entering { var s string if r.isVerbatim { if r.isQuoting { s = "> " + strings.ReplaceAll(string(node.Literal), "\n", "\n> ") + "\n" } else { s = string(node.Literal) } } else { if node.Parent.Type == bf.Link { r.footLinks[len(r.footLinks)-1].Description = node.Literal } s = strings.ReplaceAll(string(node.Literal), "\n", " ") } w.Write([]byte(s)) } case bf.BlockQuote: r.isVerbatim = entering r.isQuoting = entering if !entering { r.nl(w) } case bf.List: if !entering { r.nl(w) } case bf.Item: if r.inLink = entering; r.inLink { w.Write([]byte{'*', ' '}) } else { r.nl(w) } case bf.Paragraph: if r.inLink || r.isVerbatim { break } if !entering { if r.footLinksOffset < len(r.footLinks) { r.nl(w) } for i, l := range r.footLinks[r.footLinksOffset:] { w.Write([]byte(fmt.Sprintf("\n=> %s [%d] %s", l.URL, i+r.footLinksOffset+1, l.Description))) } r.footLinksOffset = len(r.footLinks) r.nl(w) r.nl(w) } case bf.Heading: if entering { w.Write([]byte(strings.Repeat("#", node.Level) + " ")) } else { r.nl(w) r.nl(w) } case bf.HorizontalRule: case bf.Emph: case bf.Strong: case bf.Del: case bf.Link: if entering { r.footLinks = append(r.footLinks, Link{node.LinkData.Destination, nil}) } else { w.Write([]byte(fmt.Sprintf("[%d]", len(r.footLinks)))) } case bf.Image: if entering { w.Write([]byte(fmt.Sprintf("=> %s ", node.LinkData.Destination))) } case bf.HTMLBlock: case bf.CodeBlock: w.Write([]byte(fmt.Sprintf("```\n%s```\n\n", node.Literal))) case bf.Softbreak: case bf.Hardbreak: case bf.Code: w.Write([]byte(fmt.Sprintf("`%s`", node.Literal))) case bf.HTMLSpan: case bf.Table: case bf.TableCell: case bf.TableHead: case bf.TableBody: case bf.TableRow: } return bf.GoToNext} func (r *GeminiRenderer) RenderHeader(w io.Writer, ast *bf.Node) {} func (r *GeminiRenderer) RenderFooter(w io.Writer, ast *bf.Node) {} /*func main() { if c, err := ioutil.ReadFile("1.md"); err != nil { log.Fatal(err) } else { b := bf.Run(c, bf.WithExtensions(bf.FencedCode|bf.Autolink), bf.WithRenderer(NewGeminiRenderer())) fmt.Printf("%s\n", b) }}*/
package bfg
import (
"fmt"
"io"
"strings"
bf "github.com/russross/blackfriday/v2"
)
type Link struct {
URL []byte
Description []byte
}
type GeminiRenderer struct {
footLinks []Link
footLinksOffset int
inLink bool
isVerbatim bool
isQuoting bool
}
func NewGeminiRenderer() *GeminiRenderer {
return &GeminiRenderer{}
}
func (r *GeminiRenderer) nl(w io.Writer) {
w.Write([]byte{'\n'})
}
func (r *GeminiRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus {
switch node.Type {
case bf.Text:
if entering {
var s string
if r.isVerbatim {
if r.isQuoting {
s = "> " + strings.ReplaceAll(string(node.Literal), "\n", "\n> ") + "\n"
} else {
s = string(node.Literal)
}
} else {
if node.Parent.Type == bf.Link {
r.footLinks[len(r.footLinks)-1].Description = node.Literal
}
s = strings.ReplaceAll(string(node.Literal), "\n", " ")
}
w.Write([]byte(s))
}
case bf.BlockQuote:
r.isVerbatim = entering
r.isQuoting = entering
if !entering {
r.nl(w)
}
case bf.List:
if !entering {
r.nl(w)
}
case bf.Item:
if r.inLink = entering; r.inLink {
w.Write([]byte{'*', ' '})
} else {
r.nl(w)
}
case bf.Paragraph:
if r.inLink || r.isVerbatim {
break
}
if !entering {
if r.footLinksOffset < len(r.footLinks) {
r.nl(w)
}
for i, l := range r.footLinks[r.footLinksOffset:] {
w.Write([]byte(fmt.Sprintf("\n=> %s [%d] %s", l.URL, i+r.footLinksOffset+1, l.Description)))
}
r.footLinksOffset = len(r.footLinks)
r.nl(w)
r.nl(w)
}
case bf.Heading:
if entering {
w.Write([]byte(strings.Repeat("#", node.Level) + " "))
} else {
r.nl(w)
r.nl(w)
}
case bf.HorizontalRule:
case bf.Emph:
case bf.Strong:
case bf.Del:
case bf.Link:
if entering {
r.footLinks = append(r.footLinks, Link{node.LinkData.Destination, nil})
} else {
w.Write([]byte(fmt.Sprintf("[%d]", len(r.footLinks))))
}
case bf.Image:
if entering {
w.Write([]byte(fmt.Sprintf("=> %s ", node.LinkData.Destination)))
}
case bf.HTMLBlock:
case bf.CodeBlock:
w.Write([]byte(fmt.Sprintf("```\n%s```\n\n", node.Literal)))
case bf.Softbreak:
case bf.Hardbreak:
case bf.Code:
w.Write([]byte(fmt.Sprintf("`%s`", node.Literal)))
case bf.HTMLSpan:
case bf.Table:
case bf.TableCell:
case bf.TableHead:
case bf.TableBody:
case bf.TableRow:
}
return bf.GoToNext
}
func (r *GeminiRenderer) RenderHeader(w io.Writer, ast *bf.Node) {
}
func (r *GeminiRenderer) RenderFooter(w io.Writer, ast *bf.Node) {
}
/*
func main() {
if c, err := ioutil.ReadFile("1.md"); err != nil {
log.Fatal(err)
} else {
b := bf.Run(c, bf.WithExtensions(bf.FencedCode|bf.Autolink), bf.WithRenderer(NewGeminiRenderer()))
fmt.Printf("%s\n", b)
}
}
*/