@@ -103,6 +103,7 @@ module Hakyll.Core.Compiler
103103 , unsafeCompiler
104104 , mapCompiler
105105 , timedCompiler
106+ , byExtension
106107 ) where
107108
108109import Prelude hiding ((.), id)
@@ -112,6 +113,7 @@ import Control.Monad.Reader (ask)
112113import Control.Monad.Trans (liftIO)
113114import Control.Category (Category, (.), id)
114115import Data.Maybe (fromMaybe)
116+import System.FilePath (takeExtension)
115117
116118import Data.Binary (Binary)
117119import Data.Typeable (Typeable)
@@ -289,3 +291,34 @@ timedCompiler :: String -- ^ Message
289291timedCompiler msg (Compiler d j) = Compiler d $ \x -> CompilerM $ do
290292 logger <- compilerLogger <$> ask
291293 timed logger msg $ unCompilerM $ j x
294+
295+-- | Choose a compiler by extension
296+--
297+-- Example:
298+--
299+-- > route "css/*" $ setExtension "css"
300+-- > compile "css/*" $ byExtension (error "Not a (S)CSS file")
301+-- > [ (".css", compressCssCompiler)
302+-- > , (".scss", sass)
303+-- > ]
304+--
305+-- This piece of code will select the @compressCssCompiler@ for @.css@ files,
306+-- and the @sass@ compiler (defined elsewhere) for @.scss@ files.
307+--
308+byExtension :: Compiler a b -- ^ Default compiler
309+ -> [(String, Compiler a b)] -- ^ Choices
310+ -> Compiler a b -- ^ Resulting compiler
311+byExtension defaultCompiler choices = Compiler deps job
312+ where
313+ -- Lookup the compiler, give an error when it is not found
314+ lookup' identifier =
315+ let extension = takeExtension $ toFilePath identifier
316+ in fromMaybe defaultCompiler $ lookup extension choices
317+ -- Collect the dependencies of the choice
318+ deps = do
319+ identifier <- dependencyIdentifier <$> ask
320+ compilerDependencies $ lookup' identifier
321+ -- Collect the job of the choice
322+ job x = CompilerM $ do
323+ identifier <- compilerIdentifier <$> ask
324+ unCompilerM $ compilerJob (lookup' identifier) x