--------------------------------------------------------------------------------
-- | Module exporting convenient pandoc bindings
module Hakyll.Web.Pandoc
    ( -- * The basic building blocks
      readPandoc
    , readPandocWith
    , writePandoc
    , writePandocWith
    , renderPandoc
    , renderPandocWith
    , renderPandocWithTransform
    , renderPandocWithTransformM

      -- * Derived compilers
    , pandocCompiler
    , pandocCompilerWith
    , pandocCompilerWithTransform
    , pandocCompilerWithTransformM

      -- * Default options
    , defaultHakyllReaderOptions
    , defaultHakyllWriterOptions
    ) where


--------------------------------------------------------------------------------
import qualified Data.Text                  as T
import           Text.Pandoc
import           Text.Pandoc.Highlighting   (pygments)


--------------------------------------------------------------------------------
import           Hakyll.Core.Compiler
import           Hakyll.Core.Item
import           Hakyll.Web.Pandoc.FileType


--------------------------------------------------------------------------------
-- | Read a string using pandoc, with the default options
readPandoc
    :: Item String             -- ^ String to read
    -> Compiler (Item Pandoc)  -- ^ Resulting document
readPandoc :: Item String -> Compiler (Item Pandoc)
readPandoc = ReaderOptions -> Item String -> Compiler (Item Pandoc)
readPandocWith ReaderOptions
defaultHakyllReaderOptions


--------------------------------------------------------------------------------
-- | Read a string using pandoc, with the supplied options
readPandocWith
    :: ReaderOptions           -- ^ Parser options
    -> Item String             -- ^ String to read
    -> Compiler (Item Pandoc)  -- ^ Resulting document
readPandocWith :: ReaderOptions -> Item String -> Compiler (Item Pandoc)
readPandocWith ReaderOptions
ropt Item String
item =
    case forall a. PandocPure a -> Either PandocError a
runPure forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (forall {m :: * -> *} {a}.
(PandocMonad m, ToSources a) =>
ReaderOptions -> FileType -> a -> m Pandoc
reader ReaderOptions
ropt (forall a. Item a -> FileType
itemFileType Item String
item)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Text
T.pack Item String
item) of
        Left PandocError
err    -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$
            String
"Hakyll.Web.Pandoc.readPandocWith: parse failed: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show PandocError
err
        Right Item Pandoc
item' -> forall (m :: * -> *) a. Monad m => a -> m a
return Item Pandoc
item'
  where
    reader :: ReaderOptions -> FileType -> a -> m Pandoc
reader ReaderOptions
ro FileType
t = case FileType
t of
        FileType
DocBook            -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readDocBook ReaderOptions
ro
        FileType
Html               -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readHtml ReaderOptions
ro
        FileType
Jupyter            -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readIpynb ReaderOptions
ro
        FileType
LaTeX              -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readLaTeX ReaderOptions
ro
        LiterateHaskell FileType
t' -> ReaderOptions -> FileType -> a -> m Pandoc
reader (ReaderOptions -> Extension -> ReaderOptions
addExt ReaderOptions
ro Extension
Ext_literate_haskell) FileType
t'
        FileType
Markdown           -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readMarkdown ReaderOptions
ro
        FileType
MediaWiki          -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readMediaWiki ReaderOptions
ro
        FileType
OrgMode            -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readOrg ReaderOptions
ro
        FileType
Rst                -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readRST ReaderOptions
ro
        FileType
Textile            -> forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readTextile ReaderOptions
ro
        FileType
_                  -> forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$
            String
"Hakyll.Web.readPandocWith: I don't know how to read a file of " forall a. [a] -> [a] -> [a]
++
            String
"the type " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show FileType
t forall a. [a] -> [a] -> [a]
++ String
" for: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Item a -> Identifier
itemIdentifier Item String
item)

    addExt :: ReaderOptions -> Extension -> ReaderOptions
addExt ReaderOptions
ro Extension
e = ReaderOptions
ro {readerExtensions :: Extensions
readerExtensions = Extension -> Extensions -> Extensions
enableExtension Extension
e forall a b. (a -> b) -> a -> b
$ ReaderOptions -> Extensions
readerExtensions ReaderOptions
ro}


--------------------------------------------------------------------------------
-- | Write a document (as HTML) using pandoc, with the default options
writePandoc :: Item Pandoc  -- ^ Document to write
            -> Item String  -- ^ Resulting HTML
writePandoc :: Item Pandoc -> Item String
writePandoc = WriterOptions -> Item Pandoc -> Item String
writePandocWith WriterOptions
defaultHakyllWriterOptions


--------------------------------------------------------------------------------
-- | Write a document (as HTML) using pandoc, with the supplied options
writePandocWith :: WriterOptions  -- ^ Writer options for pandoc
                -> Item Pandoc    -- ^ Document to write
                -> Item String    -- ^ Resulting HTML
writePandocWith :: WriterOptions -> Item Pandoc -> Item String
writePandocWith WriterOptions
wopt (Item Identifier
itemi Pandoc
doc) =
    case forall a. PandocPure a -> Either PandocError a
runPure forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
PandocMonad m =>
WriterOptions -> Pandoc -> m Text
writeHtml5String WriterOptions
wopt Pandoc
doc of
        Left PandocError
err    -> forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Hakyll.Web.Pandoc.writePandocWith: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show PandocError
err
        Right Text
item' -> forall a. Identifier -> a -> Item a
Item Identifier
itemi forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
item'


--------------------------------------------------------------------------------
-- | Render the resource using pandoc
renderPandoc :: Item String -> Compiler (Item String)
renderPandoc :: Item String -> Compiler (Item String)
renderPandoc =
    ReaderOptions
-> WriterOptions -> Item String -> Compiler (Item String)
renderPandocWith ReaderOptions
defaultHakyllReaderOptions WriterOptions
defaultHakyllWriterOptions


--------------------------------------------------------------------------------
-- | Render the resource using pandoc
renderPandocWith
    :: ReaderOptions -> WriterOptions -> Item String -> Compiler (Item String)
renderPandocWith :: ReaderOptions
-> WriterOptions -> Item String -> Compiler (Item String)
renderPandocWith ReaderOptions
ropt WriterOptions
wopt Item String
item =
    WriterOptions -> Item Pandoc -> Item String
writePandocWith WriterOptions
wopt forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderOptions -> Item String -> Compiler (Item Pandoc)
readPandocWith ReaderOptions
ropt Item String
item


--------------------------------------------------------------------------------
-- | An extension of `renderPandocWith`, which allows you to specify a custom
-- Pandoc transformation on the input `Item`.
-- Useful if you want to do your own transformations before running
-- custom Pandoc transformations, e.g. using a `funcField` to transform raw content.
renderPandocWithTransform :: ReaderOptions -> WriterOptions
                    -> (Pandoc -> Pandoc)
                    -> Item String
                    -> Compiler (Item String)
renderPandocWithTransform :: ReaderOptions
-> WriterOptions
-> (Pandoc -> Pandoc)
-> Item String
-> Compiler (Item String)
renderPandocWithTransform ReaderOptions
ropt WriterOptions
wopt Pandoc -> Pandoc
f =
    ReaderOptions
-> WriterOptions
-> (Pandoc -> Compiler Pandoc)
-> Item String
-> Compiler (Item String)
renderPandocWithTransformM ReaderOptions
ropt WriterOptions
wopt (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pandoc -> Pandoc
f)


--------------------------------------------------------------------------------
-- | Similar to `renderPandocWithTransform`, but the Pandoc transformation is
-- monadic. This is useful when you want the pandoc
-- transformation to use the `Compiler` information such as routes,
-- metadata, etc. along with your own transformations beforehand.
renderPandocWithTransformM :: ReaderOptions -> WriterOptions
                    -> (Pandoc -> Compiler Pandoc)
                    -> Item String
                    -> Compiler (Item String)
renderPandocWithTransformM :: ReaderOptions
-> WriterOptions
-> (Pandoc -> Compiler Pandoc)
-> Item String
-> Compiler (Item String)
renderPandocWithTransformM ReaderOptions
ropt WriterOptions
wopt Pandoc -> Compiler Pandoc
f Item String
i =
    WriterOptions -> Item Pandoc -> Item String
writePandocWith WriterOptions
wopt forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Pandoc -> Compiler Pandoc
f forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ReaderOptions -> Item String -> Compiler (Item Pandoc)
readPandocWith ReaderOptions
ropt Item String
i)


--------------------------------------------------------------------------------
-- | Read a page render using pandoc
pandocCompiler :: Compiler (Item String)
pandocCompiler :: Compiler (Item String)
pandocCompiler =
    ReaderOptions -> WriterOptions -> Compiler (Item String)
pandocCompilerWith ReaderOptions
defaultHakyllReaderOptions WriterOptions
defaultHakyllWriterOptions


--------------------------------------------------------------------------------
-- | A version of 'pandocCompiler' which allows you to specify your own pandoc
-- options
pandocCompilerWith :: ReaderOptions -> WriterOptions -> Compiler (Item String)
pandocCompilerWith :: ReaderOptions -> WriterOptions -> Compiler (Item String)
pandocCompilerWith ReaderOptions
ropt WriterOptions
wopt =
    forall a.
(Binary a, Typeable a) =>
String -> Compiler a -> Compiler a
cached String
"Hakyll.Web.Pandoc.pandocCompilerWith" forall a b. (a -> b) -> a -> b
$
        ReaderOptions
-> WriterOptions -> (Pandoc -> Pandoc) -> Compiler (Item String)
pandocCompilerWithTransform ReaderOptions
ropt WriterOptions
wopt forall a. a -> a
id


--------------------------------------------------------------------------------
-- | An extension of 'pandocCompilerWith' which allows you to specify a custom
-- pandoc transformation for the content
pandocCompilerWithTransform :: ReaderOptions -> WriterOptions
                            -> (Pandoc -> Pandoc)
                            -> Compiler (Item String)
pandocCompilerWithTransform :: ReaderOptions
-> WriterOptions -> (Pandoc -> Pandoc) -> Compiler (Item String)
pandocCompilerWithTransform ReaderOptions
ropt WriterOptions
wopt Pandoc -> Pandoc
f =
    ReaderOptions
-> WriterOptions
-> (Pandoc -> Compiler Pandoc)
-> Compiler (Item String)
pandocCompilerWithTransformM ReaderOptions
ropt WriterOptions
wopt (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pandoc -> Pandoc
f)


--------------------------------------------------------------------------------
-- | Similar to 'pandocCompilerWithTransform', but the transformation
-- function is monadic. This is useful when you want the pandoc
-- transformation to use the 'Compiler' information such as routes,
-- metadata, etc
pandocCompilerWithTransformM :: ReaderOptions -> WriterOptions
                    -> (Pandoc -> Compiler Pandoc)
                    -> Compiler (Item String)
pandocCompilerWithTransformM :: ReaderOptions
-> WriterOptions
-> (Pandoc -> Compiler Pandoc)
-> Compiler (Item String)
pandocCompilerWithTransformM ReaderOptions
ropt WriterOptions
wopt Pandoc -> Compiler Pandoc
f =
    Compiler (Item String)
getResourceBody forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ReaderOptions
-> WriterOptions
-> (Pandoc -> Compiler Pandoc)
-> Item String
-> Compiler (Item String)
renderPandocWithTransformM ReaderOptions
ropt WriterOptions
wopt Pandoc -> Compiler Pandoc
f


--------------------------------------------------------------------------------
-- | The default reader options for pandoc parsing in hakyll
defaultHakyllReaderOptions :: ReaderOptions
defaultHakyllReaderOptions :: ReaderOptions
defaultHakyllReaderOptions = forall a. Default a => a
def
    { -- The following option causes pandoc to read smart typography, a nice
      -- and free bonus.
      readerExtensions :: Extensions
readerExtensions = Extension -> Extensions -> Extensions
enableExtension Extension
Ext_smart Extensions
pandocExtensions
    }


--------------------------------------------------------------------------------
-- | The default writer options for pandoc rendering in hakyll
defaultHakyllWriterOptions :: WriterOptions
defaultHakyllWriterOptions :: WriterOptions
defaultHakyllWriterOptions = forall a. Default a => a
def
    { -- This option causes literate haskell to be written using '>' marks in
      -- html, which I think is a good default.
      writerExtensions :: Extensions
writerExtensions = Extension -> Extensions -> Extensions
enableExtension Extension
Ext_smart Extensions
pandocExtensions
    , -- We want to have hightlighting by default, to be compatible with earlier
      -- Hakyll releases
      writerHighlightStyle :: Maybe Style
writerHighlightStyle = forall a. a -> Maybe a
Just Style
pygments
    , -- Do not word-wrap produced HTML, and do not undo any word-wrapping
      -- that's already present in the markup. This is how Pandoc operated
      -- prior to 2.17, but the behaviour was changed for consistency with
      -- other Pandoc writers. We retain the old behaviour because it spares us
      -- the trouble of updating our golden tests.
      writerWrapText :: WrapOption
writerWrapText = WrapOption
WrapPreserve
    }