blog @main -
refs -
log -
-
https://git.jolheiser.com/blog.git
My nonexistent blog
wip
Signed-off-by: jolheiser <john.olheiser@gmail.com>
Signature
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEgqEQpE3xoo1QwJO/uFOtpdp7v3oFAmXRTB4ACgkQuFOtpdp7
v3pfXg//ftDf+cwFxMFmazovPkyArIxj1Yp7kZdZtW8YKrq3hNOf86v1l+7uMRt1
jf/cm8Oa51xj9sf6HX84soD2k81llOwJRK4R0PJcADyQ9KtHeXMgVONPVhjS+y5i
IEmedx4u/mNaq5ORMGSdpieOguAfBhva6NuFnAvydC98mYJ5+xhkrh6G11VUyxW8
d/GVMSaeoc12E9H6pR/pC+IQOfk/aUHTNh3Lv7+52gZijX5iICEGxZZZh9JcAUT5
OlvK+/4aQ7Urxka2mq4gXTP28YjiNnn6dU0s2oyaSlGhlW6YFHVXkHW8uRt6fAze
0UF3zyAhfCJuIx7twa9F2CqgHZAeGRFW5YkiwpCpeoNEdoPZXKADam2IEKMU3PVL
c76R32YDczmhZM14VvUtmh/1yWYlcNYkGZNNTv2QzcTcF1kyzmUrWMwtjpMu071m
MKiFFpddbbi9G9G7hbdD6DDN2CgPKjc7iocTYqyCrFhHRRwFcTBWGEqqDZd673Ni
24Xnxzc+kK5KHipuQ9cyj9fpeeRNpkT/gaMk3xsDg5TaCUSlG0qk3VhHhlBqQxyv
9Dp6MejY46gP0zQAmOAmPsk8GUYeniqmedgpZ8UnB+c0dUJR0E6XykHr5DOzjREf
3NQuxRxFz6lXs5AAuXA9Px3eP6bFigwBxWW8ZAbGs1lA2ccMRTU=
=fMbW
-----END PGP SIGNATURE-----
12 changed files, 567 additions(+), 17 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c6aa2a4851f3a5271fdf9b86ce78e6e8ce1cbcef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/blog*
+!blog.go
+!blog_test.go
+
+_example/out
diff --git a/_example/articles/introduction.md b/_example/articles/introduction.md
new file mode 100644
index 0000000000000000000000000000000000000000..ac53dbc5a9a19fa49dab18849b89e6f1fa8b26ee
--- /dev/null
+++ b/_example/articles/introduction.md
@@ -0,0 +1,36 @@
+---
+title: "Introduction"
+summary: "An introduction of `blog`"
+time: 2024-02-17
+authors:
+ - name: "jolheiser"
+ email: "john+blog@jolheiser.com"
+---
+
+# Hello and welcome to blog!
+
+`blog` is a simple static blog generator!
+
+<small>Truly cutting edge, I know. Never seen one of these before, have you?</small>
+
+```go
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, blog!")
+}
+````
+
+Things it can do:
+
+- [x] Render code
+- [ ] Fill the void
+
+## Why was blog created?
+
+~~Because I needed a specific thing that other generators couldn't give me. Blog is up to 1000 times faster than \<hot other blog generator\>!!!~~
+
+Because I wanted to, like many other projects in this space. Blog is designed to be simple (to me) with enough flexibility for someone else to use without
+cursing at me (too much).
diff --git a/_example/templates/article.tmpl b/_example/templates/article.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..63c40605857d22e08af8ee9b7ad86b377094dd97
--- /dev/null
+++ b/_example/templates/article.tmpl
@@ -0,0 +1,4 @@
+{{template "head" .article.Title}}
+<body>
+<main>{{.article.Content}}</main>
+</body>
diff --git a/_example/templates/base.tmpl b/_example/templates/base.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..ea524bba9a9adc390eb0fa0525bdcc34ee7cac80
--- /dev/null
+++ b/_example/templates/base.tmpl
@@ -0,0 +1,12 @@
+{{define "head"}}
+<!DOCTYPE html>
+<head>
+<title>{{.}}</title>
+<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sakura.css/css/sakura.css" type="text/css"> -->
+<link
+ rel="stylesheet"
+ href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
+/>
+<link rel="stylesheet" href="chroma.css"/>
+</head>
+{{end}}
diff --git a/_example/templates/index.tmpl b/_example/templates/index.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..8f02204de131292ae68007925ca62f4a782d2d87
--- /dev/null
+++ b/_example/templates/index.tmpl
@@ -0,0 +1,8 @@
+{{template "head" .author.Name}}
+<body>
+<main>
+{{range $article := .articles}}
+<a href="{{$article.Filename}}.html">{{$article.Title}}</a>
+{{end}}
+</main>
+</body>
diff --git a/blog.go b/blog.go
index 5f29fbbd4e2e070101295601d62d5c76e0a1b995..644353a354057efe605a8a87576faa2ecb9dc9c9 100644
--- a/blog.go
+++ b/blog.go
@@ -1,15 +1,22 @@
package blog
import (
+ "bytes"
"errors"
"fmt"
"html/template"
+ "io"
"io/fs"
"net/url"
"os"
+ "path/filepath"
+ "sort"
+ "strings"
"time"
"github.com/bmatcuk/doublestar/v4"
+ "github.com/pelletier/go-toml/v2"
+ "gopkg.in/yaml.v3"
)
// Blog is a collection of [Article]
@@ -17,23 +24,31 @@ type Blog struct {
indexTemplate *template.Template
articleTemplate *template.Template
Articles []Article
+ Author Author
}
// Article is a blog post/article
type Article struct {
+ "io/fs"
+ Content template.HTML
+ ArticleMeta
package blog
+ "net/url"
+
+// ArticleMeta is the metadata of an [Article]
+type ArticleMeta struct {
Title string
Subtitle string
Summary string
- Content string
Time time.Time
-
+ "io/fs"
"io/fs"
Tags []string
+ Category string
}
-
+ "io/fs"
"os"
type Author struct {
Name string
@@ -45,39 +60,86 @@
// Link is a link name and URL
type Link struct {
Name string
-import (
+ URL LinkURL
+package blog
"net/url"
+
+ "net/url"
package blog
"net/url"
+
+ "net/url"
import (
- "os"
+ "net/url"
"errors"
if err != nil {
- return nil, fmt.Errorf("could not parse templates in %q: %w", dir, err)
+ return err
}
+ *l = LinkURL(*u)
+ return nil
+}
+
+// NewBlog constructs a new blog from articles in articleDir and templates in templateDir
+func NewBlog(articleDir, templateDir string, author Author) (*Blog, error) {
+ tmpl, err := parseTemplates(os.DirFS(templateDir))
"errors"
+package blog
+ return nil, fmt.Errorf("could not parse templates in %q: %w", templateDir, err)
"errors"
+import (
+ indexTmpl := tmpl.Lookup("index.tmpl")
+ if indexTmpl == nil {
+ "os"
"errors"
+ "os"
"fmt"
- "errors"
+ "os"
"html/template"
+ }
}
- "errors"
+ articleTmpl := tmpl.Lookup("article.tmpl")
+ if articleTmpl == nil {
+ articleTmpl = tmpl.Lookup("article")
+ if articleTmpl == nil {
+ return nil, errors.New("`article` template is required but was not found")
+ "os"
"io/fs"
"errors"
- "net/url"
+import (
+ articles, err := parseArticles(os.DirFS(articleDir))
"errors"
- "os"
+package blog
+ return nil, fmt.Errorf("could not parse articles in %q: %w", articleDir, err)
}
return &Blog{
+ "time"
"fmt"
package blog
+ "html/template"
+ Articles: articles,
+ Author: author,
"fmt"
+import (
+}
- "fmt"
+// Index renders the blog index to w
+func (b *Blog) Index(w io.Writer) error {
+ return b.indexTemplate.Execute(w, map[string]any{
+ "articles": b.Articles,
+ "github.com/bmatcuk/doublestar/v4"
import (
package blog
+type Blog struct {
+}
+
+// Article renders an article to w
+func (b *Blog) Article(w io.Writer, a Article) error {
+ return b.articleTemplate.Execute(w, map[string]any{
+ "article": a,
+ "author": b.Author,
+ })
+package blog
"net/url"
func parseTemplates(fs fs.FS) (*template.Template, error) {
@@ -84,26 +145,135 @@ matches, err := doublestar.Glob(fs, "**/*.{tmpl,gohtml}")
if err != nil {
return nil, fmt.Errorf("could not glob templates: %w", err)
}
+ tmpl, err := template.New("").ParseFS(fs, matches...)
+ if err != nil {
"fmt"
+ "net/url"
+ }
+ return tmpl, nil
+}
+
+func parseArticles(fs fs.FS) ([]Article, error) {
+ matches, err := doublestar.Glob(fs, "**/*.md")
+ if err != nil {
+ return nil, fmt.Errorf("could not glob articles: %w", err)
+ }
+ articles := make([]Article, 0, len(matches))
+ for _, match := range matches {
+ if err := func() error {
+ fi, err := fs.Open(match)
+ if err != nil {
+ return err
+ }
+)
"io/fs"
+
+ content, err := io.ReadAll(fi)
+)
"errors"
package blog
+ Content string
+ }
+
+ article, err := parseArticle(string(content))
+ if err != nil {
+)
"fmt"
+ }
+ article.Filename = strings.TrimSuffix(filepath.Base(match), filepath.Ext(match))
+ articles = append(articles, article)
+ return nil
+ }(); err != nil {
+ return nil, err
+ }
+ }
+ sort.SliceStable(articles, func(i, j int) bool {
+ return articles[i].Time.After(articles[j].Time)
+ })
+ return articles, nil
+package blog
"net/url"
+
+func parseArticle(content string) (Article, error) {
+ lines := strings.Split(content, "\n")
+
+ start, end := -1, -1
+ var isSep func(string) bool
+ var decoder func([]byte, any) error
+
+package blog
}
+ if strings.TrimSpace(line) == "" {
+type Blog struct {
"fmt"
"os"
+ "io/fs"
package blog
+ return nil, errors.New("`index` template is required but was not found")
+ end = idx
+type Blog struct {
"net/url"
+ }
+ if isTOMLSeparator(line) {
+ start = idx
+ isSep = isTOMLSeparator
+ decoder = toml.Unmarshal
+ continue
+ }
+
+ if isYAMLSeparator(line) {
+ start = idx
+ isSep = isYAMLSeparator
+ decoder = yaml.Unmarshal
+ continue
+ }
+ }
+
+ var meta ArticleMeta
+ body := content
+ if start != -1 && end != -1 {
+ body = strings.Join(lines[end+1:], "\n")
+package blog
func parseArticles(fs fs.FS) ([]Article, error) {
+package blog
matches, err := doublestar.Glob(fs, "**/*.md")
+ }
"errors"
+import (
+
package blog
+ return nil, fmt.Errorf("could not glob articles: %w", err)
+package blog
"html/template"
-
+import (
+ if err != nil {
+ return Article{}, fmt.Errorf("could not convert article: %w", err)
}
+
+package blog
"html/template"
+ "fmt"
+ Content: template.HTML(buf.String()),
+ ArticleMeta: meta,
+ "fmt"
import (
+}
+
+func isTOMLSeparator(line string) bool {
+ for _, char := range line {
+ if char != '+' {
+ return false
+ }
}
+ return true
+}
+
+func isYAMLSeparator(line string) bool {
+ for _, char := range line {
+ if char != '-' {
+ return false
+ }
+ }
+ return true
}
diff --git a/blog_test.go b/blog_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..821a659ae04f26a6c4bb1157f8c4835e58de07b2
--- /dev/null
+++ b/blog_test.go
@@ -0,0 +1,72 @@
+package blog
+
+import (
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/alecthomas/assert"
+)
+
+func TestParseArticle(t *testing.T) {
+ var (
+ raw = `+++
+title = "Honk"
+subtitle = "Bonk"
+summary = """This
+is
+a
+summary"""
+time = 2024-02-16
+tags = ["bocchi", "rocks"]
+
+[author]
+name = "Bocchi"
+job = "Guitarist"
+email = "bocchi@rock.s"
+
+[[author.links]]
+name = "website"
+url = "https://example.com/bocchi"
++++
+
+# Hello world
+
+Beep boop`
+ meta = ArticleMeta{
+ Title: "Honk",
+ Subtitle: "Bonk",
+ Summary: `This
+is
+a
+summary`,
+ Time: func() time.Time {
+ t, _ := time.ParseInLocation("2006-01-02", "2024-02-16", time.Local)
+ return t
+ }(),
+ Author: Author{
+ Name: "Bocchi",
+ Job: "Guitarist",
+ Email: "bocchi@rock.s",
+ Links: []Link{
+ {
+ Name: "website",
+ URL: func() LinkURL {
+ u, _ := url.Parse("https://example.com/bocchi")
+ return LinkURL(*u)
+ }(),
+ },
+ },
+ },
+ Tags: []string{"bocchi", "rocks"},
+ }
+ body = `<h1 id="hello-world">Hello world</h1>
+<p>Beep boop</p>
+`
+ )
+
+ article, err := parseArticle(raw)
+ assert.NoError(t, err)
+ assert.Equal(t, meta, article.ArticleMeta)
+ assert.Equal(t, body, article.Content)
+}
diff --git a/cmd/blog/main.go b/cmd/blog/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..d5d835e2eab4153e10fc157dd07aec9cbb7507d4
--- /dev/null
+++ b/cmd/blog/main.go
@@ -0,0 +1,116 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/pelletier/go-toml/v2"
+ "go.jolheiser.com/blog"
+ "gopkg.in/yaml.v3"
+)
+
+type args struct {
+ ArticleDir string `yaml:"article-dir" toml:"article-dir"`
+ TemplateDir string `yaml:"template-dir" toml:"template-dir"`
+ OutDir string `yaml:"out-dir" toml:"out-dir"`
+ Author blog.Author `yaml:"author" toml:"author"`
+}
+
+func main() {
+ if err := maine(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+}
+
+func maine() error {
+ var args args
+
+ fs := flag.NewFlagSet("blog", flag.ExitOnError)
+
+ configFlag := fs.String("config", "", "Configuration, TOML or YAML")
+ fs.StringVar(configFlag, "c", *configFlag, "--config")
+ articlesFlag := fs.String("articles", "", "Path to articles")
+ fs.StringVar(articlesFlag, "a", *articlesFlag, "--articles")
+ templatesFlag := fs.String("templates", "", "Path to templates")
+ fs.StringVar(templatesFlag, "t", *templatesFlag, "--templates")
+ outFlag := fs.String("out", "", "Path to output")
+ fs.StringVar(outFlag, "o", *outFlag, "--out")
+
+ if err := fs.Parse(os.Args[1:]); err != nil {
+ return err
+ }
+
+ if *configFlag != "" {
+ data, err := os.ReadFile(*configFlag)
+ if err != nil {
+ return err
+ }
+ switch ext := filepath.Ext(*configFlag); ext {
+ case ".yaml", ".yml":
+ if err := yaml.Unmarshal(data, &args); err != nil {
+ return err
+ }
+ case ".toml":
+ if err := toml.Unmarshal(data, &args); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("could not determine config type %q", ext)
+ }
+ }
+
+ if *articlesFlag != "" {
+ args.ArticleDir = *articlesFlag
+ }
+ if args.ArticleDir == "" {
+ args.ArticleDir = "articles"
+ }
+ if *templatesFlag != "" {
+ args.TemplateDir = *templatesFlag
+ }
+ if args.TemplateDir == "" {
+ args.TemplateDir = "templates"
+ }
+ if *outFlag != "" {
+ args.OutDir = *outFlag
+ }
+ if args.OutDir == "" {
+ args.OutDir = "out"
+ }
+
+ if err := os.MkdirAll(args.OutDir, os.ModePerm); err != nil {
+ return err
+ }
+
+ blog, err := blog.NewBlog(args.ArticleDir, args.TemplateDir, args.Author)
+ if err != nil {
+ return err
+ }
+
+ indexFile, err := os.Create(filepath.Join(args.OutDir, "index.html"))
+ if err != nil {
+ return err
+ }
+ defer indexFile.Close()
+ if err := blog.Index(indexFile); err != nil {
+ return err
+ }
+
+ for _, article := range blog.Articles {
+ if err := func() error {
+ articleFile, err := os.Create(filepath.Join(args.OutDir, article.Filename+".html"))
+ if err != nil {
+ return err
+ }
+ defer articleFile.Close()
+ return blog.Article(articleFile, article)
+ }(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/cmd/chromacss/main.go b/cmd/chromacss/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..edf8cd5022a0e2574837c673ee0f869f4389a39f
--- /dev/null
+++ b/cmd/chromacss/main.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/alecthomas/chroma/v2/formatters/html"
+ "github.com/alecthomas/chroma/v2/styles"
+)
+
+func main() {
+ if err := maine(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+}
+
+func maine() error {
+ fs := flag.NewFlagSet("chromacss", flag.ExitOnError)
+ lightFlag := fs.String("light", "catppuccin-latte", "Light theme")
+ fs.StringVar(lightFlag, "l", *lightFlag, "--light")
+ darkFlag := fs.String("dark", "catppuccin-mocha", "Dark theme")
+ fs.StringVar(darkFlag, "d", *darkFlag, "--dark")
+ outFlag := fs.String("out", "", "Output (default: stdout)")
+ fs.StringVar(outFlag, "o", *outFlag, "--out")
+ if err := fs.Parse(os.Args[1:]); err != nil {
+ return err
+ }
+
+ out := os.Stdout
+ if *outFlag != "" {
+ fi, err := os.Create(*outFlag)
+ if err != nil {
+ return err
+ }
+ defer fi.Close()
+ out = fi
+ }
+
+ formatter := html.New(html.WithClasses(true), html.WithAllClasses(true))
+
+ lightStyle := *lightFlag
+ darkStyle := *darkFlag
+
+ if lightStyle == "" {
+ lightStyle = "catppuccin-latte"
+ if darkStyle != "" {
+ lightStyle = darkStyle
+ darkStyle = ""
+ }
+ }
+
+ styles.Fallback = styles.Get("catppuccin-latte")
+ style := styles.Get(lightStyle)
+ if err := formatter.WriteCSS(out, style); err != nil {
+ return err
+ }
+
+ if darkStyle != "" {
+ out.WriteString("@media (prefers-color-scheme: dark) {")
+ styles.Fallback = styles.Get("catpuccin-mocha")
+ style = styles.Get(darkStyle)
+ if err := formatter.WriteCSS(out, style); err != nil {
+ return err
+ }
+ out.WriteString("}")
+ }
+
+ return nil
+}
diff --git a/go.mod b/go.mod
index ebf428e62bc7377fd661ad412ab8c6c312f3c820..8c1aa017c7924a7b8ed3b4ceab8cde26ece9de51 100644
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,28 @@
go 1.21.6
require (
+module go.jolheiser.com/blog
github.com/alecthomas/chroma/v2 v2.12.0 // indirect
+module go.jolheiser.com/blog
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
+ github.com/alecthomas/chroma/v2 v2.12.0 // indirect
+module go.jolheiser.com/blog
github.com/dlclark/regexp2 v1.10.0 // indirect
+module go.jolheiser.com/blog
github.com/peterbourgon/ff/v3 v3.4.0 // indirect
+ github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
+ github.com/dlclark/regexp2 v1.10.0 // indirect
+ github.com/gorilla/feeds v1.1.2 // indirect
+ github.com/jolheiser/goldmark-meta v0.0.2 // indirect
+ github.com/mattn/go-isatty v0.0.14 // indirect
+ github.com/pelletier/go-toml/v2 v2.1.1 // indirect
+ github.com/peterbourgon/ff/v3 v3.4.0 // indirect
+ github.com/sergi/go-diff v1.2.0 // indirect
github.com/yuin/goldmark v1.7.0 // indirect
github.com/yuin/goldmark-emoji v1.0.2 // indirect
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
+ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index caa7d4f6c0a660af8270928e7bdf133b7c732019..62a81853e4095cb8c64512a1f9d8ff9e25a8fc83 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,16 @@
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/alecthomas/assert v1.0.0 h1:3XmGh/PSuLzDbK3W2gUbRXwgW5lqPkuqvRgeQ30FI5o=
+github.com/alecthomas/assert v1.0.0/go.mod h1:va/d2JC+M7F6s+80kl/R3G7FUiW6JzUO+hPhLyJ36ZY=
github.com/alecthomas/chroma/v2 v2.2.0 h1:Aten8jfQwUqEdadVFFjNyjx7HTexhKP0XuqBG67mRDY=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
+github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=
+github.com/alecthomas/colour v0.1.0/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
+github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
+github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -12,12 +20,33 @@ github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
+github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
+github.com/jolheiser/goldmark-meta v0.0.2 h1:3qnvGnp1n7Cdu1L9LpuZrM6dfmbMAS22+hNJnxGPn6s=
+github.com/jolheiser/goldmark-meta v0.0.2/go.mod h1:x5vZW1+kBEhR4+AKHwnNsD+nQaYdgmXoiFgG3fc6ZFc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
+github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
+github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc=
github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
github.com/alecthomas/chroma/v2 v2.2.0 h1:Aten8jfQwUqEdadVFFjNyjx7HTexhKP0XuqBG67mRDY=
+github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.3.7 h1:NSaHgaeJFCtWXCBkBKXw0rhgMuJ0VoE9FB5mWldcrQ4=
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.15 h1:CFa84T0goNn/UIXYS+dmjjVxMyTAvpOmzld40N/nfK0=
@@ -30,7 +59,14 @@ github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/goldmark.go b/goldmark.go
index 99f519f9fdc3e2bc2d605a469bc28c8d51a4eba7..404e8a5ff1189ddd0c7569bb22b4a44217dca46b 100644
--- a/goldmark.go
+++ b/goldmark.go
@@ -1,13 +1,14 @@
package blog
import (
- "github.com/alecthomas/chroma/v2/formatters/html"
+ chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
"github.com/yuin/goldmark"
emoji "github.com/yuin/goldmark-emoji"
highlighting "github.com/yuin/goldmark-highlighting/v2"
meta "github.com/yuin/goldmark-meta"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark/renderer/html"
)
// Markdown is the default markdown converter
@@ -16,19 +17,22 @@ var Markdown = goldmark.New(
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
+ goldmark.WithRendererOptions(
+ html.WithUnsafe(),
+ ),
goldmark.WithExtensions(
extension.GFM,
meta.Meta,
emoji.Emoji,
highlighting.NewHighlighting(
highlighting.WithFormatOptions(
-
+import (
"github.com/alecthomas/chroma/v2/formatters/html"
-
+import (
"github.com/yuin/goldmark"
-
+import (
emoji "github.com/yuin/goldmark-emoji"
-
+import (
highlighting "github.com/yuin/goldmark-highlighting/v2"
),
),