summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hakyll.cabal1
-rw-r--r--src/Hakyll/Web/Page/Read.hs80
-rw-r--r--tests/Hakyll/Web/Page/Tests.hs14
3 files changed, 50 insertions, 45 deletions
diff --git a/hakyll.cabal b/hakyll.cabal
index 2816e88..6c19232 100644
--- a/hakyll.cabal
+++ b/hakyll.cabal
@@ -68,6 +68,7 @@ Library
old-locale >= 1.0 && < 2.0,
old-time >= 1.0 && < 1.3,
pandoc >= 1.6 && < 2.0,
+ parsec >= 2.1 && < 3.2,
process >= 1.0 && < 1.4,
regex-base >= 0.93 && < 1.0,
regex-pcre >= 0.93 && < 1.0,
diff --git a/src/Hakyll/Web/Page/Read.hs b/src/Hakyll/Web/Page/Read.hs
index cf39ddd..bd77789 100644
--- a/src/Hakyll/Web/Page/Read.hs
+++ b/src/Hakyll/Web/Page/Read.hs
@@ -4,57 +4,53 @@ module Hakyll.Web.Page.Read
( readPage
) where
-import Control.Applicative ((<$>), (<*>))
-import Control.Arrow (second, (***))
-import Control.Monad.State (State, get, put, evalState)
-import Data.List (isPrefixOf)
-import Data.Map (Map)
+import Control.Applicative ((<$>), (<*>), (<*))
import qualified Data.Map as M
-import Hakyll.Web.Page.Internal
+import Text.Parsec.Char (alphaNum, anyChar, char, newline, oneOf, string)
+import Text.Parsec.Combinator (choice, many1, manyTill, option, skipMany1)
+import Text.Parsec.Prim (many, parse, skipMany, (<?>))
+import Text.Parsec.String (Parser)
+
import Hakyll.Core.Util.String
+import Hakyll.Web.Page.Internal
--- | We're using a simple state monad as parser
---
-type LineParser = State [String]
+-- | Space or tab, no newline
+inlineSpace :: Parser Char
+inlineSpace = oneOf ['\t', ' '] <?> "space"
--- | Read the metadata section from a page
+-- | Parse a single metadata field
--
-parseMetadata :: LineParser (Map String String)
-parseMetadata = get >>= \content -> case content of
- -- No lines means no metadata
- [] -> return M.empty
- -- Check if the file begins with a delimiter
- (l : ls) -> if not (isPossibleDelimiter l)
- then -- No delimiter means no metadata
- return M.empty
- else do -- Break the metadata section
- let (metadata, rest) = second (drop 1) $ break (== l) ls
- -- Put the rest back
- put rest
- -- Parse the metadata
- return $ M.fromList $ map parseMetadata' metadata
+metadataField :: Parser (String, String)
+metadataField = do
+ key <- manyTill alphaNum $ char ':'
+ skipMany1 inlineSpace
+ value <- manyTill anyChar newline
+ trailing' <- many trailing
+ return (key, trim $ value ++ concat trailing')
where
- -- Check if a line can be a delimiter
- isPossibleDelimiter = isPrefixOf "---"
+ trailing = (++) <$> many1 inlineSpace <*> manyTill anyChar newline
- -- Parse a "key: value" string to a (key, value) tupple
- parseMetadata' = (trim *** trim . drop 1) . break (== ':')
-
--- | Read the body section of a page
+-- | Parse a metadata block, including delimiters and trailing newlines
--
-parseBody :: LineParser String
-parseBody = do
- body <- get
- put []
- return $ unlines body
-
--- | Read an entire page
+metadata :: Parser [(String, String)]
+metadata = do
+ open <- many1 (char '-') <* many inlineSpace <* newline
+ metadata' <- many metadataField
+ _ <- choice $ map (string . replicate (length open)) ['-', '.']
+ skipMany inlineSpace
+ skipMany1 newline
+ return metadata'
+
+-- | Parse a Hakyll page
--
-parsePage :: LineParser (Page String)
-parsePage = Page <$> parseMetadata <*> parseBody
+page :: Parser ([(String, String)], String)
+page = do
+ metadata' <- option [] metadata
+ body <- many anyChar
+ return (metadata', body)
--- | Read a page from a string
---
readPage :: String -> Page String
-readPage = evalState parsePage . lines
+readPage input = case parse page "page" input of
+ Left err -> error (show err)
+ Right (md, b) -> Page (M.fromList md) b
diff --git a/tests/Hakyll/Web/Page/Tests.hs b/tests/Hakyll/Web/Page/Tests.hs
index b44daca..8e01302 100644
--- a/tests/Hakyll/Web/Page/Tests.hs
+++ b/tests/Hakyll/Web/Page/Tests.hs
@@ -14,13 +14,13 @@ import TestSuite.Util
tests :: [Test]
tests = fromAssertions "readPage"
- [ Page (M.singleton "foo" "bar") "body\n" @=? readPage
+ [ Page (M.singleton "foo" "bar") "body" @=? readPage
"--- \n\
\foo: bar \n\
\--- \n\
\body"
- , Page M.empty "line one\nlijn twee\n" @=? readPage
+ , Page M.empty "line one\nlijn twee" @=? readPage
"line one\n\
\lijn twee"
@@ -28,5 +28,13 @@ tests = fromAssertions "readPage"
"---\n\
\veld02: deux\n\
\field1: unos\n\
- \---"
+ \---\n"
+
+ , Page (M.fromList [("author", "jasper"), ("title", "lol")]) "O hai\n"
+ @=? readPage
+ "---\n\
+ \author: jasper\n\
+ \title: lol\n\
+ \...\n\
+ \O hai\n"
]