summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Data/List/Extended.hs15
-rw-r--r--src/Data/Yaml/Extended.hs20
-rw-r--r--src/Hakyll/Check.hs61
-rw-r--r--src/Hakyll/Commands.hs3
-rw-r--r--src/Hakyll/Core/Compiler.hs1
-rw-r--r--src/Hakyll/Core/Compiler/Internal.hs6
-rw-r--r--src/Hakyll/Core/Compiler/Require.hs1
-rw-r--r--src/Hakyll/Core/Dependencies.hs1
-rw-r--r--src/Hakyll/Core/File.hs1
-rw-r--r--src/Hakyll/Core/Identifier.hs1
-rw-r--r--src/Hakyll/Core/Identifier/Pattern.hs2
-rw-r--r--src/Hakyll/Core/Item.hs2
-rw-r--r--src/Hakyll/Core/Logger.hs1
-rw-r--r--src/Hakyll/Core/Metadata.hs88
-rw-r--r--src/Hakyll/Core/Provider/Internal.hs2
-rw-r--r--src/Hakyll/Core/Provider/Metadata.hs134
-rw-r--r--src/Hakyll/Core/Provider/MetadataCache.hs9
-rw-r--r--src/Hakyll/Core/Routes.hs1
-rw-r--r--src/Hakyll/Core/Rules.hs2
-rw-r--r--src/Hakyll/Core/Rules/Internal.hs2
-rw-r--r--src/Hakyll/Core/Runtime.hs8
-rw-r--r--src/Hakyll/Core/Store.hs1
-rw-r--r--src/Hakyll/Core/UnixFilter.hs3
-rw-r--r--src/Hakyll/Core/Util/File.hs1
-rw-r--r--src/Hakyll/Core/Util/Parser.hs2
-rw-r--r--src/Hakyll/Web/CompressCss.hs1
-rw-r--r--src/Hakyll/Web/Feed.hs1
-rw-r--r--src/Hakyll/Web/Paginate.hs1
-rw-r--r--src/Hakyll/Web/Pandoc.hs2
-rw-r--r--src/Hakyll/Web/Pandoc/Biblio.hs17
-rw-r--r--src/Hakyll/Web/Tags.hs12
-rw-r--r--src/Hakyll/Web/Template.hs15
-rw-r--r--src/Hakyll/Web/Template/Context.hs10
-rw-r--r--src/Hakyll/Web/Template/Internal.hs2
34 files changed, 257 insertions, 172 deletions
diff --git a/src/Data/List/Extended.hs b/src/Data/List/Extended.hs
new file mode 100644
index 0000000..485cba8
--- /dev/null
+++ b/src/Data/List/Extended.hs
@@ -0,0 +1,15 @@
+module Data.List.Extended
+ ( module Data.List
+ , breakWhen
+ ) where
+
+import Data.List
+
+-- | Like 'break', but can act on the entire tail of the list.
+breakWhen :: ([a] -> Bool) -> [a] -> ([a], [a])
+breakWhen predicate = go []
+ where
+ go buf [] = (reverse buf, [])
+ go buf (x : xs)
+ | predicate (x : xs) = (reverse buf, x : xs)
+ | otherwise = go (x : buf) xs
diff --git a/src/Data/Yaml/Extended.hs b/src/Data/Yaml/Extended.hs
new file mode 100644
index 0000000..099e945
--- /dev/null
+++ b/src/Data/Yaml/Extended.hs
@@ -0,0 +1,20 @@
+module Data.Yaml.Extended
+ ( module Data.Yaml
+ , toString
+ , toList
+ ) where
+
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import Data.Yaml
+
+toString :: Value -> Maybe String
+toString (String t) = Just (T.unpack t)
+toString (Bool True) = Just "true"
+toString (Bool False) = Just "false"
+toString (Number d) = Just (show d)
+toString _ = Nothing
+
+toList :: Value -> Maybe [Value]
+toList (Array a) = Just (V.toList a)
+toList _ = Nothing
diff --git a/src/Hakyll/Check.hs b/src/Hakyll/Check.hs
index 8e808ba..8bfc2aa 100644
--- a/src/Hakyll/Check.hs
+++ b/src/Hakyll/Check.hs
@@ -8,42 +8,44 @@ module Hakyll.Check
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
-import Control.Monad (forM_)
-import Control.Monad.Reader (ask)
-import Control.Monad.RWS (RWST, runRWST)
-import Control.Monad.Trans (liftIO)
-import Control.Monad.Writer (tell)
-import Data.List (isPrefixOf)
-import Data.Monoid (Monoid (..))
-import Data.Set (Set)
-import qualified Data.Set as S
-import Network.URI (unEscapeString)
-import System.Directory (doesDirectoryExist, doesFileExist)
-import System.Exit (ExitCode (..))
-import System.FilePath (takeDirectory, takeExtension, (</>))
-import qualified Text.HTML.TagSoup as TS
+import Control.Monad (forM_)
+import Control.Monad.Reader (ask)
+import Control.Monad.RWS (RWST, runRWST)
+import Control.Monad.Trans (liftIO)
+import Control.Monad.Trans.Resource (runResourceT)
+import Control.Monad.Writer (tell)
+import Data.List (isPrefixOf)
+import Data.Set (Set)
+import qualified Data.Set as S
+import Network.URI (unEscapeString)
+import System.Directory (doesDirectoryExist,
+ doesFileExist)
+import System.Exit (ExitCode (..))
+import System.FilePath (takeDirectory, takeExtension,
+ (</>))
+import qualified Text.HTML.TagSoup as TS
--------------------------------------------------------------------------------
#ifdef CHECK_EXTERNAL
-import Control.Exception (AsyncException (..),
- SomeException (..), handle, throw)
-import Control.Monad.State (get, modify)
-import Data.List (intercalate)
-import Data.Typeable (cast)
-import Data.Version (versionBranch)
-import GHC.Exts (fromString)
-import qualified Network.HTTP.Conduit as Http
-import qualified Network.HTTP.Types as Http
-import qualified Paths_hakyll as Paths_hakyll
+import Control.Exception (AsyncException (..),
+ SomeException (..), handle,
+ throw)
+import Control.Monad.State (get, modify)
+import Data.List (intercalate)
+import Data.Typeable (cast)
+import Data.Version (versionBranch)
+import GHC.Exts (fromString)
+import qualified Network.HTTP.Conduit as Http
+import qualified Network.HTTP.Types as Http
+import qualified Paths_hakyll as Paths_hakyll
#endif
--------------------------------------------------------------------------------
import Hakyll.Core.Configuration
-import Hakyll.Core.Logger (Logger)
-import qualified Hakyll.Core.Logger as Logger
+import Hakyll.Core.Logger (Logger)
+import qualified Hakyll.Core.Logger as Logger
import Hakyll.Core.Util.File
import Hakyll.Web.Html
@@ -196,8 +198,9 @@ checkExternalUrl url = do
if not needsCheck || checked
then Logger.debug logger "Already checked, skipping"
else do
- isOk <- liftIO $ handle (failure logger) $
- Http.withManager $ \mgr -> do
+ isOk <- liftIO $ handle (failure logger) $ do
+ mgr <- Http.newManager Http.tlsManagerSettings
+ runResourceT $ do
request <- Http.parseUrl urlToCheck
response <- Http.http (settings request) mgr
let code = Http.statusCode (Http.responseStatus response)
diff --git a/src/Hakyll/Commands.hs b/src/Hakyll/Commands.hs
index 6f81080..5906247 100644
--- a/src/Hakyll/Commands.hs
+++ b/src/Hakyll/Commands.hs
@@ -14,11 +14,8 @@ module Hakyll.Commands
--------------------------------------------------------------------------------
-import Control.Applicative
import Control.Concurrent
-import Control.Monad (void)
import System.Exit (ExitCode, exitWith)
-import System.IO.Error (catchIOError)
--------------------------------------------------------------------------------
import qualified Hakyll.Check as Check
diff --git a/src/Hakyll/Core/Compiler.hs b/src/Hakyll/Core/Compiler.hs
index f99f93b..ae9fbf1 100644
--- a/src/Hakyll/Core/Compiler.hs
+++ b/src/Hakyll/Core/Compiler.hs
@@ -28,7 +28,6 @@ module Hakyll.Core.Compiler
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Monad (when)
import Data.Binary (Binary)
import Data.ByteString.Lazy (ByteString)
diff --git a/src/Hakyll/Core/Compiler/Internal.hs b/src/Hakyll/Core/Compiler/Internal.hs
index 61fb640..7b1df83 100644
--- a/src/Hakyll/Core/Compiler/Internal.hs
+++ b/src/Hakyll/Core/Compiler/Internal.hs
@@ -28,12 +28,10 @@ module Hakyll.Core.Compiler.Internal
--------------------------------------------------------------------------------
-import Control.Applicative (Alternative (..),
- Applicative (..), (<$>))
+import Control.Applicative (Alternative (..))
import Control.Exception (SomeException, handle)
import Control.Monad (forM_)
-import Control.Monad.Error (MonadError (..))
-import Data.Monoid (Monoid (..))
+import Control.Monad.Except (MonadError (..))
import Data.Set (Set)
import qualified Data.Set as S
diff --git a/src/Hakyll/Core/Compiler/Require.hs b/src/Hakyll/Core/Compiler/Require.hs
index d7635a9..c9373bf 100644
--- a/src/Hakyll/Core/Compiler/Require.hs
+++ b/src/Hakyll/Core/Compiler/Require.hs
@@ -13,7 +13,6 @@ module Hakyll.Core.Compiler.Require
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Monad (when)
import Data.Binary (Binary)
import qualified Data.Set as S
diff --git a/src/Hakyll/Core/Dependencies.hs b/src/Hakyll/Core/Dependencies.hs
index ebb6fd0..4a51b9c 100644
--- a/src/Hakyll/Core/Dependencies.hs
+++ b/src/Hakyll/Core/Dependencies.hs
@@ -8,7 +8,6 @@ module Hakyll.Core.Dependencies
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>), (<*>))
import Control.Monad (foldM, forM_, unless, when)
import Control.Monad.Reader (ask)
import Control.Monad.RWS (RWS, runRWS)
diff --git a/src/Hakyll/Core/File.hs b/src/Hakyll/Core/File.hs
index 26724e1..1c3a9df 100644
--- a/src/Hakyll/Core/File.hs
+++ b/src/Hakyll/Core/File.hs
@@ -11,7 +11,6 @@ module Hakyll.Core.File
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Data.Binary (Binary (..))
import Data.Typeable (Typeable)
import System.Directory (copyFile, doesFileExist,
diff --git a/src/Hakyll/Core/Identifier.hs b/src/Hakyll/Core/Identifier.hs
index 7ac06d8..777811c 100644
--- a/src/Hakyll/Core/Identifier.hs
+++ b/src/Hakyll/Core/Identifier.hs
@@ -19,7 +19,6 @@ module Hakyll.Core.Identifier
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>), (<*>))
import Control.DeepSeq (NFData (..))
import Data.List (intercalate)
import System.FilePath (dropTrailingPathSeparator, splitPath)
diff --git a/src/Hakyll/Core/Identifier/Pattern.hs b/src/Hakyll/Core/Identifier/Pattern.hs
index 92d7705..47ad21b 100644
--- a/src/Hakyll/Core/Identifier/Pattern.hs
+++ b/src/Hakyll/Core/Identifier/Pattern.hs
@@ -57,13 +57,11 @@ module Hakyll.Core.Identifier.Pattern
--------------------------------------------------------------------------------
-import Control.Applicative (pure, (<$>), (<*>))
import Control.Arrow ((&&&), (>>>))
import Control.Monad (msum)
import Data.Binary (Binary (..), getWord8, putWord8)
import Data.List (inits, isPrefixOf, tails)
import Data.Maybe (isJust)
-import Data.Monoid (Monoid, mappend, mempty)
import Data.Set (Set)
import qualified Data.Set as S
diff --git a/src/Hakyll/Core/Item.hs b/src/Hakyll/Core/Item.hs
index 840b6a8..e05df42 100644
--- a/src/Hakyll/Core/Item.hs
+++ b/src/Hakyll/Core/Item.hs
@@ -10,10 +10,8 @@ module Hakyll.Core.Item
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>), (<*>))
import Data.Binary (Binary (..))
import Data.Foldable (Foldable (..))
-import Data.Traversable (Traversable (..))
import Data.Typeable (Typeable)
import Prelude hiding (foldr)
diff --git a/src/Hakyll/Core/Logger.hs b/src/Hakyll/Core/Logger.hs
index 4731c20..6f950a6 100644
--- a/src/Hakyll/Core/Logger.hs
+++ b/src/Hakyll/Core/Logger.hs
@@ -13,7 +13,6 @@ module Hakyll.Core.Logger
--------------------------------------------------------------------------------
-import Control.Applicative (pure, (<$>), (<*>))
import Control.Concurrent (forkIO)
import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
diff --git a/src/Hakyll/Core/Metadata.hs b/src/Hakyll/Core/Metadata.hs
index 3ce854f..1cf536e 100644
--- a/src/Hakyll/Core/Metadata.hs
+++ b/src/Hakyll/Core/Metadata.hs
@@ -1,28 +1,46 @@
--------------------------------------------------------------------------------
module Hakyll.Core.Metadata
( Metadata
+ , lookupString
+ , lookupStringList
+
, MonadMetadata (..)
, getMetadataField
, getMetadataField'
, makePatternDependency
+
+ , BinaryMetadata (..)
) where
--------------------------------------------------------------------------------
+import Control.Arrow (second)
import Control.Monad (forM)
-import Data.Map (Map)
-import qualified Data.Map as M
+import Data.Binary (Binary (..), getWord8,
+ putWord8, Get)
+import qualified Data.HashMap.Strict as HMS
import qualified Data.Set as S
-
-
---------------------------------------------------------------------------------
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import qualified Data.Yaml.Extended as Yaml
import Hakyll.Core.Dependencies
import Hakyll.Core.Identifier
import Hakyll.Core.Identifier.Pattern
--------------------------------------------------------------------------------
-type Metadata = Map String String
+type Metadata = Yaml.Object
+
+
+--------------------------------------------------------------------------------
+lookupString :: String -> Metadata -> Maybe String
+lookupString key meta = HMS.lookup (T.pack key) meta >>= Yaml.toString
+
+
+--------------------------------------------------------------------------------
+lookupStringList :: String -> Metadata -> Maybe [String]
+lookupStringList key meta =
+ HMS.lookup (T.pack key) meta >>= Yaml.toList >>= mapM Yaml.toString
--------------------------------------------------------------------------------
@@ -42,7 +60,7 @@ class Monad m => MonadMetadata m where
getMetadataField :: MonadMetadata m => Identifier -> String -> m (Maybe String)
getMetadataField identifier key = do
metadata <- getMetadata identifier
- return $ M.lookup key metadata
+ return $ lookupString key metadata
--------------------------------------------------------------------------------
@@ -62,3 +80,59 @@ makePatternDependency :: MonadMetadata m => Pattern -> m Dependency
makePatternDependency pattern = do
matches' <- getMatches pattern
return $ PatternDependency pattern (S.fromList matches')
+
+
+--------------------------------------------------------------------------------
+-- | Newtype wrapper for serialization.
+newtype BinaryMetadata = BinaryMetadata
+ {unBinaryMetadata :: Metadata}
+
+
+instance Binary BinaryMetadata where
+ put (BinaryMetadata obj) = put (BinaryYaml $ Yaml.Object obj)
+ get = do
+ BinaryYaml (Yaml.Object obj) <- get
+ return $ BinaryMetadata obj
+
+
+--------------------------------------------------------------------------------
+newtype BinaryYaml = BinaryYaml {unBinaryYaml :: Yaml.Value}
+
+
+--------------------------------------------------------------------------------
+instance Binary BinaryYaml where
+ put (BinaryYaml yaml) = case yaml of
+ Yaml.Object obj -> do
+ putWord8 0
+ let list :: [(T.Text, BinaryYaml)]
+ list = map (second BinaryYaml) $ HMS.toList obj
+ put list
+
+ Yaml.Array arr -> do
+ putWord8 1
+ let list = map BinaryYaml (V.toList arr) :: [BinaryYaml]
+ put list
+
+ Yaml.String s -> putWord8 2 >> put s
+ Yaml.Number n -> putWord8 3 >> put n
+ Yaml.Bool b -> putWord8 4 >> put b
+ Yaml.Null -> putWord8 5
+
+ get = do
+ tag <- getWord8
+ case tag of
+ 0 -> do
+ list <- get :: Get [(T.Text, BinaryYaml)]
+ return $ BinaryYaml $ Yaml.Object $
+ HMS.fromList $ map (second unBinaryYaml) list
+
+ 1 -> do
+ list <- get :: Get [BinaryYaml]
+ return $ BinaryYaml $
+ Yaml.Array $ V.fromList $ map unBinaryYaml list
+
+ 2 -> BinaryYaml . Yaml.String <$> get
+ 3 -> BinaryYaml . Yaml.Number <$> get
+ 4 -> BinaryYaml . Yaml.Bool <$> get
+ 5 -> return $ BinaryYaml Yaml.Null
+ _ -> fail "Data.Binary.get: Invalid Binary Metadata"
diff --git a/src/Hakyll/Core/Provider/Internal.hs b/src/Hakyll/Core/Provider/Internal.hs
index 34400fd..c298653 100644
--- a/src/Hakyll/Core/Provider/Internal.hs
+++ b/src/Hakyll/Core/Provider/Internal.hs
@@ -20,7 +20,6 @@ module Hakyll.Core.Provider.Internal
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>), (<*>))
import Control.DeepSeq (NFData (..), deepseq)
import Control.Monad (forM)
import Data.Binary (Binary (..))
@@ -28,7 +27,6 @@ import qualified Data.ByteString.Lazy as BL
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
-import Data.Monoid (mempty)
import Data.Set (Set)
import qualified Data.Set as S
import Data.Time (Day (..), UTCTime (..))
diff --git a/src/Hakyll/Core/Provider/Metadata.hs b/src/Hakyll/Core/Provider/Metadata.hs
index 7e4d7ed..0b0291c 100644
--- a/src/Hakyll/Core/Provider/Metadata.hs
+++ b/src/Hakyll/Core/Provider/Metadata.hs
@@ -1,33 +1,31 @@
--------------------------------------------------------------------------------
-- | Internal module to parse metadata
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
module Hakyll.Core.Provider.Metadata
( loadMetadata
- , metadata
- , page
+ , parsePage
- -- This parser can be reused in some places
- , metadataKey
+ , MetadataException (..)
) where
--------------------------------------------------------------------------------
-import Control.Applicative
import Control.Arrow (second)
+import Control.Exception (Exception, throwIO)
+import Control.Monad (guard)
import qualified Data.ByteString.Char8 as BC
-import Data.List (intercalate)
+import Data.List.Extended (breakWhen)
import qualified Data.Map as M
-import System.IO as IO
-import Text.Parsec ((<?>))
-import qualified Text.Parsec as P
-import Text.Parsec.String (Parser)
-
-
---------------------------------------------------------------------------------
+import Data.Maybe (fromMaybe)
+import Data.Monoid ((<>))
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Yaml as Yaml
import Hakyll.Core.Identifier
import Hakyll.Core.Metadata
import Hakyll.Core.Provider.Internal
-import Hakyll.Core.Util.Parser
-import Hakyll.Core.Util.String
+import System.IO as IO
--------------------------------------------------------------------------------
@@ -36,13 +34,13 @@ loadMetadata p identifier = do
hasHeader <- probablyHasMetadataHeader fp
(md, body) <- if hasHeader
then second Just <$> loadMetadataHeader fp
- else return (M.empty, Nothing)
+ else return (mempty, Nothing)
emd <- case mi of
- Nothing -> return M.empty
+ Nothing -> return mempty
Just mi' -> loadMetadataFile $ resourceFilePath p mi'
- return (M.union md emd, body)
+ return (md <> emd, body)
where
normal = setVersion Nothing identifier
fp = resourceFilePath p identifier
@@ -52,19 +50,17 @@ loadMetadata p identifier = do
--------------------------------------------------------------------------------
loadMetadataHeader :: FilePath -> IO (Metadata, String)
loadMetadataHeader fp = do
- contents <- readFile fp
- case P.parse page fp contents of
- Left err -> error (show err)
- Right (md, b) -> return (M.fromList md, b)
+ fileContent <- readFile fp
+ case parsePage fileContent of
+ Right x -> return x
+ Left err -> throwIO $ MetadataException fp err
--------------------------------------------------------------------------------
loadMetadataFile :: FilePath -> IO Metadata
loadMetadataFile fp = do
- contents <- readFile fp
- case P.parse metadata fp contents of
- Left err -> error (show err)
- Right md -> return $ M.fromList md
+ errOrMeta <- Yaml.decodeFileEither fp
+ either (fail . show) return errOrMeta
--------------------------------------------------------------------------------
@@ -83,53 +79,71 @@ probablyHasMetadataHeader fp = do
--------------------------------------------------------------------------------
--- | Space or tab, no newline
-inlineSpace :: Parser Char
-inlineSpace = P.oneOf ['\t', ' '] <?> "space"
+-- | Parse the page metadata and body.
+splitMetadata :: String -> (Maybe String, String)
+splitMetadata str0 = fromMaybe (Nothing, str0) $ do
+ guard $ leading >= 3
+ let !str1 = drop leading str0
+ guard $ all isNewline (take 1 str1)
+ let !(!meta, !content0) = breakWhen isTrailing str1
+ guard $ not $ null content0
+ let !content1 = drop (leading + 1) content0
+ !content2 = dropWhile isNewline $ dropWhile isInlineSpace content1
+ -- Adding this newline fixes the line numbers reported by the YAML parser.
+ -- It's a bit ugly but it works.
+ return (Just ('\n' : meta), content2)
+ where
+ -- Parse the leading "---"
+ !leading = length $ takeWhile (== '-') str0
+
+ -- Predicate to recognize the trailing "---" or "..."
+ isTrailing [] = False
+ isTrailing (x : xs) =
+ isNewline x && length (takeWhile isDash xs) == leading
+
+ -- Characters
+ isNewline c = c == '\n' || c == '\r'
+ isDash c = c == '-' || c == '.'
+ isInlineSpace c = c == '\t' || c == ' '
--------------------------------------------------------------------------------
--- | Parse Windows newlines as well (i.e. "\n" or "\r\n")
-newline :: Parser String
-newline = P.string "\n" <|> P.string "\r\n"
+parseMetadata :: String -> Either Yaml.ParseException Metadata
+parseMetadata = Yaml.decodeEither' . T.encodeUtf8 . T.pack
--------------------------------------------------------------------------------
--- | Parse a single metadata field
-metadataField :: Parser (String, String)
-metadataField = do
- key <- metadataKey
- _ <- P.char ':'
- P.skipMany1 inlineSpace <?> "space followed by metadata for: " ++ key
- value <- P.manyTill P.anyChar newline
- trailing' <- P.many trailing
- return (key, trim $ intercalate " " $ value : trailing')
+parsePage :: String -> Either Yaml.ParseException (Metadata, String)
+parsePage fileContent = case mbMetaBlock of
+ Nothing -> return (mempty, content)
+ Just metaBlock -> case parseMetadata metaBlock of
+ Left err -> Left err
+ Right meta -> return (meta, content)
where
- trailing = P.many1 inlineSpace *> P.manyTill P.anyChar newline
+ !(!mbMetaBlock, !content) = splitMetadata fileContent
--------------------------------------------------------------------------------
--- | Parse a metadata block
-metadata :: Parser [(String, String)]
-metadata = P.many metadataField
+-- | Thrown in the IO monad if things go wrong. Provides a nice-ish error
+-- message.
+data MetadataException = MetadataException FilePath Yaml.ParseException
--------------------------------------------------------------------------------
--- | Parse a metadata block, including delimiters and trailing newlines
-metadataBlock :: Parser [(String, String)]
-metadataBlock = do
- open <- P.many1 (P.char '-') <* P.many inlineSpace <* newline
- metadata' <- metadata
- _ <- P.choice $ map (P.string . replicate (length open)) ['-', '.']
- P.skipMany inlineSpace
- P.skipMany1 newline
- return metadata'
+instance Exception MetadataException
--------------------------------------------------------------------------------
--- | Parse a page consisting of a metadata header and a body
-page :: Parser ([(String, String)], String)
-page = do
- metadata' <- P.option [] metadataBlock
- body <- P.many P.anyChar
- return (metadata', body)
+instance Show MetadataException where
+ show (MetadataException fp err) =
+ fp ++ ": " ++ Yaml.prettyPrintParseException err ++ hint
+
+ where
+ hint = case err of
+ Yaml.InvalidYaml (Just (Yaml.YamlParseException {..}))
+ | yamlProblem == problem -> "\n" ++
+ "Hint: if the metadata value contains characters such\n" ++
+ "as ':' or '-', try enclosing it in quotes."
+ _ -> ""
+
+ problem = "mapping values are not allowed in this context"
diff --git a/src/Hakyll/Core/Provider/MetadataCache.hs b/src/Hakyll/Core/Provider/MetadataCache.hs
index 28d2bd5..46dbf3e 100644
--- a/src/Hakyll/Core/Provider/MetadataCache.hs
+++ b/src/Hakyll/Core/Provider/MetadataCache.hs
@@ -8,9 +8,6 @@ module Hakyll.Core.Provider.MetadataCache
--------------------------------------------------------------------------------
import Control.Monad (unless)
-import qualified Data.Map as M
-
---------------------------------------------------------------------------------
import Hakyll.Core.Identifier
import Hakyll.Core.Metadata
import Hakyll.Core.Provider.Internal
@@ -21,11 +18,11 @@ import qualified Hakyll.Core.Store as Store
--------------------------------------------------------------------------------
resourceMetadata :: Provider -> Identifier -> IO Metadata
resourceMetadata p r
- | not (resourceExists p r) = return M.empty
+ | not (resourceExists p r) = return mempty
| otherwise = do
-- TODO keep time in md cache
load p r
- Store.Found md <- Store.get (providerStore p)
+ Store.Found (BinaryMetadata md) <- Store.get (providerStore p)
[name, toFilePath r, "metadata"]
return md
@@ -52,7 +49,7 @@ load p r = do
mmof <- Store.isMember store mdk
unless mmof $ do
(md, body) <- loadMetadata p r
- Store.set store mdk md
+ Store.set store mdk (BinaryMetadata md)
Store.set store bk body
where
store = providerStore p
diff --git a/src/Hakyll/Core/Routes.hs b/src/Hakyll/Core/Routes.hs
index 470d727..513725f 100644
--- a/src/Hakyll/Core/Routes.hs
+++ b/src/Hakyll/Core/Routes.hs
@@ -42,7 +42,6 @@ module Hakyll.Core.Routes
--------------------------------------------------------------------------------
-import Data.Monoid (Monoid, mappend, mempty)
import System.FilePath (replaceExtension)
diff --git a/src/Hakyll/Core/Rules.hs b/src/Hakyll/Core/Rules.hs
index 14befde..41b9a73 100644
--- a/src/Hakyll/Core/Rules.hs
+++ b/src/Hakyll/Core/Rules.hs
@@ -33,13 +33,11 @@ module Hakyll.Core.Rules
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Monad.Reader (ask, local)
import Control.Monad.State (get, modify, put)
import Control.Monad.Trans (liftIO)
import Control.Monad.Writer (censor, tell)
import Data.Maybe (fromMaybe)
-import Data.Monoid (mempty)
import qualified Data.Set as S
diff --git a/src/Hakyll/Core/Rules/Internal.hs b/src/Hakyll/Core/Rules/Internal.hs
index a7c2059..0641dcf 100644
--- a/src/Hakyll/Core/Rules/Internal.hs
+++ b/src/Hakyll/Core/Rules/Internal.hs
@@ -12,12 +12,10 @@ module Hakyll.Core.Rules.Internal
--------------------------------------------------------------------------------
-import Control.Applicative (Applicative, (<$>))
import Control.Monad.Reader (ask)
import Control.Monad.RWS (RWST, runRWST)
import Control.Monad.Trans (liftIO)
import qualified Data.Map as M
-import Data.Monoid (Monoid, mappend, mempty)
import Data.Set (Set)
diff --git a/src/Hakyll/Core/Runtime.hs b/src/Hakyll/Core/Runtime.hs
index e85d60d..16a5d9e 100644
--- a/src/Hakyll/Core/Runtime.hs
+++ b/src/Hakyll/Core/Runtime.hs
@@ -5,9 +5,8 @@ module Hakyll.Core.Runtime
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Monad (unless)
-import Control.Monad.Error (ErrorT, runErrorT, throwError)
+import Control.Monad.Except (ExceptT, runExceptT, throwError)
import Control.Monad.Reader (ask)
import Control.Monad.RWS (RWST, runRWST)
import Control.Monad.State (get, modify)
@@ -15,7 +14,6 @@ import Control.Monad.Trans (liftIO)
import Data.List (intercalate)
import Data.Map (Map)
import qualified Data.Map as M
-import Data.Monoid (mempty)
import Data.Set (Set)
import qualified Data.Set as S
import System.Exit (ExitCode (..))
@@ -77,7 +75,7 @@ run config logger rules = do
}
-- Run the program and fetch the resulting state
- result <- runErrorT $ runRWST build read' state
+ result <- runExceptT $ runRWST build read' state
case result of
Left e -> do
Logger.error logger e
@@ -117,7 +115,7 @@ data RuntimeState = RuntimeState
--------------------------------------------------------------------------------
-type Runtime a = RWST RuntimeRead () RuntimeState (ErrorT String IO) a
+type Runtime a = RWST RuntimeRead () RuntimeState (ExceptT String IO) a
--------------------------------------------------------------------------------
diff --git a/src/Hakyll/Core/Store.hs b/src/Hakyll/Core/Store.hs
index 5c3667d..fdbcf11 100644
--- a/src/Hakyll/Core/Store.hs
+++ b/src/Hakyll/Core/Store.hs
@@ -16,7 +16,6 @@ module Hakyll.Core.Store
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Exception (IOException, handle)
import qualified Crypto.Hash.MD5 as MD5
import Data.Binary (Binary, decode, encodeFile)
diff --git a/src/Hakyll/Core/UnixFilter.hs b/src/Hakyll/Core/UnixFilter.hs
index edc8eac..734d8d8 100644
--- a/src/Hakyll/Core/UnixFilter.hs
+++ b/src/Hakyll/Core/UnixFilter.hs
@@ -16,7 +16,6 @@ import Control.Monad (forM_)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as LB
import Data.IORef (newIORef, readIORef, writeIORef)
-import Data.Monoid (Monoid, mempty)
import System.Exit (ExitCode (..))
import System.IO (Handle, hClose, hFlush, hGetContents,
hPutStr, hSetEncoding, localeEncoding)
@@ -30,7 +29,7 @@ import Hakyll.Core.Compiler
-- | Use a unix filter as compiler. For example, we could use the 'rev' program
-- as a compiler.
--
--- > rev :: Compiler String
+-- > rev :: Compiler (Item String)
-- > rev = getResourceString >>= withItemBody (unixFilter "rev" [])
--
-- A more realistic example: one can use this to call, for example, the sass
diff --git a/src/Hakyll/Core/Util/File.hs b/src/Hakyll/Core/Util/File.hs
index b20576f..9db6b11 100644
--- a/src/Hakyll/Core/Util/File.hs
+++ b/src/Hakyll/Core/Util/File.hs
@@ -8,7 +8,6 @@ module Hakyll.Core.Util.File
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Control.Monad (filterM, forM, when)
import System.Directory (createDirectoryIfMissing,
doesDirectoryExist, getDirectoryContents,
diff --git a/src/Hakyll/Core/Util/Parser.hs b/src/Hakyll/Core/Util/Parser.hs
index c5789ed..e958b76 100644
--- a/src/Hakyll/Core/Util/Parser.hs
+++ b/src/Hakyll/Core/Util/Parser.hs
@@ -7,7 +7,7 @@ module Hakyll.Core.Util.Parser
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>), (<*>), (<|>))
+import Control.Applicative ((<|>))
import Control.Monad (mzero)
import qualified Text.Parsec as P
import Text.Parsec.String (Parser)
diff --git a/src/Hakyll/Web/CompressCss.hs b/src/Hakyll/Web/CompressCss.hs
index f3290f3..0534b9f 100644
--- a/src/Hakyll/Web/CompressCss.hs
+++ b/src/Hakyll/Web/CompressCss.hs
@@ -8,7 +8,6 @@ module Hakyll.Web.CompressCss
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import Data.Char (isSpace)
import Data.List (isPrefixOf)
diff --git a/src/Hakyll/Web/Feed.hs b/src/Hakyll/Web/Feed.hs
index 1d18430..8598f8a 100644
--- a/src/Hakyll/Web/Feed.hs
+++ b/src/Hakyll/Web/Feed.hs
@@ -25,7 +25,6 @@ module Hakyll.Web.Feed
--------------------------------------------------------------------------------
import Control.Monad ((<=<))
-import Data.Monoid (mconcat)
--------------------------------------------------------------------------------
diff --git a/src/Hakyll/Web/Paginate.hs b/src/Hakyll/Web/Paginate.hs
index cd35a2d..65b4525 100644
--- a/src/Hakyll/Web/Paginate.hs
+++ b/src/Hakyll/Web/Paginate.hs
@@ -13,7 +13,6 @@ module Hakyll.Web.Paginate
--------------------------------------------------------------------------------
import Control.Monad (forM_)
import qualified Data.Map as M
-import Data.Monoid (mconcat)
import qualified Data.Set as S
diff --git a/src/Hakyll/Web/Pandoc.hs b/src/Hakyll/Web/Pandoc.hs
index f6e9ff1..eec0a8a 100644
--- a/src/Hakyll/Web/Pandoc.hs
+++ b/src/Hakyll/Web/Pandoc.hs
@@ -22,9 +22,7 @@ module Hakyll.Web.Pandoc
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
import qualified Data.Set as S
-import Data.Traversable (traverse)
import Text.Pandoc
import Text.Pandoc.Error (PandocError (..))
diff --git a/src/Hakyll/Web/Pandoc/Biblio.hs b/src/Hakyll/Web/Pandoc/Biblio.hs
index 53e3419..dfe6d93 100644
--- a/src/Hakyll/Web/Pandoc/Biblio.hs
+++ b/src/Hakyll/Web/Pandoc/Biblio.hs
@@ -23,22 +23,19 @@ module Hakyll.Web.Pandoc.Biblio
--------------------------------------------------------------------------------
-import Control.Applicative ((<$>))
-import Control.Monad (replicateM, liftM)
-import Data.Binary (Binary (..))
-import Data.Default (def)
-import Data.Typeable (Typeable)
-import qualified Text.CSL as CSL
-import Text.CSL.Pandoc (processCites)
-import Text.Pandoc (Pandoc, ReaderOptions (..))
-
---------------------------------------------------------------------------------
+import Control.Monad (liftM, replicateM)
+import Data.Binary (Binary (..))
+import Data.Default (def)
+import Data.Typeable (Typeable)
import Hakyll.Core.Compiler
import Hakyll.Core.Identifier
import Hakyll.Core.Item
import Hakyll.Core.Writable
import Hakyll.Web.Pandoc
import Hakyll.Web.Pandoc.Binary ()
+import qualified Text.CSL as CSL
+import Text.CSL.Pandoc (processCites)
+import Text.Pandoc (Pandoc, ReaderOptions (..))
--------------------------------------------------------------------------------
diff --git a/src/Hakyll/Web/Tags.hs b/src/Hakyll/Web/Tags.hs
index 0887856..b5b44fc 100644
--- a/src/Hakyll/Web/Tags.hs
+++ b/src/Hakyll/Web/Tags.hs
@@ -63,13 +63,12 @@ module Hakyll.Web.Tags
--------------------------------------------------------------------------------
import Control.Arrow ((&&&))
-import Control.Monad (foldM, forM, forM_)
+import Control.Monad (foldM, forM, forM_, mplus)
import Data.Char (toLower)
import Data.List (intercalate, intersperse,
sortBy)
import qualified Data.Map as M
import Data.Maybe (catMaybes, fromMaybe)
-import Data.Monoid (mconcat)
import Data.Ord (comparing)
import qualified Data.Set as S
import System.FilePath (takeBaseName, takeDirectory)
@@ -88,8 +87,8 @@ import Hakyll.Core.Item
import Hakyll.Core.Metadata
import Hakyll.Core.Rules
import Hakyll.Core.Util.String
-import Hakyll.Web.Template.Context
import Hakyll.Web.Html
+import Hakyll.Web.Template.Context
--------------------------------------------------------------------------------
@@ -103,11 +102,14 @@ data Tags = Tags
--------------------------------------------------------------------------------
-- | Obtain tags from a page in the default way: parse them from the @tags@
--- metadata field.
+-- metadata field. This can either be a list or a comma-separated string.
getTags :: MonadMetadata m => Identifier -> m [String]
getTags identifier = do
metadata <- getMetadata identifier
- return $ maybe [] (map trim . splitAll ",") $ M.lookup "tags" metadata
+ return $ fromMaybe [] $
+ (lookupStringList "tags" metadata) `mplus`
+ (map trim . splitAll "," <$> lookupString "tags" metadata)
+
--------------------------------------------------------------------------------
-- | Obtain categories from a page.
diff --git a/src/Hakyll/Web/Template.hs b/src/Hakyll/Web/Template.hs
index 194949d..65c4ac9 100644
--- a/src/Hakyll/Web/Template.hs
+++ b/src/Hakyll/Web/Template.hs
@@ -54,7 +54,7 @@
-- The @for@ macro is used for enumerating 'Context' elements that are
-- lists, i.e. constructed using the 'listField' function. Assume that
-- in a context we have an element @listField \"key\" c itms@. Then
--- the snippet
+-- the snippet
--
-- > $for(key)$
-- > $x$
@@ -70,21 +70,21 @@
--
-- > listField "things" (field "thing" (return . itemBody))
-- > (sequence [makeItem "fruits", makeItem "vegetables"])
---
+--
-- and a template
--
-- > I like
-- > $for(things)$
--- > fresh $thing$$sep$, and
+-- > fresh $thing$$sep$, and
-- > $endfor$
--
-- the resulting page would look like
--
-- > <p>
-- > I like
--- >
--- > fresh fruits, and
--- >
+-- >
+-- > fresh fruits, and
+-- >
-- > fresh vegetables
-- > </p>
--
@@ -129,9 +129,8 @@ module Hakyll.Web.Template
--------------------------------------------------------------------------------
import Control.Monad (liftM)
-import Control.Monad.Error (MonadError (..))
+import Control.Monad.Except (MonadError (..))
import Data.List (intercalate)
-import Data.Monoid (mappend)
import Prelude hiding (id)
diff --git a/src/Hakyll/Web/Template/Context.hs b/src/Hakyll/Web/Template/Context.hs
index 28e2ec5..b6c7994 100644
--- a/src/Hakyll/Web/Template/Context.hs
+++ b/src/Hakyll/Web/Template/Context.hs
@@ -32,18 +32,13 @@ module Hakyll.Web.Template.Context
--------------------------------------------------------------------------------
-import Control.Applicative (Alternative (..), pure, (<$>))
+import Control.Applicative (Alternative (..))
import Control.Monad (msum)
import Data.List (intercalate)
-import qualified Data.Map as M
-import Data.Monoid (Monoid (..))
import Data.Time.Clock (UTCTime (..))
import Data.Time.Format (formatTime)
import qualified Data.Time.Format as TF
import Data.Time.Locale.Compat (TimeLocale, defaultTimeLocale)
-import System.FilePath (splitDirectories, takeBaseName)
-
---------------------------------------------------------------------------------
import Hakyll.Core.Compiler
import Hakyll.Core.Compiler.Internal
import Hakyll.Core.Identifier
@@ -52,6 +47,7 @@ import Hakyll.Core.Metadata
import Hakyll.Core.Provider
import Hakyll.Core.Util.String (needlePrefix, splitAll)
import Hakyll.Web.Html
+import System.FilePath (splitDirectories, takeBaseName)
--------------------------------------------------------------------------------
@@ -291,7 +287,7 @@ getItemUTC :: MonadMetadata m
-> m UTCTime -- ^ Parsed UTCTime
getItemUTC locale id' = do
metadata <- getMetadata id'
- let tryField k fmt = M.lookup k metadata >>= parseTime' fmt
+ let tryField k fmt = lookupString k metadata >>= parseTime' fmt
paths = splitDirectories $ toFilePath id'
maybe empty' return $ msum $
diff --git a/src/Hakyll/Web/Template/Internal.hs b/src/Hakyll/Web/Template/Internal.hs
index 2d9de5e..45db2e4 100644
--- a/src/Hakyll/Web/Template/Internal.hs
+++ b/src/Hakyll/Web/Template/Internal.hs
@@ -12,7 +12,7 @@ module Hakyll.Web.Template.Internal
--------------------------------------------------------------------------------
-import Control.Applicative (pure, (<$), (<$>), (<*>), (<|>))
+import Control.Applicative ((<|>))
import Control.Monad (void)
import Data.Binary (Binary, get, getWord8, put, putWord8)
import Data.Typeable (Typeable)