summaryrefslogtreecommitdiff
path: root/src/gmi/gemtext/gemtext.go
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2024-05-17 23:37:43 +0200
committerBrian Picciano <mediocregopher@gmail.com>2024-05-18 14:47:09 +0200
commit8d7e708d98a3a46ba3ba08f9c8deeb4838bb8ca5 (patch)
tree6662c3e4c6c3baaea058a3deaba0d9cfc8e9cc40 /src/gmi/gemtext/gemtext.go
parentfac06df97a47cda6e8989bfc5f40f2a627279b92 (diff)
Render posts completely using common rendering methods
The aim is to reduce reliance on custom logic in the handlers for every protocol, eventually outsourcing all of it into `render.Methods`, leaving each protocol to simply direct calls to the correct template.
Diffstat (limited to 'src/gmi/gemtext/gemtext.go')
-rw-r--r--src/gmi/gemtext/gemtext.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/gmi/gemtext/gemtext.go b/src/gmi/gemtext/gemtext.go
new file mode 100644
index 0000000..5c8f594
--- /dev/null
+++ b/src/gmi/gemtext/gemtext.go
@@ -0,0 +1,88 @@
+// Package gemtext contains code related to processing and producing gemtext
+// documents.
+package gemtext
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "net/url"
+ "path"
+ "regexp"
+ "strings"
+)
+
+func hasImgExt(p string) bool {
+ switch path.Ext(strings.ToLower(p)) {
+ case ".jpg", ".jpeg", ".png", ".gif", ".svg":
+ return true
+ default:
+ return false
+ }
+}
+
+// matches `=> dstURL [optional description]`
+var linkRegexp = regexp.MustCompile(`^=>\s+(\S+)\s*(.*?)\s*$`)
+
+// ToMarkdown reads a gemtext formatted body from the Reader and writes
+// the markdown version of that body to the Writer.
+//
+// gmiGateway, if given, is used for all `gemini://` links. The `gemini://`
+// prefix will be stripped, and replaced with the given URL.
+func ToMarkdown(dst io.Writer, src io.Reader, gmiGateway *url.URL) error {
+
+ bufSrc := bufio.NewReader(src)
+
+ for {
+
+ line, err := bufSrc.ReadString('\n')
+ if err != nil && !errors.Is(err, io.EOF) {
+ return fmt.Errorf("reading: %w", err)
+ }
+
+ last := err == io.EOF
+
+ if match := linkRegexp.FindStringSubmatch(line); len(match) > 0 {
+
+ u, err := url.Parse(match[1])
+ if err != nil {
+ return fmt.Errorf("link to invalid url %q: %w", match[1], err)
+ }
+
+ if u.Scheme == "gemini" && gmiGateway != nil {
+ newUStr := gmiGateway.String() + u.Host + u.Path
+ if u, err = url.Parse(newUStr); err != nil {
+ return fmt.Errorf("parsing proxied URL %q: %w", newUStr, err)
+ }
+ }
+
+ isImg := hasImgExt(u.Path)
+
+ descr := match[2]
+
+ if descr != "" {
+ // ok
+ } else if isImg {
+ descr = "Image"
+ } else {
+ descr = "Link"
+ }
+
+ line = fmt.Sprintf("[%s](%s)\n", descr, u.String())
+
+ if isImg {
+ line = "!" + line
+ }
+ }
+
+ if _, err := dst.Write([]byte(line)); err != nil {
+ return fmt.Errorf("writing: %w", err)
+ }
+
+ if last {
+ return nil
+ }
+ }
+
+}