forked from briansniffen/gwern.net
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hakyll.hs
executable file
·153 lines (135 loc) · 7.73 KB
/
hakyll.hs
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
#!/usr/bin/env runhaskell
{-# LANGUAGE OverloadedStrings #-}
import Control.Arrow (arr, (>>>), (>>^))
import Data.FileStore (darcsFileStore)
import Data.Monoid (mempty, mconcat)
import Network.HTTP (urlEncode)
import Network.URI (unEscapeString, isUnescapedInURI)
import Network.URL (encString)
import System.Directory (copyFile)
import System.Process (runCommand)
import qualified Data.Map as M (fromList, lookup, Map)
import Hakyll
import Feed (filestoreToXmlFeed, FeedConfig(..))
import Text.Pandoc (bottomUp, defaultWriterOptions, HTMLMathMethod(MathML), Inline(Link, Str), Pandoc, WriterOptions(..), ParserState(stateSmart))
import Text.Pandoc.Shared (ObfuscationMethod(NoObfuscation))
main :: IO ()
main = do hakyll $ do
-- handle the simple non-.page files
let static = route idRoute >> compile copyFileCompiler
mapM_ (`match` static) ["docs/**",
"images/**",
"**.hs",
"static/css/**",
"static/img/**",
"static/js/**"]
_ <- match "**.css" $ route idRoute >> compile compressCssCompiler
_ <- match "static/templates/*.html" $ compile templateCompiler
-- handle the much more complex content pages, with tags & metadata etc.
pages <- group "html" $ match "**.page" $ do
route $ setExtension "" -- cool URLs
compile $ myPageCompiler
>>> renderTagsField "prettytags" (fromCapture "tags/*")
>>> renderModificationTime "modified" "%e %b %Y" -- populate $modified$
>>> applyTemplateCompiler "static/templates/default.html"
-- Add a tag list compiler for every tag
create "tags" $ requireAll pages (\_ ps -> readTags ps :: Tags String)
match "tags/*" $ route $ setExtension ""
metaCompile $ require_ "tags"
>>> arr tagsMap
>>> arr (map (\(t, p) -> (fromCapture "tags/*" t, makeTagList t p)))
print "generating & copying RSS feed..."
writeFile "_site/atom.xml" =<< filestoreToXmlFeed rssConfig (darcsFileStore "./") Nothing
print "executing Apache configuration (caching, compression, redirects)..."
_ <- runCommand "find _site/ -type d \\( -name _darcs \\) -prune -type f -o \
\ -not -name \"*.o\" -not -name \"*.hi\" -not -name \"*.hs\" \
\ -not -name \"*.png\" -not -name \"*.jpg\" -not -name \"*.gif\" \
\ -not -name \"*.pdf\" -not -name \"*.avi\" -not -name \"*.svg\" \
\ -not -name \".htaccess\" -not -name \"*.gz\" -type f \
\ -exec /bin/sh -c \"gzip --stdout --best --no-name \
\ --rsyncable \\\"{}\\\" > \\\"{}.gz\\\"\" \\;"
copyFile ".htaccess" "_site/.htaccess"
addPostList :: Compiler (Page String, [Page String]) (Page String)
addPostList = setFieldA "posts" $
arr (reverse . chronological)
>>> require "static/templates/postitem.html" (\p t -> map (applyTemplate t) p)
>>> arr mconcat
>>> arr pageBody
makeTagList :: String
-> [Page String]
-> Compiler () (Page String)
makeTagList tag posts =
constA (mempty, posts)
>>> addPostList
>>> arr (setField "title" ("Posts tagged ‘" ++ tag ++ "’"))
>>> applyTemplateCompiler "static/templates/tags.html"
>>> relativizeUrlsCompiler
options :: WriterOptions
options = defaultWriterOptions{ writerSectionDivs = True,
writerStandalone = True,
writerTableOfContents = True,
writerTemplate = "<div id=\"TOC\">$toc$</div>\n$body$",
writerHTMLMathMethod = Text.Pandoc.MathML Nothing,
writerEmailObfuscation = NoObfuscation }
rssConfig :: FeedConfig
rssConfig = FeedConfig { fcTitle = "Joining Clouds", fcBaseUrl = "http://www.gwern.net", fcFeedDays = 30 }
myPageCompiler :: Compiler Resource (Page String)
myPageCompiler = cached "myPageCompiler" $ readPageCompiler >>> addDefaultFields >>> arr (changeField "description" escapeHtml) >>> arr applySelf >>> myPageRenderPandocWith
myPageRenderPandocWith :: Compiler (Page String) (Page String)
myPageRenderPandocWith = pageReadPandocWith defaultHakyllParserState{stateSmart=False} >>^ fmap pandocTransform >>^ fmap (writePandocWith options)
pandocTransform :: Pandoc -> Pandoc
pandocTransform = bottomUp (map (convertInterwikiLinks . convertHakyllLinks))
-- GITIT -> HAKYLL LINKS PLUGIN
-- | Convert links with no URL to wikilinks.
convertHakyllLinks :: Inline -> Inline
convertHakyllLinks (Link ref ("", "")) = let ref' = inlinesToURL ref in Link ref (ref', "Go to wiki page: " ++ ref')
convertHakyllLinks x = x
-- INTERWIKI PLUGIN
-- | Derives a URL from a list of Pandoc Inline elements.
inlinesToURL :: [Inline] -> String
inlinesToURL x = let x' = inlinesToString x
(a,b) = break (=='%') x'
in encString False isUnescapedInURI a ++ b
-- | Convert a list of inlines into a string.
inlinesToString :: [Inline] -> String
inlinesToString = concatMap go
where go x = case x of
Str s -> s
_ -> " "
convertInterwikiLinks :: Inline -> Inline
convertInterwikiLinks (Link ref (interwiki, article)) =
case interwiki of
('!':interwiki') ->
case M.lookup interwiki' interwikiMap of
Just url -> case article of
"" -> Link ref (url `interwikiurl` inlinesToString ref, summary $ unEscapeString $ inlinesToString ref)
_ -> Link ref (url `interwikiurl` article, summary article)
Nothing -> Link ref (interwiki, article)
where -- 'http://starwars.wikia.com/wiki/Emperor_Palpatine'
-- TODO: `urlEncode` breaks Unicode strings like "Shōtetsu"!
interwikiurl u a = u ++ urlEncode a
-- 'Wookieepedia: Emperor Palpatine'
summary a = interwiki' ++ ": " ++ a
_ -> Link ref (interwiki, article)
convertInterwikiLinks x = x
-- | Large table of constants; this is a mapping from shortcuts to a URL. The URL can be used by
-- appending to it the article name (suitably URL-escaped, of course).
interwikiMap :: M.Map String String
interwikiMap = M.fromList $ wpInterwikiMap ++ customInterwikiMap
wpInterwikiMap, customInterwikiMap :: [(String, String)]
customInterwikiMap = [("Hackage", "http://hackage.haskell.org/package/"),
("Hawiki", "http://haskell.org/haskellwiki/"),
("Hayoo", "http://holumbus.fh-wedel.de/hayoo/hayoo.html#0:"),
("Hoogle", "http://www.haskell.org/hoogle/?hoogle=")]
wpInterwikiMap = [ ("Commons", "http://commons.wikimedia.org/wiki/"),
("EmacsWiki", "http://www.emacswiki.org/cgi-bin/wiki.pl?"),
("Google", "http://www.google.com/search?q="),
("Wikimedia", "http://wikimediafoundation.org/wiki/"),
("Wikinews", "http://en.wikinews.org/wiki/"),
("Wikipedia", "http://en.wikipedia.org/wiki/"),
("Wikiquote", "http://en.wikiquote.org/wiki/"),
("Wikischool", "http://www.wikischool.de/wiki/"),
("Wikisource", "http://en.wikisource.org/wiki/"),
("Wiktionary", "http://en.wiktionary.org/wiki/"),
("WMF", "http://wikimediafoundation.org/wiki/"),
("Wookieepedia", "http://starwars.wikia.com/wiki/") ]