-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmarkdown.go
160 lines (136 loc) · 4.03 KB
/
markdown.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"text/template"
"github.com/ericaro/frontmatter"
"github.com/russross/blackfriday"
)
const (
htmlFlags = 0 |
blackfriday.HTML_USE_XHTML |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_FRACTIONS |
blackfriday.HTML_SMARTYPANTS_DASHES |
blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
markdownExtensions = 0 |
blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
blackfriday.EXTENSION_TABLES |
blackfriday.EXTENSION_FENCED_CODE |
blackfriday.EXTENSION_AUTOLINK |
blackfriday.EXTENSION_STRIKETHROUGH |
blackfriday.EXTENSION_SPACE_HEADERS |
blackfriday.EXTENSION_HEADER_IDS |
blackfriday.EXTENSION_AUTO_HEADER_IDS |
blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
blackfriday.EXTENSION_DEFINITION_LISTS
)
type Document struct {
Title string `fm:"title"`
Content string `fm:"content"`
MarkdownTheme string
TypekitKitID string
CodeTheme string
}
type MarkdownHandlerOptions struct {
DocRoot string
DocExtension string
DirIndex string
MarkdownTheme string
TypekitKitID string
CodeTheme string
}
func markdownHandleFunc(opts MarkdownHandlerOptions) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path, err := filepath.Abs(filepath.Join(opts.DocRoot, r.URL.Path))
if err != nil {
serveInternalError(w, r, opts)
fmt.Fprintf(os.Stderr, "Error finding absolute path (%s)", err)
return
}
info, err := os.Stat(path)
if os.IsNotExist(err) {
servePageNotFound(w, r, opts)
return
}
if info.IsDir() {
serveDirectory(w, r, path, opts)
return
}
// Serve file
serveFile(w, r, path, opts)
}
}
func serveDirectory(w http.ResponseWriter, r *http.Request, path string, opts MarkdownHandlerOptions) {
indexFile := filepath.Join(path, opts.DirIndex+opts.DocExtension)
serveFile(w, r, indexFile, opts)
}
func serveFile(w http.ResponseWriter, r *http.Request, path string, opts MarkdownHandlerOptions) {
ext := filepath.Ext(path)
if ext == opts.DocExtension {
serveMarkdown(w, r, path, opts)
} else {
http.ServeFile(w, r, path)
}
}
func serveMarkdown(w http.ResponseWriter, r *http.Request, path string, opts MarkdownHandlerOptions) {
data, err := ioutil.ReadFile(path)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading file (%s).\n", err)
serveInternalError(w, r, opts)
return
}
doc := Document{
MarkdownTheme: opts.MarkdownTheme,
TypekitKitID: opts.TypekitKitID,
CodeTheme: opts.CodeTheme,
}
err = frontmatter.Unmarshal(data, &doc)
if err != nil {
serveInternalError(w, r, opts)
fmt.Fprintf(os.Stderr, "Error unmarshalling frontmatter (%s).\n", err)
}
doc.Content = parseMarkdown(doc.Content)
serveDocument(w, r, doc)
}
func parseMarkdown(input string) string {
// set up the HTML renderer
renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")
outputBytes := blackfriday.MarkdownOptions([]byte(input), renderer, blackfriday.Options{
Extensions: markdownExtensions})
return string(outputBytes)
}
func serveDocument(w http.ResponseWriter, r *http.Request, doc Document) {
templateData, err := Asset("assets/templates/document.html")
if err != nil {
fmt.Fprintf(os.Stderr, "Error finding template (%s).\n", err)
}
t, err := template.New("document").Parse(string(templateData))
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing template (%s).\n", err)
}
t.Execute(w, doc)
}
func servePageNotFound(w http.ResponseWriter, r *http.Request, opts MarkdownHandlerOptions) {
w.WriteHeader(http.StatusNotFound)
doc := Document{
MarkdownTheme: opts.MarkdownTheme,
CodeTheme: opts.CodeTheme,
Title: "Page Not Found",
Content: "<h1>Page Not Found</h1>",
}
serveDocument(w, r, doc)
}
func serveInternalError(w http.ResponseWriter, r *http.Request, opts MarkdownHandlerOptions) {
w.WriteHeader(http.StatusInternalServerError)
doc := Document{
MarkdownTheme: opts.MarkdownTheme,
CodeTheme: opts.CodeTheme,
Title: "Invalid Request",
Content: "<h1>Invalid Request</h1>",
}
serveDocument(w, r, doc)
}