    --------------------------------------------------------------------------------
    -- | Module for trimming whitespace from tempaltes.
    module Hakyll.Web.Template.Internal.Trim
        ( trim
        ) where

    --------------------------------------------------------------------------------
    import           Data.Char                            (isSpace)
    import           Data.List                            (dropWhileEnd)

    --------------------------------------------------------------------------------
    import           Hakyll.Web.Template.Internal.Element

    --------------------------------------------------------------------------------
    trim :: [TemplateElement] -> [TemplateElement]
    trim :: [TemplateElement] -> [TemplateElement]
    trim = [TemplateElement] -> [TemplateElement]
    cleanse ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    canonicalize

    --------------------------------------------------------------------------------
    -- | Apply the Trim nodes to the Chunks.
    cleanse :: [TemplateElement] -> [TemplateElement]
    cleanse :: [TemplateElement] -> [TemplateElement]
    cleanse = ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    cleanse ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    process
        where process :: [TemplateElement] -> [TemplateElement]
    process [] = []
              process (TemplateElement
    TrimR:Chunk String
    str:[TemplateElement]
    ts) = let str' :: String
    str' = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhile Char -> Bool
    isSpace String
    str
                                             in if String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    str'
                                                    then [TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts
                                                    -- Might need to TrimL.
                                                    else [TemplateElement] -> [TemplateElement]
    process ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    forall a b. (a -> b) -> a -> b
    $ String -> TemplateElement
    Chunk String
    str'TemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement]
    ts

              process (Chunk String
    str:TemplateElement
    TrimL:[TemplateElement]
    ts) = let str' :: String
    str' = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhileEnd Char -> Bool
    isSpace String
    str
                                             in if String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    str'
                                                    then [TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts
                                                    else String -> TemplateElement
    Chunk String
    str'TemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts

              process (TemplateElement
    t:[TemplateElement]
    ts) = TemplateElement
    tTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts

    --------------------------------------------------------------------------------
    -- | Enforce the invariant that:
    --
    --     * Every 'TrimL' has a 'Chunk' to its left.
    --     * Every 'TrimR' has a 'Chunk' to its right.
    --
    canonicalize :: [TemplateElement] -> [TemplateElement]
    canonicalize :: [TemplateElement] -> [TemplateElement]
    canonicalize = [TemplateElement] -> [TemplateElement]
    go
        where go :: [TemplateElement] -> [TemplateElement]
    go [TemplateElement]
    t = let t' :: [TemplateElement]
    t' = [TemplateElement] -> [TemplateElement]
    redundant ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    swap ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    forall a b. (a -> b) -> a -> b
    $ [TemplateElement] -> [TemplateElement]
    dedupe [TemplateElement]
    t
                     in if [TemplateElement]
    t [TemplateElement] -> [TemplateElement] -> Bool
    forall a. Eq a => a -> a -> Bool
    == [TemplateElement]
    t' then [TemplateElement]
    t else [TemplateElement] -> [TemplateElement]
    go [TemplateElement]
    t'

    --------------------------------------------------------------------------------
    -- | Remove the 'TrimR' and 'TrimL's that are no-ops.
    redundant :: [TemplateElement] -> [TemplateElement]
    redundant :: [TemplateElement] -> [TemplateElement]
    redundant = ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    redundant ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    process
        where -- Remove the leading 'TrimL's.
              process :: [TemplateElement] -> [TemplateElement]
    process (TemplateElement
    TrimL:[TemplateElement]
    ts) = [TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts
              -- Remove trailing 'TrimR's.
              process [TemplateElement]
    ts = (TemplateElement -> [TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement] -> [TemplateElement]
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr TemplateElement -> [TemplateElement] -> [TemplateElement]
    trailing [] [TemplateElement]
    ts
                  where trailing :: TemplateElement -> [TemplateElement] -> [TemplateElement]
    trailing TemplateElement
    TrimR [] = []
                        trailing TemplateElement
    x [TemplateElement]
    xs     = TemplateElement
    xTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement]
    xs

    --------------------------------------------------------------------------------
    -- >>> swap $ [TrimR, TrimL]
    -- [TrimL, TrimR]
    swap :: [TemplateElement] -> [TemplateElement]
    swap :: [TemplateElement] -> [TemplateElement]
    swap = ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    swap ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    process
        where process :: [TemplateElement] -> [TemplateElement]
    process []               = []
              process (TemplateElement
    TrimR:TemplateElement
    TrimL:[TemplateElement]
    ts) = TemplateElement
    TrimLTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement] -> [TemplateElement]
    process (TemplateElement
    TrimRTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement]
    ts)
              process (TemplateElement
    t:[TemplateElement]
    ts)           = TemplateElement
    tTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts

    --------------------------------------------------------------------------------
    -- | Remove 'TrimR' and 'TrimL' duplication.
    dedupe :: [TemplateElement] -> [TemplateElement]
    dedupe :: [TemplateElement] -> [TemplateElement]
    dedupe = ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    dedupe ([TemplateElement] -> [TemplateElement])
    -> ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement]
    -> [TemplateElement]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [TemplateElement] -> [TemplateElement]
    process
        where process :: [TemplateElement] -> [TemplateElement]
    process []               = []
              process (TemplateElement
    TrimR:TemplateElement
    TrimR:[TemplateElement]
    ts) = [TemplateElement] -> [TemplateElement]
    process (TemplateElement
    TrimRTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement]
    ts)
              process (TemplateElement
    TrimL:TemplateElement
    TrimL:[TemplateElement]
    ts) = [TemplateElement] -> [TemplateElement]
    process (TemplateElement
    TrimLTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement]
    ts)
              process (TemplateElement
    t:[TemplateElement]
    ts)           = TemplateElement
    tTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :[TemplateElement] -> [TemplateElement]
    process [TemplateElement]
    ts

    --------------------------------------------------------------------------------
    -- | @'recurse' f t@ applies f to every '[TemplateElement]' in t.
    recurse :: ([TemplateElement] -> [TemplateElement])
            -> [TemplateElement]
            -> [TemplateElement]
    recurse :: ([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    _ []     = []
    recurse [TemplateElement] -> [TemplateElement]
    f (TemplateElement
    x:[TemplateElement]
    xs) = TemplateElement -> TemplateElement
    process TemplateElement
    xTemplateElement -> [TemplateElement] -> [TemplateElement]
    forall a. a -> [a] -> [a]
    :([TemplateElement] -> [TemplateElement])
    -> [TemplateElement] -> [TemplateElement]
    recurse [TemplateElement] -> [TemplateElement]
    f [TemplateElement]
    xs
        where process :: TemplateElement -> TemplateElement
    process TemplateElement
    y = case TemplateElement
    y of
                              If TemplateExpr
    e [TemplateElement]
    tb Maybe [TemplateElement]
    eb -> TemplateExpr
    -> [TemplateElement] -> Maybe [TemplateElement] -> TemplateElement
    If TemplateExpr
    e ([TemplateElement] -> [TemplateElement]
    f [TemplateElement]
    tb) ([TemplateElement] -> [TemplateElement]
    f ([TemplateElement] -> [TemplateElement])
    -> Maybe [TemplateElement] -> Maybe [TemplateElement]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe [TemplateElement]
    eb)
                              For TemplateExpr
    e [TemplateElement]
    t Maybe [TemplateElement]
    s  -> TemplateExpr
    -> [TemplateElement] -> Maybe [TemplateElement] -> TemplateElement
    For TemplateExpr
    e ([TemplateElement] -> [TemplateElement]
    f [TemplateElement]
    t) ([TemplateElement] -> [TemplateElement]
    f ([TemplateElement] -> [TemplateElement])
    -> Maybe [TemplateElement] -> Maybe [TemplateElement]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe [TemplateElement]
    s)
                              TemplateElement
    _          -> TemplateElement
    y