on 40945cd help sign in
112 files changed+836−1854
since splitsnapshots
unifiedsplit
.circleci/config.yml−19 .circleci/tickle.sh−24 .travis.yml+20 CHANGELOG.md−126 Makefile+6−6 README.markdown+1−1 data/example/css/default.css+29−114 hakyll.cabal+125−128 lib/Hakyll/Core/Identifier/Pattern/Internal.hs−92 lib/Hakyll/Web/CompressCss.hs−101 lib/Data/List/Extended.hs → src/Data/List/Extended.hs lib/Data/Yaml/Extended.hs → src/Data/Yaml/Extended.hs lib/Hakyll.hs → src/Hakyll.hs+1−5 lib/Hakyll/Check.hs → src/Hakyll/Check.hs+1−13 lib/Hakyll/Commands.hs → src/Hakyll/Commands.hs+2−6 lib/Hakyll/Core/Compiler.hs → src/Hakyll/Core/Compiler.hs+2−35 lib/Hakyll/Core/Compiler/Internal.hs → src/Hakyll/Core/Compiler/Internal.hs+41−140 lib/Hakyll/Core/Compiler/Require.hs → src/Hakyll/Core/Compiler/Require.hs−2 lib/Hakyll/Core/Configuration.hs → src/Hakyll/Core/Configuration.hs lib/Hakyll/Core/Dependencies.hs → src/Hakyll/Core/Dependencies.hs lib/Hakyll/Core/File.hs → src/Hakyll/Core/File.hs lib/Hakyll/Core/Identifier.hs → src/Hakyll/Core/Identifier.hs+1−1 lib/Hakyll/Core/Identifier/Pattern.hs → src/Hakyll/Core/Identifier/Pattern.hs+72−14 lib/Hakyll/Core/Item.hs → src/Hakyll/Core/Item.hs lib/Hakyll/Core/Item/SomeItem.hs → src/Hakyll/Core/Item/SomeItem.hs lib/Hakyll/Core/Logger.hs → src/Hakyll/Core/Logger.hs+3−9 lib/Hakyll/Core/Metadata.hs → src/Hakyll/Core/Metadata.hs lib/Hakyll/Core/Provider.hs → src/Hakyll/Core/Provider.hs lib/Hakyll/Core/Provider/Internal.hs → src/Hakyll/Core/Provider/Internal.hs lib/Hakyll/Core/Provider/Metadata.hs → src/Hakyll/Core/Provider/Metadata.hs+2−3 lib/Hakyll/Core/Provider/MetadataCache.hs → src/Hakyll/Core/Provider/MetadataCache.hs lib/Hakyll/Core/Routes.hs → src/Hakyll/Core/Routes.hs−17 lib/Hakyll/Core/Rules.hs → src/Hakyll/Core/Rules.hs lib/Hakyll/Core/Rules/Internal.hs → src/Hakyll/Core/Rules/Internal.hs−14 lib/Hakyll/Core/Runtime.hs → src/Hakyll/Core/Runtime.hs+3−3 lib/Hakyll/Core/Store.hs → src/Hakyll/Core/Store.hs+23−26 lib/Hakyll/Core/UnixFilter.hs → src/Hakyll/Core/UnixFilter.hs+1−2 lib/Hakyll/Core/Util/File.hs → src/Hakyll/Core/Util/File.hs lib/Hakyll/Core/Util/Parser.hs → src/Hakyll/Core/Util/Parser.hs+1 lib/Hakyll/Core/Util/String.hs → src/Hakyll/Core/Util/String.hs+1−1 lib/Hakyll/Core/Writable.hs → src/Hakyll/Core/Writable.hs src/Init.hs → src/Hakyll/Init.hs+17−44 lib/Hakyll/Main.hs → src/Hakyll/Main.hs+29−71 lib/Hakyll/Preview/Poll.hs → src/Hakyll/Preview/Poll.hs+18−8 lib/Hakyll/Preview/Server.hs → src/Hakyll/Preview/Server.hs src/Hakyll/Web/CompressCss.hs+86 lib/Hakyll/Web/Feed.hs → src/Hakyll/Web/Feed.hs+21−59 lib/Hakyll/Web/Html.hs → src/Hakyll/Web/Html.hs+2−6 lib/Hakyll/Web/Html/RelativizeUrls.hs → src/Hakyll/Web/Html/RelativizeUrls.hs lib/Hakyll/Web/Paginate.hs → src/Hakyll/Web/Paginate.hs lib/Hakyll/Web/Pandoc.hs → src/Hakyll/Web/Pandoc.hs+12−13 lib/Hakyll/Web/Pandoc/Biblio.hs → src/Hakyll/Web/Pandoc/Biblio.hs+6−17 lib/Hakyll/Web/Pandoc/Binary.hs → src/Hakyll/Web/Pandoc/Binary.hs+17−19 lib/Hakyll/Web/Pandoc/FileType.hs → src/Hakyll/Web/Pandoc/FileType.hs lib/Hakyll/Web/Redirect.hs → src/Hakyll/Web/Redirect.hs+1−14 lib/Hakyll/Web/Tags.hs → src/Hakyll/Web/Tags.hs+1−2 lib/Hakyll/Web/Template.hs → src/Hakyll/Web/Template.hs−24 lib/Hakyll/Web/Template/Context.hs → src/Hakyll/Web/Template/Context.hs+33−135 lib/Hakyll/Web/Template/Internal.hs → src/Hakyll/Web/Template/Internal.hs+45−103 lib/Hakyll/Web/Template/Internal/Element.hs → src/Hakyll/Web/Template/Internal/Element.hs+14−7 lib/Hakyll/Web/Template/Internal/Trim.hs → src/Hakyll/Web/Template/Internal/Trim.hs lib/Hakyll/Web/Template/List.hs → src/Hakyll/Web/Template/List.hs stack.yaml+7−27 test.hs−30 tests/Hakyll/Core/Identifier/Tests.hs−1 tests/Hakyll/Core/Provider/Tests.hs+2−2 tests/Hakyll/Core/Rules/Tests.hs+4−3 tests/Hakyll/Core/Runtime/Tests.hs+1−1 tests/Hakyll/Core/Store/Tests.hs+7−7 tests/Hakyll/Core/UnixFilter/Tests.hs+12−22 tests/Hakyll/Web/CompressCss/Tests.hs+11−12 tests/Hakyll/Web/Html/Tests.hs+6−6 tests/Hakyll/Web/Template/Context/Tests.hs+3−40 tests/Hakyll/Web/Template/Tests.hs+19−52 tests/TestSuite.hs−7 tests/TestSuite/Util.hs+5−27 tests/data/embed.html−1 tests/data/posts/2018-09-26.md−1 tests/data/posts/2019/05/10/tomorrow.md−1 web/css/syntax.css+18−61 web/examples.markdown+30−32 web/libraries.markdown−1 web/site.hs+32−14 web/templates/default.html+6−1 web/templates/tutorials.html+18−24 web/tutorials/01-installation.markdown+1−4 web/tutorials/02-basics.markdown−1 web/tutorials/03-rules-routes-compilers.markdown−1 web/tutorials/04-compilers.markdown+3−4 web/tutorials/05-snapshots-feeds.markdown−1 web/tutorials/06-versions.markdown−1 web/tutorials/a-guide-to-the-hakyll-module-zoo.markdown−1 web/tutorials/external-add-tags-to-your-hakyll-blog.md+1−1 web/tutorials/external-blogger-port.md+1−1 web/tutorials/external-cassius-template.md+1−1 web/tutorials/external-clean-urls-with-hakyll.md+1−1 web/tutorials/external-deploying-with-widely.md+1−1 web/tutorials/external-external-code-inclusion.md−6 web/tutorials/external-functionfield.md+1−1 web/tutorials/external-github-pages-circle-ci.md+1−1 web/tutorials/external-inlining-and-compressing-css.md+1−1 web/tutorials/external-live-reload.md+6 web/tutorials/faq.markdown−1 web/tutorials/github-pages-tutorial.md−1 web/tutorials/hakyll-3-to-hakyll4-migration-guide.markdown−1 web/tutorials/robertwpearce-01-setup-and-initial-customization.html−5 web/tutorials/robertwpearce-02-generating-a-sitemap-xml-file.html−5 web/tutorials/robertwpearce-03-generating-rss-and-atom-xml-feeds.html−5 web/tutorials/robertwpearce-04-copying-static-files-for-your-build.html−5 web/tutorials/robertwpearce-05-generating-custom-post-filenames-from-a-title-slug.html−5 web/tutorials/using-clay-with-hakyll.markdown−1 web/tutorials/using-teasers-in-hakyll.markdown−1
.circleci/config.ymldeleted−19
@@ -1,19 +0,0 @@
1−version: 2
2−jobs:
3− build:
4− docker:
5− - image: 'fpco/stack-build:latest'
6− steps:
7− - checkout
8− - restore_cache:
9− key: 'v3-hakyll-{{ arch }}-{{ .Branch }}'
10− - run:
11− # We set jobs to 1 here because that prevents Out-Of-Memory exceptions
12− # while compiling dependencies.
13− name: 'Install dependencies'
14− command: '.circleci/tickle.sh stack build --test --copy-bins --jobs=1'
15− - save_cache:
16− key: 'v3-hakyll-{{ arch }}-{{ .Branch }}-{{ .Revision }}'
17− paths:
18− - '~/.stack-work'
19− - '~/.stack'
.circleci/tickle.shdeleted−24
@@ -1,24 +0,0 @@
1−#!/bin/bash
2−set -o nounset -o errexit -o pipefail
3−
4−function tickle() {
5− while [ true ]; do
6− echo "[$(date +%H:%M:%S)] Tickling..."
7− sleep 60
8− done
9−}
10−
11−echo "Forking tickle process..."
12−tickle &
13−TICKLE_PID=$!
14−
15−echo "Forking build process..."
16−eval $@ &
17−BUILD_PID=$!
18−
19−echo "Waiting for build thread ($BUILD_PID)..."
20−wait $BUILD_PID
21−
22−echo "Killing tickle thread ($TICKLE_PID)..."
23−kill $TICKLE_PID
24−echo "All done!"
.travis.ymlnew file+20
@@ -0,0 +1,20 @@
1+language: haskell
2+ghc: '7.10'
3+branches:
4+ only:
5+ - master
6+cache:
7+ directories:
8+ - $HOME/.stack
9+before_install:
10+ - echo "override before_install"
11+install:
12+ - wget https://github.com/commercialhaskell/stack/releases/download/v1.0.0/stack-1.0.0-linux-x86_64.tar.gz -O stack.gz
13+ - tar xvf stack.gz
14+ - chmod +x stack-1.0.0-linux-x86_64/stack
15+ - stack-1.0.0-linux-x86_64/stack setup
16+ - stack-1.0.0-linux-x86_64/stack build
17+before_script:
18+ - echo "override before_script"
19+script:
20+ - stack-1.0.0-linux-x86_64/stack test
CHANGELOG.md−126
@@ -4,132 +4,6 @@ title: Releases
44
55# Releases
66
7−## Hakyll 4.13.0.0 (2019-08-30)
8−
9−- Improved documentation in many places (contribution by Bergi)
10−- Significantly improve error messages when reading and applying templates
11− (contribution by Bergi)
12− * `empty` and `fail` for `Compiler` now fail without or with a message,
13− allowing for much better debug output
14− * `renderFeed`, `renderRssWithTemplates` and `renderAtomWithTemplates` now
15− take `Template` rather than `String` arguments
16−- Add option to specify date in directory structure,e.g.
17− `posts/2019/05/10/tomorrow.md` (contribution by Taeer Bar-Ya)
18−- Bump QuickCheck to 2.13
19−
20−## Hakyll 4.12.5.2 (2019-05-09)
21−
22−- Bump pandoc to 2.7
23−- Add `srcset` to the list of URL attributes (contribution by c50a326)
24−- Expose `getCategory` in `Hakyll.Web.Tags` (contribution by Ng Wei En)
25−- Fix issue where `published` overwrites the user's context (contribution by
26− ncaq)
27−
28−## Hakyll 4.12.5.1 (2019-02-03)
29−
30−- Bump pandoc to 2.6
31−- Bump pandoc-citeproc to 0.16
32−
33−## Hakyll 4.12.5.0 (2019-01-12)
34−
35−- Update dependencies (contribution by Hexirp):
36− * Bump containers to 0.6
37− * Bump yaml to 0.11
38− * Bump pandoc to 2.5
39− * Bump pandoc-citeproc to 0.15
40− * Bump tasty to 1.2
41−- Correct assertion in unixFilterError test
42− (contribution by Jim McStanton)
43−- Add renderRssWithTemplates, renderAtomWithTemplates
44− (contribution by Abhinav Sarkar)
45−- Speed up hashing in cache (contribution by 0xd34df00d)
46−- Update type of fromFilePath to use FilePath instead of String
47− (contribution by Jim McStanton)
48−- Drop extension when parsing dates in filepaths (contribution by
49− Gabriel Aumala)
50−
51−## Hakyll 4.12.4.0 (2018-08-13)
52−
53−- Bump yaml to 0.10
54−- Bump file-embed to 0.0.11
55−- Bump QuickCheck to 2.12
56−- Use makeRelativeToProject with embedFile for stack ghci (contribution by
57− Michael Sloan)
58−
59−## Hakyll 4.12.3.0 (2018-05-29)
60−
61−- Bump tasty to 1.1
62−- Bump fsnotify to 0.3
63−
64−## Hakyll 4.12.2.0
65−
66−- Bump pandoc to 2.2
67−- Fix path resolution in Pandoc.Biblio (contribution by knih)
68−
69−## Hakyll 4.12.1.0
70−
71−- Fix hakyll-init on older GHC versions
72−- Make the Pandoc dependency optional
73−
74−## Hakyll 4.12.0.1
75−
76−- Bump resourcet to 1.2 in test section
77−
78−## Hakyll 4.12.0.0
79−
80−- Add Semigroup instances for existing Monoids (contribution by
81− Christian Barcenas)
82−- Fix issue with CPP and comment containing `/*`
83−- Add `withTagList` (contribution by Oleg Grenrus)
84−- Improve CSS compression (contribution by Bergi)
85−- Bump pandoc-citeproc to 0.14
86−- Bump resourcet to 1.2
87−- Bump time to 1.9
88−- Bump http-types to 0.12
89−- Bump http-conduit to 2.3
90−- Bump tasty-quickcheck to 0.10
91−
92−## Hakyll 4.11.0.0
93−
94−- Bump binary to 0.9
95−- Bump pandoc to 2.1
96−- Bump pandoc-citeproc to 0.13
97−- Bump http-types to 0.11
98−- Bump QuickCheck to 2.11
99−- Bump tasty to 1.0
100−- Bump tasty-hunit to 0.10
101−- Remove system-filepath dependency
102−- Embed feed templates rather than using data-files (contribution by Roman
103− Kuznetsov)
104−- Fix pthread link error on GHC-8.2.2 (contribution by Shinya Yamaguchi)
105−- Extend capture with Regex handling (contribution by frederik-h)
106−
107−## Hakyll 4.10.0.0
108−
109−- Bump Pandoc to 2.0 (contribution by Vaibhav Sagar)
110−- Fix compression of calc() in CSS (contribution by Krzysztof Jurewicz)
111−- Make unixFilter output stderr when failing (contribution by Nick Boultbee)
112−- Export Check type from `Hakyll.Commands` (contribution by Futtetennista)
113−- Add overwritten files check to `hakyll-init` (contribution by Ilya Murzinov)
114−- Expose & document `hakyllWithExitCodeAndArgs`, `Options`, and `Command`
115− (contribution by Michael Walker)
116−- Add check for non-overlapping redirects (contribution by gwern)
117−- Fix early exit when calling check as a library
118−
119−## Hakyll 4.9.8.0
120−
121−- Bump pandoc-citeproc to 0.10.5
122−- Bump optparse-applicative to 0.14
123−- Bump QuickCheck to 2.10
124−- Bump tasty-quickcheck to 0.9
125−- Restructure .cabal to avoid redundant compilation (contribution by
126− Christopher League)
127−
128−## Hakyll 4.9.7.0
129−
130−- Fix compilation trouble with `Options.Applicative`
131−- Some small CSS compression improvements (contribution by Nicole Rauch)
132−
1337## Hakyll 4.9.6.0
1348
1359- Tighten dependency on `pandoc-citeproc` (contribution by Mikhail Glushenkov)
Makefile+6−6
@@ -1,9 +1,9 @@
1−PACKAGE="$(shell stack list-dependencies --separator='-' | grep hakyll)"
2−LOCAL_DOC_ROOT="$(shell stack path --local-doc-root)"
3−
41# Generate the docs and copy them to the website dir
52haddock:
6− stack build --haddock --no-haddock-deps
7− rsync -r "$(LOCAL_DOC_ROOT)/$(PACKAGE)/" web/reference/
3+ cabal haddock --hyperlink-source
4+ rm -rf web/reference/
5+ cp -r dist/doc/html/hakyll/ web/reference/
86
9−.PHONY: haddock
7+# Run the tests
8+test:
9+ runghc -isrc -itests tests/TestSuite.hs
README.markdown+1−1
@@ -1,6 +1,6 @@
11# hakyll
22
3−[![Build Status](https://img.shields.io/circleci/project/github/jaspervdj/hakyll.svg)](https://circleci.com/gh/jaspervdj/hakyll)
3+[![Build Status](https://img.shields.io/travis/jaspervdj/hakyll.svg)](http://travis-ci.org/jaspervdj/hakyll)
44
55Hakyll is a static site generator library in Haskell. More information
66(including a tutorial) can be found on
data/example/css/default.css+29−114
@@ -1,141 +1,56 @@
1−html {
2− font-size: 62.5%;
3−}
4−
51body {
6− font-size: 1.6rem;
7− color: #000;
2+ color: black;
3+ font-size: 16px;
4+ margin: 0px auto 0px auto;
5+ width: 600px;
86}
97
108header {
11− border-bottom: 0.2rem solid #000;
9+ border-bottom: 2px solid black;
10+ margin-bottom: 30px;
11+ padding: 12px 0px 12px 0px;
1212}
1313
1414nav {
15− text-align: right;
15+ text-align: right;
1616}
1717
1818nav a {
19− font-size: 1.8rem;
20− font-weight: bold;
21− color: black;
22− text-decoration: none;
23− text-transform: uppercase;
19+ color: black;
20+ font-size: 18px;
21+ font-weight: bold;
22+ margin-left: 12px;
23+ text-decoration: none;
24+ text-transform: uppercase;
2425}
2526
2627footer {
27− margin-top: 3rem;
28− padding: 1.2rem 0;
29− border-top: 0.2rem solid #000;
30− font-size: 1.2rem;
31− color: #555;
28+ border-top: solid 2px black;
29+ color: #555;
30+ font-size: 12px;
31+ margin-top: 30px;
32+ padding: 12px 0px 12px 0px;
33+ text-align: right;
3234}
3335
3436h1 {
35− font-size: 2.4rem;
37+ font-size: 24px;
3638}
3739
3840h2 {
39− font-size: 2rem;
41+ font-size: 20px;
4042}
4143
4244article .header {
43− font-size: 1.4rem;
44− font-style: italic;
45− color: #555;
45+ color: #555;
46+ font-size: 14px;
47+ font-style: italic;
4648}
4749
4850.logo a {
49− font-weight: bold;
50− color: #000;
51− text-decoration: none;
52−}
53−
54−@media (max-width: 319px) {
55− body {
56− width: 90%;
57− margin: 0;
58− padding: 0 5%;
59− }
60− header {
61− margin: 4.2rem 0;
62− }
63− nav {
64− margin: 0 auto 3rem;
65− text-align: center;
66− }
67− footer {
68− text-align: center;
69− }
70− .logo {
71− text-align: center;
72− margin: 1rem auto 3rem;
73− }
74− .logo a {
75− font-size: 2.4rem;
76− }
77− nav a {
78− display: block;
79− line-height: 1.6;
80− }
81−}
82−
83−@media (min-width: 320px) {
84− body {
85− width: 90%;
86− margin: 0;
87− padding: 0 5%;
88− }
89− header {
90− margin: 4.2rem 0;
91− }
92− nav {
93− margin: 0 auto 3rem;
94− text-align: center;
95− }
96− footer {
97− text-align: center;
98− }
99− .logo {
100− text-align: center;
101− margin: 1rem auto 3rem;
102− }
103− .logo a {
104− font-size: 2.4rem;
105− }
106− nav a {
107− display: inline;
108− margin: 0 0.6rem;
109− }
110−}
111−
112−@media (min-width: 640px) {
113− body {
114− width: 60rem;
115− margin: 0 auto;
116− padding: 0;
117− }
118− header {
119− margin: 0 0 3rem;
120− padding: 1.2rem 0;
121− }
122− nav {
123− margin: 0;
124− text-align: right;
125− }
126− nav a {
127− margin: 0 0 0 1.2rem;
128− display: inline;
129− }
130− footer {
131− text-align: right;
132− }
133− .logo {
134− margin: 0;
135− text-align: left;
136− }
137− .logo a {
51+ color: black;
13852 float: left;
139− font-size: 1.8rem;
140− }
53+ font-size: 18px;
54+ font-weight: bold;
55+ text-decoration: none;
14156}
hakyll.cabal+125−128
@@ -1,5 +1,5 @@
11Name: hakyll
2−Version: 4.13.0.0
2+Version: 4.9.6.0
33
44Synopsis: A static website compiler library
55Description:
@@ -37,7 +37,7 @@ License: BSD3
3737License-File: LICENSE
3838Category: Web
3939
40−Cabal-Version: >= 1.10
40+Cabal-Version: >= 1.8
4141Build-Type: Simple
4242Data-Dir: data
4343
@@ -56,6 +56,10 @@ Data-files:
5656 example/index.html
5757 example/about.rst
5858 example/contact.markdown
59+ templates/atom-item.xml
60+ templates/atom.xml
61+ templates/rss-item.xml
62+ templates/rss.xml
5963
6064Extra-source-files:
6165 CHANGELOG.md
@@ -68,16 +72,11 @@ Extra-source-files:
6872 tests/data/partial.html
6973 tests/data/partial.html.out
7074 tests/data/posts/2010-08-26-birthday.md
71− tests/data/posts/2018-09-26.md
7275 tests/data/russian.md
7376 tests/data/strip.html
7477 tests/data/strip.html.out
7578 tests/data/template.html
7679 tests/data/template.html.out
77− data/templates/atom-item.xml
78− data/templates/atom.xml
79− data/templates/rss-item.xml
80− data/templates/rss.xml
8180
8281Source-Repository head
8382 Type: git
@@ -95,43 +94,24 @@ Flag checkExternal
9594 Description: Include external link checking
9695 Default: True
9796
98−Flag buildWebsite
99− Description: Build the hakyll website
100− Default: False
101− Manual: True
102−
103−Flag usePandoc
104− Description: Include Pandoc support
105− Default: True
106− Manual: True
107−
10897Library
109− Ghc-Options: -Wall
110− Hs-Source-Dirs: lib
111− Default-language: Haskell2010
98+ Ghc-Options: -Wall
99+ Hs-Source-Dirs: src
112100
113101 Exposed-Modules:
114102 Hakyll
115103 Hakyll.Commands
116104 Hakyll.Core.Compiler
117− Hakyll.Core.Compiler.Internal
118105 Hakyll.Core.Configuration
119106 Hakyll.Core.Dependencies
120107 Hakyll.Core.File
121108 Hakyll.Core.Identifier
122109 Hakyll.Core.Identifier.Pattern
123110 Hakyll.Core.Item
124− Hakyll.Core.Logger
125111 Hakyll.Core.Metadata
126− Hakyll.Core.Provider
127− Hakyll.Core.Provider.Metadata
128112 Hakyll.Core.Routes
129113 Hakyll.Core.Rules
130− Hakyll.Core.Rules.Internal
131− Hakyll.Core.Runtime
132− Hakyll.Core.Store
133114 Hakyll.Core.UnixFilter
134− Hakyll.Core.Util.File
135115 Hakyll.Core.Util.String
136116 Hakyll.Core.Writable
137117 Hakyll.Main
@@ -139,9 +119,12 @@ Library
139119 Hakyll.Web.Feed
140120 Hakyll.Web.Html
141121 Hakyll.Web.Html.RelativizeUrls
142− Hakyll.Web.Paginate
122+ Hakyll.Web.Pandoc
123+ Hakyll.Web.Pandoc.Biblio
124+ Hakyll.Web.Pandoc.FileType
143125 Hakyll.Web.Redirect
144126 Hakyll.Web.Tags
127+ Hakyll.Web.Paginate
145128 Hakyll.Web.Template
146129 Hakyll.Web.Template.Context
147130 Hakyll.Web.Template.Internal
@@ -153,53 +136,64 @@ Library
153136 Data.List.Extended
154137 Data.Yaml.Extended
155138 Hakyll.Check
139+ Hakyll.Core.Compiler.Internal
156140 Hakyll.Core.Compiler.Require
157− Hakyll.Core.Identifier.Pattern.Internal
158141 Hakyll.Core.Item.SomeItem
142+ Hakyll.Core.Logger
143+ Hakyll.Core.Provider
159144 Hakyll.Core.Provider.Internal
145+ Hakyll.Core.Provider.Metadata
160146 Hakyll.Core.Provider.MetadataCache
147+ Hakyll.Core.Rules.Internal
148+ Hakyll.Core.Runtime
149+ Hakyll.Core.Store
150+ Hakyll.Core.Util.File
161151 Hakyll.Core.Util.Parser
152+ Hakyll.Web.Pandoc.Binary
162153 Paths_hakyll
163154
164155 Build-Depends:
165− base >= 4.8 && < 5,
166− binary >= 0.5 && < 0.10,
167− blaze-html >= 0.5 && < 0.10,
168− blaze-markup >= 0.5.1 && < 0.9,
169− bytestring >= 0.9 && < 0.11,
170− containers >= 0.3 && < 0.7,
171− cryptohash >= 0.7 && < 0.12,
172− data-default >= 0.4 && < 0.8,
173− deepseq >= 1.3 && < 1.5,
174− directory >= 1.0 && < 1.4,
175− file-embed >= 0.0.10.1 && < 0.0.12,
176− filepath >= 1.0 && < 1.5,
177− lrucache >= 1.1.1 && < 1.3,
178− mtl >= 1 && < 2.3,
179− network-uri >= 2.6 && < 2.7,
180− optparse-applicative >= 0.12 && < 0.15,
181− parsec >= 3.0 && < 3.2,
182− process >= 1.6 && < 1.7,
183− random >= 1.0 && < 1.2,
184− regex-tdfa >= 1.1 && < 1.3,
185− resourcet >= 1.1 && < 1.3,
186− scientific >= 0.3.4 && < 0.4,
187− tagsoup >= 0.13.1 && < 0.15,
188− template-haskell >= 2.14 && < 2.15,
189− text >= 0.11 && < 1.3,
190− time >= 1.8 && < 1.10,
191− time-locale-compat >= 0.1 && < 0.2,
192− unordered-containers >= 0.2 && < 0.3,
193− vector >= 0.11 && < 0.13,
194− yaml >= 0.8.11 && < 0.12
156+ base >= 4.8 && < 5,
157+ binary >= 0.5 && < 0.9,
158+ blaze-html >= 0.5 && < 0.10,
159+ blaze-markup >= 0.5.1 && < 0.9,
160+ bytestring >= 0.9 && < 0.11,
161+ containers >= 0.3 && < 0.6,
162+ cryptohash >= 0.7 && < 0.12,
163+ data-default >= 0.4 && < 0.8,
164+ deepseq >= 1.3 && < 1.5,
165+ directory >= 1.0 && < 1.4,
166+ filepath >= 1.0 && < 1.5,
167+ lrucache >= 1.1.1 && < 1.3,
168+ mtl >= 1 && < 2.3,
169+ network >= 2.6 && < 2.7,
170+ network-uri >= 2.6 && < 2.7,
171+ pandoc >= 1.14 && < 1.20,
172+ pandoc-citeproc >= 0.4 && < 0.10.5,
173+ parsec >= 3.0 && < 3.2,
174+ process >= 1.0 && < 1.6,
175+ random >= 1.0 && < 1.2,
176+ regex-base >= 0.93 && < 0.94,
177+ regex-tdfa >= 1.1 && < 1.3,
178+ resourcet >= 1.1 && < 1.2,
179+ scientific >= 0.3.4 && < 0.4,
180+ tagsoup >= 0.13.1 && < 0.15,
181+ text >= 0.11 && < 1.3,
182+ time >= 1.4 && < 1.8,
183+ time-locale-compat >= 0.1 && < 0.2,
184+ unordered-containers >= 0.2 && < 0.3,
185+ vector >= 0.11 && < 0.13,
186+ yaml >= 0.8.11 && < 0.9,
187+ optparse-applicative >= 0.12 && < 0.14
195188
196189 If flag(previewServer)
197190 Build-depends:
198191 wai >= 3.2 && < 3.3,
199192 warp >= 3.2 && < 3.3,
200193 wai-app-static >= 3.1 && < 3.2,
201− http-types >= 0.9 && < 0.13,
202− fsnotify >= 0.2 && < 0.4
194+ http-types >= 0.9 && < 0.10,
195+ fsnotify >= 0.2 && < 0.3,
196+ system-filepath >= 0.4.6 && <= 0.5
203197 Cpp-options:
204198 -DPREVIEW_SERVER
205199 Other-modules:
@@ -208,7 +202,8 @@ Library
208202
209203 If flag(watchServer)
210204 Build-depends:
211− fsnotify >= 0.2 && < 0.4
205+ fsnotify >= 0.2 && < 0.3,
206+ system-filepath >= 0.4.6 && <= 0.5
212207 Cpp-options:
213208 -DWATCH_SERVER
214209 Other-modules:
@@ -216,31 +211,16 @@ Library
216211
217212 If flag(checkExternal)
218213 Build-depends:
219− http-conduit >= 2.2 && < 2.4,
220− http-types >= 0.7 && < 0.13
214+ http-conduit >= 2.2 && < 2.3,
215+ http-types >= 0.7 && < 0.10
221216 Cpp-options:
222217 -DCHECK_EXTERNAL
223218
224− If flag(usePandoc)
225− Exposed-Modules:
226− Hakyll.Web.Pandoc
227− Hakyll.Web.Pandoc.Biblio
228− Hakyll.Web.Pandoc.FileType
229− Other-Modules:
230− Hakyll.Web.Pandoc.Binary
231− Build-Depends:
232− pandoc >= 2.0.5 && < 2.8,
233− pandoc-citeproc >= 0.14 && < 0.17
234− Cpp-options:
235− -DUSE_PANDOC
236−
237219Test-suite hakyll-tests
238− Type: exitcode-stdio-1.0
239− Hs-source-dirs: tests
240− Main-is: TestSuite.hs
241− Ghc-options: -Wall -threaded
242− Default-language: Haskell2010
243−
220+ Type: exitcode-stdio-1.0
221+ Hs-source-dirs: src tests
222+ Main-is: TestSuite.hs
223+ Ghc-options: -Wall
244224 Other-modules:
245225 Hakyll.Core.Dependencies.Tests
246226 Hakyll.Core.Identifier.Tests
@@ -255,73 +235,90 @@ Test-suite hakyll-tests
255235 Hakyll.Web.CompressCss.Tests
256236 Hakyll.Web.Html.RelativizeUrls.Tests
257237 Hakyll.Web.Html.Tests
258− Hakyll.Web.Tags.Tests
238+ Hakyll.Web.Pandoc.FileType.Tests
259239 Hakyll.Web.Template.Context.Tests
260240 Hakyll.Web.Template.Tests
261241 TestSuite.Util
262242
263243 Build-Depends:
264− hakyll,
265− QuickCheck >= 2.8 && < 2.14,
266− tasty >= 0.11 && < 1.3,
267− tasty-hunit >= 0.9 && < 0.11,
268− tasty-quickcheck >= 0.8 && < 0.11,
244+ QuickCheck >= 2.8 && < 2.10,
245+ tasty >= 0.11 && < 0.12,
246+ tasty-hunit >= 0.9 && < 0.10,
247+ tasty-quickcheck >= 0.8 && < 0.9,
269248 -- Copy pasted from hakyll dependencies:
270− base >= 4.8 && < 5,
271− bytestring >= 0.9 && < 0.11,
272− containers >= 0.3 && < 0.7,
273− filepath >= 1.0 && < 1.5,
274− text >= 0.11 && < 1.3,
275− unordered-containers >= 0.2 && < 0.3,
276− yaml >= 0.8.11 && < 0.12
249+ base >= 4.8 && < 5,
250+ binary >= 0.5 && < 0.9,
251+ blaze-html >= 0.5 && < 0.10,
252+ blaze-markup >= 0.5.1 && < 0.9,
253+ bytestring >= 0.9 && < 0.11,
254+ containers >= 0.3 && < 0.6,
255+ cryptohash >= 0.7 && < 0.12,
256+ data-default >= 0.4 && < 0.8,
257+ deepseq >= 1.3 && < 1.5,
258+ directory >= 1.0 && < 1.4,
259+ filepath >= 1.0 && < 1.5,
260+ lrucache >= 1.1.1 && < 1.3,
261+ mtl >= 1 && < 2.3,
262+ network >= 2.6 && < 2.7,
263+ network-uri >= 2.6 && < 2.7,
264+ pandoc >= 1.14 && < 1.20,
265+ pandoc-citeproc >= 0.4 && < 0.11,
266+ parsec >= 3.0 && < 3.2,
267+ process >= 1.0 && < 1.6,
268+ random >= 1.0 && < 1.2,
269+ regex-base >= 0.93 && < 0.94,
270+ regex-tdfa >= 1.1 && < 1.3,
271+ resourcet >= 1.1 && < 1.2,
272+ scientific >= 0.3.4 && < 0.4,
273+ tagsoup >= 0.13.1 && < 0.15,
274+ text >= 0.11 && < 1.3,
275+ time >= 1.4 && < 1.8,
276+ time-locale-compat >= 0.1 && < 0.2,
277+ unordered-containers >= 0.2 && < 0.3,
278+ vector >= 0.11 && < 0.13,
279+ yaml >= 0.8.11 && < 0.9,
280+ optparse-applicative >= 0.12 && < 0.14
277281
278282 If flag(previewServer)
283+ Build-depends:
284+ wai >= 3.2 && < 3.3,
285+ warp >= 3.2 && < 3.3,
286+ wai-app-static >= 3.1 && < 3.2,
287+ http-types >= 0.9 && < 0.10,
288+ fsnotify >= 0.2 && < 0.3,
289+ system-filepath >= 0.4.6 && <= 0.5
279290 Cpp-options:
280291 -DPREVIEW_SERVER
292+ Other-modules:
293+ Hakyll.Preview.Poll
294+ Hakyll.Preview.Server
281295
282296 If flag(watchServer)
297+ Build-depends:
298+ fsnotify >= 0.2 && < 0.3,
299+ system-filepath >= 0.4.6 && <= 0.5
283300 Cpp-options:
284301 -DWATCH_SERVER
302+ Other-modules:
303+ Hakyll.Preview.Poll
285304
286305 If flag(checkExternal)
306+ Build-depends:
307+ http-conduit >= 2.2 && < 2.3,
308+ http-types >= 0.7 && < 0.10
287309 Cpp-options:
288310 -DCHECK_EXTERNAL
289311
290− If flag(usePandoc)
291− Other-modules:
292− Hakyll.Web.Pandoc.FileType.Tests
293− Cpp-options:
294− -DUSE_PANDOC
295−
296312Executable hakyll-init
297− Main-is: Init.hs
298− Ghc-options: -Wall -threaded
299− Hs-source-dirs: src
300− Default-language: Haskell2010
301−
302− Other-modules:
303− Paths_hakyll
313+ Ghc-options: -Wall
314+ Hs-source-dirs: src
315+ Main-is: Hakyll/Init.hs
304316
305317 Build-depends:
306− hakyll,
307318 base >= 4 && < 5,
308319 directory >= 1.0 && < 1.4,
309320 filepath >= 1.0 && < 1.5
310321
311−Executable hakyll-website
312− Main-is: site.hs
313− Ghc-options: -Wall -threaded
314− Hs-source-dirs: web
315− Default-language: Haskell2010
316−
317− If flag(buildWebsite)
318− Buildable: True
319− Else
320− Buildable: False
321−
322− Build-depends:
323− hakyll,
324− base >= 4 && < 5,
325− directory >= 1.0 && < 1.4,
326− filepath >= 1.0 && < 1.5,
327− pandoc >= 2.0.5 && < 2.8
322+ Other-modules:
323+ Hakyll.Core.Util.File
324+ Paths_hakyll
lib/Hakyll/Core/Identifier/Pattern/Internal.hsdeleted−92
@@ -1,92 +0,0 @@
1−-- | This internal module is mostly here to prevent CPP conflicting with Haskell
2−-- comments.
3−{-# LANGUAGE CPP #-}
4−module Hakyll.Core.Identifier.Pattern.Internal
5− ( GlobComponent (..)
6− , Pattern (..)
7− ) where
8−
9−
10−--------------------------------------------------------------------------------
11−import Data.Binary (Binary (..), getWord8, putWord8)
12−import Data.Set (Set)
13−
14−
15−--------------------------------------------------------------------------------
16−#if MIN_VERSION_base(4,9,0)
17−import Data.Semigroup (Semigroup (..))
18−#endif
19−
20−
21−--------------------------------------------------------------------------------
22−import Hakyll.Core.Identifier
23−
24−
25−--------------------------------------------------------------------------------
26−-- | Elements of a glob pattern
27−data GlobComponent
28− = Capture
29− | CaptureMany
30− | Literal String
31− deriving (Eq, Show)
32−
33−
34−--------------------------------------------------------------------------------
35−instance Binary GlobComponent where
36− put Capture = putWord8 0
37− put CaptureMany = putWord8 1
38− put (Literal s) = putWord8 2 >> put s
39−
40− get = getWord8 >>= \t -> case t of
41− 0 -> pure Capture
42− 1 -> pure CaptureMany
43− 2 -> Literal <$> get
44− _ -> error "Data.Binary.get: Invalid GlobComponent"
45−
46−
47−--------------------------------------------------------------------------------
48−-- | Type that allows matching on identifiers
49−data Pattern
50− = Everything
51− | Complement Pattern
52− | And Pattern Pattern
53− | Glob [GlobComponent]
54− | List (Set Identifier)
55− | Regex String
56− | Version (Maybe String)
57− deriving (Show)
58−
59−
60−--------------------------------------------------------------------------------
61−instance Binary Pattern where
62− put Everything = putWord8 0
63− put (Complement p) = putWord8 1 >> put p
64− put (And x y) = putWord8 2 >> put x >> put y
65− put (Glob g) = putWord8 3 >> put g
66− put (List is) = putWord8 4 >> put is
67− put (Regex r) = putWord8 5 >> put r
68− put (Version v) = putWord8 6 >> put v
69−
70− get = getWord8 >>= \t -> case t of
71− 0 -> pure Everything
72− 1 -> Complement <$> get
73− 2 -> And <$> get <*> get
74− 3 -> Glob <$> get
75− 4 -> List <$> get
76− 5 -> Regex <$> get
77− _ -> Version <$> get
78−
79−
80−--------------------------------------------------------------------------------
81−#if MIN_VERSION_base(4,9,0)
82−instance Semigroup Pattern where
83− (<>) = And
84−
85−instance Monoid Pattern where
86− mempty = Everything
87− mappend = (<>)
88−#else
89−instance Monoid Pattern where
90− mempty = Everything
91− mappend = And
92−#endif
lib/Hakyll/Web/CompressCss.hsdeleted−101
@@ -1,101 +0,0 @@
1−--------------------------------------------------------------------------------
2−-- | Module used for CSS compression. The compression is currently in a simple
3−-- state, but would typically reduce the number of bytes by about 25%.
4−module Hakyll.Web.CompressCss
5− ( compressCssCompiler
6− , compressCss
7− ) where
8−
9−
10−--------------------------------------------------------------------------------
11−import Data.Char (isSpace)
12−import Data.List (dropWhileEnd, isPrefixOf)
13−
14−
15−--------------------------------------------------------------------------------
16−import Hakyll.Core.Compiler
17−import Hakyll.Core.Item
18−import Hakyll.Core.Util.String
19−
20−
21−--------------------------------------------------------------------------------
22−-- | Compiler form of 'compressCss'
23−compressCssCompiler :: Compiler (Item String)
24−compressCssCompiler = fmap compressCss <$> getResourceString
25−
26−
27−--------------------------------------------------------------------------------
28−-- | Compress CSS to speed up your site.
29−compressCss :: String -> String
30−compressCss = withoutStrings (handleCalcExpressions compressSeparators . compressWhitespace)
31− . dropWhileEnd isSpace
32− . dropWhile isSpace
33− . stripComments
34−
35−
36−--------------------------------------------------------------------------------
37−-- | Compresses certain forms of separators.
38−compressSeparators :: String -> String
39−compressSeparators =
40− replaceAll "; *}" (const "}") .
41− replaceAll ";+" (const ";") .
42− replaceAll " *[{};,>+~!] *" (take 1 . dropWhile isSpace) .
43− replaceAll ": *" (take 1) -- not destroying pseudo selectors (#323)
44−
45−-- | Uses `compressCalcExpression` on all parenthesised calc expressions
46−-- and applies `transform` to all parts outside of them
47−handleCalcExpressions :: (String -> String) -> String -> String
48−handleCalcExpressions transform = top transform
49− where
50− top f "" = f ""
51− top f str | "calc(" `isPrefixOf` str = f "calc" ++ nested 0 compressCalcExpression (drop 4 str)
52− top f (x:xs) = top (f . (x:)) xs
53−
54− -- when called with depth=0, the first character must be a '('
55− nested :: Int -> (String -> String) -> String -> String
56− nested _ f "" = f "" -- shouldn't happen, mismatched nesting
57− nested depth f str | "calc(" `isPrefixOf` str = nested depth f (drop 4 str)
58− nested 1 f (')':xs) = f ")" ++ top transform xs
59− nested depth f (x:xs) = nested (case x of
60− '(' -> depth + 1
61− ')' -> depth - 1 -- assert: depth > 1
62− _ -> depth
63− ) (f . (x:)) xs
64−
65−-- | does not remove whitespace around + and -, which is important in calc() expressions
66−compressCalcExpression :: String -> String
67−compressCalcExpression =
68− replaceAll " *[*/] *| *\\)|\\( *" (take 1 . dropWhile isSpace)
69−
70−--------------------------------------------------------------------------------
71−-- | Compresses all whitespace.
72−compressWhitespace :: String -> String
73−compressWhitespace = replaceAll "[ \t\n\r]+" (const " ")
74−
75−--------------------------------------------------------------------------------
76−-- | Function that strips CSS comments away (outside of strings).
77−stripComments :: String -> String
78−stripComments "" = ""
79−stripComments ('/':'*':str) = stripComments $ eatComment str
80−stripComments (x:xs) | x `elem` "\"'" = retainString x xs stripComments
81− | otherwise = x : stripComments xs
82−
83−eatComment :: String -> String
84−eatComment "" = ""
85−eatComment ('*':'/':str) = str
86−eatComment (_:str) = eatComment str
87−
88−
89−--------------------------------------------------------------------------------
90−-- | Helper functions to handle string tokens correctly.
91−
92−-- TODO: handle backslash escapes
93−withoutStrings :: (String -> String) -> String -> String
94−withoutStrings f str = case span (`notElem` "\"'") str of
95− (text, "") -> f text
96− (text, d:rest) -> f text ++ retainString d rest (withoutStrings f)
97−
98−retainString :: Char -> String -> (String -> String) -> String
99−retainString delim str cont = case span (/= delim) str of
100− (val, "") -> delim : val
101− (val, _:rest) -> delim : val ++ delim : cont rest
lib/Data/List/Extended.hs → src/Data/List/Extended.hsrenamed

The content is the same.

lib/Data/Yaml/Extended.hs → src/Data/Yaml/Extended.hsrenamed

The content is the same.

lib/Hakyll.hs → src/Hakyll.hsrenamed+1−5
@@ -20,12 +20,10 @@ module Hakyll
2020 , module Hakyll.Web.Feed
2121 , module Hakyll.Web.Html
2222 , module Hakyll.Web.Html.RelativizeUrls
23− , module Hakyll.Web.Paginate
24−#ifdef USE_PANDOC
2523 , module Hakyll.Web.Pandoc
24+ , module Hakyll.Web.Paginate
2625 , module Hakyll.Web.Pandoc.Biblio
2726 , module Hakyll.Web.Pandoc.FileType
28−#endif
2927 , module Hakyll.Web.Redirect
3028 , module Hakyll.Web.Tags
3129 , module Hakyll.Web.Template
@@ -54,11 +52,9 @@ import Hakyll.Web.Feed
5452import Hakyll.Web.Html
5553import Hakyll.Web.Html.RelativizeUrls
5654import Hakyll.Web.Paginate
57−#ifdef USE_PANDOC
5855import Hakyll.Web.Pandoc
5956import Hakyll.Web.Pandoc.Biblio
6057import Hakyll.Web.Pandoc.FileType
61−#endif
6258import Hakyll.Web.Redirect
6359import Hakyll.Web.Tags
6460import Hakyll.Web.Template
lib/Hakyll/Check.hs → src/Hakyll/Check.hsrenamed+1−13
@@ -17,11 +17,9 @@ import Control.Monad.Reader (ReaderT, ask, runReaderT)
1717import Control.Monad.State (StateT, get, modify, runStateT)
1818import Control.Monad.Trans (liftIO)
1919import Control.Monad.Trans.Resource (runResourceT)
20+import Data.ByteString.Char8 (unpack)
2021import Data.List (isPrefixOf)
2122import qualified Data.Map.Lazy as Map
22−#if MIN_VERSION_base(4,9,0)
23−import Data.Semigroup (Semigroup (..))
24−#endif
2523import Network.URI (unEscapeString)
2624import System.Directory (doesDirectoryExist,
2725 doesFileExist)
@@ -88,20 +86,10 @@ data CheckerWrite = CheckerWrite
8886
8987
9088--------------------------------------------------------------------------------
91−#if MIN_VERSION_base(4,9,0)
92−instance Semigroup CheckerWrite where
93− (<>) (CheckerWrite f1 o1) (CheckerWrite f2 o2) =
94− CheckerWrite (f1 + f2) (o1 + o2)
95−
96−instance Monoid CheckerWrite where
97− mempty = CheckerWrite 0 0
98− mappend = (<>)
99−#else
10089instance Monoid CheckerWrite where
10190 mempty = CheckerWrite 0 0
10291 mappend (CheckerWrite f1 o1) (CheckerWrite f2 o2) =
10392 CheckerWrite (f1 + f2) (o1 + o2)
104−#endif
10593
10694
10795--------------------------------------------------------------------------------
lib/Hakyll/Commands.hs → src/Hakyll/Commands.hsrenamed+2−6
@@ -2,8 +2,7 @@
22-- | Implementation of Hakyll commands: build, preview...
33{-# LANGUAGE CPP #-}
44module Hakyll.Commands
5− ( Check(..)
6− , build
5+ ( build
76 , check
87 , clean
98 , preview
@@ -16,11 +15,9 @@ module Hakyll.Commands
1615
1716--------------------------------------------------------------------------------
1817import Control.Concurrent
19−import System.Exit (ExitCode)
20−
18+import System.Exit (ExitCode, exitWith)
2119
2220--------------------------------------------------------------------------------
23−import Hakyll.Check (Check(..))
2421import qualified Hakyll.Check as Check
2522import Hakyll.Core.Configuration
2623import Hakyll.Core.Logger (Logger)
@@ -30,7 +27,6 @@ import Hakyll.Core.Rules.Internal
3027import Hakyll.Core.Runtime
3128import Hakyll.Core.Util.File
3229
33−
3430--------------------------------------------------------------------------------
3531#ifdef WATCH_SERVER
3632import Hakyll.Preview.Poll (watchUpdates)
lib/Hakyll/Core/Compiler.hs → src/Hakyll/Core/Compiler.hsrenamed+2−35
@@ -24,16 +24,13 @@ module Hakyll.Core.Compiler
2424 , cached
2525 , unsafeCompiler
2626 , debugCompiler
27− , noResult
28− , withErrorMessage
2927 ) where
3028
3129
3230--------------------------------------------------------------------------------
33−import Control.Monad (unless, when, (>=>))
31+import Control.Monad (when, unless)
3432import Data.Binary (Binary)
3533import Data.ByteString.Lazy (ByteString)
36−import qualified Data.List.NonEmpty as NonEmpty
3734import Data.Typeable (Typeable)
3835import System.Environment (getProgName)
3936import System.FilePath (takeExtension)
@@ -65,7 +62,6 @@ getUnderlyingExtension = takeExtension . toFilePath <$> getUnderlying
6562
6663
6764--------------------------------------------------------------------------------
68−-- | Create an item from the underlying identifier and a given value.
6965makeItem :: a -> Compiler (Item a)
7066makeItem x = do
7167 identifier <- getUnderlying
@@ -145,10 +141,6 @@ saveSnapshot snapshot item = do
145141
146142
147143--------------------------------------------------------------------------------
148−-- | Turn on caching for a compilation value to avoid recomputing it
149−-- on subsequent Hakyll runs.
150−-- The storage key consists of the underlying identifier of the compiled
151−-- ressource and the given name.
152144cached :: (Binary a, Typeable a)
153145 => String
154146 -> Compiler a
@@ -185,37 +177,12 @@ cached name compiler = do
185177
186178
187179--------------------------------------------------------------------------------
188−-- | Run an IO computation without dependencies in a Compiler
189180unsafeCompiler :: IO a -> Compiler a
190181unsafeCompiler = compilerUnsafeIO
191182
192183
193184--------------------------------------------------------------------------------
194−-- | Fail so that it is treated as non-defined in an @\$if()\$@ branching
195−-- "Hakyll.Web.Template" macro, and alternative
196−-- 'Hakyll.Web.Template.Context.Context's are tried
197−--
198−-- @since 4.13.0
199−noResult :: String -> Compiler a
200−noResult = compilerNoResult . return
201−
202−
203−--------------------------------------------------------------------------------
204−-- | Prepend an error line to the error, if there is one. This allows you to
205−-- add helpful context to error messages.
206−--
207−-- @since 4.13.0
208−withErrorMessage :: String -> Compiler a -> Compiler a
209−withErrorMessage x = do
210− compilerTry >=> either (compilerResult . CompilerError . prepend) return
211− where
212− prepend (CompilationFailure es) = CompilationFailure (x `NonEmpty.cons` es)
213− prepend (CompilationNoResult es) = CompilationNoResult (x : es)
214−
215−
216−--------------------------------------------------------------------------------
217−-- | Compiler for debugging purposes.
218−-- Passes a message to the debug logger that is printed in verbose mode.
185+-- | Compiler for debugging purposes
219186debugCompiler :: String -> Compiler ()
220187debugCompiler msg = do
221188 logger <- compilerLogger <$> compilerAsk
lib/Hakyll/Core/Compiler/Internal.hs → src/Hakyll/Core/Compiler/Internal.hsrenamed+41−140
@@ -1,7 +1,5 @@
11--------------------------------------------------------------------------------
22-- | Internally used compiler module
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE DeriveFunctor #-}
53{-# LANGUAGE FlexibleInstances #-}
64{-# LANGUAGE GADTs #-}
75{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -11,26 +9,19 @@ module Hakyll.Core.Compiler.Internal
119 Snapshot
1210 , CompilerRead (..)
1311 , CompilerWrite (..)
14− , CompilerErrors (..)
1512 , CompilerResult (..)
1613 , Compiler (..)
1714 , runCompiler
1815
1916 -- * Core operations
20− , compilerResult
2117 , compilerTell
2218 , compilerAsk
23− , compilerUnsafeIO
24−
25− -- * Error operations
2619 , compilerThrow
27− , compilerNoResult
2820 , compilerCatch
29− , compilerTry
30− , compilerErrorMessages
21+ , compilerResult
22+ , compilerUnsafeIO
3123
3224 -- * Utilities
33− , compilerDebugEntries
3425 , compilerTellDependencies
3526 , compilerTellCacheHits
3627 ) where
@@ -40,12 +31,7 @@ module Hakyll.Core.Compiler.Internal
4031import Control.Applicative (Alternative (..))
4132import Control.Exception (SomeException, handle)
4233import Control.Monad (forM_)
43−import Control.Monad.Except (MonadError (..))
44−import Data.List.NonEmpty (NonEmpty (..))
45−import qualified Data.List.NonEmpty as NonEmpty
46−#if MIN_VERSION_base(4,9,0)
47−import Data.Semigroup (Semigroup (..))
48−#endif
34+import Control.Monad.Except (MonadError (..))
4935import Data.Set (Set)
5036import qualified Data.Set as S
5137
@@ -55,6 +41,7 @@ import Hakyll.Core.Configuration
5541import Hakyll.Core.Dependencies
5642import Hakyll.Core.Identifier
5743import Hakyll.Core.Identifier.Pattern
44+import Hakyll.Core.Logger (Logger)
5845import qualified Hakyll.Core.Logger as Logger
5946import Hakyll.Core.Metadata
6047import Hakyll.Core.Provider
@@ -84,7 +71,7 @@ data CompilerRead = CompilerRead
8471 , -- | Compiler store
8572 compilerStore :: Store
8673 , -- | Logger
87− compilerLogger :: Logger.Logger
74+ compilerLogger :: Logger
8875 }
8976
9077
@@ -96,46 +83,18 @@ data CompilerWrite = CompilerWrite
9683
9784
9885--------------------------------------------------------------------------------
99−#if MIN_VERSION_base(4,9,0)
100−instance Semigroup CompilerWrite where
101− (<>) (CompilerWrite d1 h1) (CompilerWrite d2 h2) =
102− CompilerWrite (d1 ++ d2) (h1 + h2)
103−
104−instance Monoid CompilerWrite where
105− mempty = CompilerWrite [] 0
106− mappend = (<>)
107−#else
10886instance Monoid CompilerWrite where
10987 mempty = CompilerWrite [] 0
11088 mappend (CompilerWrite d1 h1) (CompilerWrite d2 h2) =
11189 CompilerWrite (d1 ++ d2) (h1 + h2)
112−#endif
11390
11491
11592--------------------------------------------------------------------------------
116−-- | Distinguishes reasons in a 'CompilerError'
117−data CompilerErrors a
118− -- | One or more exceptions occured during compilation
119− = CompilationFailure (NonEmpty a)
120− -- | Absence of any result, most notably in template contexts. May still
121− -- have error messages.
122− | CompilationNoResult [a]
123− deriving Functor
124−
125−
126−-- | Unwrap a `CompilerErrors`
127−compilerErrorMessages :: CompilerErrors a -> [a]
128−compilerErrorMessages (CompilationFailure x) = NonEmpty.toList x
129−compilerErrorMessages (CompilationNoResult x) = x
130−
131−
132−--------------------------------------------------------------------------------
133−-- | An intermediate result of a compilation step
134−data CompilerResult a
135− = CompilerDone a CompilerWrite
136− | CompilerSnapshot Snapshot (Compiler a)
137− | CompilerRequire (Identifier, Snapshot) (Compiler a)
138− | CompilerError (CompilerErrors String)
93+data CompilerResult a where
94+ CompilerDone :: a -> CompilerWrite -> CompilerResult a
95+ CompilerSnapshot :: Snapshot -> Compiler a -> CompilerResult a
96+ CompilerError :: [String] -> CompilerResult a
97+ CompilerRequire :: (Identifier, Snapshot) -> Compiler a -> CompilerResult a
13998
14099
141100--------------------------------------------------------------------------------
@@ -153,14 +112,14 @@ instance Functor Compiler where
153112 return $ case res of
154113 CompilerDone x w -> CompilerDone (f x) w
155114 CompilerSnapshot s c' -> CompilerSnapshot s (fmap f c')
156− CompilerRequire i c' -> CompilerRequire i (fmap f c')
157115 CompilerError e -> CompilerError e
116+ CompilerRequire i c' -> CompilerRequire i (fmap f c')
158117 {-# INLINE fmap #-}
159118
160119
161120--------------------------------------------------------------------------------
162121instance Monad Compiler where
163− return x = compilerResult $ CompilerDone x mempty
122+ return x = Compiler $ \_ -> return $ CompilerDone x mempty
164123 {-# INLINE return #-}
165124
166125 Compiler c >>= f = Compiler $ \r -> do
@@ -173,14 +132,14 @@ instance Monad Compiler where
173132 CompilerSnapshot s c' -> CompilerSnapshot s $ do
174133 compilerTell w -- Save dependencies!
175134 c'
135+ CompilerError e -> CompilerError e
176136 CompilerRequire i c' -> CompilerRequire i $ do
177137 compilerTell w -- Save dependencies!
178138 c'
179− CompilerError e -> CompilerError e
180139
181140 CompilerSnapshot s c' -> return $ CompilerSnapshot s (c' >>= f)
182− CompilerRequire i c' -> return $ CompilerRequire i (c' >>= f)
183141 CompilerError e -> return $ CompilerError e
142+ CompilerRequire i c' -> return $ CompilerRequire i (c' >>= f)
184143 {-# INLINE (>>=) #-}
185144
186145 fail = compilerThrow . return
@@ -197,145 +156,87 @@ instance Applicative Compiler where
197156
198157
199158--------------------------------------------------------------------------------
200−-- | Access provided metadata from anywhere
201159instance MonadMetadata Compiler where
202160 getMetadata = compilerGetMetadata
203161 getMatches = compilerGetMatches
204162
205163
206164--------------------------------------------------------------------------------
207−-- | Compilation may fail with multiple error messages.
208−-- 'catchError' handles errors from 'throwError', 'fail' and 'Hakyll.Core.Compiler.noResult'
209165instance MonadError [String] Compiler where
210− throwError = compilerThrow
211− catchError c = compilerCatch c . (. compilerErrorMessages)
166+ throwError = compilerThrow
167+ catchError = compilerCatch
212168
213169
214170--------------------------------------------------------------------------------
215−-- | Like 'unCompiler' but treating IO exceptions as 'CompilerError's
216171runCompiler :: Compiler a -> CompilerRead -> IO (CompilerResult a)
217172runCompiler compiler read' = handle handler $ unCompiler compiler read'
218173 where
219174 handler :: SomeException -> IO (CompilerResult a)
220− handler e = return $ CompilerError $ CompilationFailure $ show e :| []
175+ handler e = return $ CompilerError [show e]
221176
222177
223178--------------------------------------------------------------------------------
224−-- | Trying alternative compilers if the first fails, regardless whether through
225−-- 'fail', 'throwError' or 'Hakyll.Core.Compiler.noResult'.
226−-- Aggregates error messages if all fail.
227179instance Alternative Compiler where
228− empty = compilerNoResult []
229− x <|> y = x `compilerCatch` (\rx -> y `compilerCatch` (\ry ->
230− case (rx, ry) of
231− (CompilationFailure xs, CompilationFailure ys) ->
232− compilerThrow $ NonEmpty.toList xs ++ NonEmpty.toList ys
233− (CompilationFailure xs, CompilationNoResult ys) ->
234− debug ys >> compilerThrow (NonEmpty.toList xs)
235− (CompilationNoResult xs, CompilationFailure ys) ->
236− debug xs >> compilerThrow (NonEmpty.toList ys)
237− (CompilationNoResult xs, CompilationNoResult ys) -> compilerNoResult $ xs ++ ys
238− ))
239− where
240− debug = compilerDebugEntries "Hakyll.Core.Compiler.Internal: Alternative fail suppressed"
180+ empty = compilerThrow []
181+ x <|> y = compilerCatch x $ \es -> do
182+ logger <- compilerLogger <$> compilerAsk
183+ forM_ es $ \e -> compilerUnsafeIO $ Logger.debug logger $
184+ "Hakyll.Core.Compiler.Internal: Alternative failed: " ++ e
185+ y
241186 {-# INLINE (<|>) #-}
242187
243188
244189--------------------------------------------------------------------------------
245−-- | Put the result back in a compiler
246−compilerResult :: CompilerResult a -> Compiler a
247−compilerResult x = Compiler $ \_ -> return x
248−{-# INLINE compilerResult #-}
249−
250−
251−--------------------------------------------------------------------------------
252−-- | Get the current environment
253190compilerAsk :: Compiler CompilerRead
254191compilerAsk = Compiler $ \r -> return $ CompilerDone r mempty
255192{-# INLINE compilerAsk #-}
256193
257194
258195--------------------------------------------------------------------------------
259−-- | Put a 'CompilerWrite'
260196compilerTell :: CompilerWrite -> Compiler ()
261−compilerTell = compilerResult . CompilerDone ()
197+compilerTell deps = Compiler $ \_ -> return $ CompilerDone () deps
262198{-# INLINE compilerTell #-}
263199
264200
265201--------------------------------------------------------------------------------
266−-- | Run an IO computation without dependencies in a Compiler
267−compilerUnsafeIO :: IO a -> Compiler a
268−compilerUnsafeIO io = Compiler $ \_ -> do
269− x <- io
270− return $ CompilerDone x mempty
271−{-# INLINE compilerUnsafeIO #-}
272−
273−
274−--------------------------------------------------------------------------------
275−-- | Throw errors in the 'Compiler'.
276−--
277−-- If no messages are given, this is considered a 'CompilationNoResult' error.
278−-- Otherwise, it is treated as a proper compilation failure.
279202compilerThrow :: [String] -> Compiler a
280−compilerThrow = compilerResult . CompilerError .
281− maybe (CompilationNoResult []) CompilationFailure .
282− NonEmpty.nonEmpty
283−
284−-- | Put a 'CompilerError' with multiple messages as 'CompilationNoResult'
285−compilerNoResult :: [String] -> Compiler a
286−compilerNoResult = compilerResult . CompilerError . CompilationNoResult
203+compilerThrow es = Compiler $ \_ -> return $ CompilerError es
204+{-# INLINE compilerThrow #-}
287205
288206
289207--------------------------------------------------------------------------------
290−-- | Allows to distinguish 'CompilerError's and branch on them with 'Either'
291−--
292−-- prop> compilerTry = (`compilerCatch` return . Left) . fmap Right
293−compilerTry :: Compiler a -> Compiler (Either (CompilerErrors String) a)
294−compilerTry (Compiler x) = Compiler $ \r -> do
295− res <- x r
296− case res of
297− CompilerDone res' w -> return (CompilerDone (Right res') w)
298− CompilerSnapshot s c -> return (CompilerSnapshot s (compilerTry c))
299− CompilerRequire i c -> return (CompilerRequire i (compilerTry c))
300− CompilerError e -> return (CompilerDone (Left e) mempty)
301−{-# INLINE compilerTry #-}
302−
303−
304−--------------------------------------------------------------------------------
305−-- | Allows you to recover from 'CompilerError's.
306−-- Uses the same parameter order as 'catchError' so that it can be used infix.
307−--
308−-- prop> c `compilerCatch` f = compilerTry c >>= either f return
309−compilerCatch :: Compiler a -> (CompilerErrors String -> Compiler a) -> Compiler a
208+compilerCatch :: Compiler a -> ([String] -> Compiler a) -> Compiler a
310209compilerCatch (Compiler x) f = Compiler $ \r -> do
311210 res <- x r
312211 case res of
313212 CompilerDone res' w -> return (CompilerDone res' w)
314213 CompilerSnapshot s c -> return (CompilerSnapshot s (compilerCatch c f))
315− CompilerRequire i c -> return (CompilerRequire i (compilerCatch c f))
316214 CompilerError e -> unCompiler (f e) r
215+ CompilerRequire i c -> return (CompilerRequire i (compilerCatch c f))
317216{-# INLINE compilerCatch #-}
318217
319218
320219--------------------------------------------------------------------------------
321−compilerDebugLog :: [String] -> Compiler ()
322−compilerDebugLog ms = do
323− logger <- compilerLogger <$> compilerAsk
324− compilerUnsafeIO $ forM_ ms $ Logger.debug logger
220+-- | Put the result back in a compiler
221+compilerResult :: CompilerResult a -> Compiler a
222+compilerResult x = Compiler $ \_ -> return x
223+{-# INLINE compilerResult #-}
224+
325225
326226--------------------------------------------------------------------------------
327−-- | Pass a list of messages with a heading to the debug logger
328−compilerDebugEntries :: String -> [String] -> Compiler ()
329−compilerDebugEntries msg = compilerDebugLog . (msg:) . map indent
330− where
331− indent = unlines . map (" "++) . lines
227+compilerUnsafeIO :: IO a -> Compiler a
228+compilerUnsafeIO io = Compiler $ \_ -> do
229+ x <- io
230+ return $ CompilerDone x mempty
231+{-# INLINE compilerUnsafeIO #-}
332232
333233
334234--------------------------------------------------------------------------------
335235compilerTellDependencies :: [Dependency] -> Compiler ()
336236compilerTellDependencies ds = do
337− compilerDebugLog $ map (\d ->
338− "Hakyll.Core.Compiler.Internal: Adding dependency: " ++ show d) ds
237+ logger <- compilerLogger <$> compilerAsk
238+ forM_ ds $ \d -> compilerUnsafeIO $ Logger.debug logger $
239+ "Hakyll.Core.Compiler.Internal: Adding dependency: " ++ show d
339240 compilerTell mempty {compilerDependencies = ds}
340241{-# INLINE compilerTellDependencies #-}
341242
lib/Hakyll/Core/Compiler/Require.hs → src/Hakyll/Core/Compiler/Require.hsrenamed−2
@@ -91,7 +91,6 @@ loadBody id' = loadSnapshotBody id' final
9191
9292
9393--------------------------------------------------------------------------------
94−-- | A shortcut for only requiring the body for a specific snapshot of an item
9594loadSnapshotBody :: (Binary a, Typeable a)
9695 => Identifier -> Snapshot -> Compiler a
9796loadSnapshotBody id' snapshot = fmap itemBody $ loadSnapshot id' snapshot
@@ -104,7 +103,6 @@ loadAll pattern = loadAllSnapshots pattern final
104103
105104
106105--------------------------------------------------------------------------------
107−-- | Load a specific snapshot for each of dynamic list of items
108106loadAllSnapshots :: (Binary a, Typeable a)
109107 => Pattern -> Snapshot -> Compiler [Item a]
110108loadAllSnapshots pattern snapshot = do
lib/Hakyll/Core/Configuration.hs → src/Hakyll/Core/Configuration.hsrenamed

The content is the same.

lib/Hakyll/Core/Dependencies.hs → src/Hakyll/Core/Dependencies.hsrenamed

The content is the same.

lib/Hakyll/Core/File.hs → src/Hakyll/Core/File.hsrenamed

The content is the same.

lib/Hakyll/Core/Identifier.hs → src/Hakyll/Core/Identifier.hsrenamed+1−1
@@ -62,7 +62,7 @@ instance Show Identifier where
6262
6363--------------------------------------------------------------------------------
6464-- | Parse an identifier from a string
65−fromFilePath :: FilePath -> Identifier
65+fromFilePath :: String -> Identifier
6666fromFilePath = Identifier Nothing .
6767 intercalate "/" . filter (not . null) . split'
6868 where
lib/Hakyll/Core/Identifier/Pattern.hs → src/Hakyll/Core/Identifier/Pattern.hsrenamed+72−14
@@ -27,8 +27,7 @@
2727-- * @\"foo\/*.html\"@ will match all HTML files in the @\"foo\/\"@ directory.
2828--
2929-- The 'capture' function allows the user to get access to the elements captured
30−-- by the capture elements in a glob or regex pattern.
31−{-# OPTIONS_GHC -fno-warn-orphans #-}
30+-- by the capture elements in the pattern.
3231module Hakyll.Core.Identifier.Pattern
3332 ( -- * The pattern type
3433 Pattern
@@ -58,22 +57,77 @@ module Hakyll.Core.Identifier.Pattern
5857
5958
6059--------------------------------------------------------------------------------
61−import Control.Arrow ((&&&), (>>>))
62−import Control.Monad (msum)
63−import Data.List (inits, isPrefixOf,
64− tails)
65−import Data.Maybe (isJust)
66−import qualified Data.Set as S
60+import Control.Arrow ((&&&), (>>>))
61+import Control.Monad (msum)
62+import Data.Binary (Binary (..), getWord8, putWord8)
63+import Data.List (inits, isPrefixOf, tails)
64+import Data.Maybe (isJust)
65+import Data.Set (Set)
66+import qualified Data.Set as S
6767
6868
6969--------------------------------------------------------------------------------
70−import GHC.Exts (IsString, fromString)
71−import Text.Regex.TDFA ((=~))
70+import GHC.Exts (IsString, fromString)
71+import Text.Regex.TDFA ((=~))
7272
7373
7474--------------------------------------------------------------------------------
7575import Hakyll.Core.Identifier
76−import Hakyll.Core.Identifier.Pattern.Internal
76+
77+
78+--------------------------------------------------------------------------------
79+-- | Elements of a glob pattern
80+data GlobComponent
81+ = Capture
82+ | CaptureMany
83+ | Literal String
84+ deriving (Eq, Show)
85+
86+
87+--------------------------------------------------------------------------------
88+instance Binary GlobComponent where
89+ put Capture = putWord8 0
90+ put CaptureMany = putWord8 1
91+ put (Literal s) = putWord8 2 >> put s
92+
93+ get = getWord8 >>= \t -> case t of
94+ 0 -> pure Capture
95+ 1 -> pure CaptureMany
96+ 2 -> Literal <$> get
97+ _ -> error "Data.Binary.get: Invalid GlobComponent"
98+
99+
100+--------------------------------------------------------------------------------
101+-- | Type that allows matching on identifiers
102+data Pattern
103+ = Everything
104+ | Complement Pattern
105+ | And Pattern Pattern
106+ | Glob [GlobComponent]
107+ | List (Set Identifier)
108+ | Regex String
109+ | Version (Maybe String)
110+ deriving (Show)
111+
112+
113+--------------------------------------------------------------------------------
114+instance Binary Pattern where
115+ put Everything = putWord8 0
116+ put (Complement p) = putWord8 1 >> put p
117+ put (And x y) = putWord8 2 >> put x >> put y
118+ put (Glob g) = putWord8 3 >> put g
119+ put (List is) = putWord8 4 >> put is
120+ put (Regex r) = putWord8 5 >> put r
121+ put (Version v) = putWord8 6 >> put v
122+
123+ get = getWord8 >>= \t -> case t of
124+ 0 -> pure Everything
125+ 1 -> Complement <$> get
126+ 2 -> And <$> get <*> get
127+ 3 -> Glob <$> get
128+ 4 -> List <$> get
129+ 5 -> Regex <$> get
130+ _ -> Version <$> get
77131
78132
79133--------------------------------------------------------------------------------
@@ -81,6 +135,12 @@ instance IsString Pattern where
81135 fromString = fromGlob
82136
83137
138+--------------------------------------------------------------------------------
139+instance Monoid Pattern where
140+ mempty = Everything
141+ mappend = (.&&.)
142+
143+
84144--------------------------------------------------------------------------------
85145-- | Parse a pattern from a string
86146fromGlob :: String -> Pattern
@@ -200,11 +260,9 @@ splits = inits &&& tails >>> uncurry zip >>> reverse
200260
201261
202262--------------------------------------------------------------------------------
203−-- | Match a glob or regex pattern against an identifier, generating a list of captures
263+-- | Match a glob against a pattern, generating a list of captures
204264capture :: Pattern -> Identifier -> Maybe [String]
205265capture (Glob p) i = capture' p (toFilePath i)
206−capture (Regex pat) i = Just groups
207− where (_, _, _, groups) = ((toFilePath i) =~ pat) :: (String, String, String, [String])
208266capture _ _ = Nothing
209267
210268
lib/Hakyll/Core/Item.hs → src/Hakyll/Core/Item.hsrenamed

The content is the same.

lib/Hakyll/Core/Item/SomeItem.hs → src/Hakyll/Core/Item/SomeItem.hsrenamed

The content is the same.

lib/Hakyll/Core/Logger.hs → src/Hakyll/Core/Logger.hsrenamed+3−9
@@ -18,7 +18,6 @@ import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
1818import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
1919import Control.Monad (forever)
2020import Control.Monad.Trans (MonadIO, liftIO)
21−import Data.List (intercalate)
2221import Prelude hiding (error)
2322
2423
@@ -80,7 +79,7 @@ string l v m
8079
8180--------------------------------------------------------------------------------
8281error :: MonadIO m => Logger -> String -> m ()
83−error l m = string l Error $ " [ERROR] " ++ indent m
82+error l m = string l Error $ " [ERROR] " ++ m
8483
8584
8685--------------------------------------------------------------------------------
@@ -90,14 +89,9 @@ header l = string l Message
9089
9190--------------------------------------------------------------------------------
9291message :: MonadIO m => Logger -> String -> m ()
93−message l m = string l Message $ " " ++ indent m
92+message l m = string l Message $ " " ++ m
9493
9594
9695--------------------------------------------------------------------------------
9796debug :: MonadIO m => Logger -> String -> m ()
98−debug l m = string l Debug $ " [DEBUG] " ++ indent m
99−
100−
101−--------------------------------------------------------------------------------
102−indent :: String -> String
103−indent = intercalate "\n " . lines
97+debug l m = string l Debug $ " [DEBUG] " ++ m
lib/Hakyll/Core/Metadata.hs → src/Hakyll/Core/Metadata.hsrenamed

The content is the same.

lib/Hakyll/Core/Provider.hs → src/Hakyll/Core/Provider.hsrenamed

The content is the same.

lib/Hakyll/Core/Provider/Internal.hs → src/Hakyll/Core/Provider/Internal.hsrenamed

The content is the same.

lib/Hakyll/Core/Provider/Metadata.hs → src/Hakyll/Core/Provider/Metadata.hsrenamed+2−3
@@ -27,7 +27,6 @@ import Hakyll.Core.Identifier
2727import Hakyll.Core.Metadata
2828import Hakyll.Core.Provider.Internal
2929import System.IO as IO
30−import System.IO.Error (modifyIOError, ioeSetLocation)
3130
3231
3332--------------------------------------------------------------------------------
@@ -52,7 +51,7 @@ loadMetadata p identifier = do
5251--------------------------------------------------------------------------------
5352loadMetadataHeader :: FilePath -> IO (Metadata, String)
5453loadMetadataHeader fp = do
55− fileContent <- modifyIOError (`ioeSetLocation` "loadMetadataHeader") $ readFile fp
54+ fileContent <- readFile fp
5655 case parsePage fileContent of
5756 Right x -> return x
5857 Left err -> throwIO $ MetadataException fp err
@@ -61,7 +60,7 @@ loadMetadataHeader fp = do
6160--------------------------------------------------------------------------------
6261loadMetadataFile :: FilePath -> IO Metadata
6362loadMetadataFile fp = do
64− fileContent <- modifyIOError (`ioeSetLocation` "loadMetadataFile") $ B.readFile fp
63+ fileContent <- B.readFile fp
6564 let errOrMeta = Yaml.decodeEither' fileContent
6665 either (fail . show) return errOrMeta
6766
lib/Hakyll/Core/Provider/MetadataCache.hs → src/Hakyll/Core/Provider/MetadataCache.hsrenamed

The content is the same.

lib/Hakyll/Core/Routes.hs → src/Hakyll/Core/Routes.hsrenamed−17
@@ -25,7 +25,6 @@
2525-- not appear in your site directory.
2626--
2727-- * If an item matches multiple routes, the first rule will be chosen.
28−{-# LANGUAGE CPP #-}
2928{-# LANGUAGE Rank2Types #-}
3029module Hakyll.Core.Routes
3130 ( UsedMetadata
@@ -43,9 +42,6 @@ module Hakyll.Core.Routes
4342
4443
4544--------------------------------------------------------------------------------
46−#if MIN_VERSION_base(4,9,0)
47−import Data.Semigroup (Semigroup (..))
48−#endif
4945import System.FilePath (replaceExtension)
5046
5147
@@ -78,18 +74,6 @@ newtype Routes = Routes
7874
7975
8076--------------------------------------------------------------------------------
81−#if MIN_VERSION_base(4,9,0)
82−instance Semigroup Routes where
83− (<>) (Routes f) (Routes g) = Routes $ \p id' -> do
84− (mfp, um) <- f p id'
85− case mfp of
86− Nothing -> g p id'
87− Just _ -> return (mfp, um)
88−
89−instance Monoid Routes where
90− mempty = Routes $ \_ _ -> return (Nothing, False)
91− mappend = (<>)
92−#else
9377instance Monoid Routes where
9478 mempty = Routes $ \_ _ -> return (Nothing, False)
9579 mappend (Routes f) (Routes g) = Routes $ \p id' -> do
@@ -97,7 +81,6 @@ instance Monoid Routes where
9781 case mfp of
9882 Nothing -> g p id'
9983 Just _ -> return (mfp, um)
100−#endif
10184
10285
10386--------------------------------------------------------------------------------
lib/Hakyll/Core/Rules.hs → src/Hakyll/Core/Rules.hsrenamed

The content is the same.

lib/Hakyll/Core/Rules/Internal.hs → src/Hakyll/Core/Rules/Internal.hsrenamed−14
@@ -1,5 +1,4 @@
11--------------------------------------------------------------------------------
2−{-# LANGUAGE CPP #-}
32{-# LANGUAGE GeneralizedNewtypeDeriving #-}
43{-# LANGUAGE Rank2Types #-}
54module Hakyll.Core.Rules.Internal
@@ -17,9 +16,6 @@ import Control.Monad.Reader (ask)
1716import Control.Monad.RWS (RWST, runRWST)
1817import Control.Monad.Trans (liftIO)
1918import qualified Data.Map as M
20−#if MIN_VERSION_base(4,9,0)
21−import Data.Semigroup (Semigroup (..))
22−#endif
2319import Data.Set (Set)
2420
2521
@@ -56,20 +52,10 @@ data RuleSet = RuleSet
5652
5753
5854--------------------------------------------------------------------------------
59−#if MIN_VERSION_base(4,9,0)
60−instance Semigroup RuleSet where
61− (<>) (RuleSet r1 c1 s1 p1) (RuleSet r2 c2 s2 p2) =
62− RuleSet (mappend r1 r2) (mappend c1 c2) (mappend s1 s2) (p1 .||. p2)
63−
64−instance Monoid RuleSet where
65− mempty = RuleSet mempty mempty mempty mempty
66− mappend = (<>)
67−#else
6855instance Monoid RuleSet where
6956 mempty = RuleSet mempty mempty mempty mempty
7057 mappend (RuleSet r1 c1 s1 p1) (RuleSet r2 c2 s2 p2) =
7158 RuleSet (mappend r1 r2) (mappend c1 c2) (mappend s1 s2) (p1 .||. p2)
72−#endif
7359
7460
7561--------------------------------------------------------------------------------
lib/Hakyll/Core/Runtime.hs → src/Hakyll/Core/Runtime.hsrenamed+3−3
@@ -199,9 +199,9 @@ chase trail id'
199199 result <- liftIO $ runCompiler compiler read'
200200 case result of
201201 -- Rethrow error
202− CompilerError e -> throwError $ case compilerErrorMessages e of
203− [] -> "Compiler failed but no info given, try running with -v?"
204− es -> intercalate "; " es
202+ CompilerError [] -> throwError
203+ "Compiler failed but no info given, try running with -v?"
204+ CompilerError es -> throwError $ intercalate "; " es
205205
206206 -- Signal that a snapshot was saved ->
207207 CompilerSnapshot snapshot c -> do
lib/Hakyll/Core/Store.hs → src/Hakyll/Core/Store.hsrenamed+23−26
@@ -16,6 +16,7 @@ module Hakyll.Core.Store
1616
1717
1818--------------------------------------------------------------------------------
19+import Control.Exception (IOException, handle)
1920import qualified Crypto.Hash.MD5 as MD5
2021import Data.Binary (Binary, decode, encodeFile)
2122import qualified Data.ByteString as B
@@ -26,13 +27,11 @@ import Data.Maybe (isJust)
2627import qualified Data.Text as T
2728import qualified Data.Text.Encoding as T
2829import Data.Typeable (TypeRep, Typeable, cast, typeOf)
29−import Numeric (showHex)
3030import System.Directory (createDirectoryIfMissing)
3131import System.Directory (doesFileExist, removeFile)
3232import System.FilePath ((</>))
3333import System.IO (IOMode (..), hClose, openFile)
34−import System.IO.Error (catchIOError, ioeSetFileName,
35− ioeSetLocation, modifyIOError)
34+import Text.Printf (printf)
3635
3736
3837--------------------------------------------------------------------------------
@@ -85,14 +84,6 @@ new inMemory directory = do
8584 where
8685 csize = Just 500
8786
88−--------------------------------------------------------------------------------
89−withStore :: Store -> String -> (String -> FilePath -> IO a) -> [String] -> IO a
90−withStore store loc run identifier = modifyIOError handle $ run key path
91− where
92− key = hash identifier
93− path = storeDirectory store </> key
94− handle e = e `ioeSetFileName` (path ++ " for " ++ intercalate "/" identifier)
95− `ioeSetLocation` ("Store." ++ loc)
9687
9788--------------------------------------------------------------------------------
9889-- | Auxiliary: add an item to the in-memory cache
@@ -133,16 +124,17 @@ cacheDelete (Store _ (Just lru)) key = do
133124--------------------------------------------------------------------------------
134125-- | Store an item
135126set :: (Binary a, Typeable a) => Store -> [String] -> a -> IO ()
136−set store identifier value = withStore store "set" (\key path -> do
137− encodeFile path value
127+set store identifier value = do
128+ encodeFile (storeDirectory store </> key) value
138129 cacheInsert store key value
139− ) identifier
130+ where
131+ key = hash identifier
140132
141133
142134--------------------------------------------------------------------------------
143135-- | Load an item
144136get :: (Binary a, Typeable a) => Store -> [String] -> IO (Result a)
145−get store = withStore store "get" $ \key path -> do
137+get store identifier = do
146138 -- First check the in-memory map
147139 ref <- cacheLookup store key
148140 case ref of
@@ -154,14 +146,17 @@ get store = withStore store "get" $ \key path -> do
154146 then return NotFound
155147 -- Found in the filesystem
156148 else do
157− v <- decodeClose path
149+ v <- decodeClose
158150 cacheInsert store key v
159151 return $ Found v
160152 -- Found in the in-memory map (or wrong type), just return
161153 s -> return s
162154 where
155+ key = hash identifier
156+ path = storeDirectory store </> key
157+
163158 -- 'decodeFile' from Data.Binary which closes the file ASAP
164− decodeClose path = do
159+ decodeClose = do
165160 h <- openFile path ReadMode
166161 lbs <- BL.hGetContents h
167162 BL.length lbs `seq` hClose h
@@ -171,30 +166,32 @@ get store = withStore store "get" $ \key path -> do
171166--------------------------------------------------------------------------------
172167-- | Strict function
173168isMember :: Store -> [String] -> IO Bool
174−isMember store = withStore store "isMember" $ \key path -> do
169+isMember store identifier = do
175170 inCache <- cacheIsMember store key
176171 if inCache then return True else doesFileExist path
172+ where
173+ key = hash identifier
174+ path = storeDirectory store </> key
177175
178176
179177--------------------------------------------------------------------------------
180178-- | Delete an item
181179delete :: Store -> [String] -> IO ()
182−delete store = withStore store "delete" $ \key path -> do
180+delete store identifier = do
183181 cacheDelete store key
184− deleteFile path
182+ deleteFile $ storeDirectory store </> key
183+ where
184+ key = hash identifier
185185
186186
187187--------------------------------------------------------------------------------
188188-- | Delete a file unless it doesn't exist...
189189deleteFile :: FilePath -> IO ()
190−deleteFile = (`catchIOError` \_ -> return ()) . removeFile
190+deleteFile = handle (\(_ :: IOException) -> return ()) . removeFile
191191
192192
193193--------------------------------------------------------------------------------
194194-- | Mostly meant for internal usage
195195hash :: [String] -> String
196−hash = toHex . B.unpack . MD5.hash . T.encodeUtf8 . T.pack . intercalate "/"
197− where
198− toHex [] = ""
199− toHex (x : xs) | x < 16 = '0' : showHex x (toHex xs)
200− | otherwise = showHex x (toHex xs)
196+hash = concatMap (printf "%02x") . B.unpack .
197+ MD5.hash . T.encodeUtf8 . T.pack . intercalate "/"
lib/Hakyll/Core/UnixFilter.hs → src/Hakyll/Core/UnixFilter.hsrenamed+1−2
@@ -92,8 +92,7 @@ unixFilterWith writer reader programName args input = do
9292 ExitSuccess -> return output
9393 ExitFailure e -> fail $
9494 "Hakyll.Core.UnixFilter.unixFilterWith: " ++
95− unwords (programName : args) ++ " gave exit code " ++ show e ++
96− ". (Error: " ++ err ++ ")"
95+ unwords (programName : args) ++ " gave exit code " ++ show e
9796
9897
9998--------------------------------------------------------------------------------
lib/Hakyll/Core/Util/File.hs → src/Hakyll/Core/Util/File.hsrenamed

The content is the same.

lib/Hakyll/Core/Util/Parser.hs → src/Hakyll/Core/Util/Parser.hsrenamed+1
@@ -2,6 +2,7 @@
22-- | Parser utilities
33module Hakyll.Core.Util.Parser
44 ( metadataKey
5+ , reservedKeys
56 ) where
67
78
lib/Hakyll/Core/Util/String.hs → src/Hakyll/Core/Util/String.hsrenamed+1−1
@@ -27,7 +27,7 @@ trim = reverse . trim' . reverse . trim'
2727--------------------------------------------------------------------------------
2828-- | A simple (but inefficient) regex replace funcion
2929replaceAll :: String -- ^ Pattern
30− -> (String -> String) -- ^ Replacement (called on match)
30+ -> (String -> String) -- ^ Replacement (called on capture)
3131 -> String -- ^ Source string
3232 -> String -- ^ Result
3333replaceAll pattern f source = replaceAll' source
lib/Hakyll/Core/Writable.hs → src/Hakyll/Core/Writable.hsrenamed

The content is the same.

src/Init.hs → src/Hakyll/Init.hsrenamed+17−44
@@ -6,12 +6,12 @@ module Main
66
77--------------------------------------------------------------------------------
88import Control.Arrow (first)
9−import Control.Monad (forM, forM_)
9+import Control.Monad (forM_)
1010import Data.Char (isAlphaNum, isNumber)
11−import Data.List (foldl', intercalate, isPrefixOf)
11+import Data.List (foldl')
12+import Data.List (intercalate, isPrefixOf)
1213import Data.Version (Version (..))
13−import System.Directory (canonicalizePath, copyFile,
14− doesFileExist)
14+import System.Directory (canonicalizePath, copyFile)
1515import System.Environment (getArgs, getProgName)
1616import System.Exit (exitFailure)
1717import System.FilePath (splitDirectories, (</>))
@@ -22,10 +22,6 @@ import Hakyll.Core.Util.File
2222import Paths_hakyll
2323
2424
25−--------------------------------------------------------------------------------
26−import Prelude
27−
28−
2925--------------------------------------------------------------------------------
3026main :: IO ()
3127main = do
@@ -41,44 +37,21 @@ main = do
4137 -- If dstDir begins with hyphens, the guard will prevent it from creating
4238 -- directory with that name so we can fall to the second alternative
4339 -- which prints a usage info for user.
44− [dstDir] | not ("-" `isPrefixOf` dstDir) ->
45− createFiles False srcDir files dstDir
46− ["-f", dstDir] ->
47− createFiles True srcDir files dstDir
48− _ -> do
49− putStrLn $ "Usage: " ++ progName ++ "[-f] <directory>"
50− exitFailure
40+ [dstDir] | not ("-" `isPrefixOf` dstDir) -> do
41+ forM_ files $ \file -> do
42+ let dst = dstDir </> file
43+ src = srcDir </> file
44+ putStrLn $ "Creating " ++ dst
45+ makeDirectories dst
46+ copyFile src dst
5147
52− where
53− createFiles force srcDir files dstDir = do
5448 name <- makeName dstDir
5549 let cabalPath = dstDir </> name ++ ".cabal"
56−
57− diff <- if force then return []
58− else existingFiles dstDir (cabalPath : files)
59−
60− case diff of
61− [] -> do
62− forM_ files $ \file -> do
63− let dst = dstDir </> file
64− src = srcDir </> file
65− putStrLn $ "Creating " ++ dst
66− makeDirectories dst
67− copyFile src dst
68−
69− putStrLn $ "Creating " ++ cabalPath
70− createCabal cabalPath name
71− fs -> do
72− putStrLn $ "The following files will be overwritten:"
73− mapM_ putStrLn fs
74− putStrLn $ "Use -f to overwrite them"
75− exitFailure
76−
77−existingFiles :: FilePath -> [FilePath] -> IO [FilePath]
78−existingFiles dstDir files = fmap concat $ forM files $ \file -> do
79− let dst = dstDir </> file
80− exists <- doesFileExist dst
81− return $ if exists then [dst] else []
50+ putStrLn $ "Creating " ++ cabalPath
51+ createCabal cabalPath name
52+ _ -> do
53+ putStrLn $ "Usage: " ++ progName ++ " <directory>"
54+ exitFailure
8255
8356-- | Figure out a good cabal package name from the given (existing) directory
8457-- name
@@ -104,7 +77,7 @@ makeName dstDir = do
10477 safeLast = foldl' (\_ x -> Just x) Nothing
10578
10679createCabal :: FilePath -> String -> IO ()
107−createCabal path name =
80+createCabal path name = do
10881 writeFile path $ unlines [
10982 "name: " ++ name
11083 , "version: 0.1.0.0"
lib/Hakyll/Main.hs → src/Hakyll/Main.hsrenamed+29−71
@@ -1,34 +1,30 @@
11--------------------------------------------------------------------------------
22-- | Module providing the main hakyll function and command-line argument parsing
3−{-# LANGUAGE CPP #-}
3+{-# LANGUAGE CPP #-}
44
55module Hakyll.Main
66 ( hakyll
77 , hakyllWith
88 , hakyllWithArgs
99 , hakyllWithExitCode
10− , hakyllWithExitCodeAndArgs
11− , Options(..)
12− , Command(..)
1310 ) where
1411
1512
1613--------------------------------------------------------------------------------
17−import System.Environment (getProgName)
18−import System.Exit (ExitCode (ExitSuccess), exitWith)
19−import System.IO.Unsafe (unsafePerformIO)
14+import System.Environment (getProgName)
15+import System.IO.Unsafe (unsafePerformIO)
16+import System.Exit (ExitCode(ExitSuccess), exitWith)
2017
2118
2219--------------------------------------------------------------------------------
23−import Data.Monoid ((<>))
24−import qualified Options.Applicative as OA
20+import Options.Applicative
2521
2622
2723--------------------------------------------------------------------------------
28−import qualified Hakyll.Check as Check
29−import qualified Hakyll.Commands as Commands
30−import qualified Hakyll.Core.Configuration as Config
31−import qualified Hakyll.Core.Logger as Logger
24+import qualified Hakyll.Check as Check
25+import qualified Hakyll.Commands as Commands
26+import qualified Hakyll.Core.Configuration as Config
27+import qualified Hakyll.Core.Logger as Logger
3228import Hakyll.Core.Rules
3329
3430
@@ -72,9 +68,9 @@ hakyllWithExitCodeAndArgs conf args rules = do
7268--------------------------------------------------------------------------------
7369defaultParser :: Config.Configuration -> IO Options
7470defaultParser conf =
75− OA.customExecParser (OA.prefs OA.showHelpOnError)
76− (OA.info (OA.helper <*> optionParser conf)
77− (OA.fullDesc <> OA.progDesc
71+ customExecParser (prefs showHelpOnError)
72+ (info (helper <*> optionParser conf)
73+ (fullDesc <> progDesc
7874 (progName ++ " - Static site compiler created with Hakyll")))
7975
8076
@@ -84,7 +80,7 @@ invokeCommands :: Command -> Config.Configuration ->
8480invokeCommands args conf check logger rules =
8581 case args of
8682 Build -> Commands.build conf logger rules
87− Check _ -> Commands.check conf logger check
83+ Check _ -> Commands.check conf logger check >> ok
8884 Clean -> Commands.clean conf logger >> ok
8985 Deploy -> Commands.deploy conf
9086 Preview p -> Commands.preview conf logger rules p >> ok
@@ -97,79 +93,41 @@ invokeCommands args conf check logger rules =
9793
9894--------------------------------------------------------------------------------
9995
100−-- | The parsed command-line options.
10196data Options = Options {verbosity :: Bool, optCommand :: Command}
10297 deriving (Show)
10398
104−-- | The command to run.
10599data Command
106100 = Build
107− -- ^ Generate the site.
108101 | Check {internal_links :: Bool}
109− -- ^ Validate the site output.
110102 | Clean
111− -- ^ Clean up and remove cache.
112103 | Deploy
113− -- ^ Upload/deploy your site.
114104 | Preview {port :: Int}
115− -- ^ [DEPRECATED] Please use the watch command.
116105 | Rebuild
117− -- ^ Clean and build again.
118106 | Server {host :: String, port :: Int}
119− -- ^ Start a preview server.
120107 | Watch {host :: String, port :: Int, no_server :: Bool }
121− -- ^ Autocompile on changes and start a preview server.
122108 deriving (Show)
123109
124−{-# DEPRECATED Preview "Use Watch instead." #-}
125−
126−optionParser :: Config.Configuration -> OA.Parser Options
110+optionParser :: Config.Configuration -> Parser Options
127111optionParser conf = Options <$> verboseParser <*> commandParser conf
128112 where
129− verboseParser = OA.switch (OA.long "verbose" <> OA.short 'v' <> OA.help "Run in verbose mode")
113+ verboseParser = switch (long "verbose" <> short 'v' <> help "Run in verbose mode")
130114
131115
132−commandParser :: Config.Configuration -> OA.Parser Command
133−commandParser conf = OA.subparser $ foldr ((<>) . produceCommand) mempty commands
116+commandParser :: Config.Configuration -> Parser Command
117+commandParser conf = subparser $ foldr ((<>) . produceCommand) mempty commands
134118 where
135− portParser = OA.option OA.auto (OA.long "port" <> OA.help "Port to listen on" <> OA.value (Config.previewPort conf))
136− hostParser = OA.strOption (OA.long "host" <> OA.help "Host to bind on" <> OA.value (Config.previewHost conf))
137−
138− produceCommand (c,a,b) = OA.command c (OA.info (OA.helper <*> a) (b))
139−
140− commands =
141− [ ( "build"
142− , pure Build
143− , OA.fullDesc <> OA.progDesc "Generate the site"
144− )
145− , ( "check"
146− , pure Check <*> OA.switch (OA.long "internal-links" <> OA.help "Check internal links only")
147− , OA.fullDesc <> OA.progDesc "Validate the site output"
148− )
149− , ( "clean"
150− , pure Clean
151− , OA.fullDesc <> OA.progDesc "Clean up and remove cache"
152− )
153− , ( "deploy"
154− , pure Deploy
155− , OA.fullDesc <> OA.progDesc "Upload/deploy your site"
156− )
157− , ( "preview"
158− , pure Preview <*> portParser
159− , OA.fullDesc <> OA.progDesc "[DEPRECATED] Please use the watch command"
160− )
161− , ( "rebuild"
162− , pure Rebuild
163− , OA.fullDesc <> OA.progDesc "Clean and build again"
164− )
165− , ( "server"
166− , pure Server <*> hostParser <*> portParser
167− , OA.fullDesc <> OA.progDesc "Start a preview server"
168− )
169− , ( "watch"
170− , pure Watch <*> hostParser <*> portParser <*> OA.switch (OA.long "no-server" <> OA.help "Disable the built-in web server")
171− , OA.fullDesc <> OA.progDesc "Autocompile on changes and start a preview server. You can watch and recompile without running a server with --no-server."
172− )
119+ produceCommand (a,b) = command a (info (helper <*> fst b) (snd b))
120+ portParser = option auto (long "port" <> help "Port to listen on" <> value (Config.previewPort conf))
121+ hostParser = strOption (long "host" <> help "Host to bind on" <> value (Config.previewHost conf))
122+ commands = [
123+ ("build", (pure Build,fullDesc <> progDesc "Generate the site")),
124+ ("check", (pure Check <*> switch (long "internal-links" <> help "Check internal links only"), fullDesc <> progDesc "Validate the site output")),
125+ ("clean", (pure Clean,fullDesc <> progDesc "Clean up and remove cache")),
126+ ("deploy", (pure Deploy,fullDesc <> progDesc "Upload/deploy your site")),
127+ ("preview", (pure Preview <*> portParser,fullDesc <> progDesc "[DEPRECATED] Please use the watch command")),
128+ ("rebuild", (pure Rebuild,fullDesc <> progDesc "Clean and build again")),
129+ ("server", (pure Server <*> hostParser <*> portParser,fullDesc <> progDesc "Start a preview server")),
130+ ("watch", (pure Watch <*> hostParser <*> portParser <*> switch (long "no-server" <> help "Disable the built-in web server"),fullDesc <> progDesc "Autocompile on changes and start a preview server. You can watch and recompile without running a server with --no-server."))
173131 ]
174132
175133
lib/Hakyll/Preview/Poll.hs → src/Hakyll/Preview/Poll.hsrenamed+18−8
@@ -14,7 +14,8 @@ import Control.Exception (AsyncException, fromException,
1414import Control.Monad (forever, void, when)
1515import System.Directory (canonicalizePath)
1616import System.FilePath (pathSeparators)
17−import qualified System.FSNotify as FSNotify
17+import System.FSNotify (Event (..), startManager,
18+ watchTree)
1819
1920#ifdef mingw32_HOST_OS
2021import Control.Concurrent (threadDelay)
@@ -43,12 +44,12 @@ watchUpdates conf update = do
4344 shouldBuild <- newEmptyMVar
4445 pattern <- update
4546 fullProviderDir <- canonicalizePath $ providerDirectory conf
46− manager <- FSNotify.startManager
47+ manager <- startManager
4748
4849 let allowed event = do
4950 -- Absolute path of the changed file. This must be inside provider
5051 -- dir, since that's the only dir we're watching.
51− let path = FSNotify.eventPath event
52+ let path = eventPath event
5253 relative = dropWhile (`elem` pathSeparators) $
5354 drop (length fullProviderDir) path
5455 identifier = fromFilePath relative
@@ -68,7 +69,7 @@ watchUpdates conf update = do
6869
6970 -- Send an event whenever something occurs so that the thread described
7071 -- above will do a build.
71− void $ FSNotify.watchTree manager providerDir (not . isRemove) $ \event -> do
72+ void $ watchTree manager providerDir (not . isRemove) $ \event -> do
7273 allowed' <- allowed event
7374 when allowed' $ void $ tryPutMVar shouldBuild event
7475 where
@@ -76,7 +77,7 @@ watchUpdates conf update = do
7677 update' _ _ = void update
7778#else
7879 update' event provider = do
79− let path = provider </> FSNotify.eventPath event
80+ let path = provider </> eventPath event
8081 -- on windows, a 'Modified' event is also sent on file deletion
8182 fileExists <- doesFileExist path
8283
@@ -104,6 +105,15 @@ watchUpdates conf update = do
104105
105106
106107--------------------------------------------------------------------------------
107−isRemove :: FSNotify.Event -> Bool
108−isRemove (FSNotify.Removed {}) = True
109−isRemove _ = False
108+eventPath :: Event -> FilePath
109+eventPath evt = evtPath evt
110+ where
111+ evtPath (Added p _) = p
112+ evtPath (Modified p _) = p
113+ evtPath (Removed p _) = p
114+
115+
116+--------------------------------------------------------------------------------
117+isRemove :: Event -> Bool
118+isRemove (Removed _ _) = True
119+isRemove _ = False
lib/Hakyll/Preview/Server.hs → src/Hakyll/Preview/Server.hsrenamed

The content is the same.

src/Hakyll/Web/CompressCss.hsnew file+86
@@ -0,0 +1,86 @@
1+--------------------------------------------------------------------------------
2+-- | Module used for CSS compression. The compression is currently in a simple
3+-- state, but would typically reduce the number of bytes by about 25%.
4+module Hakyll.Web.CompressCss
5+ ( compressCssCompiler
6+ , compressCss
7+ ) where
8+
9+
10+--------------------------------------------------------------------------------
11+import Data.List (isPrefixOf)
12+
13+
14+--------------------------------------------------------------------------------
15+import Hakyll.Core.Compiler
16+import Hakyll.Core.Item
17+
18+
19+--------------------------------------------------------------------------------
20+-- | Compiler form of 'compressCss'
21+compressCssCompiler :: Compiler (Item String)
22+compressCssCompiler = fmap compressCss <$> getResourceString
23+
24+
25+--------------------------------------------------------------------------------
26+-- | Compress CSS to speed up your site.
27+compressCss :: String -> String
28+compressCss = compressSeparators . stripComments . compressWhitespace
29+
30+
31+--------------------------------------------------------------------------------
32+-- | Compresses certain forms of separators.
33+compressSeparators :: String -> String
34+compressSeparators [] = []
35+compressSeparators str
36+ | isConstant = head str : retainConstants compressSeparators (head str) (drop 1 str)
37+ | stripFirst = compressSeparators (drop 1 str)
38+ | stripSecond = compressSeparators (head str : (drop 2 str))
39+ | otherwise = head str : compressSeparators (drop 1 str)
40+ where
41+ isConstant = or $ map (isOfPrefix str) ["\"", "'"]
42+ stripFirst = or $ map (isOfPrefix str) $ [";;", ";}"] ++ (map (\c -> " " ++ c) separators)
43+ stripSecond = or $ map (isOfPrefix str) $ map (\c -> c ++ " ") separators
44+ separators = [" ", "{", "}", ":", ";", ",", ">", "+", "!"]
45+
46+--------------------------------------------------------------------------------
47+-- | Compresses all whitespace.
48+compressWhitespace :: String -> String
49+compressWhitespace [] = []
50+compressWhitespace str
51+ | isConstant = head str : retainConstants compressWhitespace (head str) (drop 1 str)
52+ | replaceOne = compressWhitespace (' ' : (drop 1 str))
53+ | replaceTwo = compressWhitespace (' ' : (drop 2 str))
54+ | otherwise = head str : compressWhitespace (drop 1 str)
55+ where
56+ isConstant = or $ map (isOfPrefix str) ["\"", "'"]
57+ replaceOne = or $ map (isOfPrefix str) ["\t", "\n", "\r"]
58+ replaceTwo = or $ map (isOfPrefix str) [" \t", " \n", " \r", " "]
59+
60+--------------------------------------------------------------------------------
61+-- | Function that strips CSS comments away.
62+stripComments :: String -> String
63+stripComments [] = []
64+stripComments str
65+ | isConstant = head str : retainConstants stripComments (head str) (drop 1 str)
66+ | isPrefixOf "/*" str = stripComments $ eatComments $ drop 2 str
67+ | otherwise = head str : stripComments (drop 1 str)
68+ where
69+ isConstant = or $ map (isOfPrefix str) ["\"", "'"]
70+ eatComments str'
71+ | null str' = []
72+ | isPrefixOf "*/" str' = drop 2 str'
73+ | otherwise = eatComments $ drop 1 str'
74+
75+--------------------------------------------------------------------------------
76+-- | Helper function to handle string constants correctly.
77+retainConstants :: (String -> String) -> Char -> String -> String
78+retainConstants f delim str
79+ | null str = []
80+ | isPrefixOf [delim] str = head str : f (drop 1 str)
81+ | otherwise = head str : retainConstants f delim (drop 1 str)
82+
83+--------------------------------------------------------------------------------
84+-- | Helper function to determine whether a string is a substring.
85+isOfPrefix :: String -> String -> Bool
86+isOfPrefix = flip isPrefixOf
lib/Hakyll/Web/Feed.hs → src/Hakyll/Web/Feed.hsrenamed+21−59
@@ -1,6 +1,3 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3−
41--------------------------------------------------------------------------------
52-- | A Module that allows easy rendering of RSS feeds.
63--
@@ -23,40 +20,21 @@ module Hakyll.Web.Feed
2320 ( FeedConfiguration (..)
2421 , renderRss
2522 , renderAtom
26− , renderRssWithTemplates
27− , renderAtomWithTemplates
2823 ) where
2924
3025
3126--------------------------------------------------------------------------------
3227import Hakyll.Core.Compiler
28+import Hakyll.Core.Compiler.Internal
3329import Hakyll.Core.Item
34−import Hakyll.Core.Util.String (replaceAll)
30+import Hakyll.Core.Util.String (replaceAll)
3531import Hakyll.Web.Template
3632import Hakyll.Web.Template.Context
3733import Hakyll.Web.Template.List
3834
3935
4036--------------------------------------------------------------------------------
41−import Data.FileEmbed (makeRelativeToProject)
42−
43−
44−--------------------------------------------------------------------------------
45−rssTemplate :: Template
46−rssTemplate =
47− $(makeRelativeToProject "data/templates/rss.xml" >>= embedTemplate)
48−
49−rssItemTemplate :: Template
50−rssItemTemplate =
51− $(makeRelativeToProject "data/templates/rss-item.xml" >>= embedTemplate)
52−
53−atomTemplate :: Template
54−atomTemplate =
55− $(makeRelativeToProject "data/templates/atom.xml" >>= embedTemplate)
56−
57−atomItemTemplate :: Template
58−atomItemTemplate =
59− $(makeRelativeToProject "data/templates/atom-item.xml" >>= embedTemplate)
37+import Paths_hakyll
6038
6139
6240--------------------------------------------------------------------------------
@@ -77,13 +55,16 @@ data FeedConfiguration = FeedConfiguration
7755
7856--------------------------------------------------------------------------------
7957-- | Abstract function to render any feed.
80−renderFeed :: Template -- ^ Default feed template
81− -> Template -- ^ Default item template
58+renderFeed :: FilePath -- ^ Feed template
59+ -> FilePath -- ^ Item template
8260 -> FeedConfiguration -- ^ Feed configuration
8361 -> Context String -- ^ Context for the items
8462 -> [Item String] -- ^ Input items
8563 -> Compiler (Item String) -- ^ Resulting item
86−renderFeed feedTpl itemTpl config itemContext items = do
64+renderFeed feedPath itemPath config itemContext items = do
65+ feedTpl <- loadTemplate feedPath
66+ itemTpl <- loadTemplate itemPath
67+
8768 protectedItems <- mapM (applyFilter protectCDATA) items
8869 body <- makeItem =<< applyTemplateList itemTpl itemContext' protectedItems
8970 applyTemplate feedTpl feedContext body
@@ -92,6 +73,10 @@ renderFeed feedTpl itemTpl config itemContext items = do
9273 applyFilter tr str = return $ fmap tr str
9374 protectCDATA :: String -> String
9475 protectCDATA = replaceAll "]]>" (const "]]&gt;")
76+ -- Auxiliary: load a template from a datafile
77+ loadTemplate path = do
78+ file <- compilerUnsafeIO $ getDataFileName path
79+ unsafeReadTemplateFile file
9580
9681 itemContext' = mconcat
9782 [ itemContext
@@ -117,35 +102,8 @@ renderFeed feedTpl itemTpl config itemContext items = do
117102 updatedField = field "updated" $ \_ -> case items of
118103 [] -> return "Unknown"
119104 (x : _) -> unContext itemContext' "updated" [] x >>= \cf -> case cf of
105+ ListField _ _ -> fail "Hakyll.Web.Feed.renderFeed: Internal error"
120106 StringField s -> return s
121− _ -> fail "Hakyll.Web.Feed.renderFeed: Internal error"
122−
123−--------------------------------------------------------------------------------
124−-- | Render an RSS feed using given templates with a number of items.
125−renderRssWithTemplates ::
126− Template -- ^ Feed template
127− -> Template -- ^ Item template
128− -> FeedConfiguration -- ^ Feed configuration
129− -> Context String -- ^ Item context
130− -> [Item String] -- ^ Feed items
131− -> Compiler (Item String) -- ^ Resulting feed
132−renderRssWithTemplates feedTemplate itemTemplate config context = renderFeed
133− feedTemplate itemTemplate config
134− (makeItemContext "%a, %d %b %Y %H:%M:%S UT" context)
135−
136−
137−--------------------------------------------------------------------------------
138−-- | Render an Atom feed using given templates with a number of items.
139−renderAtomWithTemplates ::
140− Template -- ^ Feed template
141− -> Template -- ^ Item template
142− -> FeedConfiguration -- ^ Feed configuration
143− -> Context String -- ^ Item context
144− -> [Item String] -- ^ Feed items
145− -> Compiler (Item String) -- ^ Resulting feed
146−renderAtomWithTemplates feedTemplate itemTemplate config context = renderFeed
147− feedTemplate itemTemplate config
148− (makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)
149107
150108
151109--------------------------------------------------------------------------------
@@ -154,7 +112,9 @@ renderRss :: FeedConfiguration -- ^ Feed configuration
154112 -> Context String -- ^ Item context
155113 -> [Item String] -- ^ Feed items
156114 -> Compiler (Item String) -- ^ Resulting feed
157−renderRss = renderRssWithTemplates rssTemplate rssItemTemplate
115+renderRss config context = renderFeed
116+ "templates/rss.xml" "templates/rss-item.xml" config
117+ (makeItemContext "%a, %d %b %Y %H:%M:%S UT" context)
158118
159119
160120--------------------------------------------------------------------------------
@@ -163,11 +123,13 @@ renderAtom :: FeedConfiguration -- ^ Feed configuration
163123 -> Context String -- ^ Item context
164124 -> [Item String] -- ^ Feed items
165125 -> Compiler (Item String) -- ^ Resulting feed
166−renderAtom = renderAtomWithTemplates atomTemplate atomItemTemplate
126+renderAtom config context = renderFeed
127+ "templates/atom.xml" "templates/atom-item.xml" config
128+ (makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)
167129
168130
169131--------------------------------------------------------------------------------
170132-- | Copies @$updated$@ from @$published$@ if it is not already set.
171133makeItemContext :: String -> Context a -> Context a
172134makeItemContext fmt context = mconcat
173− [context, dateField "published" fmt, dateField "updated" fmt]
135+ [dateField "published" fmt, context, dateField "updated" fmt]
lib/Hakyll/Web/Html.hs → src/Hakyll/Web/Html.hsrenamed+2−6
@@ -3,7 +3,6 @@
33module Hakyll.Web.Html
44 ( -- * Generic
55 withTags
6− , withTagList
76
87 -- * Headers
98 , demoteHeaders
@@ -37,11 +36,8 @@ import Network.URI (isUnreserved, escapeURIString)
3736--------------------------------------------------------------------------------
3837-- | Map over all tags in the document
3938withTags :: (TS.Tag String -> TS.Tag String) -> String -> String
40−withTags = withTagList . map
39+withTags f = renderTags' . map f . parseTags'
4140
42−-- | Map over all tags (as list) in the document
43−withTagList :: ([TS.Tag String] -> [TS.Tag String]) -> String -> String
44−withTagList f = renderTags' . f . parseTags'
4541
4642--------------------------------------------------------------------------------
4743-- | Map every @h1@ to an @h2@, @h2@ to @h3@, etc.
@@ -59,7 +55,7 @@ demoteHeaders = withTags $ \tag -> case tag of
5955
6056--------------------------------------------------------------------------------
6157isUrlAttribute :: String -> Bool
62−isUrlAttribute = (`elem` ["src", "href", "data", "poster", "srcset"])
58+isUrlAttribute = (`elem` ["src", "href", "data", "poster"])
6359
6460
6561--------------------------------------------------------------------------------
lib/Hakyll/Web/Html/RelativizeUrls.hs → src/Hakyll/Web/Html/RelativizeUrls.hsrenamed

The content is the same.

lib/Hakyll/Web/Paginate.hs → src/Hakyll/Web/Paginate.hsrenamed

The content is the same.

lib/Hakyll/Web/Pandoc.hs → src/Hakyll/Web/Pandoc.hsrenamed+12−13
@@ -22,9 +22,9 @@ module Hakyll.Web.Pandoc
2222
2323
2424--------------------------------------------------------------------------------
25−import qualified Data.Text as T
25+import qualified Data.Set as S
2626import Text.Pandoc
27−import Text.Pandoc.Highlighting (pygments)
27+import Text.Pandoc.Error (PandocError (..))
2828
2929
3030--------------------------------------------------------------------------------
@@ -48,10 +48,12 @@ readPandocWith
4848 -> Item String -- ^ String to read
4949 -> Compiler (Item Pandoc) -- ^ Resulting document
5050readPandocWith ropt item =
51− case runPure $ traverse (reader ropt (itemFileType item)) (fmap T.pack item) of
52− Left err -> fail $
51+ case traverse (reader ropt (itemFileType item)) item of
52+ Left (ParseFailure err) -> fail $
53+ "Hakyll.Web.Pandoc.readPandocWith: parse failed: " ++ err
54+ Left (ParsecError _ err) -> fail $
5355 "Hakyll.Web.Pandoc.readPandocWith: parse failed: " ++ show err
54− Right item' -> return item'
56+ Right item' -> return item'
5557 where
5658 reader ro t = case t of
5759 DocBook -> readDocBook ro
@@ -67,7 +69,7 @@ readPandocWith ropt item =
6769 "Hakyll.Web.readPandocWith: I don't know how to read a file of " ++
6870 "the type " ++ show t ++ " for: " ++ show (itemIdentifier item)
6971
70− addExt ro e = ro {readerExtensions = enableExtension e $ readerExtensions ro}
72+ addExt ro e = ro {readerExtensions = S.insert e $ readerExtensions ro}
7173
7274
7375--------------------------------------------------------------------------------
@@ -82,10 +84,7 @@ writePandoc = writePandocWith defaultHakyllWriterOptions
8284writePandocWith :: WriterOptions -- ^ Writer options for pandoc
8385 -> Item Pandoc -- ^ Document to write
8486 -> Item String -- ^ Resulting HTML
85−writePandocWith wopt (Item itemi doc) =
86− case runPure $ writeHtml5String wopt doc of
87− Left err -> error $ "Hakyll.Web.Pandoc.writePandocWith: " ++ show err
88− Right item' -> Item itemi $ T.unpack item'
87+writePandocWith wopt = fmap $ writeHtmlString wopt
8988
9089
9190--------------------------------------------------------------------------------
@@ -148,7 +147,7 @@ defaultHakyllReaderOptions :: ReaderOptions
148147defaultHakyllReaderOptions = def
149148 { -- The following option causes pandoc to read smart typography, a nice
150149 -- and free bonus.
151− readerExtensions = enableExtension Ext_smart pandocExtensions
150+ readerSmart = True
152151 }
153152
154153
@@ -158,8 +157,8 @@ defaultHakyllWriterOptions :: WriterOptions
158157defaultHakyllWriterOptions = def
159158 { -- This option causes literate haskell to be written using '>' marks in
160159 -- html, which I think is a good default.
161− writerExtensions = enableExtension Ext_smart pandocExtensions
160+ writerExtensions = S.insert Ext_literate_haskell (writerExtensions def)
162161 , -- We want to have hightlighting by default, to be compatible with earlier
163162 -- Hakyll releases
164− writerHighlightStyle = Just pygments
163+ writerHighlight = True
165164 }
lib/Hakyll/Web/Pandoc/Biblio.hs → src/Hakyll/Web/Pandoc/Biblio.hsrenamed+6−17
@@ -25,19 +25,17 @@ module Hakyll.Web.Pandoc.Biblio
2525--------------------------------------------------------------------------------
2626import Control.Monad (liftM, replicateM)
2727import Data.Binary (Binary (..))
28+import Data.Default (def)
2829import Data.Typeable (Typeable)
2930import Hakyll.Core.Compiler
30−import Hakyll.Core.Compiler.Internal
3131import Hakyll.Core.Identifier
3232import Hakyll.Core.Item
33−import Hakyll.Core.Provider
3433import Hakyll.Core.Writable
3534import Hakyll.Web.Pandoc
3635import Hakyll.Web.Pandoc.Binary ()
3736import qualified Text.CSL as CSL
3837import Text.CSL.Pandoc (processCites)
39−import Text.Pandoc (Pandoc, ReaderOptions (..),
40− enableExtension, Extension (..))
38+import Text.Pandoc (Pandoc, ReaderOptions (..))
4139
4240
4341--------------------------------------------------------------------------------
@@ -85,11 +83,8 @@ instance Writable Biblio where
8583--------------------------------------------------------------------------------
8684biblioCompiler :: Compiler (Item Biblio)
8785biblioCompiler = do
88− filePath <- getResourceFilePath
89− makeItem =<< unsafeCompiler (Biblio <$> CSL.readBiblioFile idpred filePath)
90− where
91− -- This is a filter on citations. We include all citations.
92− idpred = const True
86+ filePath <- toFilePath <$> getUnderlying
87+ makeItem =<< unsafeCompiler (Biblio <$> CSL.readBiblioFile filePath)
9388
9489
9590--------------------------------------------------------------------------------
@@ -100,9 +95,7 @@ readPandocBiblio :: ReaderOptions
10095 -> Compiler (Item Pandoc)
10196readPandocBiblio ropt csl biblio item = do
10297 -- Parse CSL file, if given
103− provider <- compilerProvider <$> compilerAsk
104− style <- unsafeCompiler $
105− CSL.readCSLFile Nothing . (resourceFilePath provider) . itemIdentifier $ csl
98+ style <- unsafeCompiler $ CSL.readCSLFile Nothing . toFilePath . itemIdentifier $ csl
10699
107100 -- We need to know the citation keys, add then *before* actually parsing the
108101 -- actual page. If we don't do this, pandoc won't even consider them
@@ -119,8 +112,4 @@ pandocBiblioCompiler cslFileName bibFileName = do
119112 csl <- load $ fromFilePath cslFileName
120113 bib <- load $ fromFilePath bibFileName
121114 liftM writePandoc
122− (getResourceBody >>= readPandocBiblio ropt csl bib)
123− where ropt = defaultHakyllReaderOptions
124− { -- The following option enables citation rendering
125− readerExtensions = enableExtension Ext_citations $ readerExtensions defaultHakyllReaderOptions
126− }
115+ (getResourceBody >>= readPandocBiblio def csl bib)
lib/Hakyll/Web/Pandoc/Binary.hs → src/Hakyll/Web/Pandoc/Binary.hsrenamed+17−19
@@ -1,33 +1,31 @@
11{-# OPTIONS_GHC -fno-warn-orphans #-}
2−{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE DeriveGeneric #-}
33module Hakyll.Web.Pandoc.Binary where
44
5−import Data.Binary (Binary (..))
5+import Data.Binary (Binary (..))
66
7−import qualified Text.CSL as CSL
8−import qualified Text.CSL.Reference as REF
9−import qualified Text.CSL.Style as STY
10−import Text.Pandoc
7+import qualified Text.CSL as CSL
8+import qualified Text.CSL.Reference as REF
9+import qualified Text.CSL.Style as STY
10+import Text.Pandoc
1111
1212--------------------------------------------------------------------------------
1313-- orphans
1414
15−instance Binary Alignment
16−instance Binary Block
17−instance Binary CSL.Reference
18−instance Binary Citation
19−instance Binary CitationMode
20−instance Binary Format
21−instance Binary Inline
22−instance Binary ListNumberDelim
23−instance Binary ListNumberStyle
24−instance Binary MathType
25−instance Binary QuoteType
26−instance Binary REF.CLabel
2715instance Binary REF.CNum
2816instance Binary REF.Literal
2917instance Binary REF.RefDate
3018instance Binary REF.RefType
31−instance Binary REF.Season
3219instance Binary STY.Agent
3320instance Binary STY.Formatted
21+instance Binary Inline
22+instance Binary Block
23+instance Binary Citation
24+instance Binary MathType
25+instance Binary Alignment
26+instance Binary CitationMode
27+instance Binary QuoteType
28+instance Binary Format
29+instance Binary ListNumberDelim
30+instance Binary ListNumberStyle
31+instance Binary CSL.Reference
lib/Hakyll/Web/Pandoc/FileType.hs → src/Hakyll/Web/Pandoc/FileType.hsrenamed

The content is the same.

lib/Hakyll/Web/Redirect.hs → src/Hakyll/Web/Redirect.hsrenamed+1−14
@@ -7,9 +7,8 @@ module Hakyll.Web.Redirect
77 ) where
88
99import Control.Applicative ((<$>))
10−import Control.Monad (forM_, when)
10+import Control.Monad (forM_)
1111import Data.Binary (Binary (..))
12−import Data.List (sort, group)
1312import Hakyll.Core.Compiler
1413import Hakyll.Core.Identifier
1514import Hakyll.Core.Routes
@@ -56,17 +55,6 @@ import Hakyll.Core.Writable (Writable (..))
5655-- See also <https://groups.google.com/d/msg/hakyll/sWc6zxfh-uM/fUpZPsFNDgAJ>.
5756createRedirects :: [(Identifier, String)] -> Rules ()
5857createRedirects redirects =
59− do -- redirects are many-to-fewer; keys must be unique, and must point somewhere else:
60− let gkeys = group $ sort $ map fst redirects
61− forM_ gkeys $ \gkey -> case gkey of
62− (k : _ : _) -> fail $
63− "Duplicate 301 redirects; " ++ show k ++ " is ambiguous."
64− _ -> return ()
65−
66− forM_ redirects $ \(r, t) ->
67− when (toFilePath r == t) $ fail $
68− "Self-redirect detected: " ++ show r ++ " points to itself."
69−
7058 forM_ redirects $ \(ident, to) ->
7159 create [ident] $ do
7260 route idRoute
@@ -93,7 +81,6 @@ instance Writable Redirect where
9381redirectToHtml :: Redirect -> String
9482redirectToHtml (Redirect working) =
9583 "<!DOCTYPE html><html><head><meta charset=\"utf-8\"/><meta name=\"generator\" content=\"hakyll\"/>" ++
96− "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" ++
9784 "<meta http-equiv=\"refresh\" content=\"0; url=" ++ working ++
9885 "\"><link rel=\"canonical\" href=\"" ++ working ++
9986 "\"><title>Permanent Redirect</title></head><body><p>The page has moved to: <a href=\"" ++ working ++
lib/Hakyll/Web/Tags.hs → src/Hakyll/Web/Tags.hsrenamed+1−2
@@ -43,7 +43,6 @@
4343module Hakyll.Web.Tags
4444 ( Tags (..)
4545 , getTags
46− , getCategory
4746 , buildTagsWith
4847 , buildTags
4948 , buildCategories
@@ -113,7 +112,7 @@ getTags identifier = do
113112
114113
115114--------------------------------------------------------------------------------
116−-- | Obtain category from a page.
115+-- | Obtain categories from a page.
117116getCategory :: MonadMetadata m => Identifier -> m [String]
118117getCategory = return . return . takeBaseName . takeDirectory . toFilePath
119118
lib/Hakyll/Web/Template.hs → src/Hakyll/Web/Template.hsrenamed−24
@@ -138,7 +138,6 @@
138138-- > 3...2...1
139139-- > </p>
140140--
141−{-# LANGUAGE TemplateHaskell #-}
142141module Hakyll.Web.Template
143142 ( Template
144143 , templateBodyCompiler
@@ -147,32 +146,9 @@ module Hakyll.Web.Template
147146 , loadAndApplyTemplate
148147 , applyAsTemplate
149148 , readTemplate
150− , compileTemplateItem
151149 , unsafeReadTemplateFile
152− , embedTemplate
153150 ) where
154151
155152
156153--------------------------------------------------------------------------------
157154import Hakyll.Web.Template.Internal
158−
159−
160−--------------------------------------------------------------------------------
161−import Data.FileEmbed (embedFile)
162−import qualified Data.Text as T
163−import qualified Data.Text.Encoding as T
164−import Language.Haskell.TH (Exp, Q)
165−
166−
167−--------------------------------------------------------------------------------
168−-- | Embed template allows you embed a template within the Haskell binary.
169−-- Example:
170−--
171−-- > myTemplate :: Template
172−-- > myTemplate = $(embedTemplate "test.html")
173−embedTemplate :: FilePath -> Q Exp
174−embedTemplate filePath = [|
175− let source = T.unpack $ T.decodeUtf8 $(embedFile filePath) in
176− case parseTemplateElemsFile filePath source of
177− Left err -> error err
178− Right tpl -> template filePath tpl |]
lib/Hakyll/Web/Template/Context.hs → src/Hakyll/Web/Template/Context.hsrenamed+33−135
@@ -1,27 +1,6 @@
1−-- | This module provides 'Context's which are used to expand expressions in
2−-- templates and allow for arbitrary customisation.
3−--
4−-- 'Template's define a small expression DSL which consists of strings,
5−-- identifiers and function application. There is no type system, every value is
6−-- a string and on the top level they get substituted verbatim into the page.
7−--
8−-- For example, you can build a context that contains
9−--
10−-- > … <> functionField "concat" (const . concat) <> …
11−--
12−-- which will allow you to use the @concat@ identifier as a function that takes
13−-- arbitrarily many stings and concatenates them to a new string:
14−--
15−-- > $partial(concat("templates/categories/", category))$
16−--
17−-- This will evaluate the @category@ field in the context, then prepend he path,
18−-- and include the referenced file as a template.
19−
20−
211--------------------------------------------------------------------------------
222{-# LANGUAGE CPP #-}
233{-# LANGUAGE ExistentialQuantification #-}
24−{-# LANGUAGE RankNTypes #-}
254module Hakyll.Web.Template.Context
265 ( ContextField (..)
276 , Context (..)
@@ -49,17 +28,13 @@ module Hakyll.Web.Template.Context
4928 , teaserField
5029 , teaserFieldWithSeparator
5130 , missingField
52− , bindItem
5331 ) where
5432
5533
5634--------------------------------------------------------------------------------
5735import Control.Applicative (Alternative (..))
5836import Control.Monad (msum)
59−import Data.List (intercalate, tails)
60−#if MIN_VERSION_base(4,9,0)
61−import Data.Semigroup (Semigroup (..))
62−#endif
37+import Data.List (intercalate)
6338import Data.Time.Clock (UTCTime (..))
6439import Data.Time.Format (formatTime)
6540import qualified Data.Time.Format as TF
@@ -72,16 +47,13 @@ import Hakyll.Core.Metadata
7247import Hakyll.Core.Provider
7348import Hakyll.Core.Util.String (needlePrefix, splitAll)
7449import Hakyll.Web.Html
75−import Prelude hiding (id)
76−import System.FilePath (dropExtension, splitDirectories,
77− takeBaseName)
50+import System.FilePath (splitDirectories, takeBaseName)
7851
7952
8053--------------------------------------------------------------------------------
8154-- | Mostly for internal usage
8255data ContextField
83− = EmptyField
84− | StringField String
56+ = StringField String
8557 | forall a. ListField (Context a) [Item a]
8658
8759
@@ -106,123 +78,71 @@ newtype Context a = Context
10678
10779
10880--------------------------------------------------------------------------------
109−-- | Tries to find a key in the left context,
110−-- or when that fails in the right context.
111−#if MIN_VERSION_base(4,9,0)
112−instance Semigroup (Context a) where
113− (<>) (Context f) (Context g) = Context $ \k a i -> f k a i <|> g k a i
114−
115−instance Monoid (Context a) where
116− mempty = missingField
117− mappend = (<>)
118−#else
11981instance Monoid (Context a) where
12082 mempty = missingField
12183 mappend (Context f) (Context g) = Context $ \k a i -> f k a i <|> g k a i
122−#endif
12384
12485
12586--------------------------------------------------------------------------------
12687field' :: String -> (Item a -> Compiler ContextField) -> Context a
127−field' key value = Context $ \k _ i ->
128− if k == key
129− then value i
130− else noResult $ "Tried field " ++ key
88+field' key value = Context $ \k _ i -> if k == key then value i else empty
13189
13290
13391--------------------------------------------------------------------------------
134−-- | Constructs a new field for a 'Context'.
135−-- If the key matches, the compiler is run and its result is substituted in the
136−-- template.
137−--
138−-- If the compiler fails, the field will be considered non-existent
139−-- in an @$if()$@ macro or ultimately break the template application
140−-- (unless the key is found in another context when using '<>').
141−-- Use 'empty' or 'noResult' for intentional failures of fields used in
142−-- @$if()$@, to distinguish them from exceptions thrown with 'fail'.
92+-- | Constructs a new field in the 'Context.'
14393field
14494 :: String -- ^ Key
14595 -> (Item a -> Compiler String) -- ^ Function that constructs a value based
146− -- on the item (e.g. accessing metadata)
96+ -- on the item
14797 -> Context a
14898field key value = field' key (fmap StringField . value)
14999
150100
151101--------------------------------------------------------------------------------
152102-- | Creates a 'field' to use with the @$if()$@ template macro.
153−-- Attempting to substitute the field into the template will cause an error.
154103boolField
155104 :: String
156105 -> (Item a -> Bool)
157106 -> Context a
158−boolField name f = field' name (\i -> if f i
159− then return EmptyField
160− else noResult $ "Field " ++ name ++ " is false")
107+boolField name f = field name (\i -> if f i
108+ then pure (error $ unwords ["no string value for bool field:",name])
109+ else empty)
161110
162111
163112--------------------------------------------------------------------------------
164−-- | Creates a 'field' that does not depend on the 'Item' but always yields
165−-- the same string
166−constField :: String -- ^ Key
167− -> String -- ^ Value
168− -> Context a
113+-- | Creates a 'field' that does not depend on the 'Item'
114+constField :: String -> String -> Context a
169115constField key = field key . const . return
170116
171117
172118--------------------------------------------------------------------------------
173−-- | Creates a list field to be consumed by a @$for(…)$@ expression.
174−-- The compiler returns multiple items which are rendered in the loop body
175−-- with the supplied context.
176119listField :: String -> Context a -> Compiler [Item a] -> Context b
177120listField key c xs = listFieldWith key c (const xs)
178121
179122
180123--------------------------------------------------------------------------------
181−-- | Produces a new 'Context' which has list field 'key'. All fields from
182−-- 'c' are also accessible from the produced context.
183−-- Be careful when doing @listFieldWith k ca f <> cb@ as any fields in @ca@
184−-- will override fields in @cb@ with the same name.
185−-- Creates a list field like 'listField', but supplies the current page
186−-- to the compiler.
187124listFieldWith
188125 :: String -> Context a -> (Item b -> Compiler [Item a]) -> Context b
189126listFieldWith key c f = field' key $ fmap (ListField c) . f
190127
191128
192129--------------------------------------------------------------------------------
193−-- | Creates a variadic function field.
194−--
195−-- The function will be called with the dynamically evaluated string arguments
196−-- from the template as well as the page that is currently rendered.
197−functionField :: String -- ^ Key
198− -> ([String] -> Item a -> Compiler String) -- ^ Function
199− -> Context a
130+functionField :: String -> ([String] -> Item a -> Compiler String) -> Context a
200131functionField name value = Context $ \k args i ->
201132 if k == name
202133 then StringField <$> value args i
203− else noResult $ "Tried function field " ++ name
134+ else empty
204135
205136
206137--------------------------------------------------------------------------------
207−-- | Transform the respective string results of all fields in a context.
208−-- For example,
209−--
210−-- > mapContext (++"c") (constField "x" "a" <> constField "y" "b")
211−--
212−-- is equivalent to
213−--
214−-- > constField "x" "ac" <> constField "y" "bc"
215−--
216138mapContext :: (String -> String) -> Context a -> Context a
217139mapContext f (Context c) = Context $ \k a i -> do
218140 fld <- c k a i
219141 case fld of
220− EmptyField -> wrongType "boolField"
221142 StringField str -> return $ StringField (f str)
222− _ -> wrongType "ListField"
223− where
224− wrongType typ = fail $ "Hakyll.Web.Template.Context.mapContext: " ++
225− "can't map over a " ++ typ ++ "!"
143+ ListField _ _ -> fail $
144+ "Hakyll.Web.Template.Context.mapContext: " ++
145+ "can't map over a ListField!"
226146
227147--------------------------------------------------------------------------------
228148-- | A context that allows snippet inclusion. In processed file, use as:
@@ -231,15 +151,15 @@ mapContext f (Context c) = Context $ \k a i -> do
231151-- > $snippet("path/to/snippet/")$
232152-- > ...
233153--
234−-- The contents of the included file will not be interpolated like @partial@
235−-- does it.
154+-- The contents of the included file will not be interpolated.
236155--
237156snippetField :: Context String
238157snippetField = functionField "snippet" f
239158 where
240159 f [contentsPath] _ = loadBody (fromFilePath contentsPath)
241− f [] _ = fail "No argument to function 'snippet()'"
242− f _ _ = fail "Too many arguments to function 'snippet()'"
160+ f _ i = error $
161+ "Too many arguments to function 'snippet()' in item " ++
162+ show (itemIdentifier i)
243163
244164--------------------------------------------------------------------------------
245165-- | A context that contains (in that order)
@@ -259,7 +179,8 @@ defaultContext =
259179 metadataField `mappend`
260180 urlField "url" `mappend`
261181 pathField "path" `mappend`
262− titleField "title"
182+ titleField "title" `mappend`
183+ missingField
263184
264185
265186--------------------------------------------------------------------------------
@@ -277,20 +198,15 @@ bodyField key = field key $ return . itemBody
277198-- | Map any field to its metadata value, if present
278199metadataField :: Context a
279200metadataField = Context $ \k _ i -> do
280− let id = itemIdentifier i
281− empty' = noResult $ "No '" ++ k ++ "' field in metadata " ++
282− "of item " ++ show id
283− value <- getMetadataField id k
284− maybe empty' (return . StringField) value
201+ value <- getMetadataField (itemIdentifier i) k
202+ maybe empty (return . StringField) value
285203
286204
287205--------------------------------------------------------------------------------
288206-- | Absolute url to the resulting item
289207urlField :: String -> Context a
290−urlField key = field key $ \i -> do
291− let id = itemIdentifier i
292− empty' = fail $ "No route url found for item " ++ show id
293− fmap (maybe empty' toUrl) $ getRoute id
208+urlField key = field key $
209+ fmap (maybe empty toUrl) . getRoute . itemIdentifier
294210
295211
296212--------------------------------------------------------------------------------
@@ -341,12 +257,6 @@ titleField = mapContext takeBaseName . pathField
341257-- that begins with @yyyy-mm-dd@ . For example:
342258-- @folder//yyyy-mm-dd-title//dist//main.extension@ .
343259-- In case of multiple matches, the rightmost one is used.
344−--
345−-- As another alternative, if none of the above matches, and the file has a
346−-- path which contains nested directories specifying a date, then that date
347−-- will be used. In other words, if the path is of the form
348−-- @**//yyyy//mm//dd//**//main.extension@ .
349−-- As above, in case of multiple matches, the rightmost one is used.
350260
351261dateField :: String -- ^ Key in which the rendered date should be placed
352262 -> String -- ^ Format to use on the date
@@ -357,7 +267,7 @@ dateField = dateFieldWith defaultTimeLocale
357267--------------------------------------------------------------------------------
358268-- | This is an extended version of 'dateField' that allows you to
359269-- specify a time locale that is used for outputting the date. For more
360−-- details, see 'dateField' and 'formatTime'.
270+-- details, see 'dateField'.
361271dateFieldWith :: TimeLocale -- ^ Output time locale
362272 -> String -- ^ Destination key
363273 -> String -- ^ Format to use on the date
@@ -378,13 +288,12 @@ getItemUTC :: MonadMetadata m
378288getItemUTC locale id' = do
379289 metadata <- getMetadata id'
380290 let tryField k fmt = lookupString k metadata >>= parseTime' fmt
381− paths = splitDirectories $ (dropExtension . toFilePath) id'
291+ paths = splitDirectories $ toFilePath id'
382292
383293 maybe empty' return $ msum $
384294 [tryField "published" fmt | fmt <- formats] ++
385295 [tryField "date" fmt | fmt <- formats] ++
386− [parseTime' "%Y-%m-%d" $ intercalate "-" $ take 3 $ splitAll "-" fnCand | fnCand <- reverse paths] ++
387− [parseTime' "%Y-%m-%d" $ intercalate "-" $ fnCand | fnCand <- map (take 3) $ reverse . tails $ paths]
296+ [parseTime' "%Y-%m-%d" $ intercalate "-" $ take 3 $ splitAll "-" fnCand | fnCand <- reverse paths]
388297 where
389298 empty' = fail $ "Hakyll.Web.Template.Context.getItemUTC: " ++
390299 "could not parse time for " ++ show id'
@@ -412,16 +321,13 @@ getItemModificationTime identifier = do
412321
413322
414323--------------------------------------------------------------------------------
415−-- | Creates a field with the last modification date of the underlying item.
416324modificationTimeField :: String -- ^ Key
417325 -> String -- ^ Format
418− -> Context a -- ^ Resulting context
326+ -> Context a -- ^ Resuting context
419327modificationTimeField = modificationTimeFieldWith defaultTimeLocale
420328
421329
422330--------------------------------------------------------------------------------
423−-- | Creates a field with the last modification date of the underlying item
424−-- in a custom localisation format (see 'formatTime').
425331modificationTimeFieldWith :: TimeLocale -- ^ Time output locale
426332 -> String -- ^ Key
427333 -> String -- ^ Format
@@ -460,11 +366,10 @@ teaserFieldWithSeparator separator key snapshot = field key $ \item -> do
460366
461367
462368--------------------------------------------------------------------------------
463−-- | Constantly reports any field as missing. Mostly for internal usage,
464−-- it is the last choice in every context used in a template application.
465369missingField :: Context a
466−missingField = Context $ \k _ _ -> noResult $
467− "Missing field '" ++ k ++ "' in context"
370+missingField = Context $ \k _ i -> fail $
371+ "Missing field $" ++ k ++ "$ in context for item " ++
372+ show (itemIdentifier i)
468373
469374parseTimeM :: Bool -> TimeLocale -> String -> String -> Maybe UTCTime
470375#if MIN_VERSION_time(1,5,0)
@@ -472,10 +377,3 @@ parseTimeM = TF.parseTimeM
472377#else
473378parseTimeM _ = TF.parseTime
474379#endif
475−
476−--------------------------------------------------------------------------------
477−
478−-- | Binds an 'Item' to a given 'Context', allowing it to be combined with any
479−-- other 'Context' of any type.
480−bindItem :: Context a -> Item a -> forall b. Context b
481−bindItem (Context ctx) ia = Context $ \k args _ -> ctx k args ia
lib/Hakyll/Web/Template/Internal.hs → src/Hakyll/Web/Template/Internal.hsrenamed+45−103
@@ -1,18 +1,15 @@
1−{-# LANGUAGE DeriveAnyClass #-}
2−{-# LANGUAGE DeriveGeneric #-}
31{-# LANGUAGE GeneralizedNewtypeDeriving #-}
42{-# LANGUAGE ScopedTypeVariables #-}
5−
63module Hakyll.Web.Template.Internal
74 ( Template (..)
85 , template
96 , templateBodyCompiler
107 , templateCompiler
118 , applyTemplate
9+ , applyTemplate'
1210 , loadAndApplyTemplate
1311 , applyAsTemplate
1412 , readTemplate
15− , compileTemplateItem
1613 , unsafeReadTemplateFile
1714
1815 , module Hakyll.Web.Template.Internal.Element
@@ -21,19 +18,16 @@ module Hakyll.Web.Template.Internal
2118
2219
2320--------------------------------------------------------------------------------
24−import Control.Monad (forM)
25−import Control.Monad.Except (MonadError (..), catchError)
21+import Control.Monad.Except (MonadError (..))
2622import Data.Binary (Binary)
2723import Data.List (intercalate)
28−import qualified Data.List.NonEmpty as NonEmpty
2924import Data.Typeable (Typeable)
3025import GHC.Exts (IsString (..))
31−import GHC.Generics (Generic)
26+import Prelude hiding (id)
3227
3328
3429--------------------------------------------------------------------------------
3530import Hakyll.Core.Compiler
36−import Hakyll.Core.Compiler.Internal
3731import Hakyll.Core.Identifier
3832import Hakyll.Core.Item
3933import Hakyll.Core.Writable
@@ -44,10 +38,9 @@ import Hakyll.Web.Template.Internal.Trim
4438
4539--------------------------------------------------------------------------------
4640-- | Datatype used for template substitutions.
47−data Template = Template
48− { tplElements :: [TemplateElement]
49− , tplOrigin :: FilePath -- Only for error messages.
50− } deriving (Show, Eq, Generic, Binary, Typeable)
41+newtype Template = Template
42+ { unTemplate :: [TemplateElement]
43+ } deriving (Show, Eq, Binary, Typeable)
5144
5245
5346--------------------------------------------------------------------------------
@@ -63,68 +56,39 @@ instance IsString Template where
6356
6457--------------------------------------------------------------------------------
6558-- | Wrap the constructor to ensure trim is called.
66−template :: FilePath -> [TemplateElement] -> Template
67−template p = flip Template p . trim
59+template :: [TemplateElement] -> Template
60+template = Template . trim
6861
6962
7063--------------------------------------------------------------------------------
71−-- | Parse a string into a template.
72−-- You should prefer 'compileTemplateItem' over this.
7364readTemplate :: String -> Template
74−readTemplate = either error (template origin) . parseTemplateElemsFile origin
75− where
76− origin = "{literal}"
77−{-# DEPRECATED readTemplate "Use templateCompiler instead" #-}
78−
79−--------------------------------------------------------------------------------
80−-- | Parse an item body into a template.
81−-- Provides useful error messages in the 'Compiler' monad.
82−compileTemplateItem :: Item String -> Compiler Template
83−compileTemplateItem item = let file = itemIdentifier item
84− in compileTemplateFile file (itemBody item)
85−
86−--------------------------------------------------------------------------------
87−compileTemplateFile :: Identifier -> String -> Compiler Template
88−compileTemplateFile file = either fail (return . template origin)
89− . parseTemplateElemsFile origin
90− where
91− origin = show file
65+readTemplate = Template . trim . readTemplateElems
9266
9367--------------------------------------------------------------------------------
9468-- | Read a template, without metadata header
9569templateBodyCompiler :: Compiler (Item Template)
9670templateBodyCompiler = cached "Hakyll.Web.Template.templateBodyCompiler" $ do
9771 item <- getResourceBody
98− file <- getUnderlying
99− withItemBody (compileTemplateFile file) item
72+ file <- getResourceFilePath
73+ return $ fmap (template . readTemplateElemsFile file) item
10074
10175--------------------------------------------------------------------------------
10276-- | Read complete file contents as a template
10377templateCompiler :: Compiler (Item Template)
10478templateCompiler = cached "Hakyll.Web.Template.templateCompiler" $ do
10579 item <- getResourceString
106− file <- getUnderlying
107− withItemBody (compileTemplateFile file) item
80+ file <- getResourceFilePath
81+ return $ fmap (template . readTemplateElemsFile file) item
10882
10983
11084--------------------------------------------------------------------------------
111−-- | Interpolate template expressions from context values in a page
11285applyTemplate :: Template -- ^ Template
11386 -> Context a -- ^ Context
11487 -> Item a -- ^ Page
11588 -> Compiler (Item String) -- ^ Resulting item
11689applyTemplate tpl context item = do
117− body <- applyTemplate' (tplElements tpl) context item `catchError` handler
90+ body <- applyTemplate' (unTemplate tpl) context item
11891 return $ itemSetBody body item
119− where
120− tplName = tplOrigin tpl
121− itemName = show $ itemIdentifier item
122− handler es = fail $ "Hakyll.Web.Template.applyTemplate: Failed to " ++
123− (if tplName == itemName
124− then "interpolate template in item " ++ itemName
125− else "apply template " ++ tplName ++ " to item " ++ itemName) ++
126− ":\n" ++ intercalate ",\n" es
127−
12892
12993
13094--------------------------------------------------------------------------------
@@ -141,6 +105,9 @@ applyTemplate' tes context x = go tes
141105
142106 go = fmap concat . mapM applyElem
143107
108+ trimError = error $ "Hakyll.Web.Template.applyTemplate: template not " ++
109+ "fully trimmed."
110+
144111 ---------------------------------------------------------------------------
145112
146113 applyElem :: TemplateElement -> Compiler String
@@ -151,43 +118,29 @@ applyTemplate' tes context x = go tes
151118
152119 applyElem (Chunk c) = return c
153120
154− applyElem (Expr e) = withErrorMessage evalMsg (applyStringExpr typeMsg e)
155− where
156− evalMsg = "In expr '$" ++ show e ++ "$'"
157− typeMsg = "expr '$" ++ show e ++ "$'"
121+ applyElem (Expr e) = applyExpr e >>= getString e
158122
159123 applyElem Escaped = return "$"
160124
161− applyElem (If e t mf) = compilerTry (applyExpr e) >>= handle
125+ applyElem (If e t mf) = (applyExpr e >> go t) `catchError` handler
162126 where
163− f = maybe (return "") go mf
164− handle (Right _) = go t
165− handle (Left (CompilationNoResult _)) = f
166− handle (Left (CompilationFailure es)) = debug (NonEmpty.toList es) >> f
167− debug = compilerDebugEntries ("Hakyll.Web.Template.applyTemplate: " ++
168− "[ERROR] in 'if' condition on expr '" ++ show e ++ "':")
169−
170− applyElem (For e b s) = withErrorMessage headMsg (applyExpr e) >>= \cf -> case cf of
171− EmptyField -> expected "list" "boolean" typeMsg
172− StringField _ -> expected "list" "string" typeMsg
173− ListField c xs -> withErrorMessage bodyMsg $ do
127+ handler _ = case mf of
128+ Nothing -> return ""
129+ Just f -> go f
130+
131+ applyElem (For e b s) = applyExpr e >>= \cf -> case cf of
132+ StringField _ -> fail $
133+ "Hakyll.Web.Template.applyTemplateWith: expected ListField but " ++
134+ "got StringField for expr " ++ show e
135+ ListField c xs -> do
174136 sep <- maybe (return "") go s
175− bs <- forM xs $ applyTemplate' b $ c <> bindItem context x
137+ bs <- mapM (applyTemplate' b c) xs
176138 return $ intercalate sep bs
177− where
178− headMsg = "In expr '$for(" ++ show e ++ ")$'"
179− typeMsg = "loop expr '" ++ show e ++ "'"
180− bodyMsg = "In loop context of '$for(" ++ show e ++ ")$'"
181−
182− applyElem (Partial e) = withErrorMessage headMsg $
183− applyStringExpr typeMsg e >>= \p ->
184− withErrorMessage inclMsg $ do
185− tpl' <- loadBody (fromFilePath p)
186− itemBody <$> applyTemplate tpl' context x
187− where
188− headMsg = "In expr '$partial(" ++ show e ++ ")$'"
189− typeMsg = "partial expr '" ++ show e ++ "'"
190− inclMsg = "In inclusion of '$partial(" ++ show e ++ ")$'"
139+
140+ applyElem (Partial e) = do
141+ p <- applyExpr e >>= getString e
142+ Template tpl' <- loadBody (fromFilePath p)
143+ applyTemplate' tpl' context x
191144
192145 ---------------------------------------------------------------------------
193146
@@ -196,29 +149,17 @@ applyTemplate' tes context x = go tes
196149 applyExpr (Ident (TemplateKey k)) = context' k [] x
197150
198151 applyExpr (Call (TemplateKey k) args) = do
199− args' <- mapM (\e -> applyStringExpr (typeMsg e) e) args
152+ args' <- mapM (\e -> applyExpr e >>= getString e) args
200153 context' k args' x
201− where
202− typeMsg e = "argument '" ++ show e ++ "'"
203154
204155 applyExpr (StringLiteral s) = return (StringField s)
205156
206157 ----------------------------------------------------------------------------
207158
208− applyStringExpr :: String -> TemplateExpr -> Compiler String
209− applyStringExpr msg expr =
210− applyExpr expr >>= getString
211− where
212− getString EmptyField = expected "string" "boolean" msg
213− getString (StringField s) = return s
214− getString (ListField _ _) = expected "string" "list" msg
215−
216− expected typ act expr = fail $ unwords ["Hakyll.Web.Template.applyTemplate:",
217− "expected", typ, "but got", act, "for", expr]
218−
219− -- expected to never happen with all templates constructed by 'template'
220− trimError = fail $
221− "Hakyll.Web.Template.applyTemplate: template not fully trimmed."
159+ getString _ (StringField s) = return s
160+ getString e (ListField _ _) = fail $
161+ "Hakyll.Web.Template.applyTemplateWith: expected StringField but " ++
162+ "got ListField for expr " ++ show e
222163
223164
224165--------------------------------------------------------------------------------
@@ -248,14 +189,15 @@ loadAndApplyTemplate identifier context item = do
248189applyAsTemplate :: Context String -- ^ Context
249190 -> Item String -- ^ Item and template
250191 -> Compiler (Item String) -- ^ Resulting item
251−applyAsTemplate context item = do
252− tpl <- compileTemplateItem item
253− applyTemplate tpl context item
192+applyAsTemplate context item =
193+ let tpl = template $ readTemplateElemsFile file (itemBody item)
194+ file = toFilePath $ itemIdentifier item
195+ in applyTemplate tpl context item
254196
255197
256198--------------------------------------------------------------------------------
257199unsafeReadTemplateFile :: FilePath -> Compiler Template
258200unsafeReadTemplateFile file = do
259201 tpl <- unsafeCompiler $ readFile file
260− compileTemplateFile (fromFilePath file) tpl
261−{-# DEPRECATED unsafeReadTemplateFile "Use templateCompiler" #-}
202+ pure $ template $ readTemplateElemsFile file tpl
203+
lib/Hakyll/Web/Template/Internal/Element.hs → src/Hakyll/Web/Template/Internal/Element.hsrenamed+14−7
@@ -7,14 +7,14 @@ module Hakyll.Web.Template.Internal.Element
77 , TemplateExpr (..)
88 , TemplateElement (..)
99 , templateElems
10− , parseTemplateElemsFile
10+ , readTemplateElems
11+ , readTemplateElemsFile
1112 ) where
1213
1314
1415--------------------------------------------------------------------------------
15−import Control.Applicative ((<|>), (<*))
16+import Control.Applicative ((<|>))
1617import Control.Monad (void)
17−import Control.Arrow (left)
1818import Data.Binary (Binary, get, getWord8, put, putWord8)
1919import Data.List (intercalate)
2020import Data.Maybe (isJust)
@@ -107,10 +107,17 @@ instance Binary TemplateExpr where
107107 2 -> StringLiteral <$> get
108108 _ -> error "Hakyll.Web.Template.Internal: Error reading cached template"
109109
110+
111+--------------------------------------------------------------------------------
112+readTemplateElems :: String -> [TemplateElement]
113+readTemplateElems = readTemplateElemsFile "{literal}"
114+
115+
110116--------------------------------------------------------------------------------
111−parseTemplateElemsFile :: FilePath -> String -> Either String [TemplateElement]
112−parseTemplateElemsFile file = left (\e -> "Cannot parse template " ++ show e)
113− . P.parse (templateElems <* P.eof) file
117+readTemplateElemsFile :: FilePath -> String -> [TemplateElement]
118+readTemplateElemsFile file input = case P.parse templateElems file input of
119+ Left err -> error $ "Cannot parse template: " ++ show err
120+ Right t -> t
114121
115122
116123--------------------------------------------------------------------------------
@@ -160,7 +167,7 @@ trimOpen = do
160167--------------------------------------------------------------------------------
161168trimClose :: P.Parser Bool
162169trimClose = do
163− trimIfR <- P.optionMaybe $ (P.char '-')
170+ trimIfR <- P.optionMaybe $ P.try (P.char '-')
164171 void $ P.char '$'
165172 pure $ isJust trimIfR
166173
lib/Hakyll/Web/Template/Internal/Trim.hs → src/Hakyll/Web/Template/Internal/Trim.hsrenamed

The content is the same.

lib/Hakyll/Web/Template/List.hs → src/Hakyll/Web/Template/List.hsrenamed

The content is the same.

stack.yaml+7−27
@@ -1,33 +1,13 @@
1−resolver: lts-13.29
2−save-hackage-creds: false
1+resolver: nightly-2016-10-31
2+extra-package-dbs: []
3+extra-deps:
4+ - 'QuickCheck-2.9.2'
35
46flags:
57 hakyll:
6− previewServer: true
7− watchServer: true
8− checkExternal: true
9− usePandoc: true
10− buildWebsite: true
8+ previewServer: True
9+ watchServer: True
10+ checkExternal: True
1111
1212packages:
1313 - '.'
14−
15−nix:
16− enable: false
17− packages:
18− - zlib
19−
20−build:
21− haddock: true
22− haddock-hyperlink-source: true
23− haddock-deps: false
24−
25−extra-deps:
26−- 'cmark-gfm-0.2.0'
27−- 'hslua-module-system-0.2.1'
28−- 'ipynb-0.1'
29−- 'lrucache-1.2.0.1'
30−- 'pandoc-2.7.3'
31−- 'pandoc-citeproc-0.16.2'
32−- 'skylighting-0.8.2'
33−- 'skylighting-core-0.8.2'
test.hsdeleted−30
@@ -1,30 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−import Control.Monad (forM)
3−import qualified Crypto.Hash.SHA256 as SHA256
4−import qualified Data.ByteString.Base16 as Base16
5−import qualified Data.ByteString.Char8 as BS8
6−import qualified Data.ByteString.Lazy as BSL
7−import Data.Map (Map)
8−import qualified Data.Map as Map
9−import Hakyll
10−import System.FilePath ((</>))
11−
12−type FileHashes = Map Identifier String
13−
14−mkFileHashes :: FilePath -> IO FileHashes
15−mkFileHashes dir = do
16− allFiles <- getRecursiveContents (\_ -> return False) dir
17− fmap Map.fromList $ forM allFiles $ \path0 -> do
18− let path1 = dir </> path0
19− !h <- hash path1
20− return (fromFilePath path1, h)
21− where
22− hash :: FilePath -> IO String
23− hash fp = do
24− !h <- SHA256.hashlazy <$> BSL.readFile fp
25− return $! BS8.unpack $! Base16.encode h
26−
27−main :: IO ()
28−main = hakyll $ do
29− fileHashes <- preprocess (mkFileHashes "images")
30− undefined
tests/Hakyll/Core/Identifier/Tests.hs−1
@@ -42,7 +42,6 @@ captureTests = fromAssertions "capture"
4242 , Just ["lol", "fun/large"] @=? capture "*cat/**.jpg" "lolcat/fun/large.jpg"
4343 , Just [] @=? capture "\\*.jpg" "*.jpg"
4444 , Nothing @=? capture "\\*.jpg" "foo.jpg"
45− , Just ["xyz","42"] @=? capture (fromRegex "cat-([a-z]+)/foo([0-9]+).jpg") "cat-xyz/foo42.jpg"
4645 ]
4746
4847
tests/Hakyll/Core/Provider/Tests.hs+2−2
@@ -9,7 +9,7 @@ module Hakyll.Core.Provider.Tests
99import Hakyll.Core.Metadata
1010import Hakyll.Core.Provider
1111import Test.Tasty (TestTree, testGroup)
12−import Test.Tasty.HUnit (Assertion, testCase, (@=?))
12+import Test.Tasty.HUnit (Assertion, assert, testCase, (@=?))
1313import TestSuite.Util
1414
1515
@@ -25,7 +25,7 @@ case01 :: Assertion
2525case01 = do
2626 store <- newTestStore
2727 provider <- newTestProvider store
28− True @=? resourceExists provider "example.md"
28+ assert $ resourceExists provider "example.md"
2929
3030 metadata <- resourceMetadata provider "example.md"
3131 Just "An example" @=? lookupString "title" metadata
tests/Hakyll/Core/Rules/Tests.hs+4−3
@@ -17,9 +17,10 @@ import Hakyll.Core.Metadata
1717import Hakyll.Core.Routes
1818import Hakyll.Core.Rules
1919import Hakyll.Core.Rules.Internal
20+import Hakyll.Web.Pandoc
2021import System.FilePath ((</>))
2122import Test.Tasty (TestTree, testGroup)
22−import Test.Tasty.HUnit (Assertion, (@=?))
23+import Test.Tasty.HUnit (Assertion, assert, (@=?))
2324import TestSuite.Util
2425
2526
@@ -49,7 +50,7 @@ case01 = do
4950 checkRoute "example.mv1" (sv "mv1" "example.md")
5051 checkRoute "example.mv2" (sv "mv2" "example.md")
5152 checkRoute "food/example.md" (sv "metadataMatch" "example.md")
52− readIORef ioref >>= (True @=?)
53+ readIORef ioref >>= assert
5354 cleanTestEnv
5455 where
5556 sv g = setVersion (Just g)
@@ -74,7 +75,7 @@ rules01 ioref = do
7475 -- Compile some posts
7576 match "*.md" $ do
7677 route $ setExtension "html"
77− compile copyFileCompiler
78+ compile pandocCompiler
7879
7980 -- Yeah. I don't know how else to test this stuff?
8081 preprocess $ writeIORef ioref True
tests/Hakyll/Core/Runtime/Tests.hs+1−1
@@ -39,7 +39,7 @@ case01 = do
3939 compile $ do
4040 getResourceBody
4141 >>= saveSnapshot "raw"
42− >>= renderParagraphs
42+ >>= renderPandoc
4343
4444 match (fromList ["partial.html", "partial-helper.html"]) $
4545 compile templateCompiler
tests/Hakyll/Core/Store/Tests.hs+7−7
@@ -63,11 +63,11 @@ wrongType = do
6363 -- Store a string and try to fetch an int
6464 Store.set store ["foo", "bar"] ("qux" :: String)
6565 value <- Store.get store ["foo", "bar"] :: IO (Store.Result Int)
66− case value of
67− Store.WrongType e t -> do
68− typeOf (undefined :: Int) H.@=? e
69− typeOf (undefined :: String) H.@=? t
70− _ -> H.assertFailure "Expecting WrongType"
66+ H.assert $ case value of
67+ Store.WrongType e t ->
68+ e == typeOf (undefined :: Int) &&
69+ t == typeOf (undefined :: String)
70+ _ -> False
7171 cleanTestEnv
7272
7373
@@ -78,6 +78,6 @@ isMembertest = do
7878 Store.set store ["foo", "bar"] ("qux" :: String)
7979 good <- Store.isMember store ["foo", "bar"]
8080 bad <- Store.isMember store ["foo", "baz"]
81− True H.@=? good
82− False H.@=? bad
81+ H.assert good
82+ H.assert (not bad)
8383 cleanTestEnv
tests/Hakyll/Core/UnixFilter/Tests.hs+12−22
@@ -6,14 +6,15 @@ module Hakyll.Core.UnixFilter.Tests
66
77
88--------------------------------------------------------------------------------
9−import Test.Tasty (TestTree, testGroup)
10−import Test.Tasty.HUnit (testCase)
11−import qualified Test.Tasty.HUnit as H
9+import Data.List (isInfixOf)
10+import Test.Tasty (TestTree, testGroup)
11+import Test.Tasty.HUnit (testCase)
12+import qualified Test.Tasty.HUnit as H
1213
1314
1415--------------------------------------------------------------------------------
1516import Hakyll.Core.Compiler
16−import Hakyll.Core.Identifier
17+import Hakyll.Core.Compiler.Internal
1718import Hakyll.Core.Item
1819import Hakyll.Core.UnixFilter
1920import TestSuite.Util
@@ -24,20 +25,17 @@ tests :: TestTree
2425tests = testGroup "Hakyll.Core.UnixFilter.Tests"
2526 [ testCase "unixFilter rev" unixFilterRev
2627 , testCase "unixFilter false" unixFilterFalse
27− , testCase "unixFilter error" unixFilterError
2828 ]
2929
30−testMarkdown :: Identifier
31−testMarkdown = "russian.md"
3230
3331--------------------------------------------------------------------------------
3432unixFilterRev :: H.Assertion
3533unixFilterRev = do
3634 store <- newTestStore
3735 provider <- newTestProvider store
38− output <- testCompilerDone store provider testMarkdown compiler
39− expected <- testCompilerDone store provider testMarkdown getResourceString
40− rev (itemBody expected) H.@=? lines (itemBody output)
36+ output <- testCompilerDone store provider "russian.md" compiler
37+ expected <- testCompilerDone store provider "russian.md" getResourceString
38+ H.assert $ rev (itemBody expected) == lines (itemBody output)
4139 cleanTestEnv
4240 where
4341 compiler = getResourceString >>= withItemBody (unixFilter "rev" [])
@@ -49,18 +47,10 @@ unixFilterFalse :: H.Assertion
4947unixFilterFalse = do
5048 store <- newTestStore
5149 provider <- newTestProvider store
52− testCompilerError store provider testMarkdown compiler "exit code"
50+ result <- testCompiler store provider "russian.md" compiler
51+ H.assert $ case result of
52+ CompilerError es -> any ("exit code" `isInfixOf`) es
53+ _ -> False
5354 cleanTestEnv
5455 where
5556 compiler = getResourceString >>= withItemBody (unixFilter "false" [])
56−
57−
58−--------------------------------------------------------------------------------
59−unixFilterError :: H.Assertion
60−unixFilterError = do
61− store <- newTestStore
62− provider <- newTestProvider store
63− testCompilerError store provider testMarkdown compiler "option"
64− cleanTestEnv
65− where
66− compiler = getResourceString >>= withItemBody (unixFilter "head" ["-#"])
tests/Hakyll/Web/CompressCss/Tests.hs+11−12
@@ -5,8 +5,9 @@ module Hakyll.Web.CompressCss.Tests
55
66
77--------------------------------------------------------------------------------
8+import Data.Char (toUpper)
89import Test.Tasty (TestTree, testGroup)
9−import Test.Tasty.HUnit ((@=?))
10+import Test.Tasty.HUnit (assert, (@=?))
1011
1112
1213--------------------------------------------------------------------------------
@@ -20,9 +21,9 @@ tests = testGroup "Hakyll.Web.CompressCss.Tests" $ concat
2021 [ fromAssertions "compressCss"
2122 [
2223 -- compress whitespace
23− "something something" @=?
24+ " something something " @=?
2425 compressCss " something \n\t\r something "
25− -- do not compress whitespace in string tokens
26+ -- do not compress whitespace in constants
2627 , "abc \" \t\n\r \" xyz" @=?
2728 compressCss "abc \" \t\n\r \" xyz"
2829 , "abc ' \t\n\r ' xyz" @=?
@@ -30,7 +31,7 @@ tests = testGroup "Hakyll.Web.CompressCss.Tests" $ concat
3031
3132 -- strip comments
3233 , "before after" @=? compressCss "before /* abc { } ;; \n\t\r */ after"
33− -- don't strip comments inside string tokens
34+ -- don't strip comments inside constants
3435 , "before \"/* abc { } ;; \n\t\r */\" after"
3536 @=? compressCss "before \"/* abc { } ;; \n\t\r */\" after"
3637
@@ -41,23 +42,21 @@ tests = testGroup "Hakyll.Web.CompressCss.Tests" $ concat
4142 , "a>b" @=? compressCss "a > b"
4243 , "a+b" @=? compressCss "a + b"
4344 , "a!b" @=? compressCss "a ! b"
44− -- compress calc()
45− , "calc(1px + 100%/(5 + 3) - (3px + 2px)*5)" @=? compressCss "calc( 1px + 100% / ( 5 + 3) - calc( 3px + 2px ) * 5 )"
4645 -- compress whitespace even after this curly brace
4746 , "}" @=? compressCss "; } "
48− -- but do not compress separators inside string tokens
47+ -- but do not compress separators inside of constants
4948 , "\" { } ; , \"" @=? compressCss "\" { } ; , \""
50− -- don't compress separators at the start or end of string tokens
49+ -- don't compress separators at the start or end of constants
5150 , "\" }\"" @=? compressCss "\" }\""
5251 , "\"{ \"" @=? compressCss "\"{ \""
53− -- don't get irritated by the wrong token delimiter
52+ -- don't get irritated by the wrong constant terminator
5453 , "\" ' \"" @=? compressCss "\" ' \""
5554 , "' \" '" @=? compressCss "' \" '"
56− -- don't compress whitespace in the middle of a string
55+ -- don't compress whitespace around separators in constants in the middle of a string
5756 , "abc '{ '" @=? compressCss "abc '{ '"
5857 , "abc \"{ \"" @=? compressCss "abc \"{ \""
59− -- compress whitespace after colons (but not before)
60− , "abc :xyz" @=? compressCss "abc : xyz"
58+ -- compress whitespace around colons
59+ , "abc:xyz" @=? compressCss "abc : xyz"
6160 -- compress multiple semicolons
6261 , ";" @=? compressCss ";;;;;;;"
6362 ]
tests/Hakyll/Web/Html/Tests.hs+6−6
@@ -7,7 +7,7 @@ module Hakyll.Web.Html.Tests
77--------------------------------------------------------------------------------
88import Data.Char (toUpper)
99import Test.Tasty (TestTree, testGroup)
10−import Test.Tasty.HUnit ((@=?))
10+import Test.Tasty.HUnit (assert, (@=?))
1111
1212
1313--------------------------------------------------------------------------------
@@ -64,11 +64,11 @@ tests = testGroup "Hakyll.Web.Html.Tests" $ concat
6464 ]
6565
6666 , fromAssertions "isExternal"
67− [ True @=? isExternal "http://reddit.com"
68− , True @=? isExternal "https://mail.google.com"
69− , True @=? isExternal "//ajax.googleapis.com"
70− , False @=? isExternal "../header.png"
71− , False @=? isExternal "/foo/index.html"
67+ [ assert (isExternal "http://reddit.com")
68+ , assert (isExternal "https://mail.google.com")
69+ , assert (isExternal "//ajax.googleapis.com")
70+ , assert (not (isExternal "../header.png"))
71+ , assert (not (isExternal "/foo/index.html"))
7272 ]
7373
7474 , fromAssertions "stripTags"
tests/Hakyll/Web/Template/Context/Tests.hs+3−40
@@ -13,19 +13,16 @@ import Test.Tasty.HUnit (Assertion, testCase, (@=?))
1313--------------------------------------------------------------------------------
1414import Hakyll.Core.Compiler
1515import Hakyll.Core.Identifier
16−import Hakyll.Core.Item
1716import Hakyll.Core.Provider
1817import Hakyll.Core.Store (Store)
1918import Hakyll.Web.Template.Context
20−import Hakyll.Web.Template.Internal
2119import TestSuite.Util
2220
2321
2422--------------------------------------------------------------------------------
2523tests :: TestTree
26−tests = testGroup "Hakyll.Web.Template.Context.Tests"
24+tests = testGroup "Hakyll.Core.Template.Context.Tests"
2725 [ testCase "testDateField" testDateField
28− , testCase "testOuerLoopContextAccess" testOuerLoopContextAccess
2926 ]
3027
3128
@@ -44,15 +41,6 @@ testDateField = do
4441 dateField "date" "%B %e, %Y"
4542 date2 @=? "August 26, 2010"
4643
47− date3 <- testContextDone store provider
48− "posts/2018-09-26.md" "date" $
49− dateField "date" "%B %e, %Y"
50− date3 @=? "September 26, 2018"
51−
52− date4 <- testContextDone store provider
53− "posts/2019/05/10/tomorrow.md" "date" $
54− dateField "date" "%B %e, %Y"
55− date4 @=? "May 10, 2019"
5644 cleanTestEnv
5745
5846
@@ -65,31 +53,6 @@ testContextDone store provider identifier key context =
6553 cf <- unContext context key [] item
6654 case cf of
6755 StringField str -> return str
68− _ -> error $
56+ ListField _ _ -> error $
6957 "Hakyll.Web.Template.Context.Tests.testContextDone: " ++
70− "expected StringField"
71−
72−--------------------------------------------------------------------------------
73−
74−testOuerLoopContextAccess :: Assertion
75−testOuerLoopContextAccess = do
76− store <- newTestStore
77− provider <- newTestProvider store
78− test store provider ctx "baz"
79− test store provider (ctx' <> ctx) "not baz"
80− test store provider (ctx <> ctx') "baz"
81−
82− cleanTestEnv
83− where
84− tpl = readTemplate "$for(foo)$$for(bar)$$qux$$endfor$$endfor$"
85− ctx = mconcat [
86− field "qux" $ const $ return "baz"
87− , listField "foo" (listField "bar" mempty $ return [mockItem])
88− $ return [mockItem]
89− ]
90− ctx' = field "qux" $ const $ return "not baz"
91− mockItem = Item "" ()
92− test store provider context str = do
93− str' <- testCompilerDone store provider ""
94− $ applyTemplate tpl context mockItem
95− str @=? itemBody str'
58+ "Didn't expect ListField"
tests/Hakyll/Web/Template/Tests.hs+19−52
@@ -1,6 +1,5 @@
11--------------------------------------------------------------------------------
22{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE TemplateHaskell #-}
43module Hakyll.Web.Template.Tests
54 ( tests
65 ) where
@@ -8,16 +7,16 @@ module Hakyll.Web.Template.Tests
87
98--------------------------------------------------------------------------------
109import Test.Tasty (TestTree, testGroup)
11−import Test.Tasty.HUnit (Assertion, assertBool, testCase,
12− (@=?), (@?=))
10+import Test.Tasty.HUnit (Assertion, testCase, (@=?),
11+ (@?=))
1312
14−import Data.Either (isLeft)
1513
1614--------------------------------------------------------------------------------
1715import Hakyll.Core.Compiler
1816import Hakyll.Core.Identifier
1917import Hakyll.Core.Item
2018import Hakyll.Core.Provider
19+import Hakyll.Web.Pandoc
2120import Hakyll.Web.Template
2221import Hakyll.Web.Template.Context
2322import Hakyll.Web.Template.Internal
@@ -27,20 +26,20 @@ import TestSuite.Util
2726
2827--------------------------------------------------------------------------------
2928tests :: TestTree
30−tests = testGroup "Hakyll.Web.Template.Tests" $ concat
29+tests = testGroup "Hakyll.Core.Template.Tests" $ concat
3130 [ [ testCase "case01" $ test ("template.html.out", "template.html", "example.md")
3231 , testCase "case02" $ test ("strip.html.out", "strip.html", "example.md")
3332 , testCase "case03" $ test ("just-meta.html.out", "just-meta.html", "example.md")
3433 , testCase "applyJoinTemplateList" testApplyJoinTemplateList
3534 ]
3635
37− , fromAssertions "parseTemplate"
38− [ Right [Chunk "Hello ", Expr (Call "guest" [])]
39− @=? parse "Hello $guest()$"
40− , Right [If (Call "a" [StringLiteral "bar"]) [Chunk "foo"] Nothing]
41− @=? parse "$if(a(\"bar\"))$foo$endif$"
36+ , fromAssertions "readTemplate"
37+ [ [Chunk "Hello ", Expr (Call "guest" [])]
38+ @=? readTemplateElems "Hello $guest()$"
39+ , [If (Call "a" [StringLiteral "bar"]) [Chunk "foo"] Nothing]
40+ @=? readTemplateElems "$if(a(\"bar\"))$foo$endif$"
4241 -- 'If' trim check.
43− , Right [ TrimL
42+ , [ TrimL
4443 , If (Ident (TemplateKey "body"))
4544 [ TrimR
4645 , Chunk "\n"
@@ -56,39 +55,29 @@ tests = testGroup "Hakyll.Web.Template.Tests" $ concat
5655 ])
5756 , TrimR
5857 ]
59− @=? parse "$-if(body)-$\n$body$\n$-else-$\n$body$\n$-endif-$"
58+ @=? readTemplateElems "$-if(body)-$\n$body$\n$-else-$\n$body$\n$-endif-$"
6059 -- 'For' trim check.
61− , Right [ TrimL
60+ , [ TrimL
6261 , For (Ident (TemplateKey "authors"))
6362 [TrimR, Chunk "\n body \n", TrimL]
6463 Nothing
6564 , TrimR
6665 ]
67− @=? parse "$-for(authors)-$\n body \n$-endfor-$"
66+ @=? readTemplateElems "$-for(authors)-$\n body \n$-endfor-$"
6867 -- 'Partial' trim check.
69− , Right [ TrimL
68+ , [ TrimL
7069 , Partial (StringLiteral "path")
7170 , TrimR
7271 ]
73− @=? parse "$-partial(\"path\")-$"
72+ @=? readTemplateElems "$-partial(\"path\")-$"
7473 -- 'Expr' trim check.
75− , Right [ TrimL
74+ , [ TrimL
7675 , Expr (Ident (TemplateKey "foo"))
7776 , TrimR
7877 ]
79− @=? parse "$-foo-$"
80− -- fail on incomplete template.
81− , assertBool "did not yield error" $ isLeft $
82− parse "a$b"
83− -- fail on mismatched template syntax.
84− , assertBool "did not fail to parse" $ isLeft $
85− parse "$for(xs)$\n <p>foo</p>\n$endif$"
78+ @=? readTemplateElems "$-foo-$"
8679 ]
87−
88− , [testCase "embeddedTemplate" testEmbeddedTemplate]
8980 ]
90− where
91− parse = parseTemplateElemsFile ""
9281
9382
9483--------------------------------------------------------------------------------
@@ -100,9 +89,7 @@ test (outf, tplf, itemf) = do
10089 out <- resourceString provider outf
10190 tpl <- testCompilerDone store provider tplf templateBodyCompiler
10291 item <- testCompilerDone store provider itemf $
103− getResourceBody
104− >>= renderParagraphs
105− >>= applyTemplate (itemBody tpl) testContext
92+ pandocCompiler >>= applyTemplate (itemBody tpl) testContext
10693
10794 out @=? itemBody item
10895 cleanTestEnv
@@ -125,8 +112,6 @@ testApplyJoinTemplateList :: Assertion
125112testApplyJoinTemplateList = do
126113 store <- newTestStore
127114 provider <- newTestProvider store
128− tpl <- testCompilerDone store provider "tpl" $
129− compileTemplateItem (Item "tpl" "<b>$body$</b>")
130115 str <- testCompilerDone store provider "item3" $
131116 applyJoinTemplateList ", " tpl defaultContext [i1, i2]
132117
@@ -135,22 +120,4 @@ testApplyJoinTemplateList = do
135120 where
136121 i1 = Item "item1" "Hello"
137122 i2 = Item "item2" "World"
138−
139−
140−--------------------------------------------------------------------------------
141−embeddedTemplate :: Template
142−embeddedTemplate = $(embedTemplate "tests/data/embed.html")
143−
144−--------------------------------------------------------------------------------
145−testEmbeddedTemplate :: Assertion
146−testEmbeddedTemplate = do
147− store <- newTestStore
148− provider <- newTestProvider store
149− str <- testCompilerDone store provider "item3" $
150− applyTemplate embeddedTemplate defaultContext item
151−
152− itemBody str @?= "<p>Hello, world</p>\n"
153− cleanTestEnv
154− where
155− item = Item "item1" "Hello, world"
156−
123+ tpl = readTemplate "<b>$body$</b>"
tests/TestSuite.hs−7
@@ -1,5 +1,4 @@
11--------------------------------------------------------------------------------
2−{-# LANGUAGE CPP #-}
32module Main
43 ( main
54 ) where
@@ -23,12 +22,9 @@ import qualified Hakyll.Core.Util.String.Tests
2322import qualified Hakyll.Web.CompressCss.Tests
2423import qualified Hakyll.Web.Html.RelativizeUrls.Tests
2524import qualified Hakyll.Web.Html.Tests
26−#ifdef USE_PANDOC
2725import qualified Hakyll.Web.Pandoc.FileType.Tests
28−#endif
2926import qualified Hakyll.Web.Template.Context.Tests
3027import qualified Hakyll.Web.Template.Tests
31−import qualified Hakyll.Web.Tags.Tests
3228
3329
3430--------------------------------------------------------------------------------
@@ -47,10 +43,7 @@ main = defaultMain $ testGroup "Hakyll"
4743 , Hakyll.Web.CompressCss.Tests.tests
4844 , Hakyll.Web.Html.RelativizeUrls.Tests.tests
4945 , Hakyll.Web.Html.Tests.tests
50−#ifdef USE_PANDOC
5146 , Hakyll.Web.Pandoc.FileType.Tests.tests
52−#endif
53− , Hakyll.Web.Tags.Tests.tests
5447 , Hakyll.Web.Template.Context.Tests.tests
5548 , Hakyll.Web.Template.Tests.tests
5649 ]
tests/TestSuite/Util.hs+5−27
@@ -6,15 +6,13 @@ module TestSuite.Util
66 , newTestProvider
77 , testCompiler
88 , testCompilerDone
9− , testCompilerError
109 , testConfiguration
1110 , cleanTestEnv
12− , renderParagraphs
1311 ) where
1412
1513
1614--------------------------------------------------------------------------------
17−import Data.List (intercalate, isInfixOf)
15+import Data.List (intercalate)
1816import Data.Monoid (mempty)
1917import qualified Data.Set as S
2018import Test.Tasty
@@ -31,7 +29,6 @@ import Hakyll.Core.Provider
3129import Hakyll.Core.Store (Store)
3230import qualified Hakyll.Core.Store as Store
3331import Hakyll.Core.Util.File
34−import Hakyll.Core.Item
3532
3633
3734--------------------------------------------------------------------------------
@@ -79,23 +76,14 @@ testCompilerDone store provider underlying compiler = do
7976 result <- testCompiler store provider underlying compiler
8077 case result of
8178 CompilerDone x _ -> return x
82− CompilerError e -> fail $
79+ CompilerError e -> error $
8380 "TestSuite.Util.testCompilerDone: compiler " ++ show underlying ++
84− " threw: " ++ intercalate "; " (compilerErrorMessages e)
85− CompilerRequire i _ -> fail $
81+ " threw: " ++ intercalate "; " e
82+ CompilerRequire i _ -> error $
8683 "TestSuite.Util.testCompilerDone: compiler " ++ show underlying ++
8784 " requires: " ++ show i
88− CompilerSnapshot _ _ -> fail
89− "TestSuite.Util.testCompilerDone: unexpected CompilerSnapshot"
9085
91−testCompilerError :: Store -> Provider -> Identifier -> Compiler a -> String -> IO ()
92−testCompilerError store provider underlying compiler expectedMessage = do
93− result <- testCompiler store provider underlying compiler
94− case result of
95− CompilerError e ->
96− any (expectedMessage `isInfixOf`) (compilerErrorMessages e) @?
97− "Expecting '" ++ expectedMessage ++ "' error"
98− _ -> assertFailure "Expecting CompilerError"
86+
9987
10088--------------------------------------------------------------------------------
10189testConfiguration :: Configuration
@@ -113,13 +101,3 @@ cleanTestEnv = do
113101 removeDirectory $ destinationDirectory testConfiguration
114102 removeDirectory $ storeDirectory testConfiguration
115103 removeDirectory $ tmpDirectory testConfiguration
116−
117−
118−--------------------------------------------------------------------------------
119−-- | like 'Hakyll.Web.Pandoc.renderPandoc'
120−-- | but allowing to test without the @usePandoc@ flag
121−renderParagraphs :: Item String -> Compiler (Item String)
122−renderParagraphs = withItemBody (return
123− . intercalate "\n" -- no trailing line
124− . map (("<p>"++) . (++"</p>"))
125− . lines)
tests/data/embed.htmldeleted−1
@@ -1 +0,0 @@
1−<p>$body$</p>
tests/data/posts/2018-09-26.mddeleted−1
@@ -1 +0,0 @@
1−Something happened today.
tests/data/posts/2019/05/10/tomorrow.mddeleted−1
@@ -1 +0,0 @@
1−This day hasn't happened yet (as of writing this).
web/css/syntax.css+18−61
@@ -1,61 +1,18 @@
1−a.sourceLine { display: inline-block; line-height: 1.25; }
2−a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
3−a.sourceLine:empty { height: 1.2em; }
4−.sourceCode { overflow: visible; }
5−code.sourceCode { white-space: pre; position: relative; }
6−div.sourceCode { margin: 1em 0; }
7−pre.sourceCode { margin: 0; }
8−@media screen {
9−div.sourceCode { overflow: auto; }
10−}
11−@media print {
12−code.sourceCode { white-space: pre-wrap; }
13−a.sourceLine { text-indent: -1em; padding-left: 1em; }
14−}
15−pre.numberSource a.sourceLine
16− { position: relative; left: -4em; }
17−pre.numberSource a.sourceLine::before
18− { content: attr(title);
19− position: relative; left: -1em; text-align: right; vertical-align: baseline;
20− border: none; pointer-events: all; display: inline-block;
21− -webkit-touch-callout: none; -webkit-user-select: none;
22− -khtml-user-select: none; -moz-user-select: none;
23− -ms-user-select: none; user-select: none;
24− padding: 0 4px; width: 4em;
25− color: #aaaaaa;
26− }
27−pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
28−div.sourceCode
29− { }
30−@media screen {
31−a.sourceLine::before { text-decoration: underline; }
32−}
33−code span.al { color: #ff0000; font-weight: bold; } /* Alert */
34−code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
35−code span.at { color: #7d9029; } /* Attribute */
36−code span.bn { color: #40a070; } /* BaseN */
37−code span.bu { } /* BuiltIn */
38−code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
39−code span.ch { color: #4070a0; } /* Char */
40−code span.cn { color: #880000; } /* Constant */
41−code span.co { color: #60a0b0; font-style: italic; } /* Comment */
42−code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
43−code span.do { color: #ba2121; font-style: italic; } /* Documentation */
44−code span.dt { color: #902000; } /* DataType */
45−code span.dv { color: #40a070; } /* DecVal */
46−code span.er { color: #ff0000; font-weight: bold; } /* Error */
47−code span.ex { } /* Extension */
48−code span.fl { color: #40a070; } /* Float */
49−code span.fu { color: #06287e; } /* Function */
50−code span.im { } /* Import */
51−code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
52−code span.kw { color: #007020; font-weight: bold; } /* Keyword */
53−code span.op { color: #666666; } /* Operator */
54−code span.ot { color: #007020; } /* Other */
55−code span.pp { color: #bc7a00; } /* Preprocessor */
56−code span.sc { color: #4070a0; } /* SpecialChar */
57−code span.ss { color: #bb6688; } /* SpecialString */
58−code span.st { color: #4070a0; } /* String */
59−code span.va { color: #19177c; } /* Variable */
60−code span.vs { color: #4070a0; } /* VerbatimString */
61−code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
1+/* Generated by pandoc. */
2+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre
3+ { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; }
4+td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
5+td.sourceCode { padding-left: 5px; }
6+.sourceCode span.kw { color: #007020; font-weight: bold; }
7+.sourceCode span.dt { color: #902000; }
8+.sourceCode span.dv { color: #40a070; }
9+.sourceCode span.bn { color: #40a070; }
10+.sourceCode span.fl { color: #40a070; }
11+.sourceCode span.ch { color: #4070a0; }
12+.sourceCode span.st { color: #4070a0; }
13+.sourceCode span.co { color: #60a0b0; font-style: italic; }
14+.sourceCode span.ot { color: #007020; }
15+.sourceCode span.al { color: red; font-weight: bold; }
16+.sourceCode span.fu { color: #06287e; }
17+.sourceCode span.re { }
18+.sourceCode span.er { color: red; font-weight: bold; }
web/examples.markdown+30−32
@@ -36,6 +36,8 @@ directly with the default Hakyll site.
3636 [source](https://github.com/dannysu/hakyll-blog)
3737- <http://meta.plasm.us/>,
3838 [source](https://github.com/travisbrown/metaplasm)
39+- <http://www.web2day-nantes.org/>,
40+ [source](https://github.com/CompanyCampus/web2day2013)
3941- <http://workforpizza.com/>,
4042 [source](https://github.com/irneh/workforpizza)
4143- <http://poleiro.info/>,
@@ -45,7 +47,9 @@ directly with the default Hakyll site.
4547- <http://www.regisfoucault.com/>,
4648 [source](https://github.com/regisfoucault/blog)
4749- <http://www.chaoxuprime.com/>,
48− [source](https://github.com/chaoxu/chaoxu.github.io/tree/develop)
50+ [source](https://github.com/Mgccl/blog)
51+- <https://benjeffrey.com/>,
52+ [source](https://github.com/jeffbr13/benjeffrey.com)
4953- <http://www.skybluetrades.net/>,
5054 [source](https://github.com/ian-ross/blog)
5155- <http://chromaticleaves.com/>,
@@ -56,6 +60,8 @@ directly with the default Hakyll site.
5660 [source](https://github.com/blaenk/blaenk.github.io)
5761- <https://xinitrc.de/>,
5862 [source](https://github.com/xinitrc/xinitrc.de)
63+- <http://blog.darkfox.id.au/>,
64+ [source](http://hub.darcs.net/DarkFox/DarkFox-blog)
5965- <http://nickcharlton.net/>,
6066 [source](https://github.com/nickcharlton/nickcharlton.net)
6167- <http://scr.stunts.hu/>,
@@ -68,10 +74,16 @@ directly with the default Hakyll site.
6874 [source](https://github.com/walkie/WebPage)
6975- <http://techblog.rosedu.org/>,
7076 [source](https://github.com/rosedu/techblog)
77+- <http://abizern.org>,
78+ [source](https://github.com/Abizern/hblog)
7179- <http://freizl.github.io>,
7280 [source](https://github.com/freizl/freizl.github.com/tree/master/build)
81+- <http://covariant.me>,
82+ [source](http://hub.darcs.net/co-dan/website)
7383- <http://www.gwern.net/>,
7484 [source](https://github.com/gwern/gwern.net)
85+- <http://www.rohanjain.in/>,
86+ [source](https://github.com/crodjer/rohanjain.in)
7587- <http://www.corentindupont.info/>,
7688 [source](https://github.com/cdupont/CorentinDupont-WebPage)
7789- <http://jelv.is>,
@@ -80,8 +92,8 @@ directly with the default Hakyll site.
8092 [source](https://github.com/plaimi/www)
8193- <http://duplode.github.io/>,
8294 [source](https://github.com/duplode/duplode.github.io/tree/sources)
83−- <http://tzemanovic.github.io/>,
84− [source](https://github.com/tzemanovic/tzemanovic)
95+- <http://maseek.codes>,
96+ [source](https://github.com/maseek/maseek-codes)
8597- <http://listx.github.io>,
8698 [source](https://github.com/listx/listx_blog)
8799- <http://kyle.marek-spartz.org>,
@@ -92,20 +104,26 @@ directly with the default Hakyll site.
92104 [source](https://github.com/rbros/reichertbrothers.com)
93105- <http://alemedeiros.sdf.org>,
94106 [source](https://github.com/alemedeiros/homepage)
107+- <https://ruudvanasseldonk.com/>,
108+ [source](https://github.com/ruud-v-a/ruudvanasseldonk.com)
95109- <http://www.haskell.mn>,
96110 [source](https://github.com/HaskellMN/www.haskell.mn)
97111- <https://axiomatic.neophilus.net/>,
98112 [source](https://github.com/Libbum/AxiomaticSemantics)
99−- [https://tesser.org/](http://web.archive.org/web/20161022221713/https://tesser.org/),
113+- <https://tesser.org/>,
100114 [source](https://github.com/fractalcat/tesser.org)
101−- <https://weien.io/>,
102−  [source](https://github.com/wei2912/blog-src)
115+- <https://wei2912.github.io/>,
116+ [source](https://github.com/wei2912/blog_src)
103117- <http://www.metasepi.org/>,
104118 [source](https://github.com/metasepi/metasepi-website)
105119- <http://gisli.hamstur.is/>,
106120 [source](https://github.com/gislik/gisli.hamstur.is)
107121- <http://blog.ssanj.net/>,
108122 [source](https://github.com/ssanj/babyloncandle)
123+- <https://rockymadden.com/>,
124+ [source](https://github.com/rockymadden/rockymadden-web)
125+- <http://blog.dshevchenko.biz/>,
126+ [source](https://github.com/denisshevchenko/blog)
109127- <http://ruhaskell.org/>,
110128 [source](https://github.com/ruHaskell/ruhaskell)
111129- <http://www.haskell.od.ua/>,
@@ -126,6 +144,8 @@ directly with the default Hakyll site.
126144 [source](https://github.com/ismailmustafa/ismailmustafa.github.io/tree/hakyll)
127145- <http://lettier.github.io/>,
128146 [source](https://github.com/lettier/lettier.github.io)
147+- <http://jozefg.bitbucket.org/>,
148+ [source](https://github.com/jozefg/blog)
129149- <http://raindev.io>,
130150 [source](https://github.com/raindev/raindev.github.io)
131151- <http://hal2016.haskell.org/>,
@@ -154,36 +174,12 @@ directly with the default Hakyll site.
154174 [source](https://github.com/beerendlauwers/HaskAnything)
155175- <https://anler.me/>,
156176 [source](https://github.com/anler/anler.me)
177+- <https://www.brandonstil.es/>,
178+ [source](https://github.com/stilesb/brandonstil.es)
157179- <http://argumatronic.com/>,
158180 [source](https://gitlab.com/GinBaby/argumatronic/tree/master)
159181- <http://sillybytes.net/>,
160182 [source](https://github.com/sillybytes/sillybytes)
161−- <https://falconpilot.github.io/>,
162− [source](https://github.com/FalconPilot/falconpilot.github.io)
163−- <http://spyhop.cafe/>,
164− [source](https://github.com/thunky-monk/spyhop-cafe)
165−- <https://bendo.github.io/>,
166− [source](https://github.com/bendo/bendo.github.io)
167−- <http://adarsh.cc/>,
168− [source](https://github.com/adarshp/adarsh.cc)
169−- <http://0a.io>,
170− [source](https://github.com/arrchyy/0a.io)
171−- <https://nasy.moe/>,
172− [source](https://github.com/nasyxx/NasyMoe)
173−- <http://uniprocess.org/>,
174− [source](https://gitlab.com/uniprocess/uniprocess.org)
175−- <https://regularflolloping.com/>,
176− [source](https://github.com/techieAgnostic/rf)
177−- <http://enter-haken.github.io/>,
178− [source](https://github.com/enter-haken/blog)
179−- <https://modular.blind.guru/>,
180− [source](https://github.com/mlang/eurorack-metadata)
181−- <http://www.jonashietala.se/>,
182− [source](https://github.com/treeman/jonashietala)
183−- <https://abhinavsarkar.net/>,
184− [source](https://github.com/abhin4v/abhin4v.github.io)
185−- <https://dailyreadingnotes.com/>,
186− [source](https://github.com/hackeryarn/daily-reading-notes)
187183
188184## Hakyll 3.X
189185
@@ -211,5 +207,7 @@ directly with the default Hakyll site.
211207 [source](http://gitorious.org/shakthimaan-blog)
212208- <http://www.alfredodinapoli.com/>,
213209 [source](https://github.com/CharlesStain/alfredodinapoli.com)
210+- <http://datahackermd.com>,
211+ [source](http://github.com/akshayjshah/datahackermd)
214212- <http://michaelxavier.net>,
215213 [source](https://github.com/michaelxavier/michaelxavier.net)
web/libraries.markdown−1
@@ -18,4 +18,3 @@ Here is a list of the ones I know of (I would be happy to hear about others).
1818 a conversion tool from other blog engines to Hakyll.
1919- [hakyll-elm](https://hackage.haskell.org/package/hakyll-elm),
2020 Hakyll wrapper for the Elm compiler.
21−- [hakyll-sass](http://hackage.haskell.org/package/hakyll-sass), a compiler for SASS templates.
web/site.hs+32−14
@@ -1,7 +1,8 @@
11--------------------------------------------------------------------------------
22{-# LANGUAGE OverloadedStrings #-}
33import Control.Arrow (second)
4−import Control.Monad (filterM, forM_)
4+import Control.Monad (forM_)
5+import Data.Char (isDigit)
56import Data.List (isPrefixOf, sortBy)
67import Data.Monoid ((<>))
78import Data.Ord (comparing)
@@ -56,11 +57,17 @@ main = hakyllWith config $ do
5657 create ["tutorials.html"] $ do
5758 route idRoute
5859 compile $ do
59− ctx <- tutorialsCtx <$>
60+ tuts <-
6061 sortBy (comparing itemIdentifier) <$> loadAll "tutorials/*"
62+
63+ let tutorialsCtx =
64+ constField "title" "Tutorials" `mappend`
65+ listField "tutorials" tutorialCtx (return tuts) `mappend`
66+ defaultContext
67+
6168 makeItem ""
62− >>= loadAndApplyTemplate "templates/tutorials.html" ctx
63− >>= loadAndApplyTemplate "templates/default.html" ctx
69+ >>= loadAndApplyTemplate "templates/tutorials.html" tutorialsCtx
70+ >>= loadAndApplyTemplate "templates/default.html" tutorialsCtx
6471 >>= relativizeUrls
6572
6673 -- Templates
@@ -101,17 +108,28 @@ hackage url
101108 reverse $ splitPath url
102109
103110
111+--------------------------------------------------------------------------------
112+data TutorialType = SeriesTutorial | ArticlesTutorial | ExternalTutorial
113+ deriving (Eq)
114+
115+
104116--------------------------------------------------------------------------------
105117-- | Partition tutorials into tutorial series, other articles, external articles
106−tutorialsCtx :: [Item String] -> Context String
107−tutorialsCtx tuts =
108− constField "title" "Tutorials" <>
109− listField "main" defaultContext (ofType "main") <>
110− listField "articles" defaultContext (ofType "article") <>
111− listField "externals" defaultContext (ofType "external") <>
112− listField "robertwpearce" defaultContext (ofType "robertwpearce") <>
118+tutorialCtx :: Context String
119+tutorialCtx =
120+ field "isSeries" (isTutorialType SeriesTutorial) <>
121+ field "isArticle" (isTutorialType ArticlesTutorial) <>
122+ field "isExternal" (isTutorialType ExternalTutorial) <>
113123 defaultContext
114124 where
115− ofType ty = filterM (\item -> do
116− mbType <- getMetadataField (itemIdentifier item) "type"
117− return $ Just ty == mbType) tuts
125+ getTutorialType item = do
126+ mbExternal <- getMetadataField (itemIdentifier item) "external"
127+ return $ case mbExternal of
128+ Just _ -> ExternalTutorial
129+ _ -> case splitPath (toFilePath $ itemIdentifier item) of
130+ [_, (x : _)] -> if isDigit x then SeriesTutorial else ArticlesTutorial
131+ _ -> ArticlesTutorial
132+
133+ isTutorialType ty0 item = do
134+ ty1 <- getTutorialType item
135+ if ty0 == ty1 then return "yes" else fail "no"
web/templates/default.html+6−1
@@ -35,7 +35,12 @@
3535 <a href="/tutorials/faq.html">faq</a>
3636 <a href="/examples.html">examples</a>
3737 <a href="/releases.html">releases</a>
38− <a href="https://jaspervdj.be/contact.html#donate" target="_blank">donate</a>
38+
39+ <!-- Flattr button -->
40+ <h1>Donate</h1>
41+ <a href="https://flattr.com/thing/291889/Hakyll" target="_blank">
42+ <img src="https://api.flattr.com/button/flattr-badge-large.png"
43+ alt="Flattr this" title="Flattr this" border="0" /></a>
3944 </div>
4045
4146 <div id="content">
web/templates/tutorials.html+18−24
@@ -1,19 +1,23 @@
11<h1>Tutorials about Hakyll</h1>
22<h2 id="series">Tutorial series</h2>
33<ul>
4− $for(main)$
5− <li>
6− <a href="$url$">$title$</a>
7− </li>
4+ $for(tutorials)$
5+ $if(isSeries)$
6+ <li>
7+ <a href="$url$">$title$</a>
8+ </li>
9+ $endif$
810 $endfor$
911</ul>
1012<h2 id="articles">Other articles</h2>
1113<p>In no particular order:</p>
1214<ul>
13− $for(articles)$
14− <li>
15− <a href="$url$">$title$</a> by <em>$author$</em>
16− </li>
15+ $for(tutorials)$
16+ $if(isArticle)$
17+ <li>
18+ <a href="$url$">$title$</a> by <em>$author$</em>
19+ </li>
20+ $endif$
1721 $endfor$
1822</ul>
1923<h2 id="external-articles">External articles</h2>
@@ -24,22 +28,12 @@
2428</p>
2529<p>In no particular order:</p>
2630<ul>
27− $for(externals)$
28− <li>
29− <a href="$url$">$title$</a> by <em>$author$</em>
30− </li>
31− $endfor$
32−</ul>
33−<h2 id="robertwpearce">Robert Pearce's series</h2>
34−<p>
35− <a href="https://robertwpearce.com/">Robert Pearce</a> has been writing an
36− excellent tutorial-style series on Hakyll as well. You can find those here:
37−</p>
38−<ul>
39− $for(robertwpearce)$
40− <li>
41− <a href="$url$">$title$</a>
42− </li>
31+ $for(tutorials)$
32+ $if(isExternal)$
33+ <li>
34+ <a href="$url$">$title$</a> by <em>$author$</em>
35+ </li>
36+ $endif$
4337 $endfor$
4438</ul>
4539<p>
web/tutorials/01-installation.markdown+1−4
@@ -1,7 +1,6 @@
11---
22title: Installation
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Installation
@@ -18,8 +17,6 @@ different distributions. For installation from source (i.e. via Hackage),
1817Linux distro packages:
1918
2019- [Debian unstable](http://packages.debian.org/source/sid/haskell-hakyll)
21−- [Fedora](https://apps.fedoraproject.org/packages/ghc-hakyll)
22−- [Nix](https://nixos.org/nixos/packages.html#hakyll): `$ nix-env -i hakyll`
2320
2421Building the example site
2522-------------------------
@@ -28,7 +25,7 @@ Apart from the main Hakyll library, the cabal package also provides you with an
2825executable `hakyll-init` to create an example site. This is an easy way to get
2926started:
3027
31− $ stack exec hakyll-init my-site
28+ $ hakyll-init my-site
3229
3330This creates a folder `my-site` in the current directory, with some example
3431content and a generic configuration.
web/tutorials/02-basics.markdown−1
@@ -1,7 +1,6 @@
11---
22title: The basics
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Building and cleaning
web/tutorials/03-rules-routes-compilers.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Rules, routes and compilers
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Basic rules
web/tutorials/04-compilers.markdown+3−4
@@ -1,7 +1,6 @@
11---
22title: 'More on compilers: load, and templates'
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Loading items
@@ -93,7 +92,7 @@ And `$title$` like this:
9392titleContext :: Context a
9493titleContext = field "title" $ \item -> do
9594 metadata <- getMetadata (itemIdentifier item)
96− return $ fromMaybe "No title" $ lookupString "title" metadata
95+ return $ fromMaybe "No title" $ M.lookup "title" metadata
9796```
9897
9998And compose them using the `Monoid` instance:
@@ -131,7 +130,7 @@ postCtx =
131130### Loading and applying templates
132131
133132Now we know about templates, context and how to load arbitrary items. This gives
134−us enough background information in order to understand how you can apply a
133+us enough background information in order to understand you can apply a
135134template:
136135
137136```haskell
@@ -152,7 +151,7 @@ Control flow in templates
152151-------------------------
153152
154153Sometimes string interpolation does not suffice, and you want a little more
155−control over how your templates are laid out. Hakyll provides a few control
154+control over how your templates are layed out. Hakyll provides a few control
156155structures for this. The syntax for these structures was based on the syntax
157156used in pandoc templates, since Hakyll already has tight integration with
158157pandoc.
web/tutorials/05-snapshots-feeds.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Snapshots, and how to produce an RSS/Atom feed
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Basic feed configuration
web/tutorials/06-versions.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Producing multiple versions of a single file
33author: Jasper Van der Jeugt
4−type: main
54---
65
76Basics
web/tutorials/a-guide-to-the-hakyll-module-zoo.markdown−1
@@ -1,7 +1,6 @@
11---
22title: A Guide to the Hakyll Module Zoo
33author: Brent Yorgey
4−type: article
54---
65
76The hakyll package [contains a bewildering array](/reference/) of modules, and
web/tutorials/external-add-tags-to-your-hakyll-blog.md+1−1
@@ -2,5 +2,5 @@
22title: Add tags to your Hakyll blog
33author: Javran Cheng
44url: https://javran.github.io/posts/2014-03-01-add-tags-to-your-hakyll-blog.html
5−type: external
5+external: true
66---
web/tutorials/external-blogger-port.md+1−1
@@ -2,5 +2,5 @@
22title: Port an existing Blogger blog to Hakyll
33author: Daniel Campoverde
44url: 'http://www.sillybytes.net/posts/from_blogger_to_hakyll.html'
5−type: external
5+external: true
66---
web/tutorials/external-cassius-template.md+1−1
@@ -2,5 +2,5 @@
22title: Using Cassius templating with Hakyll
33author: Daniel Campoverde
44url: 'http://www.sillybytes.net/posts/using_hakyll_with_cassius.html'
5−type: external
5+external: true
66---
web/tutorials/external-clean-urls-with-hakyll.md+1−1
@@ -2,5 +2,5 @@
22title: Clean URLs with Hakyll
33author: Rohan Jain
44url: http://www.rohanjain.in/hakyll-clean-urls/
5−type: external
5+external: true
66---
web/tutorials/external-deploying-with-widely.md+1−1
@@ -2,5 +2,5 @@
22title: Deploying with Widely
33author: Kyle Marek-Spartz
44url: http://kyle.marek-spartz.org/posts/2013-12-09-widely-and-hakyll.html
5−type: external
5+external: true
66---
web/tutorials/external-external-code-inclusion.mddeleted−6
@@ -1,6 +0,0 @@
1−---
2−title: 'External code inclusion with Hakyll'
3−author: 'Tobias Pleyer'
4−url: 'http://blog.tpleyer.de/posts/2019-04-21-external-code-inclusion-with-hakyll.html'
5−type: external
6−---
web/tutorials/external-functionfield.md+1−1
@@ -2,5 +2,5 @@
22title: Hakyll's functionField
33author: Beerend Lauwers
44url: http://beerendlauwers.be/posts/2015-09-21-hakylls-functionfield.html
5−type: external
5+external: true
66---
web/tutorials/external-github-pages-circle-ci.md+1−1
@@ -2,5 +2,5 @@
22title: Create a GitHub page with Hakyll and CircleCI
33author: Juan Pedro Villa
44url: https://www.stackbuilders.com/news/dr-hakyll-create-a-github-page-with-hakyll-and-circleci
5−type: external
5+external: true
66---
web/tutorials/external-inlining-and-compressing-css.md+1−1
@@ -2,5 +2,5 @@
22title: Inlining and compressing CSS
33author: Kyle Marek-Spartz
44url: http://kyle.marek-spartz.org/posts/2014-12-09-hakyll-css-template-compiler.html
5−type: external
5+external: true
66---
web/tutorials/external-live-reload.mdnew file+6
@@ -0,0 +1,6 @@
1+---
2+title: Live Reloading with Hakyll
3+author: Ben Kolera
4+url: 'http://benkolera.com/posts/2015-09-14-hakyll_livereload.html'
5+external: true
6+---
web/tutorials/faq.markdown−1
@@ -1,7 +1,6 @@
11---
22title: FAQ
33author: Jasper Van der Jeugt
4−type: article
54---
65
76## "hGetContents: invalid argument" or "commitBuffer: invalid argument"
web/tutorials/github-pages-tutorial.md−1
@@ -1,7 +1,6 @@
11---
22title: Using Hakyll with GitHub Pages
33author: Erik Stevenson
4−type: article
54---
65
76## Introduction
web/tutorials/hakyll-3-to-hakyll4-migration-guide.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Hakyll 3 to Hakyll 4 migration guide
33author: Jasper Van der Jeugt
4−type: article
54---
65
76Introduction
web/tutorials/robertwpearce-01-setup-and-initial-customization.htmldeleted−5
@@ -1,5 +0,0 @@
1−---
2−title: 'Pt. 1: Setup & Initial Customization'
3−url: 'https://robertwpearce.com/hakyll-pt-1-setup-and-initial-customization.html'
4−type: robertwpearce
5−---
web/tutorials/robertwpearce-02-generating-a-sitemap-xml-file.htmldeleted−5
@@ -1,5 +0,0 @@
1−---
2−title: 'Pt. 2: Generating a Sitemap XML File'
3−url: 'https://robertwpearce.com/hakyll-pt-2-generating-a-sitemap-xml-file.html'
4−type: robertwpearce
5−---
web/tutorials/robertwpearce-03-generating-rss-and-atom-xml-feeds.htmldeleted−5
@@ -1,5 +0,0 @@
1−---
2−title: 'Pt. 3: Generating RSS and Atom XML Feeds'
3−url: 'https://robertwpearce.com/hakyll-pt-3-generating-rss-and-atom-xml-feeds.html'
4−type: robertwpearce
5−---
web/tutorials/robertwpearce-04-copying-static-files-for-your-build.htmldeleted−5
@@ -1,5 +0,0 @@
1−---
2−title: 'Pt. 4: Copying Static Files For Your Build'
3−url: 'https://robertwpearce.com/hakyll-pt-4-copying-static-files-for-your-build.html'
4−type: robertwpearce
5−---
web/tutorials/robertwpearce-05-generating-custom-post-filenames-from-a-title-slug.htmldeleted−5
@@ -1,5 +0,0 @@
1−---
2−title: 'Pt. 5 – Generating Custom Post Filenames From a Title Slug'
3−url: 'https://robertwpearce.com/hakyll-pt-5-generating-custom-post-filenames-from-a-title-slug.html'
4−type: robertwpearce
5−---
web/tutorials/using-clay-with-hakyll.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Using Clay with Hakyll
33author: Jasper Van der Jeugt
4−type: article
54---
65
76[Clay](http://sebastiaanvisser.github.com/clay/) is a nice CSS preprocesser
web/tutorials/using-teasers-in-hakyll.markdown−1
@@ -1,7 +1,6 @@
11---
22title: Using teasers in Hakyll
33author: Ivan Veselov
4−type: article
54---
65
76## Introduction