aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rw-r--r--http/handlers/gemtext.go34
-rw-r--r--internal/gemtext/gemtext.go38
3 files changed, 71 insertions, 12 deletions
diff --git a/README.md b/README.md
index 6293bd8..829157a 100644
--- a/README.md
+++ b/README.md
@@ -65,6 +65,17 @@ The template will be rendered with these extra data fields:
* `.Body`: A string containing all rendered HTML DOM elements.
+**heading_template**
+
+Path to a template which will be used for rendering headings. If not given then
+headings will be rendered with appropriate HTML header tags.
+
+The template will be rendered with these extra data fields:
+
+* `.Level`: Which level of heading is being rendered, 1, 2, or 3.
+
+* `.Text`: The text of the heading.
+
**link_template**
Path to a template which will be used for rendering links. If not given then
diff --git a/http/handlers/gemtext.go b/http/handlers/gemtext.go
index bc617f4..7f12799 100644
--- a/http/handlers/gemtext.go
+++ b/http/handlers/gemtext.go
@@ -64,6 +64,20 @@ type Gemtext struct {
//
TemplatePath string `json:"template"`
+ // Path to a template which will be used for rendering headings. If not
+ // given then headings will be rendered with appropriate HTML header tags.
+ //
+ // The template will be rendered with these extra data fields:
+ //
+ // ##### `.Level`
+ //
+ // Which level of heading is being rendered, 1, 2, or 3.
+ //
+ // ##### `.Text`
+ //
+ // The text of the heading.
+ HeadingTemplatePath string `json:"heading_template"`
+
// Path to a template which will be used for rendering links. If not given
// then links will be rendered using an anchor tag wrapped in a paragraph
// tag.
@@ -181,9 +195,23 @@ func (g *Gemtext) ServeHTTP(
Req: r,
RespHeader: templates.WrappedHeader{Header: rec.Header()},
}
+
+ parser gemtext.HTMLTranslator
)
- parser := gemtext.HTMLTranslator{}
+ if g.HeadingTemplatePath != "" {
+ parser.RenderHeading = func(w io.Writer, level int, text string) error {
+ payload := struct {
+ *templates.TemplateContext
+ Level int
+ Text string
+ }{
+ ctx, level, text,
+ }
+
+ return g.render(w, ctx, osFS, g.HeadingTemplatePath, payload)
+ }
+ }
if g.LinkTemplatePath != "" {
parser.RenderLink = func(w io.Writer, url, label string) error {
@@ -258,6 +286,10 @@ func gemtextParseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler,
if !h.Args(&g.TemplatePath) {
return nil, h.ArgErr()
}
+ case "heading_template":
+ if !h.Args(&g.HeadingTemplatePath) {
+ return nil, h.ArgErr()
+ }
case "link_template":
if !h.Args(&g.LinkTemplatePath) {
return nil, h.ArgErr()
diff --git a/internal/gemtext/gemtext.go b/internal/gemtext/gemtext.go
index 76a990e..2b8cf77 100644
--- a/internal/gemtext/gemtext.go
+++ b/internal/gemtext/gemtext.go
@@ -14,6 +14,11 @@ import (
// HTMLTranslator is used to translate a gemtext file into equivalent HTML DOM
// elements.
type HTMLTranslator struct {
+ // RenderHeading, if given can be used to override how headings are
+ // rendered. The level indicates which heading level is being rendered: 1,
+ // 2, or 3.
+ RenderHeading func(w io.Writer, level int, text string) error
+
// RenderLink, if given, can be used to override how links are rendered.
RenderLink func(w io.Writer, url, label string) error
}
@@ -45,7 +50,7 @@ func (t HTMLTranslator) Translate(src io.Reader) (HTML, error) {
if writeErr != nil {
return
}
- fmt.Fprintf(w, fmtStr, args...)
+ _, writeErr = fmt.Fprintf(w, fmtStr, args...)
}
loop:
@@ -109,25 +114,36 @@ loop:
if t.RenderLink == nil {
write("<p><a href=\"%s\">%s</a></p>\n", urlStr, label)
} else {
- if err := t.RenderLink(w, urlStr, label); err != nil {
- return HTML{}, fmt.Errorf(
- "rendering link %q (label:%q): %w", urlStr, label, err,
- )
- }
+ writeErr = t.RenderLink(w, urlStr, label)
}
case strings.HasPrefix(line, "###"):
- write("<h3>%s</h3>\n", sanitizeText(line[3:]))
+ text := sanitizeText(line[3:])
+ if t.RenderHeading == nil {
+ write("<h3>%s</h3>\n", text)
+ } else {
+ writeErr = t.RenderHeading(w, 3, text)
+ }
case strings.HasPrefix(line, "##"):
- write("<h2>%s</h2>\n", sanitizeText(line[2:]))
+ text := sanitizeText(line[2:])
+ if t.RenderHeading == nil {
+ write("<h2>%s</h2>\n", text)
+ } else {
+ writeErr = t.RenderHeading(w, 2, text)
+ }
case strings.HasPrefix(line, "#"):
- line = sanitizeText(line[1:])
+ text := sanitizeText(line[1:])
if title == "" {
- title = line
+ title = text
+ }
+
+ if t.RenderHeading == nil {
+ write("<h1>%s</h1>\n", text)
+ } else {
+ writeErr = t.RenderHeading(w, 1, text)
}
- write("<h1>%s</h1>\n", line)
case strings.HasPrefix(line, ">"):
write("<blockquote>%s</blockquote>\n", sanitizeText(line[1:]))