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
|
package htmlconv
import (
"html/template"
"io"
"tildegit.org/tjp/sliderule/gemini/gemtext"
"tildegit.org/tjp/sliderule/gemini/gemtext/internal"
)
// Convert writes markdown to a writer from the provided gemtext document.
//
// Templates can be provided to override the output for different line types.
// The templates supported are:
// - "header" is called before any lines and is passed the full Document. It should,
// at a minimum, produce opening <html> and <body> tags.
// - "footer" is called after the lines and is passed the full Document. It should,
// at a minimum, provide closing </body> and </html> tags.
// - "textline" is called once per line of text and is passed a gemtext.TextLine.
// - "linkline" is called once per link line and is passed an object which wraps
// a gemtext.LinkLine but also supports a ValidatedURL() method returning a
// string which html/template will always allow as href attributes.
// - "preformattedtextlines" is called once for a block of preformatted text and is
// passed a slice of gemtext.PreformattedTextLines.
// - "heading1line" is called once per h1 line and is passed a gemtext.Heading1Line.
// - "heading2line" is called once per h2 line and is passed a gemtext.Heading2Line.
// - "heading3line" is called once per h3 line and is passed a gemtext.Heading3Line.
// - "listitemlines" is called once for a block of contiguous list item lines and
// is passed a slice of gemtext.ListItemLines.
// - "quoteline" is passed once per blockquote line and is passed a gemtext.QuoteLine.
//
// There exist default implementations of each of these templates, so the "overrides"
// argument can be nil.
func Convert(wr io.Writer, doc gemtext.Document, overrides *template.Template) error {
if err := internal.ValidateLinks(doc); err != nil {
return err
}
tmpl, err := baseTmpl.Clone()
if err != nil {
return err
}
tmpl, err = internal.AddHTMLTemplates(tmpl, overrides)
if err != nil {
return err
}
for _, item := range internal.RenderItems(doc) {
if err := tmpl.ExecuteTemplate(wr, item.Template, item.Object); err != nil {
return err
}
}
return nil
}
var baseTmpl = template.Must(template.New("htmlconv").Parse(`
{{ define "header" -}}
<!DOCTYPE html>
<html><body class="gemtext">{{ end }}
{{ define "textline" -}}
{{ if ne .String "\n" -}}
<p class="gemtext">{{ . }}</p>
{{- end }}
{{- end }}
{{ define "linkline" -}}
<p class="gemtext">=> <a class="gemtext" href="{{ .ValidatedURL }}">
{{- if eq .Label "" -}}
{{ .URL }}
{{- else -}}
{{ .Label }}
{{- end -}}
</a></p>
{{- end }}
{{ define "preformattedtextlines" -}}
<pre class="gemtext">
{{- range . -}}
{{ . }}
{{- end -}}
</pre>
{{- end }}
{{ define "heading1line" }}<h1 class="gemtext">{{ .Body }}</h1>{{ end }}
{{ define "heading2line" }}<h2 class="gemtext">{{ .Body }}</h2>{{ end }}
{{ define "heading3line" }}<h3 class="gemtext">{{ .Body }}</h3>{{ end }}
{{ define "listitemlines" -}}
<ul class="gemtext">
{{- range . -}}
<li class="gemtext">{{ .Body }}</li>
{{- end -}}
</ul>
{{- end }}
{{ define "quoteline" }}<blockquote class="gemtext">{{ .Body }}</blockquote>{{ end }}
{{ define "footer" }}</body></html>{{ end }}
`))
|