{-# LANGUAGE RecordWildCards #-}

-- | Types for custom render extensions to Pandoc AST nodes.
--
-- Note that unlike Pandoc *filters* (which operate on entire document), these
-- are modeled based on Text.Pandoc.Walk, ie. fine-grained on individual inline
-- and block processing. We do this only so as to render a specific node during
-- recursion (cf. `rpBlock` and `rpInline` in Render.hs).
--
-- So we expect the extensions to be in Haskell, however external script may be
-- supported using a traditional whole-AST extension API.
module Emanote.Pandoc.Renderer
  ( PandocRenderers (PandocRenderers),
    PandocInlineRenderer,
    PandocBlockRenderer,
    mkRenderCtxWithPandocRenderers,
    EmanotePandocRenderers (..),
  )
where

import Heist (HeistT)
import Heist.Extra.Splices.Pandoc qualified as Splices
import Heist.Extra.Splices.Pandoc.Ctx qualified as Splices
import Heist.Interpreted qualified as HI
import Relude
import Text.Pandoc.Definition qualified as B

-- | Custom Heist renderer function for specific Pandoc AST nodes
type PandocRenderF model route astNode =
  model ->
  PandocRenderers model route ->
  Splices.RenderCtx ->
  route ->
  astNode ->
  Maybe (HI.Splice Identity)

type PandocInlineRenderer model route = PandocRenderF model route B.Inline

type PandocBlockRenderer model route = PandocRenderF model route B.Block

data PandocRenderers model route = PandocRenderers
  { forall model route.
PandocRenderers model route -> [PandocInlineRenderer model route]
pandocInlineRenderers :: [PandocInlineRenderer model route],
    forall model route.
PandocRenderers model route -> [PandocBlockRenderer model route]
pandocBlockRenderers :: [PandocBlockRenderer model route]
  }

mkRenderCtxWithPandocRenderers ::
  forall model route m.
  (Monad m) =>
  PandocRenderers model route ->
  Map Text Text ->
  model ->
  route ->
  HeistT Identity m Splices.RenderCtx
mkRenderCtxWithPandocRenderers :: forall model route (m :: Type -> Type).
Monad m =>
PandocRenderers model route
-> Map Text Text -> model -> route -> HeistT Identity m RenderCtx
mkRenderCtxWithPandocRenderers nr :: PandocRenderers model route
nr@PandocRenderers {[PandocBlockRenderer model route]
[PandocInlineRenderer model route]
pandocBlockRenderers :: [PandocBlockRenderer model route]
pandocInlineRenderers :: [PandocInlineRenderer model route]
pandocBlockRenderers :: forall model route.
PandocRenderers model route -> [PandocBlockRenderer model route]
pandocInlineRenderers :: forall model route.
PandocRenderers model route -> [PandocInlineRenderer model route]
..} Map Text Text
classRules model
model route
x =
  Map Text Text
-> (RenderCtx -> Block -> Maybe (Splice Identity))
-> (RenderCtx -> Inline -> Maybe (Splice Identity))
-> HeistT Identity m RenderCtx
forall (m :: Type -> Type).
Monad m =>
Map Text Text
-> (RenderCtx -> Block -> Maybe (Splice Identity))
-> (RenderCtx -> Inline -> Maybe (Splice Identity))
-> HeistT Identity m RenderCtx
Splices.mkRenderCtx
    Map Text Text
classRules
    ( \RenderCtx
ctx Block
blk ->
        [Maybe (Splice Identity)] -> Maybe (Splice Identity)
forall (t :: Type -> Type) (f :: Type -> Type) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum ([Maybe (Splice Identity)] -> Maybe (Splice Identity))
-> [Maybe (Splice Identity)] -> Maybe (Splice Identity)
forall a b. (a -> b) -> a -> b
$
          [PandocBlockRenderer model route]
pandocBlockRenderers [PandocBlockRenderer model route]
-> (PandocBlockRenderer model route -> Maybe (Splice Identity))
-> [Maybe (Splice Identity)]
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> \PandocBlockRenderer model route
f ->
            PandocBlockRenderer model route
f model
model PandocRenderers model route
nr RenderCtx
ctx route
x Block
blk
    )
    ( \RenderCtx
ctx Inline
blk ->
        [Maybe (Splice Identity)] -> Maybe (Splice Identity)
forall (t :: Type -> Type) (f :: Type -> Type) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum ([Maybe (Splice Identity)] -> Maybe (Splice Identity))
-> [Maybe (Splice Identity)] -> Maybe (Splice Identity)
forall a b. (a -> b) -> a -> b
$
          [PandocInlineRenderer model route]
pandocInlineRenderers [PandocInlineRenderer model route]
-> (PandocInlineRenderer model route -> Maybe (Splice Identity))
-> [Maybe (Splice Identity)]
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> \PandocInlineRenderer model route
f ->
            PandocInlineRenderer model route
f model
model PandocRenderers model route
nr RenderCtx
ctx route
x Inline
blk
    )

data EmanotePandocRenderers a r = EmanotePandocRenderers
  { forall a r. EmanotePandocRenderers a r -> PandocRenderers a r
blockRenderers :: PandocRenderers a r,
    -- | Like `blockRenderers` but for use in inline contexts.
    --
    -- Backlinks and titles constitute an example of inline context, where we don't
    -- care about block elements.
    forall a r. EmanotePandocRenderers a r -> PandocRenderers a r
inlineRenderers :: PandocRenderers a r,
    -- | Like `inlineRenderers` but suitable for use inside links (<a> tags).
    forall a r. EmanotePandocRenderers a r -> PandocRenderers a r
linkInlineRenderers :: PandocRenderers a r
  }