63 lines
1.7 KiB
Haskell
63 lines
1.7 KiB
Haskell
|
-- | Module providing a function to parse a page from a file
|
||
|
--
|
||
|
module Hakyll.Web.Page.Read
|
||
|
( readPage
|
||
|
) where
|
||
|
|
||
|
import Control.Applicative ((<$>), (<*>))
|
||
|
import Control.Arrow (second, (***))
|
||
|
import Control.Monad.State
|
||
|
import Data.List (isPrefixOf)
|
||
|
import Data.Map (Map)
|
||
|
import qualified Data.Map as M
|
||
|
|
||
|
import Hakyll.Web.Page
|
||
|
import Hakyll.Web.Util.String
|
||
|
|
||
|
-- | We're using a simple state monad as parser
|
||
|
--
|
||
|
type LineParser = State [String]
|
||
|
|
||
|
-- | Check if the given string is a metadata delimiter.
|
||
|
--
|
||
|
isPossibleDelimiter :: String -> Bool
|
||
|
isPossibleDelimiter = isPrefixOf "---"
|
||
|
|
||
|
-- | Read the metadata section from a page
|
||
|
--
|
||
|
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 body
|
||
|
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
|
||
|
where
|
||
|
parseMetadata' :: String -> (String, String)
|
||
|
parseMetadata' = (trim *** trim . drop 1) . break (== ':')
|
||
|
|
||
|
-- | Read the body section of a page
|
||
|
--
|
||
|
parseBody :: LineParser String
|
||
|
parseBody = do
|
||
|
body <- get
|
||
|
put []
|
||
|
return $ unlines body
|
||
|
|
||
|
-- | Read an entire page
|
||
|
--
|
||
|
parsePage :: LineParser (Page String)
|
||
|
parsePage = Page <$> parseMetadata <*> parseBody
|
||
|
|
||
|
-- | Read a page from a string
|
||
|
--
|
||
|
readPage :: String -> Page String
|
||
|
readPage = evalState parsePage . lines
|