89 lines
2.9 KiB
Go
89 lines
2.9 KiB
Go
package htmlconv
|
|
|
|
import (
|
|
"html/template"
|
|
"io"
|
|
|
|
"tildegit.org/tjp/gus/gemini/gemtext"
|
|
"tildegit.org/tjp/gus/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" }}<html><body>{{ end }}
|
|
{{ define "textline" }}{{ if ne .String "\n" }}<p>{{ . }}</p>{{ end }}{{ end }}
|
|
{{ define "linkline" -}}
|
|
<p>=> <a href="{{ .ValidatedURL }}">{{ if eq .Label "" -}}
|
|
{{ .URL }}
|
|
{{- else -}}
|
|
{{ .Label }}
|
|
{{- end -}}
|
|
</a></p>
|
|
{{- end }}
|
|
{{ define "preformattedtextlines" -}}
|
|
<pre>
|
|
{{- range . -}}
|
|
{{ . }}
|
|
{{- end -}}
|
|
</pre>
|
|
{{- end }}
|
|
{{ define "heading1line" }}<h1>{{ .Body }}</h1>{{ end }}
|
|
{{ define "heading2line" }}<h2>{{ .Body }}</h2>{{ end }}
|
|
{{ define "heading3line" }}<h3>{{ .Body }}</h3>{{ end }}
|
|
{{ define "listitemlines" -}}
|
|
<ul>
|
|
{{- range . -}}
|
|
<li>{{ .Body }}</li>
|
|
{{- end -}}
|
|
</ul>
|
|
{{- end }}
|
|
{{ define "quoteline" }}<blockquote>{{ .Body }}</blockquote>{{ end }}
|
|
{{ define "footer" }}</body></html>{{ end }}
|
|
`))
|