Commit 8e0015d7de

8e0015d7dea9ddcbb069f682018d077cd0493414

parent: 54d8129f92

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-25 23:23 UTC

Parse org keywords and body

Layout: unified · split

go.mod +4
@@ -1,3 +1,7 @@
1module gitbay.org/cmc/gallery 1module gitbay.org/cmc/gallery
2 2
3go 1.27.1 3go 1.27.1
4
5require github.com/niklasfasching/go-org v1.9.1
6
7require golang.org/x/net v0.38.0 // indirect
go.sum added +6
@@ -0,0 +1,6 @@
1github.com/niklasfasching/go-org v1.9.1 h1:/3s4uTPOF06pImGa2Yvlp24yKXZoTYM+nsIlMzfpg/0=
2github.com/niklasfasching/go-org v1.9.1/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48=
3github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
6golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
internal/library/org.go added +34
@@ -0,0 +1,34 @@
1package library
2
3import (
4 "html/template"
5 "strings"
6
7 "github.com/niklasfasching/go-org/org"
8)
9
10// parseOrg splits "#+KEY: value" lines out as lower-cased keywords and
11// renders the rest of the document to HTML.
12func parseOrg(src []byte, path string) (map[string]string, template.HTML, error) {
13 kw := map[string]string{}
14 var body []string
15 for _, line := range strings.Split(string(src), "\n") {
16 t := strings.TrimSpace(line)
17 if rest, ok := strings.CutPrefix(t, "#+"); ok {
18 if k, v, ok := strings.Cut(rest, ":"); ok && k != "" && !strings.ContainsAny(k, " \t") {
19 kw[strings.ToLower(k)] = strings.TrimSpace(v)
20 continue
21 }
22 }
23 body = append(body, line)
24 }
25 text := strings.TrimSpace(strings.Join(body, "\n"))
26 if text == "" {
27 return kw, "", nil
28 }
29 out, err := org.New().Parse(strings.NewReader(text), path).Write(org.NewHTMLWriter())
30 if err != nil {
31 return nil, "", err
32 }
33 return kw, template.HTML(out), nil
34}
internal/library/org_test.go added +32
@@ -0,0 +1,32 @@
1package library
2
3import (
4 "strings"
5 "testing"
6)
7
8func TestParseOrg(t *testing.T) {
9 src := "#+title: Tokyo: nights\n#+COVER: a.jpg\n\n#+begin_quote\nA /quiet/ week.\n#+end_quote\n"
10 kw, html, err := parseOrg([]byte(src), "album.org")
11 if err != nil {
12 t.Fatal(err)
13 }
14 if len(kw) != 2 || kw["title"] != "Tokyo: nights" || kw["cover"] != "a.jpg" {
15 t.Fatalf("keywords = %v", kw)
16 }
17 for _, want := range []string{"<blockquote>", "<em>quiet</em>"} {
18 if !strings.Contains(string(html), want) {
19 t.Errorf("html missing %q:\n%s", want, html)
20 }
21 }
22}
23
24func TestParseOrgKeywordsOnly(t *testing.T) {
25 kw, html, err := parseOrg([]byte("#+title: x\n\n"), "album.org")
26 if err != nil {
27 t.Fatal(err)
28 }
29 if kw["title"] != "x" || html != "" {
30 t.Fatalf("kw=%v html=%q", kw, html)
31 }
32}