packages feed

pandoc-builder-monadic-1.0.0: src/Text/Pandoc/Builder/Monadic/Internal.hs

{-# 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 { unBuilder :: Writer (DList el) a }

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

instance Functor (BuilderM el) where
  fmap f = Builder . fmap f . unBuilder

instance Applicative (BuilderM el) where
  pure a = Builder $ pure a
  Builder f <*> Builder a = Builder $ f <*> a

instance Monad (BuilderM el) where
  Builder a >>= f = Builder $ do
    a' <- a
    unBuilder $ f a'

instance Semigroup (BuilderM el a) where
  Builder a <> Builder b = Builder $ a >> b

instance Monoid a => Monoid (BuilderM el a) where
  mempty = Builder $ pure mempty

instance B.ToMetaValue (Builder Inline) where
  toMetaValue = B.MetaInlines . runToList

-- | Useful for setting authors
instance B.ToMetaValue (Builder (Builder Inline)) where
  toMetaValue = B.MetaList . map B.toMetaValue . runToList

-- | Get elements written in the t'Builder' as a difference list
runToDList :: Builder el -> DList el
runToDList = execWriter . unBuilder

-- | Get elements written in the t'Builder' as a list
runToList :: Builder el -> [el]
runToList = DList.toList . 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 = B.fromList . DList.toList . execWriter . unBuilder

-- | Get pandoc-types' 'B.Many' as a t'Builder'.
buildMany :: B.Many a -> Builder a
buildMany = Builder . traverse_ (tell . pure)

-- | Write a single element to a t'Builder'.
tellOne :: a -> Builder a
tellOne = Builder . tell . DList.singleton

-- | Write multiple element to a t'Builder'.
tellAll :: DList a -> Builder a
tellAll = Builder . tell