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 }} `))