{-# LANGUAGE CPP               #-}
{-# LANGUAGE FlexibleInstances #-}

{-|
Internal module, exposing the Builder(..) type, you should
prefer using 'Text.Pandoc.Builder.Monadic.Utils.mapBuilder',
or adding something to 'Text.Pandoc.Builder.Monadic.Utils'.
-}

module Text.Pandoc.Builder.Monadic.Internal
  ( BuilderM(..)
  , Builder
  , buildMany
  , runToList
  , runToDList
  , runToMany
  , tellOne
  , tellAll
  ) where

import Control.Monad.Writer.Strict (Writer, execWriter, tell)
import Data.DList                  (DList)
import Data.Foldable               (traverse_)
import Text.Pandoc.Builder         (Inline)
#if __GLASGOW_HASKELL__ < 804
import Data.Semigroup
#endif

import qualified Text.Pandoc.Builder         as B
import qualified Data.DList                  as DList

-- | The pandoc element builder type. It wraps a writer monad.
-- Chances are, you only need t'Builder' (a 'BuilderM el ()').
-- All builders in this library have an `el` type in the set
-- {'B.Inline', 'B.Block'}.
newtype BuilderM el a = Builder { forall el a. BuilderM el a -> Writer (DList el) a
unBuilder :: Writer (DList el) a }

-- | Pandoc element builder. Stores written pandoc elements.
type Builder el = BuilderM el ()

instance Functor (BuilderM el) where
  fmap :: forall a b. (a -> b) -> BuilderM el a -> BuilderM el b
fmap a -> b
f = Writer (DList el) b -> BuilderM el b
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) b -> BuilderM el b)
-> (BuilderM el a -> Writer (DList el) b)
-> BuilderM el a
-> BuilderM el b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> WriterT (DList el) Identity a -> Writer (DList el) b
forall a b.
(a -> b)
-> WriterT (DList el) Identity a -> WriterT (DList el) Identity b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (WriterT (DList el) Identity a -> Writer (DList el) b)
-> (BuilderM el a -> WriterT (DList el) Identity a)
-> BuilderM el a
-> Writer (DList el) b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuilderM el a -> WriterT (DList el) Identity a
forall el a. BuilderM el a -> Writer (DList el) a
unBuilder

instance Applicative (BuilderM el) where
  pure :: forall a. a -> BuilderM el a
pure a
a = Writer (DList el) a -> BuilderM el a
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) a -> BuilderM el a)
-> Writer (DList el) a -> BuilderM el a
forall a b. (a -> b) -> a -> b
$ a -> Writer (DList el) a
forall a. a -> WriterT (DList el) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
  Builder Writer (DList el) (a -> b)
f <*> :: forall a b. BuilderM el (a -> b) -> BuilderM el a -> BuilderM el b
<*> Builder Writer (DList el) a
a = Writer (DList el) b -> BuilderM el b
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) b -> BuilderM el b)
-> Writer (DList el) b -> BuilderM el b
forall a b. (a -> b) -> a -> b
$ Writer (DList el) (a -> b)
f Writer (DList el) (a -> b)
-> Writer (DList el) a -> Writer (DList el) b
forall a b.
WriterT (DList el) Identity (a -> b)
-> WriterT (DList el) Identity a -> WriterT (DList el) Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Writer (DList el) a
a

instance Monad (BuilderM el) where
  Builder Writer (DList el) a
a >>= :: forall a b. BuilderM el a -> (a -> BuilderM el b) -> BuilderM el b
>>= a -> BuilderM el b
f = Writer (DList el) b -> BuilderM el b
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) b -> BuilderM el b)
-> Writer (DList el) b -> BuilderM el b
forall a b. (a -> b) -> a -> b
$ do
    a
a' <- Writer (DList el) a
a
    BuilderM el b -> Writer (DList el) b
forall el a. BuilderM el a -> Writer (DList el) a
unBuilder (BuilderM el b -> Writer (DList el) b)
-> BuilderM el b -> Writer (DList el) b
forall a b. (a -> b) -> a -> b
$ a -> BuilderM el b
f a
a'

instance Semigroup (BuilderM el a) where
  Builder Writer (DList el) a
a <> :: BuilderM el a -> BuilderM el a -> BuilderM el a
<> Builder Writer (DList el) a
b = Writer (DList el) a -> BuilderM el a
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) a -> BuilderM el a)
-> Writer (DList el) a -> BuilderM el a
forall a b. (a -> b) -> a -> b
$ Writer (DList el) a
a Writer (DList el) a -> Writer (DList el) a -> Writer (DList el) a
forall a b.
WriterT (DList el) Identity a
-> WriterT (DList el) Identity b -> WriterT (DList el) Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Writer (DList el) a
b

instance Monoid a => Monoid (BuilderM el a) where
  mempty :: BuilderM el a
mempty = Writer (DList el) a -> BuilderM el a
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList el) a -> BuilderM el a)
-> Writer (DList el) a -> BuilderM el a
forall a b. (a -> b) -> a -> b
$ a -> Writer (DList el) a
forall a. a -> WriterT (DList el) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
forall a. Monoid a => a
mempty
#if !(MIN_VERSION_base(4,11,0))
  mappend f g = do
    a <- f
    b <- g
    pure (mappend a b)
#endif

instance B.ToMetaValue (Builder Inline) where
  toMetaValue :: Builder Inline -> MetaValue
toMetaValue = [Inline] -> MetaValue
B.MetaInlines ([Inline] -> MetaValue)
-> (Builder Inline -> [Inline]) -> Builder Inline -> MetaValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder Inline -> [Inline]
forall el. Builder el -> [el]
runToList

-- | Useful for setting authors
instance B.ToMetaValue (Builder (Builder Inline)) where
  toMetaValue :: Builder (Builder Inline) -> MetaValue
toMetaValue = [MetaValue] -> MetaValue
B.MetaList ([MetaValue] -> MetaValue)
-> (Builder (Builder Inline) -> [MetaValue])
-> Builder (Builder Inline)
-> MetaValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder Inline -> MetaValue) -> [Builder Inline] -> [MetaValue]
forall a b. (a -> b) -> [a] -> [b]
map Builder Inline -> MetaValue
forall a. ToMetaValue a => a -> MetaValue
B.toMetaValue ([Builder Inline] -> [MetaValue])
-> (Builder (Builder Inline) -> [Builder Inline])
-> Builder (Builder Inline)
-> [MetaValue]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder (Builder Inline) -> [Builder Inline]
forall el. Builder el -> [el]
runToList

-- | Get elements written in the t'Builder' as a difference list
runToDList :: Builder el -> DList el
runToDList :: forall el. Builder el -> DList el
runToDList = Writer (DList el) () -> DList el
forall w a. Writer w a -> w
execWriter (Writer (DList el) () -> DList el)
-> (Builder el -> Writer (DList el) ()) -> Builder el -> DList el
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder el -> Writer (DList el) ()
forall el a. BuilderM el a -> Writer (DList el) a
unBuilder

-- | Get elements written in the t'Builder' as a list
runToList :: Builder el -> [el]
runToList :: forall el. Builder el -> [el]
runToList = DList el -> [el]
forall a. DList a -> [a]
DList.toList (DList el -> [el])
-> (Builder el -> DList el) -> Builder el -> [el]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder el -> DList el
forall el. Builder el -> DList el
runToDList

-- | Get elements written in a t'Builder' as a 'B.Many'.
-- This might be useful if you need to interact with pandoc-types.
runToMany :: Builder a -> B.Many a
runToMany :: forall a. Builder a -> Many a
runToMany = [a] -> Many a
forall a. [a] -> Many a
B.fromList ([a] -> Many a) -> (Builder a -> [a]) -> Builder a -> Many a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList a -> [a]
forall a. DList a -> [a]
DList.toList (DList a -> [a]) -> (Builder a -> DList a) -> Builder a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Writer (DList a) () -> DList a
forall w a. Writer w a -> w
execWriter (Writer (DList a) () -> DList a)
-> (Builder a -> Writer (DList a) ()) -> Builder a -> DList a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder a -> Writer (DList a) ()
forall el a. BuilderM el a -> Writer (DList el) a
unBuilder

-- | Get pandoc-types' 'B.Many' as a t'Builder'.
buildMany :: B.Many a -> Builder a
buildMany :: forall a. Many a -> Builder a
buildMany = Writer (DList a) () -> BuilderM a ()
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList a) () -> BuilderM a ())
-> (Many a -> Writer (DList a) ()) -> Many a -> BuilderM a ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Writer (DList a) ()) -> Many a -> Writer (DList a) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (DList a -> Writer (DList a) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (DList a -> Writer (DList a) ())
-> (a -> DList a) -> a -> Writer (DList a) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> DList a
forall a. a -> DList a
forall (f :: * -> *) a. Applicative f => a -> f a
pure)

-- | Write a single element to a t'Builder'.
tellOne :: a -> Builder a
tellOne :: forall a. a -> Builder a
tellOne = Writer (DList a) () -> BuilderM a ()
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList a) () -> BuilderM a ())
-> (a -> Writer (DList a) ()) -> a -> BuilderM a ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList a -> Writer (DList a) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (DList a -> Writer (DList a) ())
-> (a -> DList a) -> a -> Writer (DList a) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> DList a
forall a. a -> DList a
DList.singleton

-- | Write multiple element to a t'Builder'.
tellAll :: DList a -> Builder a
tellAll :: forall a. DList a -> Builder a
tellAll = Writer (DList a) () -> BuilderM a ()
forall el a. Writer (DList el) a -> BuilderM el a
Builder (Writer (DList a) () -> BuilderM a ())
-> (DList a -> Writer (DList a) ()) -> DList a -> BuilderM a ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList a -> Writer (DList a) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell