on master help sign in
WIP
f0af2a3Jasper Van der Jeugt
hakyll.cabal+1−1
@@ -108,7 +108,6 @@ Library
108 Hakyll.Core.Util.String
108 Hakyll.Core.Util.String
109 Hakyll.Core.Writable
109 Hakyll.Core.Writable
110 Hakyll.Core.Writable.CopyFile
110 Hakyll.Core.Writable.CopyFile
111− Hakyll.Core.Writable.WritableTuple
112 Hakyll.Main
111 Hakyll.Main
113 Hakyll.Web.CompressCss
112 Hakyll.Web.CompressCss
114 -- Hakyll.Web.Feed
113 -- Hakyll.Web.Feed
@@ -129,6 +128,7 @@ Library
129 Other-Modules:
128 Other-Modules:
130 Hakyll.Core.CompiledItem
129 Hakyll.Core.CompiledItem
131 Hakyll.Core.Compiler.Internal
130 Hakyll.Core.Compiler.Internal
131+ Hakyll.Core.Compiler.Require
132 Hakyll.Core.DirectedGraph
132 Hakyll.Core.DirectedGraph
133 Hakyll.Core.DirectedGraph.Dot
133 Hakyll.Core.DirectedGraph.Dot
134 Hakyll.Core.ResourceProvider.Internal
134 Hakyll.Core.ResourceProvider.Internal
src/Hakyll.hs−2
@@ -18,7 +18,6 @@ module Hakyll
18 , module Hakyll.Core.Util.String
18 , module Hakyll.Core.Util.String
19 , module Hakyll.Core.Writable
19 , module Hakyll.Core.Writable
20 , module Hakyll.Core.Writable.CopyFile
20 , module Hakyll.Core.Writable.CopyFile
21− , module Hakyll.Core.Writable.WritableTuple
22 , module Hakyll.Main
21 , module Hakyll.Main
23 , module Hakyll.Web.CompressCss
22 , module Hakyll.Web.CompressCss
24 -- , module Hakyll.Web.Feed
23 -- , module Hakyll.Web.Feed
@@ -52,7 +51,6 @@ import Hakyll.Core.Util.File
52import Hakyll.Core.Util.String
51import Hakyll.Core.Util.String
53import Hakyll.Core.Writable
52import Hakyll.Core.Writable
54import Hakyll.Core.Writable.CopyFile
53import Hakyll.Core.Writable.CopyFile
55−import Hakyll.Core.Writable.WritableTuple
56import Hakyll.Main
54import Hakyll.Main
57import Hakyll.Web.CompressCss
55import Hakyll.Web.CompressCss
58-- import Hakyll.Web.Feed
56-- import Hakyll.Web.Feed
src/Hakyll/Core/Compiler.hs+76−332
@@ -1,97 +1,8 @@
1−-- | A Compiler manages targets and dependencies between targets
1+--------------------------------------------------------------------------------
2−--
3−-- The most distinguishing property of a 'Compiler' is that it is an Arrow. A
4−-- compiler of the type @Compiler a b@ is simply a compilation phase which takes
5−-- an @a@ as input, and produces a @b@ as output.
6−--
7−-- Compilers are chained using the '>>>' arrow operation. If we have a compiler
8−--
9−-- > getResourceString :: Compiler Resource String
10−--
11−-- which reads the resource, and a compiler
12−--
13−-- > readPage :: Compiler String (Page String)
14−--
15−-- we can chain these two compilers to get a
16−--
17−-- > (getResourceString >>> readPage) :: Compiler Resource (Page String)
18−--
19−-- Most compilers can be created by combining smaller compilers using '>>>'.
20−--
21−-- More advanced constructions are also possible using arrow, and sometimes
22−-- these are needed. For a good introduction to arrow, you can refer to
23−--
24−-- <http://en.wikibooks.org/wiki/Haskell/Understanding_arrows>
25−--
26−-- A construction worth writing a few paragraphs about here are the 'require'
27−-- functions. Different variants of this function are exported here, but they
28−-- all serve more or less the same goal.
29−--
30−-- When you use only '>>>' to chain your compilers, you get a linear pipeline --
31−-- it is not possible to add extra items from other compilers along the way.
32−-- This is where the 'require' functions come in.
33−--
34−-- This function allows you to reference other items, which are then added to
35−-- the pipeline. Let's look at this crappy ASCII illustration which represents
36−-- a pretty common scenario:
37−--
38−-- > read resource >>> pandoc render >>> layout >>> relativize URL's
39−-- >
40−-- > @templates/fancy.html@
41−--
42−-- We want to construct a pipeline of compilers to go from our resource to a
43−-- proper webpage. However, the @layout@ compiler takes more than just the
44−-- rendered page as input: it needs the @templates/fancy.html@ template as well.
45−--
46−-- This is an example of where we need the @require@ function. We can solve
47−-- this using a construction that looks like:
48−--
49−-- > ... >>> pandoc render >>> require >>> layout >>> ...
50−-- > |
51−-- > @templates/fancy.html@ ------/
52−--
53−-- This illustration can help us understand the type signature of 'require'.
54−--
55−-- > require :: (Binary a, Typeable a, Writable a)
56−-- > => Identifier a
57−-- > -> (b -> a -> c)
58−-- > -> Compiler b c
59−--
60−-- Let's look at it in detail:
61−--
62−-- > (Binary a, Typeable a, Writable a)
63−--
64−-- These are constraints for the @a@ type. @a@ (the template) needs to have
65−-- certain properties for it to be required.
66−--
67−-- > Identifier a
68−--
69−-- This is simply @templates/fancy.html@: the 'Identifier' of the item we want
70−-- to 'require', in other words, the name of the item we want to add to the
71−-- pipeline somehow.
72−--
73−-- > (b -> a -> c)
74−--
75−-- This is a function given by the user, specifying /how/ the two items shall be
76−-- merged. @b@ is the output of the previous compiler, and @a@ is the item we
77−-- just required -- the template. This means @c@ will be the final output of the
78−-- 'require' combinator.
79−--
80−-- > Compiler b c
81−--
82−-- Indeed, we have now constructed a compiler which takes a @b@ and produces a
83−-- @c@. This means that we have a linear pipeline again, thanks to the 'require'
84−-- function. So, the 'require' function actually helps to reduce to complexity
85−-- of Hakyll applications!
86−--
87−-- Note that require will fetch a previously compiled item: in our example of
88−-- the type @a@. It is /very/ important that the compiler which produced this
89−-- value, produced the right type as well!
90−--
91−{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
92module Hakyll.Core.Compiler
4module Hakyll.Core.Compiler
93 ( Compiler
5 ( Compiler
94− , runCompiler
95 , getIdentifier
6 , getIdentifier
96 , getRoute
7 , getRoute
97 , getRouteFor
8 , getRouteFor
@@ -99,95 +10,52 @@ module Hakyll.Core.Compiler
99 , getResourceString
10 , getResourceString
100 , getResourceLBS
11 , getResourceLBS
101 , getResourceWith
12 , getResourceWith
102− , fromDependency
103− , require_
104 , require
13 , require
105− , requireA
106− , requireAll_
107 , requireAll
14 , requireAll
108− , requireAllA
109 , cached
15 , cached
110 , unsafeCompiler
16 , unsafeCompiler
111− , traceShowCompiler
17+ , logCompiler
112 , timedCompiler
18 , timedCompiler
113− , byPattern
114− , byExtension
115 ) where
19 ) where
116
20
117−import Prelude hiding ((.), id)
118−import Control.Arrow ((>>>), (&&&), arr, first)
119−import Control.Applicative ((<$>), (*>))
120−import Control.Exception (SomeException, handle)
121−import Control.Monad.Reader (ask)
122−import Control.Monad.Trans (liftIO)
123−import Control.Monad.Error (throwError)
124−import Control.Category (Category, (.), id)
125−import Data.List (find)
126−import System.Environment (getProgName)
127−import System.FilePath (takeExtension)
128
21
129−import Data.Binary (Binary)
22+--------------------------------------------------------------------------------
23+import Control.Applicative ((<$>))
130−import Data.Typeable (Typeable)
24+import Data.Binary (Binary)
131−import Data.ByteString.Lazy (ByteString)
25+import Data.ByteString.Lazy (ByteString)
132−
26+import Data.Typeable (Typeable)
133−import Hakyll.Core.Identifier
27+import Prelude hiding (id, (.))
134−import Hakyll.Core.Identifier.Pattern
28+import System.Environment (getProgName)
135−import Hakyll.Core.CompiledItem
136−import Hakyll.Core.Writable
137−import Hakyll.Core.ResourceProvider
138−import Hakyll.Core.Compiler.Internal
139−import Hakyll.Core.Store (Store)
140−import Hakyll.Core.Routes
141−import Hakyll.Core.Logger
142−import qualified Hakyll.Core.Store as Store
143−
144−-- | Run a compiler, yielding the resulting target and it's dependencies. This
145−-- version of 'runCompilerJob' also stores the result
146−--
147−runCompiler :: Compiler CompiledItem -- ^ Compiler to run
148− -> Identifier () -- ^ Target identifier
149− -> ResourceProvider -- ^ Resource provider
150− -> [Identifier ()] -- ^ Universe
151− -> Routes -- ^ Route
152− -> Store -- ^ Store
153− -> Bool -- ^ Was the resource modified?
154− -> Logger -- ^ Logger
155− -> IO (Throwing CompiledItem) -- ^ Resulting item
156−runCompiler compiler id' provider universe routes store modified logger = do
157− -- Run the compiler job
158− result <- handle (\(e :: SomeException) -> return $ Left $ show e) $
159− runCompilerJob compiler id' provider universe routes store modified
160− logger
161
29
162− -- Inspect the result
163− case result of
164− -- In case we compiled an item, we will store a copy in the cache first,
165− -- before we return control. This makes sure the compiled item can later
166− -- be accessed by e.g. require.
167− Right (CompiledItem x) ->
168− Store.set store ["Hakyll.Core.Compiler.runCompiler", show id'] x
169
30
170− -- Otherwise, we do nothing here
31+--------------------------------------------------------------------------------
171− _ -> return ()
32+import Hakyll.Core.Compiler.Internal
33+import Hakyll.Core.Compiler.Require
34+import Hakyll.Core.Identifier
35+import Hakyll.Core.Logger
36+import Hakyll.Core.ResourceProvider
37+import Hakyll.Core.Routes
38+import qualified Hakyll.Core.Store as Store
39+import Hakyll.Core.Writable
172
40
173− return result
174
41
42+--------------------------------------------------------------------------------
175-- | Get the identifier of the item that is currently being compiled
43-- | Get the identifier of the item that is currently being compiled
176−--
177−getIdentifier :: Compiler (Identifier b)
44+getIdentifier :: Compiler Identifier
178−getIdentifier = fromJob $ const $ CompilerM $
179− castIdentifier . compilerIdentifier <$> ask
45+getIdentifier = compilerIdentifier <$> compilerAsk
46+
180
47
48+--------------------------------------------------------------------------------
181-- | Get the route we are using for this item
49-- | Get the route we are using for this item
182−--
183getRoute :: Compiler (Maybe FilePath)
50getRoute :: Compiler (Maybe FilePath)
184−getRoute = getIdentifier >>> getRouteFor
51+getRoute = getIdentifier >>= getRouteFor
185
52
53+
54+--------------------------------------------------------------------------------
186-- | Get the route for a specified item
55-- | Get the route for a specified item
187−--
188−getRouteFor :: Compiler (Identifier a -> Maybe FilePath)
56+getRouteFor :: Identifier -> Compiler (Maybe FilePath)
189−getRouteFor = fromJob $ \identifier -> CompilerM $ do
57+getRouteFor identifier = do
190− routes <- compilerRoutes <$> ask
58+ routes <- compilerRoutes <$> compilerAsk
191 return $ runRoutes routes identifier
59 return $ runRoutes routes identifier
192
60
193
61
@@ -197,7 +65,6 @@ getResourceBody :: Compiler String
197getResourceBody = getResourceWith resourceBody
65getResourceBody = getResourceWith resourceBody
198
66
199
67
200−
201--------------------------------------------------------------------------------
68--------------------------------------------------------------------------------
202-- | Get the resource we are compiling as a string
69-- | Get the resource we are compiling as a string
203getResourceString :: Compiler String
70getResourceString :: Compiler String
@@ -213,188 +80,65 @@ getResourceLBS = getResourceWith $ const resourceLBS
213
80
214--------------------------------------------------------------------------------
81--------------------------------------------------------------------------------
215-- | Overloadable function for 'getResourceString' and 'getResourceLBS'
82-- | Overloadable function for 'getResourceString' and 'getResourceLBS'
216−getResourceWith :: (ResourceProvider -> Identifier a -> IO b) -> Compiler b
83+getResourceWith :: (ResourceProvider -> Identifier -> IO a) -> Compiler a
217−getResourceWith reader = fromJob $ \_ -> CompilerM $ do
84+getResourceWith reader = do
218− provider <- compilerResourceProvider <$> ask
85+ provider <- compilerProvider <$> compilerAsk
219− r <- compilerIdentifier <$> ask
86+ id' <- compilerIdentifier <$> compilerAsk
220− let filePath = toFilePath r
87+ let filePath = toFilePath id'
221− if resourceExists provider r
88+ if resourceExists provider id'
222− then liftIO $ reader provider $ castIdentifier r
89+ then compilerUnsafeIO $ reader provider id'
223− else throwError $ error' filePath
90+ else compilerThrow $ error' filePath
224− where
225− error' id' = "Hakyll.Core.Compiler.getResourceWith: resource "
226− ++ show id' ++ " not found"
227−
228−-- | Auxiliary: get a dependency
229−--
230−getDependency :: (Binary a, Writable a, Typeable a)
231− => Identifier a -> CompilerM a
232−getDependency id' = CompilerM $ do
233− store <- compilerStore <$> ask
234− result <- liftIO $
235− Store.get store ["Hakyll.Core.Compiler.runCompiler", show id']
236− case result of
237− Store.NotFound -> throwError notFound
238− Store.WrongType e r -> throwError $ wrongType e r
239− Store.Found x -> return x
240− where
241− notFound =
242− "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was " ++
243− "not found in the cache, the cache might be corrupted or " ++
244− "the item you are referring to might not exist"
245− wrongType e r =
246− "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was found " ++
247− "in the cache, but does not have the right type: expected " ++ show e ++
248− " but got " ++ show r
249−
250−-- | Variant of 'require' which drops the current value
251−--
252−require_ :: (Binary a, Typeable a, Writable a)
253− => Identifier a
254− -> Compiler a
255−require_ identifier =
256− fromDependency identifier >>> fromJob (const $ getDependency identifier)
257−
258−-- | Require another target. Using this function ensures automatic handling of
259−-- dependencies
260−--
261−{-
262−require :: (Binary a, Typeable a, Writable a)
263− => Identifier a
264− -> (b -> a -> c)
265− -> Compiler b c
266−require identifier = requireA identifier . arr . uncurry
267−
268−-- | Arrow-based variant of 'require'
269−--
270−requireA :: (Binary a, Typeable a, Writable a)
271− => Identifier a
272− -> Compiler (b, a) c
273− -> Compiler b c
274−requireA identifier = (id &&& require_ identifier >>>)
275−-}
276−
277−-- | Variant of 'requireAll' which drops the current value
278−--
279−requireAll_ :: (Binary a, Typeable a, Writable a)
280− => Pattern a
281− -> Compiler [a]
282−requireAll_ pattern = fromDependencies (const getDeps) *> fromJob requireAll_'
283 where
91 where
284− getDeps = map castIdentifier . filterMatches pattern . map castIdentifier
92+ error' fp = "Hakyll.Core.Compiler.getResourceWith: resource " ++
285− requireAll_' = const $ CompilerM $ do
93+ show fp ++ " not found"
286− deps <- getDeps . compilerUniverse <$> ask
287− mapM (unCompilerM . getDependency) deps
288
94
289−-- | Require a number of targets. Using this function ensures automatic handling
290−-- of dependencies
291−--
292−{-
293−requireAll :: (Binary a, Typeable a, Writable a)
294− => Pattern a
295− -> (b -> [a] -> c)
296− -> Compiler b c
297−requireAll pattern = requireAllA pattern . arr . uncurry
298−
299−-- | Arrow-based variant of 'requireAll'
300−--
301−requireAllA :: (Binary a, Typeable a, Writable a)
302− => Pattern a
303− -> Compiler (b, [a]) c
304− -> Compiler b c
305−requireAllA pattern = (id &&& requireAll_ pattern >>>)
306−-}
307
95
96+--------------------------------------------------------------------------------
308cached :: (Binary a, Typeable a, Writable a)
97cached :: (Binary a, Typeable a, Writable a)
309 => String
98 => String
310 -> Compiler a
99 -> Compiler a
311 -> Compiler a
100 -> Compiler a
312−cached name (Compiler d j) = Compiler d $ CompilerM $ do
101+cached name compiler = do
313− logger <- compilerLogger <$> ask
102+ logger <- compilerLogger <$> compilerAsk
314− identifier <- castIdentifier . compilerIdentifier <$> ask
103+ id' <- compilerIdentifier <$> compilerAsk
315− store <- compilerStore <$> ask
104+ store <- compilerStore <$> compilerAsk
316− modified <- compilerResourceModified <$> ask
105+ provider <- compilerProvider <$> compilerAsk
317− progName <- liftIO getProgName
106+ modified <- compilerUnsafeIO $ resourceModified provider id'
107+ compilerUnsafeIO $ report logger $
318− report logger $ "Checking cache: " ++ if modified then "modified" else "OK"
108+ "Checking cache: " ++ if modified then "modified" else "OK"
319 if modified
109 if modified
320− then do v <- unCompilerM $ j ()
110+ then do
111+ x <- compiler
321− liftIO $ Store.set store [name, show identifier] v
112+ compilerUnsafeIO $ Store.set store [name, show id'] x
322− return v
113+ return x
114+ else do
323− else do v <- liftIO $ Store.get store [name, show identifier]
115+ x <- compilerUnsafeIO $ Store.get store [name, show id']
116+ progName <- compilerUnsafeIO getProgName
324− case v of Store.Found v' -> return v'
117+ case x of Store.Found x' -> return x'
325− _ -> throwError (error' progName)
118+ _ -> compilerThrow (error' progName)
326 where
119 where
327 error' progName =
120 error' progName =
328 "Hakyll.Core.Compiler.cached: Cache corrupt! " ++
121 "Hakyll.Core.Compiler.cached: Cache corrupt! " ++
329 "Try running: " ++ progName ++ " clean"
122 "Try running: " ++ progName ++ " clean"
330
123
331−-- | Create an unsafe compiler from a function in IO
332−--
333−unsafeCompiler :: (a -> IO b) -- ^ Function to lift
334− -> Compiler (a -> b) -- ^ Resulting compiler
335−unsafeCompiler f = fromJob $ CompilerM . liftIO . f
336
124
337−-- | Compiler for debugging purposes
125+--------------------------------------------------------------------------------
338−--
126+unsafeCompiler :: IO a -> Compiler a
339−traceShowCompiler :: Show a => Compiler a a
127+unsafeCompiler = compilerUnsafeIO
340−traceShowCompiler = fromJob $ \x -> CompilerM $ do
341− logger <- compilerLogger <$> ask
342− report logger $ show x
343− return x
344
128
345−-- | Log and time a compiler
346−--
347−timedCompiler :: String -- ^ Message
348− -> Compiler a b -- ^ Compiler to time
349− -> Compiler a b -- ^ Resulting compiler
350−timedCompiler msg (Compiler d j) = Compiler d $ \x -> CompilerM $ do
351− logger <- compilerLogger <$> ask
352− timed logger msg $ unCompilerM $ j x
353
129
354−-- | Choose a compiler by identifier
130+--------------------------------------------------------------------------------
355−--
131+-- | Compiler for debugging purposes
356−-- For example, assume that most content files need to be compiled
132+logCompiler :: String -> Compiler ()
357−-- normally, but a select few need an extra step in the pipeline:
133+logCompiler msg = do
358−--
134+ logger <- compilerLogger <$> compilerAsk
359−-- > compile $ pageCompiler >>> byPattern id
135+ compilerUnsafeIO $ report logger msg
360−-- > [ ("projects.md", addProjectListCompiler)
361−-- > , ("sitemap.md", addSiteMapCompiler)
362−-- > ]
363−--
364−byPattern :: Compiler a b -- ^ Default compiler
365− -> [(Pattern (), Compiler a b)] -- ^ Choices
366− -> Compiler a b -- ^ Resulting compiler
367−byPattern defaultCompiler choices = Compiler deps job
368− where
369− -- Lookup the compiler, give an error when it is not found
370− lookup' identifier = maybe defaultCompiler snd $
371− find (\(p, _) -> matches p identifier) choices
372− -- Collect the dependencies of the choice
373− deps = do
374− identifier <- castIdentifier . dependencyIdentifier <$> ask
375− compilerDependencies $ lookup' identifier
376− -- Collect the job of the choice
377− job x = CompilerM $ do
378− identifier <- castIdentifier . compilerIdentifier <$> ask
379− unCompilerM $ compilerJob (lookup' identifier) x
380
136
381−-- | Choose a compiler by extension
137+
382−--
138+--------------------------------------------------------------------------------
383−-- Example:
139+-- | Log and time a compiler
384−--
140+timedCompiler :: String -- ^ Message
385−-- > match "css/*" $ do
141+ -> Compiler a -- ^ Compiler to time
386−-- > route $ setExtension "css"
387−-- > compile $ byExtension (error "Not a (S)CSS file")
388−-- > [ (".css", compressCssCompiler)
389−-- > , (".scss", sass)
390−-- > ]
391−--
392−-- This piece of code will select the @compressCssCompiler@ for @.css@ files,
393−-- and the @sass@ compiler (defined elsewhere) for @.scss@ files.
394−--
395−byExtension :: Compiler a b -- ^ Default compiler
396− -> [(String, Compiler a b)] -- ^ Choices
397− -> Compiler a b -- ^ Resulting compiler
142+ -> Compiler a -- ^ Resulting compiler
398−byExtension defaultCompiler = byPattern defaultCompiler . map (first extPattern)
143+timedCompiler msg compiler = Compiler $ \r ->
399− where
144+ timed (compilerLogger r) msg $ unCompiler compiler r
400− extPattern c = predicate $ (== c) . takeExtension . toFilePath
src/Hakyll/Core/Compiler/Internal.hs+22−11
@@ -5,19 +5,21 @@
5module Hakyll.Core.Compiler.Internal
5module Hakyll.Core.Compiler.Internal
6 ( CompilerRead (..)
6 ( CompilerRead (..)
7 , CompilerResult (..)
7 , CompilerResult (..)
8− , Compiler
8+ , Compiler (..)
9 , runCompiler
9 , runCompiler
10 , compilerTell
10 , compilerTell
11 , compilerAsk
11 , compilerAsk
12 , compilerThrow
12 , compilerThrow
13 , compilerCatch
13 , compilerCatch
14 , compilerResult
14 , compilerResult
15+ , compilerUnsafeIO
15 ) where
16 ) where
16
17
17
18
18--------------------------------------------------------------------------------
19--------------------------------------------------------------------------------
19import Control.Applicative (Alternative (..),
20import Control.Applicative (Alternative (..),
20 Applicative (..))
21 Applicative (..))
22+import Control.Exception (SomeException, handle)
21import Data.Monoid (mappend, mempty)
23import Data.Monoid (mappend, mempty)
22
24
23
25
@@ -34,19 +36,17 @@ import Hakyll.Core.Store
34-- | Environment in which a compiler runs
36-- | Environment in which a compiler runs
35data CompilerRead = CompilerRead
37data CompilerRead = CompilerRead
36 { -- | Target identifier
38 { -- | Target identifier
37− compilerIdentifier :: Identifier
39+ compilerIdentifier :: Identifier
38 , -- | Resource provider
40 , -- | Resource provider
39− compilerResourceProvider :: ResourceProvider
41+ compilerProvider :: ResourceProvider
40 , -- | List of all known identifiers
42 , -- | List of all known identifiers
41− compilerUniverse :: [Identifier]
43+ compilerUniverse :: [Identifier]
42 , -- | Site routes
44 , -- | Site routes
43− compilerRoutes :: Routes
45+ compilerRoutes :: Routes
44 , -- | Compiler store
46 , -- | Compiler store
45− compilerStore :: Store
47+ compilerStore :: Store
46− , -- | Flag indicating if the underlying resource was modified
47− compilerResourceModified :: Bool
48 , -- | Logger
48 , -- | Logger
49− compilerLogger :: Logger
49+ compilerLogger :: Logger
50 }
50 }
51
51
52
52
@@ -111,7 +111,10 @@ instance Applicative Compiler where
111
111
112--------------------------------------------------------------------------------
112--------------------------------------------------------------------------------
113runCompiler :: Compiler a -> CompilerRead -> IO (CompilerResult a)
113runCompiler :: Compiler a -> CompilerRead -> IO (CompilerResult a)
114−runCompiler = unCompiler
114+runCompiler compiler read' = handle handler $ unCompiler compiler read'
115+ where
116+ handler :: SomeException -> IO (CompilerResult a)
117+ handler e = return $ CompilerError $ show e
115
118
116
119
117--------------------------------------------------------------------------------
120--------------------------------------------------------------------------------
@@ -128,7 +131,7 @@ compilerAsk = Compiler $ \r -> return $ CompilerDone r mempty
128
131
129
132
130--------------------------------------------------------------------------------
133--------------------------------------------------------------------------------
131−compilerTell :: [Dependency] -> Compiler ()
134+compilerTell :: CompilerWrite -> Compiler ()
132compilerTell deps = Compiler $ \_ -> return $ CompilerDone () deps
135compilerTell deps = Compiler $ \_ -> return $ CompilerDone () deps
133{-# INLINE compilerTell #-}
136{-# INLINE compilerTell #-}
134
137
@@ -154,3 +157,11 @@ compilerCatch (Compiler x) f = Compiler $ \r -> do
154compilerResult :: CompilerResult a -> Compiler a
157compilerResult :: CompilerResult a -> Compiler a
155compilerResult x = Compiler $ \_ -> return x
158compilerResult x = Compiler $ \_ -> return x
156{-# INLINE compilerResult #-}
159{-# INLINE compilerResult #-}
160+
161+
162+--------------------------------------------------------------------------------
163+compilerUnsafeIO :: IO a -> Compiler a
164+compilerUnsafeIO io = Compiler $ \_ -> do
165+ x <- io
166+ return $ CompilerDone x mempty
167+{-# INLINE compilerUnsafeIO #-}
src/Hakyll/Core/Compiler/Require.hsnew file+63
@@ -0,0 +1,63 @@
1+--------------------------------------------------------------------------------
2+module Hakyll.Core.Compiler.Require
3+ ( save
4+ , require
5+ , requireAll
6+ ) where
7+
8+
9+--------------------------------------------------------------------------------
10+import Control.Applicative ((<$>))
11+import Data.Binary (Binary)
12+import Data.Typeable
13+
14+
15+--------------------------------------------------------------------------------
16+import Hakyll.Core.Compiler.Internal
17+import Hakyll.Core.Dependencies
18+import Hakyll.Core.Identifier
19+import Hakyll.Core.Identifier.Pattern
20+import Hakyll.Core.Store (Store)
21+import qualified Hakyll.Core.Store as Store
22+
23+
24+--------------------------------------------------------------------------------
25+save :: (Binary a, Typeable a) => Store -> Identifier -> a -> IO ()
26+save store identifier x = Store.set store (key identifier) x
27+
28+
29+--------------------------------------------------------------------------------
30+require :: (Binary a, Typeable a) => Identifier -> Compiler a
31+require id' = do
32+ store <- compilerStore <$> compilerAsk
33+
34+ compilerTell [Identifier id']
35+ compilerResult $ CompilerRequire id' $ do
36+ result <- compilerUnsafeIO $ Store.get store (key id')
37+ case result of
38+ Store.NotFound -> compilerThrow notFound
39+ Store.WrongType e r -> compilerThrow $ wrongType e r
40+ Store.Found x -> return x
41+ where
42+ notFound =
43+ "Hakyll.Core.Compiler.Require.require: " ++ show id' ++ " was " ++
44+ "not found in the cache, the cache might be corrupted or " ++
45+ "the item you are referring to might not exist"
46+ wrongType e r =
47+ "Hakyll.Core.Compiler.Require.require: " ++ show id' ++ " was found " ++
48+ "in the cache, but does not have the right type: expected " ++ show e ++
49+ " but got " ++ show r
50+
51+
52+--------------------------------------------------------------------------------
53+requireAll :: (Binary a, Typeable a) => Pattern -> Compiler [a]
54+requireAll pattern = do
55+ universe <- compilerUniverse <$> compilerAsk
56+ let matching = filterMatches pattern universe
57+ compilerTell [Pattern pattern matching]
58+ mapM require matching
59+
60+
61+--------------------------------------------------------------------------------
62+key :: Identifier -> [String]
63+key identifier = ["Hakyll.Core.Compiler.Require", show identifier]
src/Hakyll/Core/Runtime.hs+11−9
@@ -23,6 +23,7 @@ import System.FilePath ((</>))
23--------------------------------------------------------------------------------
23--------------------------------------------------------------------------------
24import Hakyll.Core.CompiledItem
24import Hakyll.Core.CompiledItem
25import Hakyll.Core.Compiler.Internal
25import Hakyll.Core.Compiler.Internal
26+import Hakyll.Core.Compiler.Require
26import Hakyll.Core.Configuration
27import Hakyll.Core.Configuration
27import Hakyll.Core.Dependencies
28import Hakyll.Core.Dependencies
28import Hakyll.Core.Identifier
29import Hakyll.Core.Identifier
@@ -159,16 +160,14 @@ chase trail id'
159 config <- runtimeConfiguration <$> ask
160 config <- runtimeConfiguration <$> ask
160
161
161 section logger $ "Processing " ++ show id'
162 section logger $ "Processing " ++ show id'
162− isModified <- liftIO $ resourceModified provider id'
163 let compiler = todo M.! id'
163 let compiler = todo M.! id'
164 read' = CompilerRead
164 read' = CompilerRead
165− { compilerIdentifier = id'
165+ { compilerIdentifier = id'
166− , compilerResourceProvider = provider
166+ , compilerProvider = provider
167− , compilerUniverse = map fst universe
167+ , compilerUniverse = map fst universe
168− , compilerRoutes = routes
168+ , compilerRoutes = routes
169− , compilerStore = store
169+ , compilerStore = store
170− , compilerResourceModified = isModified
171− , compilerLogger = logger
170+ , compilerLogger = logger
172 }
171 }
173
172
174 result <- timed logger "Compiling" $ liftIO $ runCompiler compiler read'
173 result <- timed logger "Compiling" $ liftIO $ runCompiler compiler read'
@@ -177,7 +176,7 @@ chase trail id'
177 CompilerError e -> throwError e
176 CompilerError e -> throwError e
178
177
179 -- Huge success
178 -- Huge success
180− CompilerDone compiled facts -> do
179+ CompilerDone (CompiledItem compiled) facts -> do
181 -- Write if necessary
180 -- Write if necessary
182 case runRoutes routes id' of
181 case runRoutes routes id' of
183 Nothing -> return ()
182 Nothing -> return ()
@@ -186,6 +185,9 @@ chase trail id'
186 liftIO $ makeDirectories path
185 liftIO $ makeDirectories path
187 liftIO $ write path compiled
186 liftIO $ write path compiled
188
187
188+ -- Save! (For require)
189+ liftIO $ save store id' compiled
190+
189 -- Update state
191 -- Update state
190 modify $ \s -> s
192 modify $ \s -> s
191 { runtimeDone = S.insert id' (runtimeDone s)
193 { runtimeDone = S.insert id' (runtimeDone s)
src/Hakyll/Core/UnixFilter.hs+39−30
@@ -1,29 +1,32 @@
1+--------------------------------------------------------------------------------
1-- | A Compiler that supports unix filters.
2-- | A Compiler that supports unix filters.
2−--
3module Hakyll.Core.UnixFilter
3module Hakyll.Core.UnixFilter
4 ( unixFilter
4 ( unixFilter
5 , unixFilterLBS
5 , unixFilterLBS
6 ) where
6 ) where
7
7
8−import Control.Concurrent (forkIO)
9−import System.Posix.Process (executeFile, forkProcess)
10−import System.Posix.IO ( dupTo, createPipe, stdInput
11− , stdOutput, closeFd, fdToHandle
12− )
13−import System.IO ( Handle, hPutStr, hClose, hGetContents
14− , hSetEncoding, localeEncoding
15− )
16
8
9+--------------------------------------------------------------------------------
10+import Control.Concurrent (forkIO)
17−import Data.ByteString.Lazy (ByteString)
11+import Data.ByteString.Lazy (ByteString)
18import qualified Data.ByteString.Lazy as LB
12import qualified Data.ByteString.Lazy as LB
13+import System.IO (Handle, hClose, hGetContents, hPutStr,
14+ hSetEncoding, localeEncoding)
15+import System.Posix.IO (closeFd, createPipe, dupTo, fdToHandle,
16+ stdInput, stdOutput)
17+import System.Posix.Process (executeFile, forkProcess)
18+
19+
20+--------------------------------------------------------------------------------
21+import Hakyll.Core.Compiler
19
22
20−import Hakyll.Core.Compiler
21
23
24+--------------------------------------------------------------------------------
22-- | Use a unix filter as compiler. For example, we could use the 'rev' program
25-- | Use a unix filter as compiler. For example, we could use the 'rev' program
23-- as a compiler.
26-- as a compiler.
24--
27--
25−-- > rev :: Compiler Resource String
28+-- > rev :: Compiler String
26−-- > rev = getResourceString >>> unixFilter "rev" []
29+-- > rev = getResourceString >>= unixFilter "rev" []
27--
30--
28-- A more realistic example: one can use this to call, for example, the sass
31-- A more realistic example: one can use this to call, for example, the sass
29-- compiler on CSS files. More information about sass can be found here:
32-- compiler on CSS files. More information about sass can be found here:
@@ -34,12 +37,13 @@ import Hakyll.Core.Compiler
34--
37--
35-- > match "style.scss" $ do
38-- > match "style.scss" $ do
36-- > route $ setExtension "css"
39-- > route $ setExtension "css"
37−-- > compile $ getResourceString >>> unixFilter "sass" ["-s", "--scss"]
40+-- > compile $ getResourceString >>=
38−-- > >>> arr compressCss
41+-- > unixFilter "sass" ["-s", "--scss"] >>=
39−--
42+-- > compressCssCompiler
40−unixFilter :: String -- ^ Program name
43+unixFilter :: String -- ^ Program name
41− -> [String] -- ^ Program args
44+ -> [String] -- ^ Program args
45+ -> String -- ^ Program input
42− -> Compiler String String -- ^ Resulting compiler
46+ -> Compiler String -- ^ Program output
43unixFilter = unixFilterWith writer reader
47unixFilter = unixFilterWith writer reader
44 where
48 where
45 writer handle input = do
49 writer handle input = do
@@ -49,30 +53,35 @@ unixFilter = unixFilterWith writer reader
49 hSetEncoding handle localeEncoding
53 hSetEncoding handle localeEncoding
50 hGetContents handle
54 hGetContents handle
51
55
56+
57+--------------------------------------------------------------------------------
52-- | Variant of 'unixFilter' that should be used for binary files
58-- | Variant of 'unixFilter' that should be used for binary files
53--
59--
54-- > match "music.wav" $ do
60-- > match "music.wav" $ do
55-- > route $ setExtension "ogg"
61-- > route $ setExtension "ogg"
56−-- > compile $ getResourceLBS >>> unixFilter "oggenc" ["-"]
62+-- > compile $ getResourceLBS >>= unixFilter "oggenc" ["-"]
57−--
58−unixFilterLBS :: String -- ^ Program name
63+unixFilterLBS :: String -- ^ Program name
59− -> [String] -- ^ Program args
64+ -> [String] -- ^ Program args
65+ -> ByteString -- ^ Program input
60− -> Compiler ByteString ByteString -- ^ Resulting compiler
66+ -> Compiler ByteString -- ^ Program output
61unixFilterLBS = unixFilterWith LB.hPutStr LB.hGetContents
67unixFilterLBS = unixFilterWith LB.hPutStr LB.hGetContents
62
68
69+
70+--------------------------------------------------------------------------------
63-- | Overloaded compiler
71-- | Overloaded compiler
64−--
65unixFilterWith :: (Handle -> i -> IO ()) -- ^ Writer
72unixFilterWith :: (Handle -> i -> IO ()) -- ^ Writer
66 -> (Handle -> IO o) -- ^ Reader
73 -> (Handle -> IO o) -- ^ Reader
67 -> String -- ^ Program name
74 -> String -- ^ Program name
68 -> [String] -- ^ Program args
75 -> [String] -- ^ Program args
69− -> Compiler i o -- ^ Resulting compiler
76+ -> i -- ^ Program input
77+ -> Compiler o -- ^ Program output
70−unixFilterWith writer reader programName args =
78+unixFilterWith writer reader programName args input =
71 timedCompiler ("Executing external program " ++ programName) $
79 timedCompiler ("Executing external program " ++ programName) $
72− unsafeCompiler $ unixFilterIO writer reader programName args
80+ unsafeCompiler $ unixFilterIO writer reader programName args input
81+
73
82
83+--------------------------------------------------------------------------------
74-- | Internally used function
84-- | Internally used function
75−--
76unixFilterIO :: (Handle -> i -> IO ())
85unixFilterIO :: (Handle -> i -> IO ())
77 -> (Handle -> IO o)
86 -> (Handle -> IO o)
78 -> String
87 -> String
@@ -83,7 +92,7 @@ unixFilterIO writer reader programName args input = do
83 -- Create pipes
92 -- Create pipes
84 (stdinRead, stdinWrite) <- createPipe
93 (stdinRead, stdinWrite) <- createPipe
85 (stdoutRead, stdoutWrite) <- createPipe
94 (stdoutRead, stdoutWrite) <- createPipe
86−
95+
87 -- Fork the child
96 -- Fork the child
88 _ <- forkProcess $ do
97 _ <- forkProcess $ do
89 -- Copy our pipes over the regular stdin/stdout
98 -- Copy our pipes over the regular stdin/stdout
src/Hakyll/Core/Writable/CopyFile.hs+11−10
@@ -1,6 +1,7 @@
1--------------------------------------------------------------------------------
1--------------------------------------------------------------------------------
2-- | Exports simple compilers to just copy files
2-- | Exports simple compilers to just copy files
3+{-# LANGUAGE DeriveDataTypeable #-}
3−{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4module Hakyll.Core.Writable.CopyFile
5module Hakyll.Core.Writable.CopyFile
5 ( CopyFile (..)
6 ( CopyFile (..)
6 , copyFileCompiler
7 , copyFileCompiler
@@ -8,16 +9,16 @@ module Hakyll.Core.Writable.CopyFile
8
9
9
10
10--------------------------------------------------------------------------------
11--------------------------------------------------------------------------------
11−import Control.Arrow ((>>^))
12+import Control.Applicative ((<$>))
13+import Data.Binary (Binary)
14+import Data.Typeable (Typeable)
12−import System.Directory (copyFile)
15+import System.Directory (copyFile)
13−import Data.Typeable (Typeable)
14−import Data.Binary (Binary)
15
16
16
17
17--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
18−import Hakyll.Core.Writable
19−import Hakyll.Core.Compiler
19+import Hakyll.Core.Compiler
20−import Hakyll.Core.Identifier
20+import Hakyll.Core.Identifier
21+import Hakyll.Core.Writable
21
22
22
23
23--------------------------------------------------------------------------------
24--------------------------------------------------------------------------------
@@ -32,5 +33,5 @@ instance Writable CopyFile where
32
33
33
34
34--------------------------------------------------------------------------------
35--------------------------------------------------------------------------------
35−copyFileCompiler :: Compiler a CopyFile
36+copyFileCompiler :: Compiler CopyFile
36−copyFileCompiler = getIdentifier >>^ CopyFile . toFilePath
37+copyFileCompiler = CopyFile . toFilePath <$> getIdentifier
src/Hakyll/Core/Writable/WritableTuple.hsdeleted−37
@@ -1,37 +0,0 @@
1−-- | This module exposes a writable type 'WritableTuple' which is a simple
2−-- newtype wrapper around a tuple.
3−--
4−-- The idea is that, given a tuple @(a, b)@, @a@ is the value you actually want
5−-- to save to the disk, and @b@ is some additional info that you /don't/ want to
6−-- save, but that you need later, for example in a 'require' clause.
7−--
8−{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
9−module Hakyll.Core.Writable.WritableTuple
10− ( WritableTuple (..)
11− , writableTupleFst
12− , writableTupleSnd
13− , writableTupleCompiler
14− ) where
15−
16−import Control.Arrow (arr)
17−
18−import Data.Typeable (Typeable)
19−import Data.Binary (Binary)
20−
21−import Hakyll.Core.Writable
22−import Hakyll.Core.Compiler
23−
24−newtype WritableTuple a b = WritableTuple {unWritableTuple :: (a, b)}
25− deriving (Show, Eq, Ord, Binary, Typeable)
26−
27−instance Writable a => Writable (WritableTuple a b) where
28− write dst (WritableTuple (x, _)) = write dst x
29−
30−writableTupleFst :: WritableTuple a b -> a
31−writableTupleFst = fst . unWritableTuple
32−
33−writableTupleSnd :: WritableTuple a b -> b
34−writableTupleSnd = snd . unWritableTuple
35−
36−writableTupleCompiler :: Compiler (a, b) (WritableTuple a b)
37−writableTupleCompiler = arr WritableTuple
src/Hakyll/Web/CompressCss.hs+31−22
@@ -1,50 +1,59 @@
1+--------------------------------------------------------------------------------
1-- | Module used for CSS compression. The compression is currently in a simple
2-- | Module used for CSS compression. The compression is currently in a simple
2-- state, but would typically reduce the number of bytes by about 25%.
3-- state, but would typically reduce the number of bytes by about 25%.
3−--
4module Hakyll.Web.CompressCss
4module Hakyll.Web.CompressCss
5 ( compressCssCompiler
5 ( compressCssCompiler
6 , compressCss
6 , compressCss
7 ) where
7 ) where
8
8
9−import Data.Char (isSpace)
10−import Data.List (isPrefixOf)
11−import Control.Arrow ((>>^))
12
9
13−import Hakyll.Core.Compiler
10+--------------------------------------------------------------------------------
14−import Hakyll.Core.Util.String
11+import Control.Applicative ((<$>))
12+import Data.Char (isSpace)
13+import Data.List (isPrefixOf)
15
14
15+
16+--------------------------------------------------------------------------------
17+import Hakyll.Core.Compiler
18+import Hakyll.Core.Util.String
19+
20+
21+--------------------------------------------------------------------------------
16-- | Compiler form of 'compressCss'
22-- | Compiler form of 'compressCss'
17−--
18−compressCssCompiler :: Compiler a String
23+compressCssCompiler :: Compiler String
19−compressCssCompiler = getResourceString >>^ compressCss
24+compressCssCompiler = compressCss <$> getResourceString
25+
20
26
27+--------------------------------------------------------------------------------
21-- | Compress CSS to speed up your site.
28-- | Compress CSS to speed up your site.
22−--
23compressCss :: String -> String
29compressCss :: String -> String
24−compressCss = compressSeparators
30+compressCss = compressSeparators . stripComments . compressWhitespace
25− . stripComments
26− . compressWhitespace
27
31
32+
33+--------------------------------------------------------------------------------
28-- | Compresses certain forms of separators.
34-- | Compresses certain forms of separators.
29−--
30compressSeparators :: String -> String
35compressSeparators :: String -> String
31−compressSeparators = replaceAll "; *}" (const "}")
36+compressSeparators =
37+ replaceAll "; *}" (const "}") .
32− . replaceAll " *([{};:]) *" (take 1 . dropWhile isSpace)
38+ replaceAll " *([{};:]) *" (take 1 . dropWhile isSpace) .
33− . replaceAll ";+" (const ";")
39+ replaceAll ";+" (const ";")
40+
34
41
42+--------------------------------------------------------------------------------
35-- | Compresses all whitespace.
43-- | Compresses all whitespace.
36−--
37compressWhitespace :: String -> String
44compressWhitespace :: String -> String
38compressWhitespace = replaceAll "[ \t\n\r]+" (const " ")
45compressWhitespace = replaceAll "[ \t\n\r]+" (const " ")
39
46
47+
48+--------------------------------------------------------------------------------
40-- | Function that strips CSS comments away.
49-- | Function that strips CSS comments away.
41−--
42stripComments :: String -> String
50stripComments :: String -> String
43stripComments [] = []
51stripComments [] = []
44stripComments str
52stripComments str
45 | isPrefixOf "/*" str = stripComments $ eatComments $ drop 2 str
53 | isPrefixOf "/*" str = stripComments $ eatComments $ drop 2 str
46 | otherwise = head str : stripComments (drop 1 str)
54 | otherwise = head str : stripComments (drop 1 str)
47 where
55 where
48− eatComments str' | null str' = []
56+ eatComments str'
57+ | null str' = []
49− | isPrefixOf "*/" str' = drop 2 str'
58+ | isPrefixOf "*/" str' = drop 2 str'
50− | otherwise = eatComments $ drop 1 str'
59+ | otherwise = eatComments $ drop 1 str'
src/Hakyll/Web/Page.hs+6−9
@@ -58,9 +58,6 @@ module Hakyll.Web.Page
58
58
59
59
60--------------------------------------------------------------------------------
60--------------------------------------------------------------------------------
61−import Control.Arrow (arr, (>>>))
62−import Control.Category (id)
63−import Prelude hiding (id)
64import Text.Pandoc (Pandoc, ParserState, WriterOptions)
61import Text.Pandoc (Pandoc, ParserState, WriterOptions)
65
62
66
63
@@ -72,14 +69,14 @@ import Hakyll.Web.Pandoc
72
69
73--------------------------------------------------------------------------------
70--------------------------------------------------------------------------------
74-- | Read a page (do not render it)
71-- | Read a page (do not render it)
75−readPageCompiler :: Compiler () Page
72+readPageCompiler :: Compiler Page
76readPageCompiler = getResourceBody
73readPageCompiler = getResourceBody
77{-# DEPRECATED readPageCompiler "Use getResourceBody" #-}
74{-# DEPRECATED readPageCompiler "Use getResourceBody" #-}
78
75
79
76
80--------------------------------------------------------------------------------
77--------------------------------------------------------------------------------
81-- | Read a page render using pandoc
78-- | Read a page render using pandoc
82−pageCompiler :: Compiler () Page
79+pageCompiler :: Compiler Page
83pageCompiler =
80pageCompiler =
84 pageCompilerWith defaultHakyllParserState defaultHakyllWriterOptions
81 pageCompilerWith defaultHakyllParserState defaultHakyllWriterOptions
85
82
@@ -87,7 +84,7 @@ pageCompiler =
87--------------------------------------------------------------------------------
84--------------------------------------------------------------------------------
88-- | A version of 'pageCompiler' which allows you to specify your own pandoc
85-- | A version of 'pageCompiler' which allows you to specify your own pandoc
89-- options
86-- options
90−pageCompilerWith :: ParserState -> WriterOptions -> Compiler () Page
87+pageCompilerWith :: ParserState -> WriterOptions -> Compiler Page
91pageCompilerWith state options = pageCompilerWithPandoc state options id
88pageCompilerWith state options = pageCompilerWithPandoc state options id
92
89
93
90
@@ -96,9 +93,9 @@ pageCompilerWith state options = pageCompilerWithPandoc state options id
96-- pandoc transformation for the content
93-- pandoc transformation for the content
97pageCompilerWithPandoc :: ParserState -> WriterOptions
94pageCompilerWithPandoc :: ParserState -> WriterOptions
98 -> (Pandoc -> Pandoc)
95 -> (Pandoc -> Pandoc)
99− -> Compiler () Page
96+ -> Compiler Page
100pageCompilerWithPandoc state options f = cached cacheName $
97pageCompilerWithPandoc state options f = cached cacheName $
101− readPageCompiler >>> pageReadPandocWith state >>>
98+ readPageCompiler >>= pageReadPandocWith state >>=
102− arr (writePandocWith options . f)
99+ return . writePandocWith options . f
103 where
100 where
104 cacheName = "Hakyll.Web.Page.pageCompilerWithPandoc"
101 cacheName = "Hakyll.Web.Page.pageCompilerWithPandoc"
src/Hakyll/Web/Pandoc.hs+20−31
@@ -10,7 +10,6 @@ module Hakyll.Web.Pandoc
10 -- * Functions working on pages/compilers
10 -- * Functions working on pages/compilers
11 , pageReadPandoc
11 , pageReadPandoc
12 , pageReadPandocWith
12 , pageReadPandocWith
13− , pageReadPandocWithA
14 , pageRenderPandoc
13 , pageRenderPandoc
15 , pageRenderPandocWith
14 , pageRenderPandocWith
16
15
@@ -21,37 +20,34 @@ module Hakyll.Web.Pandoc
21
20
22
21
23--------------------------------------------------------------------------------
22--------------------------------------------------------------------------------
24−import Control.Arrow ((&&&), (***), (>>>), (>>^))
23+import Control.Applicative ((<$>))
25−import Control.Category (id)
26import Data.Maybe (fromMaybe)
24import Data.Maybe (fromMaybe)
27−import Prelude hiding (id)
28import Text.Pandoc
25import Text.Pandoc
29
26
30
27
31--------------------------------------------------------------------------------
28--------------------------------------------------------------------------------
32import Hakyll.Core.Compiler
29import Hakyll.Core.Compiler
33import Hakyll.Core.Identifier
30import Hakyll.Core.Identifier
34−import Hakyll.Core.Util.Arrow
35import Hakyll.Web.Page.Internal
31import Hakyll.Web.Page.Internal
36import Hakyll.Web.Pandoc.FileType
32import Hakyll.Web.Pandoc.FileType
37
33
38
34
39--------------------------------------------------------------------------------
35--------------------------------------------------------------------------------
40-- | Read a string using pandoc, with the default options
36-- | Read a string using pandoc, with the default options
41−readPandoc :: FileType -- ^ Determines how parsing happens
37+readPandoc :: FileType -- ^ Determines how parsing happens
42− -> Maybe (Identifier a) -- ^ Optional, for better error messages
38+ -> Maybe Identifier -- ^ Optional, for better error messages
43− -> Page -- ^ String to read
39+ -> Page -- ^ String to read
44− -> Pandoc -- ^ Resulting document
40+ -> Pandoc -- ^ Resulting document
45readPandoc = readPandocWith defaultHakyllParserState
41readPandoc = readPandocWith defaultHakyllParserState
46
42
47
43
48--------------------------------------------------------------------------------
44--------------------------------------------------------------------------------
49-- | Read a string using pandoc, with the supplied options
45-- | Read a string using pandoc, with the supplied options
50−readPandocWith :: ParserState -- ^ Parser options
46+readPandocWith :: ParserState -- ^ Parser options
51− -> FileType -- ^ Determines parsing method
47+ -> FileType -- ^ Determines parsing method
52− -> Maybe (Identifier a) -- ^ Optional, for better error messages
48+ -> Maybe Identifier -- ^ Optional, for better error messages
53− -> Page -- ^ String to read
49+ -> Page -- ^ String to read
54− -> Pandoc -- ^ Resulting document
50+ -> Pandoc -- ^ Resulting document
55readPandocWith state fileType' id' = case fileType' of
51readPandocWith state fileType' id' = case fileType' of
56 Html -> readHtml state
52 Html -> readHtml state
57 LaTeX -> readLaTeX state
53 LaTeX -> readLaTeX state
@@ -82,38 +78,31 @@ writePandocWith = writeHtmlString
82
78
83--------------------------------------------------------------------------------
79--------------------------------------------------------------------------------
84-- | Read the resource using pandoc
80-- | Read the resource using pandoc
85−pageReadPandoc :: Compiler Page Pandoc
81+pageReadPandoc :: Page -> Compiler Pandoc
86pageReadPandoc = pageReadPandocWith defaultHakyllParserState
82pageReadPandoc = pageReadPandocWith defaultHakyllParserState
87
83
88
84
89--------------------------------------------------------------------------------
85--------------------------------------------------------------------------------
90-- | Read the resource using pandoc
86-- | Read the resource using pandoc
91−pageReadPandocWith :: ParserState -> Compiler Page Pandoc
87+pageReadPandocWith :: ParserState -> Page -> Compiler Pandoc
92−pageReadPandocWith state = constA state &&& id >>> pageReadPandocWithA
88+pageReadPandocWith state page = do
93−
89+ identifier <- getIdentifier
94−
90+ fileType' <- getFileType
95−--------------------------------------------------------------------------------
91+ return $ readPandocWith state fileType' (Just identifier) page
96−-- | Read the resource using pandoc. This is a (rarely needed) variant, which
97−-- comes in very useful when the parser state is the result of some arrow.
98−pageReadPandocWithA :: Compiler (ParserState, Page) Pandoc
99−pageReadPandocWithA =
100− id *** id &&& getIdentifier &&& getFileType >>^ pageReadPandocWithA'
101− where
102− pageReadPandocWithA' (s, (p, (i, t))) = readPandocWith s t (Just i) p
103
92
104
93
105--------------------------------------------------------------------------------
94--------------------------------------------------------------------------------
106-- | Render the resource using pandoc
95-- | Render the resource using pandoc
107−pageRenderPandoc :: Compiler Page Page
96+pageRenderPandoc :: Page -> Compiler Page
108pageRenderPandoc =
97pageRenderPandoc =
109 pageRenderPandocWith defaultHakyllParserState defaultHakyllWriterOptions
98 pageRenderPandocWith defaultHakyllParserState defaultHakyllWriterOptions
110
99
111
100
112--------------------------------------------------------------------------------
101--------------------------------------------------------------------------------
113-- | Render the resource using pandoc
102-- | Render the resource using pandoc
114−pageRenderPandocWith :: ParserState -> WriterOptions -> Compiler Page Page
103+pageRenderPandocWith :: ParserState -> WriterOptions -> Page -> Compiler Page
115−pageRenderPandocWith state options =
104+pageRenderPandocWith state options page =
116− pageReadPandocWith state >>^ writePandocWith options
105+ writePandocWith options <$> pageReadPandocWith state page
117
106
118
107
119--------------------------------------------------------------------------------
108--------------------------------------------------------------------------------
src/Hakyll/Web/Pandoc/Biblio.hs+29−30
@@ -7,7 +7,9 @@
7-- refer to these files when you use 'pageReadPandocBiblio'. This function also
7-- refer to these files when you use 'pageReadPandocBiblio'. This function also
8-- takes a parser state for completeness -- you can use
8-- takes a parser state for completeness -- you can use
9-- 'defaultHakyllParserState' if you're unsure.
9-- 'defaultHakyllParserState' if you're unsure.
10+{-# LANGUAGE Arrows #-}
11+{-# LANGUAGE DeriveDataTypeable #-}
10−{-# LANGUAGE Arrows, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}
12+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
11module Hakyll.Web.Pandoc.Biblio
13module Hakyll.Web.Pandoc.Biblio
12 ( CSL
14 ( CSL
13 , cslCompiler
15 , cslCompiler
@@ -18,21 +20,20 @@ module Hakyll.Web.Pandoc.Biblio
18
20
19
21
20--------------------------------------------------------------------------------
22--------------------------------------------------------------------------------
21−import Control.Applicative ((<$>))
23+import Control.Applicative ((<$>))
22−import Control.Arrow (arr, returnA, (>>>))
24+import Data.Binary (Binary (..))
23−import Data.Typeable (Typeable)
25+import Data.Typeable (Typeable)
24−import Data.Binary (Binary (..))
26+import qualified Text.CSL as CSL
25−import Text.Pandoc (Pandoc, ParserState (..))
27+import Text.Pandoc (Pandoc, ParserState (..))
26−import Text.Pandoc.Biblio (processBiblio)
28+import Text.Pandoc.Biblio (processBiblio)
27−import qualified Text.CSL as CSL
28
29
29
30
30--------------------------------------------------------------------------------
31--------------------------------------------------------------------------------
31−import Hakyll.Core.Compiler
32+import Hakyll.Core.Compiler
32−import Hakyll.Core.Identifier
33+import Hakyll.Core.Identifier
33−import Hakyll.Core.Writable
34+import Hakyll.Core.Writable
34−import Hakyll.Web.Page
35+import Hakyll.Web.Page
35−import Hakyll.Web.Pandoc
36+import Hakyll.Web.Pandoc
36
37
37
38
38--------------------------------------------------------------------------------
39--------------------------------------------------------------------------------
@@ -41,8 +42,8 @@ newtype CSL = CSL FilePath
41
42
42
43
43--------------------------------------------------------------------------------
44--------------------------------------------------------------------------------
44−cslCompiler :: Compiler () CSL
45+cslCompiler :: Compiler CSL
45−cslCompiler = getIdentifier >>> arr (CSL . toFilePath)
46+cslCompiler = CSL . toFilePath <$> getIdentifier
46
47
47
48
48--------------------------------------------------------------------------------
49--------------------------------------------------------------------------------
@@ -61,26 +62,24 @@ instance Writable Biblio where
61
62
62
63
63--------------------------------------------------------------------------------
64--------------------------------------------------------------------------------
64−biblioCompiler :: Compiler () Biblio
65+biblioCompiler :: Compiler Biblio
65−biblioCompiler = getIdentifier >>>
66+biblioCompiler = do
67+ filePath <- toFilePath <$> getIdentifier
66− arr toFilePath >>> unsafeCompiler CSL.readBiblioFile >>> arr Biblio
68+ unsafeCompiler $ Biblio <$> CSL.readBiblioFile filePath
67
69
68
70
69--------------------------------------------------------------------------------
71--------------------------------------------------------------------------------
70pageReadPandocBiblio :: ParserState
72pageReadPandocBiblio :: ParserState
71− -> Identifier CSL
73+ -> CSL
72− -> Identifier Biblio
74+ -> Biblio
75+ -> Page
73− -> Compiler Page Pandoc
76+ -> Compiler Pandoc
74−pageReadPandocBiblio state csl refs = proc page -> do
77+pageReadPandocBiblio state (CSL csl) (Biblio refs) page = do
75− CSL csl' <- require_ csl -< ()
76− Biblio refs' <- require_ refs -< ()
77 -- We need to know the citation keys, add then *before* actually parsing the
78 -- We need to know the citation keys, add then *before* actually parsing the
78 -- actual page. If we don't do this, pandoc won't even consider them
79 -- actual page. If we don't do this, pandoc won't even consider them
79 -- citations!
80 -- citations!
80− let cits = map CSL.refId refs'
81+ let cits = map CSL.refId refs
81 state' = state {stateCitations = stateCitations state ++ cits}
82 state' = state {stateCitations = stateCitations state ++ cits}
82− pandoc <- pageReadPandocWithA -< (state', page)
83+ pandoc <- pageReadPandocWith state' page
83− pandoc' <- unsafeCompiler processBiblio' -< (csl', refs', pandoc)
84+ pandoc' <- unsafeCompiler $ processBiblio csl Nothing refs pandoc
84− returnA -< pandoc'
85+ return pandoc'
85− where
86− processBiblio' (c, r, p) = processBiblio c Nothing r p
src/Hakyll/Web/Pandoc/FileType.hs+3−3
@@ -8,7 +8,7 @@ module Hakyll.Web.Pandoc.FileType
8
8
9
9
10--------------------------------------------------------------------------------
10--------------------------------------------------------------------------------
11−import Control.Arrow ((>>^))
11+import Control.Applicative ((<$>))
12import System.FilePath (takeExtension)
12import System.FilePath (takeExtension)
13
13
14
14
@@ -62,5 +62,5 @@ fileType = fileType' . takeExtension
62
62
63--------------------------------------------------------------------------------
63--------------------------------------------------------------------------------
64-- | Get the file type for the current file
64-- | Get the file type for the current file
65−getFileType :: Compiler a FileType
65+getFileType :: Compiler FileType
66−getFileType = getIdentifier >>^ fileType . toFilePath
66+getFileType = fileType . toFilePath <$> getIdentifier
src/Hakyll/Web/Template/Context.hs+6−8
@@ -26,16 +26,14 @@ import Hakyll.Web.Urls
26
26
27
27
28--------------------------------------------------------------------------------
28--------------------------------------------------------------------------------
29−type Context a = Compiler (String, (Identifier a, a)) String
29+type Context a = String -> Identifier -> a -> Compiler String
30
30
31
31
32--------------------------------------------------------------------------------
32--------------------------------------------------------------------------------
33−field :: String -> Compiler (Identifier a, a) String -> Context a
33+field :: String -> (Identifier -> a -> Compiler String) -> Context a
34−field key value = arr checkKey >>> (empty ||| value)
34+field key value k' id' x
35− where
36− checkKey (k, x)
37− | k /= key = Left ()
35+ | k' == key = value id' x
38− | otherwise = Right x
36+ | otherwise = empty
39
37
40
38
41--------------------------------------------------------------------------------
39--------------------------------------------------------------------------------
@@ -51,7 +49,7 @@ defaultContext =
51
49
52--------------------------------------------------------------------------------
50--------------------------------------------------------------------------------
53bodyField :: String -> Context Page
51bodyField :: String -> Context Page
54−bodyField key = field key $ arr snd
52+bodyField key = field key $ \_ x -> return x
55
53
56
54
57--------------------------------------------------------------------------------
55--------------------------------------------------------------------------------
src/Hakyll/Web/Urls/Relativize.hs+6−8
@@ -21,10 +21,7 @@ module Hakyll.Web.Urls.Relativize
21
21
22
22
23--------------------------------------------------------------------------------
23--------------------------------------------------------------------------------
24−import Control.Arrow ((&&&), (>>^))
25−import Control.Category (id)
26import Data.List (isPrefixOf)
24import Data.List (isPrefixOf)
27−import Prelude hiding (id)
28
25
29
26
30--------------------------------------------------------------------------------
27--------------------------------------------------------------------------------
@@ -36,11 +33,12 @@ import Hakyll.Web.Urls
36--------------------------------------------------------------------------------
33--------------------------------------------------------------------------------
37-- | Compiler form of 'relativizeUrls' which automatically picks the right root
34-- | Compiler form of 'relativizeUrls' which automatically picks the right root
38-- path
35-- path
39−relativizeUrlsCompiler :: Compiler Page Page
36+relativizeUrlsCompiler :: Page -> Compiler Page
40−relativizeUrlsCompiler = getRoute &&& id >>^ uncurry relativize
37+relativizeUrlsCompiler page = do
41− where
38+ route <- getRoute
39+ return $ case route of
42− relativize Nothing = id
40+ Nothing -> page
43− relativize (Just r) = relativizeUrls $ toSiteRoot r
41+ Just r -> relativizeUrls (toSiteRoot r) page
44
42
45
43
46--------------------------------------------------------------------------------
44--------------------------------------------------------------------------------