    -- | This module provides 'Context's which are used to expand expressions in
    -- templates and allow for arbitrary customisation.
    --
    -- 'Template's define a small expression DSL which consists of strings,
    -- identifiers and function application. There is no type system, every value is
    -- a string and on the top level they get substituted verbatim into the page.
    --
    -- For example, you can build a context that contains
    --
    -- > … <> functionField "concat" (const . concat) <> …
    --
    -- which will allow you to use the @concat@ identifier as a function that takes
    -- arbitrarily many strings and concatenates them to a new string:
    --
    -- > $partial(concat("templates/categories/", category))$
    --
    -- This will evaluate the @category@ field in the context, then prepend the path,
    -- and include the referenced file as a template.

    --------------------------------------------------------------------------------
    {-# LANGUAGE CPP                       #-}
    {-# LANGUAGE ExistentialQuantification #-}
    module Hakyll.Web.Template.Context
        ( ContextField (..)
        , Context (..)
        , field
        , boolField
        , constField
        , listField
        , listFieldWith
        , functionField
        , mapContext
        , mapContextBy

        , defaultContext
        , bodyField
        , metadataField
        , urlField
        , pathField
        , titleField
        , snippetField
        , dateField
        , dateFieldWith
        , getItemUTC
        , getItemModificationTime
        , modificationTimeField
        , modificationTimeFieldWith
        , teaserField
        , teaserFieldWithSeparator
        , missingField
        ) where

    --------------------------------------------------------------------------------
    import           Control.Applicative           (Alternative (..))
    import           Control.Monad                 (msum)
    #if !MIN_VERSION_base(4,13,0)
    import           Control.Monad.Fail            (MonadFail)
    #endif
    import           Data.List                     (intercalate, tails)
    import           Data.Time.Clock               (UTCTime (..))
    import           Data.Time.Format              (formatTime, parseTimeM)
    import           Data.Time.Locale.Compat       (TimeLocale, defaultTimeLocale)
    import           Hakyll.Core.Compiler
    import           Hakyll.Core.Compiler.Internal
    import           Hakyll.Core.Identifier
    import           Hakyll.Core.Item
    import           Hakyll.Core.Metadata
    import           Hakyll.Core.Provider
    import           Hakyll.Core.Util.String       (needlePrefix, splitAll)
    import           Hakyll.Web.Html
    import           Prelude                       hiding (id)
    import           System.FilePath               (dropExtension, splitDirectories,
                                                    takeBaseName)

    --------------------------------------------------------------------------------
    -- | Mostly for internal usage
    data ContextField
        = EmptyField
        | StringField String
        | forall a. ListField (Context a) [Item a]

    --------------------------------------------------------------------------------
    -- | The 'Context' monoid. Please note that the order in which you
    -- compose the items is important. For example in
    --
    -- > field "A" f1 <> field "A" f2
    --
    -- the first context will overwrite the second. This is especially
    -- important when something is being composed with
    -- 'metadataField' (or 'defaultContext'). If you want your context to be
    -- overwritten by the metadata fields, compose it from the right:
    --
    -- @
    -- 'metadataField' \<\> field \"date\" fDate
    -- @
    --
    newtype Context a = Context
        { forall a.
    Context a -> String -> [String] -> Item a -> Compiler ContextField
    unContext :: String -> [String] -> Item a -> Compiler ContextField
        }

    --------------------------------------------------------------------------------
    -- | Tries to find a key in the left context,
    -- or when that fails in the right context.
    instance Semigroup (Context a) where
        <> :: Context a -> Context a -> Context a
    (<>) (Context String -> [String] -> Item a -> Compiler ContextField
    f) (Context String -> [String] -> Item a -> Compiler ContextField
    g) = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    a Item a
    i -> String -> [String] -> Item a -> Compiler ContextField
    f String
    k [String]
    a Item a
    i Compiler ContextField
    -> Compiler ContextField -> Compiler ContextField
    forall a. Compiler a -> Compiler a -> Compiler a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> String -> [String] -> Item a -> Compiler ContextField
    g String
    k [String]
    a Item a
    i

    instance Monoid (Context a) where
        mempty :: Context a
    mempty  = Context a
    forall a. Context a
    missingField
        mappend :: Context a -> Context a -> Context a
    mappend = Context a -> Context a -> Context a
    forall a. Semigroup a => a -> a -> a
    (<>)

    --------------------------------------------------------------------------------
    field' :: String -> (Item a -> Compiler ContextField) -> Context a
    field' :: forall a. String -> (Item a -> Compiler ContextField) -> Context a
    field' String
    key Item a -> Compiler ContextField
    value = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    _ Item a
    i ->
        if String
    k String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    key
            then Item a -> Compiler ContextField
    value Item a
    i
            else String -> Compiler ContextField
    forall a. String -> Compiler a
    noResult (String -> Compiler ContextField)
    -> String -> Compiler ContextField
    forall a b. (a -> b) -> a -> b
    $ String
    "Tried field " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    key

    --------------------------------------------------------------------------------
    -- | Constructs a new field for a 'Context'.
    -- If the key matches, the compiler is run and its result is substituted in the
    -- template.
    --
    -- If the compiler fails, the field will be considered non-existent
    -- in an @$if()$@ macro or ultimately break the template application
    -- (unless the key is found in another context when using '<>').
    -- Use 'empty' or 'noResult' for intentional failures of fields used in
    -- @$if()$@, to distinguish them from exceptions thrown with 'fail'.
    field
        :: String                      -- ^ Key
        -> (Item a -> Compiler String) -- ^ Function that constructs a value based
                                       -- on the item (e.g. accessing metadata)
        -> Context a
    field :: forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key Item a -> Compiler String
    value = String -> (Item a -> Compiler ContextField) -> Context a
    forall a. String -> (Item a -> Compiler ContextField) -> Context a
    field' String
    key ((String -> ContextField)
    -> Compiler String -> Compiler ContextField
    forall a b. (a -> b) -> Compiler a -> Compiler b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap String -> ContextField
    StringField (Compiler String -> Compiler ContextField)
    -> (Item a -> Compiler String) -> Item a -> Compiler ContextField
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Item a -> Compiler String
    value)

    --------------------------------------------------------------------------------
    -- | Creates a 'field' to use with the @$if()$@ template macro.
    -- Attempting to substitute the field into the template will cause an error.
    boolField
        :: String
        -> (Item a -> Bool)
        -> Context a
    boolField :: forall a. String -> (Item a -> Bool) -> Context a
    boolField String
    name Item a -> Bool
    f = String -> (Item a -> Compiler ContextField) -> Context a
    forall a. String -> (Item a -> Compiler ContextField) -> Context a
    field' String
    name (\Item a
    i -> if Item a -> Bool
    f Item a
    i
        then ContextField -> Compiler ContextField
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ContextField
    EmptyField
        else String -> Compiler ContextField
    forall a. String -> Compiler a
    noResult (String -> Compiler ContextField)
    -> String -> Compiler ContextField
    forall a b. (a -> b) -> a -> b
    $ String
    "Field " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " is false")

    --------------------------------------------------------------------------------
    -- | Creates a 'field' that does not depend on the 'Item' but always yields
    -- the same string
    constField :: String     -- ^ Key
               -> String     -- ^ Value
               -> Context a
    constField :: forall a. String -> String -> Context a
    constField String
    key = String -> (Item a -> Compiler String) -> Context a
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item a -> Compiler String) -> Context a)
    -> (String -> Item a -> Compiler String) -> String -> Context a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Compiler String -> Item a -> Compiler String
    forall a b. a -> b -> a
    const (Compiler String -> Item a -> Compiler String)
    -> (String -> Compiler String)
    -> String
    -> Item a
    -> Compiler String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    --------------------------------------------------------------------------------
    -- | Creates a list field to be consumed by a @$for(…)$@ expression.
    -- The compiler returns multiple items which are rendered in the loop body
    -- with the supplied context.
    listField :: String -> Context a -> Compiler [Item a] -> Context b
    listField :: forall a b. String -> Context a -> Compiler [Item a] -> Context b
    listField String
    key Context a
    c Compiler [Item a]
    xs = String -> Context a -> (Item b -> Compiler [Item a]) -> Context b
    forall a b.
    String -> Context a -> (Item b -> Compiler [Item a]) -> Context b
    listFieldWith String
    key Context a
    c (Compiler [Item a] -> Item b -> Compiler [Item a]
    forall a b. a -> b -> a
    const Compiler [Item a]
    xs)

    --------------------------------------------------------------------------------
    -- | Creates a list field like 'listField', but supplies the current page
    -- to the compiler.
    listFieldWith
        :: String -> Context a -> (Item b -> Compiler [Item a]) -> Context b
    listFieldWith :: forall a b.
    String -> Context a -> (Item b -> Compiler [Item a]) -> Context b
    listFieldWith String
    key Context a
    c Item b -> Compiler [Item a]
    f = String -> (Item b -> Compiler ContextField) -> Context b
    forall a. String -> (Item a -> Compiler ContextField) -> Context a
    field' String
    key ((Item b -> Compiler ContextField) -> Context b)
    -> (Item b -> Compiler ContextField) -> Context b
    forall a b. (a -> b) -> a -> b
    $ ([Item a] -> ContextField)
    -> Compiler [Item a] -> Compiler ContextField
    forall a b. (a -> b) -> Compiler a -> Compiler b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Context a -> [Item a] -> ContextField
    forall a. Context a -> [Item a] -> ContextField
    ListField Context a
    c) (Compiler [Item a] -> Compiler ContextField)
    -> (Item b -> Compiler [Item a]) -> Item b -> Compiler ContextField
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Item b -> Compiler [Item a]
    f

    --------------------------------------------------------------------------------
    -- | Creates a variadic function field.
    --
    -- The function will be called with the dynamically evaluated string arguments
    -- from the template as well as the page that is currently rendered.
    functionField :: String                                  -- ^ Key
                  -> ([String] -> Item a -> Compiler String) -- ^ Function
                  -> Context a
    functionField :: forall a.
    String -> ([String] -> Item a -> Compiler String) -> Context a
    functionField String
    name [String] -> Item a -> Compiler String
    value = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    args Item a
    i ->
        if String
    k String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    name
            then String -> ContextField
    StringField (String -> ContextField)
    -> Compiler String -> Compiler ContextField
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [String] -> Item a -> Compiler String
    value [String]
    args Item a
    i
            else String -> Compiler ContextField
    forall a. String -> Compiler a
    noResult (String -> Compiler ContextField)
    -> String -> Compiler ContextField
    forall a b. (a -> b) -> a -> b
    $ String
    "Tried function field " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name

    --------------------------------------------------------------------------------
    -- | Transform the respective string results of all fields in a context.
    -- For example,
    --
    -- > mapContext (++"c") (constField "x" "a" <> constField "y" "b")
    --
    -- is equivalent to
    --
    -- > constField "x" "ac" <> constField "y" "bc"
    --
    mapContext :: (String -> String) -> Context a -> Context a
    mapContext :: forall a. (String -> String) -> Context a -> Context a
    mapContext = (String -> Bool) -> (String -> String) -> Context a -> Context a
    forall a.
    (String -> Bool) -> (String -> String) -> Context a -> Context a
    mapContextBy (Bool -> String -> Bool
    forall a b. a -> b -> a
    const Bool
    True)

    --------------------------------------------------------------------------------
    -- | Transform the respective string results of all fields in a context
    -- satisfying a predicate. For example,
    --
    -- > mapContextBy (=="y") (++"c") (constField "x" "a" <> constField "y" "b")
    --
    -- is equivalent to
    --
    -- > constField "x" "a" <> constField "y" "bc"
    --
    mapContextBy :: (String -> Bool) -> (String -> String) -> Context a -> Context a
    mapContextBy :: forall a.
    (String -> Bool) -> (String -> String) -> Context a -> Context a
    mapContextBy String -> Bool
    p String -> String
    f (Context String -> [String] -> Item a -> Compiler ContextField
    c) = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    a Item a
    i -> do
        ContextField
    fld <- String -> [String] -> Item a -> Compiler ContextField
    c String
    k [String]
    a Item a
    i
        case ContextField
    fld of
            ContextField
    EmptyField      -> String -> Compiler ContextField
    forall {m :: * -> *} {a}. MonadFail m => String -> m a
    wrongType String
    "boolField"
            StringField String
    str -> ContextField -> Compiler ContextField
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ContextField -> Compiler ContextField)
    -> ContextField -> Compiler ContextField
    forall a b. (a -> b) -> a -> b
    $ String -> ContextField
    StringField (String -> ContextField) -> String -> ContextField
    forall a b. (a -> b) -> a -> b
    $
                                 if String -> Bool
    p String
    k then String -> String
    f String
    str else String
    str
            ContextField
    _               -> String -> Compiler ContextField
    forall {m :: * -> *} {a}. MonadFail m => String -> m a
    wrongType String
    "ListField"
      where
        wrongType :: String -> m a
    wrongType String
    typ = String -> m a
    forall a. String -> m a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> m a) -> String -> m a
    forall a b. (a -> b) -> a -> b
    $ String
    "Hakyll.Web.Template.Context.mapContext: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
            String
    "can't map over a " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    typ String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "!"

    --------------------------------------------------------------------------------
    -- | A context that allows snippet inclusion. In processed file, use as:
    --
    -- > ...
    -- > $snippet("path/to/snippet/")$
    -- > ...
    --
    -- The contents of the included file will not be interpolated like @partial@
    -- does it.
    --
    snippetField :: Context String
    snippetField :: Context String
    snippetField = String
    -> ([String] -> Item String -> Compiler String) -> Context String
    forall a.
    String -> ([String] -> Item a -> Compiler String) -> Context a
    functionField String
    "snippet" [String] -> Item String -> Compiler String
    forall {a} {p}.
    (Binary a, Typeable a) =>
    [String] -> p -> Compiler a
    f
      where
        f :: [String] -> p -> Compiler a
    f [String
    contentsPath] p
    _ = Identifier -> Compiler a
    forall a. (Binary a, Typeable a) => Identifier -> Compiler a
    loadBody (String -> Identifier
    fromFilePath String
    contentsPath)
        f []             p
    _ = String -> Compiler a
    forall a. String -> Compiler a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "No argument to function 'snippet()'"
        f [String]
    _              p
    _ = String -> Compiler a
    forall a. String -> Compiler a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Too many arguments to function 'snippet()'"

    --------------------------------------------------------------------------------
    -- | A context that contains (in that order)
    --
    --     1. A @$body$@ field
    --
    --     2. Metadata fields
    --
    --     3. A @$url$@ 'urlField'
    --
    --     4. A @$path$@ 'pathField'
    --
    --     5. A @$title$@ 'titleField'
    defaultContext :: Context String
    defaultContext :: Context String
    defaultContext =
        String -> Context String
    bodyField     String
    "body"     Context String -> Context String -> Context String
    forall a. Monoid a => a -> a -> a
    `mappend`
        Context String
    forall a. Context a
    metadataField            Context String -> Context String -> Context String
    forall a. Monoid a => a -> a -> a
    `mappend`
        String -> Context String
    forall a. String -> Context a
    urlField      String
    "url"      Context String -> Context String -> Context String
    forall a. Monoid a => a -> a -> a
    `mappend`
        String -> Context String
    forall a. String -> Context a
    pathField     String
    "path"     Context String -> Context String -> Context String
    forall a. Monoid a => a -> a -> a
    `mappend`
        String -> Context String
    forall a. String -> Context a
    titleField    String
    "title"

    --------------------------------------------------------------------------------
    teaserSeparator :: String
    teaserSeparator :: String
    teaserSeparator = String
    "<!--more-->"

    --------------------------------------------------------------------------------
    -- | Constructs a 'field' that contains the body of the item.
    bodyField :: String -> Context String
    bodyField :: String -> Context String
    bodyField String
    key = String -> (Item String -> Compiler String) -> Context String
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item String -> Compiler String) -> Context String)
    -> (Item String -> Compiler String) -> Context String
    forall a b. (a -> b) -> a -> b
    $ String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Compiler String)
    -> (Item String -> String) -> Item String -> Compiler String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Item String -> String
    forall a. Item a -> a
    itemBody

    --------------------------------------------------------------------------------
    -- | Map any field to its metadata value, if present
    metadataField :: Context a
    metadataField :: forall a. Context a
    metadataField = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    _ Item a
    i -> do
        let id :: Identifier
    id = Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item a
    i
            empty' :: Compiler a
    empty' = String -> Compiler a
    forall a. String -> Compiler a
    noResult (String -> Compiler a) -> String -> Compiler a
    forall a b. (a -> b) -> a -> b
    $ String
    "No '" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    k String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "' field in metadata " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                String
    "of item " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Identifier -> String
    forall a. Show a => a -> String
    show Identifier
    id
        Maybe String
    value <- Identifier -> String -> Compiler (Maybe String)
    forall (m :: * -> *).
    MonadMetadata m =>
    Identifier -> String -> m (Maybe String)
    getMetadataField Identifier
    id String
    k
        Compiler ContextField
    -> (String -> Compiler ContextField)
    -> Maybe String
    -> Compiler ContextField
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Compiler ContextField
    forall {a}. Compiler a
    empty' (ContextField -> Compiler ContextField
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ContextField -> Compiler ContextField)
    -> (String -> ContextField) -> String -> Compiler ContextField
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> ContextField
    StringField) Maybe String
    value

    --------------------------------------------------------------------------------
    -- | Absolute url to the resulting item
    urlField :: String -> Context a
    urlField :: forall a. String -> Context a
    urlField String
    key = String -> (Item a -> Compiler String) -> Context a
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item a -> Compiler String) -> Context a)
    -> (Item a -> Compiler String) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    i -> do
        let id :: Identifier
    id = Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item a
    i
            empty' :: [a]
    empty' = String -> [a]
    forall a. String -> [a]
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> [a]) -> String -> [a]
    forall a b. (a -> b) -> a -> b
    $ String
    "No route url found for item " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Identifier -> String
    forall a. Show a => a -> String
    show Identifier
    id
        (Maybe String -> String)
    -> Compiler (Maybe String) -> Compiler String
    forall a b. (a -> b) -> Compiler a -> Compiler b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> (String -> String) -> Maybe String -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe String
    forall {a}. [a]
    empty' String -> String
    toUrl) (Compiler (Maybe String) -> Compiler String)
    -> Compiler (Maybe String) -> Compiler String
    forall a b. (a -> b) -> a -> b
    $ Identifier -> Compiler (Maybe String)
    getRoute Identifier
    id

    --------------------------------------------------------------------------------
    -- | Filepath of the underlying file of the item
    pathField :: String -> Context a
    pathField :: forall a. String -> Context a
    pathField String
    key = String -> (Item a -> Compiler String) -> Context a
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item a -> Compiler String) -> Context a)
    -> (Item a -> Compiler String) -> Context a
    forall a b. (a -> b) -> a -> b
    $ String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Compiler String)
    -> (Item a -> String) -> Item a -> Compiler String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Identifier -> String
    toFilePath (Identifier -> String)
    -> (Item a -> Identifier) -> Item a -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier

    --------------------------------------------------------------------------------
    -- | This title 'field' takes the basename of the underlying file by default
    titleField :: String -> Context a
    titleField :: forall a. String -> Context a
    titleField = (String -> String) -> Context a -> Context a
    forall a. (String -> String) -> Context a -> Context a
    mapContext String -> String
    takeBaseName (Context a -> Context a)
    -> (String -> Context a) -> String -> Context a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Context a
    forall a. String -> Context a
    pathField

    --------------------------------------------------------------------------------
    -- | When the metadata has a field called @published@ in one of the
    -- following formats then this function can render the date.
    --
    --   * @Mon, 06 Sep 2010 00:01:00 +0000@
    --
    --   * @Mon, 06 Sep 2010 00:01:00 UTC@
    --
    --   * @Mon, 06 Sep 2010 00:01:00@
    --
    --   * @2010-09-06T00:01:00+0000@
    --
    --   * @2010-09-06T00:01:00Z@
    --
    --   * @2010-09-06T00:01:00@
    --
    --   * @2010-09-06 00:01:00+0000@
    --
    --   * @2010-09-06 00:01:00@
    --
    --   * @September 06, 2010 00:01 AM@
    --
    -- Following date-only formats are supported too (@00:00:00@ for time is
    -- assumed)
    --
    --   * @2010-09-06@
    --
    --   * @06.09.2010@
    --
    --   * @September 06, 2010@
    --
    -- Alternatively, when the metadata has a field called @path@ in a
    -- @folder/yyyy-mm-dd-title.extension@ format (the convention for pages)
    -- and no @published@ metadata field set, this function can render
    -- the date. This pattern matches the file name or directory names
    -- that begins with @yyyy-mm-dd@ . For example:
    -- @folder//yyyy-mm-dd-title//dist//main.extension@ .
    -- In case of multiple matches, the rightmost one is used.
    --
    -- As another alternative, if none of the above matches, and the file has a
    -- path which contains nested directories specifying a date, then that date
    -- will be used. In other words, if the path is of the form
    -- @**//yyyy//mm//dd//**//main.extension@ .
    -- As above, in case of multiple matches, the rightmost one is used.

    dateField :: String     -- ^ Key in which the rendered date should be placed
              -> String     -- ^ Format to use on the date
              -> Context a  -- ^ Resulting context
    dateField :: forall a. String -> String -> Context a
    dateField = TimeLocale -> String -> String -> Context a
    forall a. TimeLocale -> String -> String -> Context a
    dateFieldWith TimeLocale
    defaultTimeLocale

    --------------------------------------------------------------------------------
    -- | This is an extended version of 'dateField' that allows you to
    -- specify a time locale that is used for outputting the date. For more
    -- details, see 'dateField' and 'formatTime'.
    dateFieldWith :: TimeLocale  -- ^ Output time locale
                  -> String      -- ^ Destination key
                  -> String      -- ^ Format to use on the date
                  -> Context a   -- ^ Resulting context
    dateFieldWith :: forall a. TimeLocale -> String -> String -> Context a
    dateFieldWith TimeLocale
    locale String
    key String
    format = String -> (Item a -> Compiler String) -> Context a
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item a -> Compiler String) -> Context a)
    -> (Item a -> Compiler String) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    i -> do
        UTCTime
    time <- TimeLocale -> Identifier -> Compiler UTCTime
    forall (m :: * -> *).
    (MonadMetadata m, MonadFail m) =>
    TimeLocale -> Identifier -> m UTCTime
    getItemUTC TimeLocale
    locale (Identifier -> Compiler UTCTime) -> Identifier -> Compiler UTCTime
    forall a b. (a -> b) -> a -> b
    $ Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item a
    i
        String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Compiler String) -> String -> Compiler String
    forall a b. (a -> b) -> a -> b
    $ TimeLocale -> String -> UTCTime -> String
    forall t. FormatTime t => TimeLocale -> String -> t -> String
    formatTime TimeLocale
    locale String
    format UTCTime
    time

    --------------------------------------------------------------------------------
    -- | Parser to try to extract and parse the time from the @published@
    -- field or from the filename. See 'dateField' for more information.
    -- Exported for user convenience.
    getItemUTC :: (MonadMetadata m, MonadFail m)
               => TimeLocale        -- ^ Output time locale
               -> Identifier        -- ^ Input page
               -> m UTCTime         -- ^ Parsed UTCTime
    getItemUTC :: forall (m :: * -> *).
    (MonadMetadata m, MonadFail m) =>
    TimeLocale -> Identifier -> m UTCTime
    getItemUTC TimeLocale
    locale Identifier
    id' = do
        Metadata
    metadata <- Identifier -> m Metadata
    forall (m :: * -> *). MonadMetadata m => Identifier -> m Metadata
    getMetadata Identifier
    id'
        let tryField :: String -> String -> Maybe UTCTime
    tryField String
    k String
    fmt = String -> Metadata -> Maybe String
    lookupString String
    k Metadata
    metadata Maybe String -> (String -> Maybe UTCTime) -> Maybe UTCTime
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= String -> String -> Maybe UTCTime
    parseTime' String
    fmt
            paths :: [String]
    paths          = String -> [String]
    splitDirectories (String -> [String]) -> String -> [String]
    forall a b. (a -> b) -> a -> b
    $ (String -> String
    dropExtension (String -> String)
    -> (Identifier -> String) -> Identifier -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Identifier -> String
    toFilePath) Identifier
    id'

        m UTCTime -> (UTCTime -> m UTCTime) -> Maybe UTCTime -> m UTCTime
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe m UTCTime
    forall {a}. m a
    empty' UTCTime -> m UTCTime
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe UTCTime -> m UTCTime) -> Maybe UTCTime -> m UTCTime
    forall a b. (a -> b) -> a -> b
    $ [Maybe UTCTime] -> Maybe UTCTime
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, MonadPlus m) =>
    t (m a) -> m a
    msum ([Maybe UTCTime] -> Maybe UTCTime)
    -> [Maybe UTCTime] -> Maybe UTCTime
    forall a b. (a -> b) -> a -> b
    $
            [String -> String -> Maybe UTCTime
    tryField String
    "published" String
    fmt | String
    fmt <- [String]
    formats] [Maybe UTCTime] -> [Maybe UTCTime] -> [Maybe UTCTime]
    forall a. [a] -> [a] -> [a]
    ++
            [String -> String -> Maybe UTCTime
    tryField String
    "date"      String
    fmt | String
    fmt <- [String]
    formats] [Maybe UTCTime] -> [Maybe UTCTime] -> [Maybe UTCTime]
    forall a. [a] -> [a] -> [a]
    ++
            [String -> String -> Maybe UTCTime
    parseTime' String
    "%Y-%m-%d" (String -> Maybe UTCTime) -> String -> Maybe UTCTime
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "-" ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ Int -> [String] -> [String]
    forall a. Int -> [a] -> [a]
    take Int
    3 ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ String -> String -> [String]
    splitAll String
    "-" String
    fnCand | String
    fnCand <- [String] -> [String]
    forall a. [a] -> [a]
    reverse [String]
    paths] [Maybe UTCTime] -> [Maybe UTCTime] -> [Maybe UTCTime]
    forall a. [a] -> [a] -> [a]
    ++
            [String -> String -> Maybe UTCTime
    parseTime' String
    "%Y-%m-%d" (String -> Maybe UTCTime) -> String -> Maybe UTCTime
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "-" ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ [String]
    fnCand | [String]
    fnCand <- ([String] -> [String]) -> [[String]] -> [[String]]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> [String] -> [String]
    forall a. Int -> [a] -> [a]
    take Int
    3) ([[String]] -> [[String]]) -> [[String]] -> [[String]]
    forall a b. (a -> b) -> a -> b
    $ [[String]] -> [[String]]
    forall a. [a] -> [a]
    reverse ([[String]] -> [[String]])
    -> ([String] -> [[String]]) -> [String] -> [[String]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [String] -> [[String]]
    forall a. [a] -> [[a]]
    tails ([String] -> [[String]]) -> [String] -> [[String]]
    forall a b. (a -> b) -> a -> b
    $ [String]
    paths]
      where
        empty' :: m a
    empty'     = String -> m a
    forall a. String -> m a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> m a) -> String -> m a
    forall a b. (a -> b) -> a -> b
    $ String
    "Hakyll.Web.Template.Context.getItemUTC: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
            String
    "could not parse time for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Identifier -> String
    forall a. Show a => a -> String
    show Identifier
    id'
        parseTime' :: String -> String -> Maybe UTCTime
    parseTime' = Bool -> TimeLocale -> String -> String -> Maybe UTCTime
    forall (m :: * -> *) t.
    (MonadFail m, ParseTime t) =>
    Bool -> TimeLocale -> String -> String -> m t
    parseTimeM Bool
    True TimeLocale
    locale
        formats :: [String]
    formats    =
            [ String
    "%a, %d %b %Y %H:%M:%S %Z"
            , String
    "%a, %d %b %Y %H:%M:%S"
            , String
    "%Y-%m-%dT%H:%M:%S%Z"
            , String
    "%Y-%m-%dT%H:%M:%S"
            , String
    "%Y-%m-%d %H:%M:%S%Z"
            , String
    "%Y-%m-%d %H:%M:%S"
            , String
    "%Y-%m-%d"
            , String
    "%d.%m.%Y"
            , String
    "%B %e, %Y %l:%M %p"
            , String
    "%B %e, %Y"
            , String
    "%b %d, %Y"
            ]

    --------------------------------------------------------------------------------
    -- | Get the time on which the actual file was last modified. This only works if
    -- there actually is an underlying file, of couse.
    getItemModificationTime
        :: Identifier
        -> Compiler UTCTime
    getItemModificationTime :: Identifier -> Compiler UTCTime
    getItemModificationTime Identifier
    identifier = do
        Provider
    provider <- CompilerRead -> Provider
    compilerProvider (CompilerRead -> Provider)
    -> Compiler CompilerRead -> Compiler Provider
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Compiler CompilerRead
    compilerAsk
        UTCTime -> Compiler UTCTime
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (UTCTime -> Compiler UTCTime) -> UTCTime -> Compiler UTCTime
    forall a b. (a -> b) -> a -> b
    $ Provider -> Identifier -> UTCTime
    resourceModificationTime Provider
    provider Identifier
    identifier

    --------------------------------------------------------------------------------
    -- | Creates a field with the last modification date of the underlying item.
    modificationTimeField :: String     -- ^ Key
                          -> String     -- ^ Format
                          -> Context  a -- ^ Resulting context
    modificationTimeField :: forall a. String -> String -> Context a
    modificationTimeField = TimeLocale -> String -> String -> Context a
    forall a. TimeLocale -> String -> String -> Context a
    modificationTimeFieldWith TimeLocale
    defaultTimeLocale

    --------------------------------------------------------------------------------
    -- | Creates a field with the last modification date of the underlying item
    -- in a custom localisation format (see 'formatTime').
    modificationTimeFieldWith :: TimeLocale  -- ^ Time output locale
                              -> String      -- ^ Key
                              -> String      -- ^ Format
                              -> Context a   -- ^ Resulting context
    modificationTimeFieldWith :: forall a. TimeLocale -> String -> String -> Context a
    modificationTimeFieldWith TimeLocale
    locale String
    key String
    fmt = String -> (Item a -> Compiler String) -> Context a
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item a -> Compiler String) -> Context a)
    -> (Item a -> Compiler String) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    i -> do
        UTCTime
    mtime <- Identifier -> Compiler UTCTime
    getItemModificationTime (Identifier -> Compiler UTCTime) -> Identifier -> Compiler UTCTime
    forall a b. (a -> b) -> a -> b
    $ Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item a
    i
        String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Compiler String) -> String -> Compiler String
    forall a b. (a -> b) -> a -> b
    $ TimeLocale -> String -> UTCTime -> String
    forall t. FormatTime t => TimeLocale -> String -> t -> String
    formatTime TimeLocale
    locale String
    fmt UTCTime
    mtime

    --------------------------------------------------------------------------------
    -- | A context with "teaser" key which contain a teaser of the item.
    -- The item is loaded from the given snapshot (which should be saved
    -- in the user code before any templates are applied).
    teaserField :: String           -- ^ Key to use
                -> Snapshot         -- ^ Snapshot to load
                -> Context String   -- ^ Resulting context
    teaserField :: String -> String -> Context String
    teaserField = String -> String -> String -> Context String
    teaserFieldWithSeparator String
    teaserSeparator

    --------------------------------------------------------------------------------
    -- | A context with "teaser" key which contain a teaser of the item, defined as
    -- the snapshot content before the teaser separator. The item is loaded from the
    -- given snapshot (which should be saved in the user code before any templates
    -- are applied).
    teaserFieldWithSeparator :: String           -- ^ Separator to use
                             -> String           -- ^ Key to use
                             -> Snapshot         -- ^ Snapshot to load
                             -> Context String   -- ^ Resulting context
    teaserFieldWithSeparator :: String -> String -> String -> Context String
    teaserFieldWithSeparator String
    separator String
    key String
    snapshot = String -> (Item String -> Compiler String) -> Context String
    forall a. String -> (Item a -> Compiler String) -> Context a
    field String
    key ((Item String -> Compiler String) -> Context String)
    -> (Item String -> Compiler String) -> Context String
    forall a b. (a -> b) -> a -> b
    $ \Item String
    item -> do
        String
    body <- Item String -> String
    forall a. Item a -> a
    itemBody (Item String -> String)
    -> Compiler (Item String) -> Compiler String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Identifier -> String -> Compiler (Item String)
    forall a.
    (Binary a, Typeable a) =>
    Identifier -> String -> Compiler (Item a)
    loadSnapshot (Item String -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item String
    item) String
    snapshot
        case String -> String -> Maybe String
    needlePrefix String
    separator String
    body of
            Maybe String
    Nothing -> String -> Compiler String
    forall a. String -> Compiler a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> Compiler String) -> String -> Compiler String
    forall a b. (a -> b) -> a -> b
    $
                String
    "Hakyll.Web.Template.Context: no teaser defined for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                Identifier -> String
    forall a. Show a => a -> String
    show (Item String -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item String
    item)
            Just String
    t -> String -> Compiler String
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    t

    --------------------------------------------------------------------------------
    -- | Constantly reports any field as missing. Mostly for internal usage,
    -- it is the last choice in every context used in a template application.
    missingField :: Context a
    missingField :: forall a. Context a
    missingField = (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a.
    (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    Context ((String -> [String] -> Item a -> Compiler ContextField)
     -> Context a)
    -> (String -> [String] -> Item a -> Compiler ContextField)
    -> Context a
    forall a b. (a -> b) -> a -> b
    $ \String
    k [String]
    _ Item a
    _ -> String -> Compiler ContextField
    forall a. String -> Compiler a
    noResult (String -> Compiler ContextField)
    -> String -> Compiler ContextField
    forall a b. (a -> b) -> a -> b
    $
        String
    "Missing field '" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    k String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "' in context"