~ft/bfg

bfg/bfg.go -rw-r--r-- 2.7 KiB
91d8f425Sigrid Haflínudóttir fixup 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package bfg

import (
	"fmt"
	"io"
	"strings"

	bf "gopkg.in/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)
	}
}
*/