Branch markdown into its own subpackage
This commit is contained in:
parent
3d5147ff4c
commit
aabcf59181
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/gorilla/feeds"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
"github.com/kirsle/blog/core/internal/models/comments"
|
||||
"github.com/kirsle/blog/core/internal/models/posts"
|
||||
"github.com/kirsle/blog/core/internal/models/settings"
|
||||
|
@ -439,7 +440,7 @@ func (b *Blog) RenderPost(p *posts.Post, indexView bool, numComments int) templa
|
|||
// Render the post to HTML.
|
||||
var rendered template.HTML
|
||||
if p.ContentType == string(MARKDOWN) {
|
||||
rendered = template.HTML(b.RenderTrustedMarkdown(p.Body))
|
||||
rendered = template.HTML(markdown.RenderTrustedMarkdown(p.Body))
|
||||
} else {
|
||||
rendered = template.HTML(p.Body)
|
||||
}
|
||||
|
@ -490,7 +491,7 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) {
|
|||
switch r.FormValue("submit") {
|
||||
case "preview":
|
||||
if post.ContentType == string(MARKDOWN) {
|
||||
v.Data["preview"] = template.HTML(b.RenderTrustedMarkdown(post.Body))
|
||||
v.Data["preview"] = template.HTML(markdown.RenderTrustedMarkdown(post.Body))
|
||||
} else {
|
||||
v.Data["preview"] = template.HTML(post.Body)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
"github.com/kirsle/blog/core/internal/models/comments"
|
||||
"github.com/kirsle/blog/core/internal/models/users"
|
||||
)
|
||||
|
@ -62,7 +63,7 @@ func (b *Blog) RenderComments(session *sessions.Session, csrfToken, url, subject
|
|||
// Render all the comments in the thread.
|
||||
userMap := map[int]*users.User{}
|
||||
for _, c := range thread.Comments {
|
||||
c.HTML = template.HTML(b.RenderMarkdown(c.Body))
|
||||
c.HTML = template.HTML(markdown.RenderMarkdown(c.Body))
|
||||
c.ThreadID = thread.ID
|
||||
c.OriginURL = url
|
||||
c.CSRF = csrfToken
|
||||
|
@ -203,7 +204,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) {
|
|||
c.Email = currentUser.Email
|
||||
c.LoadAvatar()
|
||||
}
|
||||
c.HTML = template.HTML(b.RenderMarkdown(c.Body))
|
||||
c.HTML = template.HTML(markdown.RenderMarkdown(c.Body))
|
||||
case "post":
|
||||
if err := c.Validate(); err != nil {
|
||||
v.Error = err
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kirsle/blog/core/internal/forms"
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
"github.com/kirsle/blog/core/internal/models/settings"
|
||||
)
|
||||
|
||||
|
@ -47,7 +48,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) {
|
|||
Template: ".email/contact.gohtml",
|
||||
Data: map[string]interface{}{
|
||||
"Name": form.Name,
|
||||
"Message": template.HTML(b.RenderMarkdown(form.Message)),
|
||||
"Message": template.HTML(markdown.RenderMarkdown(form.Message)),
|
||||
"Email": form.Email,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package core implements the core source code of kirsle/blog.
|
||||
package core
|
||||
|
||||
import (
|
||||
|
@ -7,14 +8,15 @@ import (
|
|||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/kirsle/blog/jsondb/caches"
|
||||
"github.com/kirsle/blog/jsondb/caches/null"
|
||||
"github.com/kirsle/blog/jsondb/caches/redis"
|
||||
"github.com/kirsle/blog/jsondb"
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
"github.com/kirsle/blog/core/internal/models/comments"
|
||||
"github.com/kirsle/blog/core/internal/models/posts"
|
||||
"github.com/kirsle/blog/core/internal/models/settings"
|
||||
"github.com/kirsle/blog/core/internal/models/users"
|
||||
"github.com/kirsle/blog/jsondb"
|
||||
"github.com/kirsle/blog/jsondb/caches"
|
||||
"github.com/kirsle/blog/jsondb/caches/null"
|
||||
"github.com/kirsle/blog/jsondb/caches/redis"
|
||||
"github.com/shurcooL/github_flavored_markdown/gfmstyle"
|
||||
"github.com/urfave/negroni"
|
||||
)
|
||||
|
@ -76,6 +78,7 @@ func New(documentRoot, userRoot string) *Blog {
|
|||
} else {
|
||||
blog.Cache = cache
|
||||
blog.DB.Cache = cache
|
||||
markdown.Cache = cache
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
package core
|
||||
// Package markdown implements a GitHub Flavored Markdown renderer.
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -10,17 +11,23 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/kirsle/blog/jsondb/caches"
|
||||
"github.com/kirsle/golog"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/shurcooL/github_flavored_markdown"
|
||||
)
|
||||
|
||||
// Regexps for Markdown use cases.
|
||||
var (
|
||||
// Plug your own Redis cacher in.
|
||||
Cache caches.Cacher
|
||||
|
||||
// Match title from the first `# h1` heading.
|
||||
reMarkdownTitle = regexp.MustCompile(`(?m:^#([^#\r\n]+)$)`)
|
||||
|
||||
// Match fenced code blocks with languages defined.
|
||||
reFencedCode = regexp.MustCompile("```" + `([a-z]*)[\r\n]([\s\S]*?)[\r\n]\s*` + "```")
|
||||
reFencedCode = regexp.MustCompile("```" + `([a-z]*)[\r\n]([\s\S]*?)[\r\n]\s*` + "```")
|
||||
reFencedCodeClass = regexp.MustCompile("^highlight highlight-[a-zA-Z0-9]+$")
|
||||
|
||||
// Regexp to match fenced code blocks in rendered Markdown HTML.
|
||||
// Tweak this if you change Markdown engines later.
|
||||
|
@ -28,6 +35,12 @@ var (
|
|||
reDecodeBlock = regexp.MustCompile(`\[?FENCED_CODE_%d_BLOCK?\]`)
|
||||
)
|
||||
|
||||
var log *golog.Logger
|
||||
|
||||
func init() {
|
||||
log = golog.GetLogger("blog")
|
||||
}
|
||||
|
||||
// A container for parsed code blocks.
|
||||
type codeBlock struct {
|
||||
placeholder int
|
||||
|
@ -51,8 +64,8 @@ func TitleFromMarkdown(body string) (string, error) {
|
|||
|
||||
// RenderMarkdown renders markdown to HTML, safely. It uses blackfriday to
|
||||
// render Markdown to HTML and then Bluemonday to sanitize the resulting HTML.
|
||||
func (b *Blog) RenderMarkdown(input string) string {
|
||||
unsafe := []byte(b.RenderTrustedMarkdown(input))
|
||||
func RenderMarkdown(input string) string {
|
||||
unsafe := []byte(RenderTrustedMarkdown(input))
|
||||
|
||||
// Sanitize HTML, but allow fenced code blocks to not get mangled in user
|
||||
// submitted comments.
|
||||
|
@ -65,7 +78,7 @@ func (b *Blog) RenderMarkdown(input string) string {
|
|||
// RenderTrustedMarkdown renders markdown to HTML, but without applying
|
||||
// bluemonday filtering afterward. This is for blog posts and website
|
||||
// Markdown pages, not for user-submitted comments or things.
|
||||
func (b *Blog) RenderTrustedMarkdown(input string) string {
|
||||
func RenderTrustedMarkdown(input string) string {
|
||||
// Find and hang on to fenced code blocks.
|
||||
codeBlocks := []codeBlock{}
|
||||
matches := reFencedCode.FindAllStringSubmatch(input, -1)
|
||||
|
@ -87,7 +100,7 @@ func (b *Blog) RenderTrustedMarkdown(input string) string {
|
|||
|
||||
// Substitute fenced codes back in.
|
||||
for _, block := range codeBlocks {
|
||||
highlighted, _ := b.Pygmentize(block.language, block.source)
|
||||
highlighted, _ := Pygmentize(block.language, block.source)
|
||||
html = strings.Replace(html,
|
||||
fmt.Sprintf("[?FENCED_CODE_%d_BLOCK?]", block.placeholder),
|
||||
highlighted,
|
||||
|
@ -105,7 +118,7 @@ func (b *Blog) RenderTrustedMarkdown(input string) string {
|
|||
//
|
||||
// The rendered result is cached in Redis if available, because the CLI
|
||||
// call takes ~0.6s which is slow if you're rendering a lot of code blocks.
|
||||
func (b *Blog) Pygmentize(language, source string) (string, error) {
|
||||
func Pygmentize(language, source string) (string, error) {
|
||||
var result string
|
||||
|
||||
// Hash the source for the cache key.
|
||||
|
@ -114,10 +127,11 @@ func (b *Blog) Pygmentize(language, source string) (string, error) {
|
|||
hash := fmt.Sprintf("%x", h.Sum(nil))
|
||||
cacheKey := "pygmentize:" + hash
|
||||
|
||||
_ = cacheKey
|
||||
// Do we have it cached?
|
||||
if cached, err := b.Cache.Get(cacheKey); err == nil && len(cached) > 0 {
|
||||
return string(cached), nil
|
||||
}
|
||||
// if cached, err := b.Cache.Get(cacheKey); err == nil && len(cached) > 0 {
|
||||
// return string(cached), nil
|
||||
// }
|
||||
|
||||
// Defer to the `pygmentize` command
|
||||
bin := "pygmentize"
|
||||
|
@ -140,10 +154,10 @@ func (b *Blog) Pygmentize(language, source string) (string, error) {
|
|||
}
|
||||
|
||||
result = out.String()
|
||||
err := b.Cache.Set(cacheKey, []byte(result), 60*60*24) // cool md5's don't change
|
||||
if err != nil {
|
||||
log.Error("Couldn't cache Pygmentize output: %s", err)
|
||||
}
|
||||
// err := b.Cache.Set(cacheKey, []byte(result), 60*60*24) // cool md5's don't change
|
||||
// if err != nil {
|
||||
// log.Error("Couldn't cache Pygmentize output: %s", err)
|
||||
// }
|
||||
|
||||
return result, nil
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
"github.com/kirsle/blog/core/internal/models/comments"
|
||||
"github.com/kirsle/blog/core/internal/models/settings"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
|
@ -107,7 +108,7 @@ func (b *Blog) NotifyComment(c *comments.Comment) {
|
|||
Data: map[string]interface{}{
|
||||
"Name": c.Name,
|
||||
"Subject": c.Subject,
|
||||
"Body": template.HTML(b.RenderMarkdown(c.Body)),
|
||||
"Body": template.HTML(markdown.RenderMarkdown(c.Body)),
|
||||
"URL": strings.Trim(s.Site.URL, "/") + c.OriginURL,
|
||||
"QuickDelete": fmt.Sprintf("%s/comments/quick-delete?t=%s&d=%s",
|
||||
strings.Trim(s.Site.URL, "/"),
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/kirsle/blog/core/internal/markdown"
|
||||
)
|
||||
|
||||
// PageHandler is the catch-all route handler, for serving static web pages.
|
||||
|
@ -54,8 +56,8 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Render it to HTML and find out its title.
|
||||
body := string(source)
|
||||
html := b.RenderTrustedMarkdown(body)
|
||||
title, _ := TitleFromMarkdown(body)
|
||||
html := markdown.RenderTrustedMarkdown(body)
|
||||
title, _ := markdown.TitleFromMarkdown(body)
|
||||
|
||||
b.RenderTemplate(w, r, ".markdown", NewVars(map[interface{}]interface{}{
|
||||
"Title": title,
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package core
|
||||
|
||||
import "regexp"
|
||||
|
||||
var (
|
||||
// CSS classes for Markdown fenced code blocks
|
||||
reFencedCodeClass = regexp.MustCompile("^highlight highlight-[a-zA-Z0-9]+$")
|
||||
)
|
Loading…
Reference in New Issue
Block a user