{-# LANGUAGE OverloadedStrings #-}

{-|
Utility functions for working with builders, and constructed pandoc ASTs
-}

module Text.Pandoc.Builder.Monadic.Utils
  ( mapBuilder
  , intersperseTablesWithBlankRows
  , vspace
  ) where

import Data.List                            (intersperse)
import Text.Pandoc.Builder.Monadic.Internal (tellAll, runToDList)
import Text.Pandoc.Builder.Monadic.Verbatim hiding (caption)

-- | Map every element written in a t'Builder'.
-- This is useful if you have laid out bespoke elements, such as
-- 
-- > mapBuilder boldStrings $ do
-- >   div "lorem ipsum "
-- >   str "dolor sit amet"
-- >
-- > boldStrings s@(Str _) = Strong s
-- > boldStrings a = a
--
-- It's also useful for creating custom pandoc builders.
-- See 'Text.Pandoc.Builder.Monadic.Veneer.tableWithColspec'.
mapBuilder :: (a -> b) -> Builder a -> Builder b
mapBuilder :: forall a b. (a -> b) -> Builder a -> Builder b
mapBuilder a -> b
f = DList b -> Builder b
forall a. DList a -> Builder a
tellAll (DList b -> Builder b)
-> (Builder a -> DList b) -> Builder a -> Builder b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> DList a -> DList b
forall a b. (a -> b) -> DList a -> DList b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (DList a -> DList b)
-> (Builder a -> DList a) -> Builder a -> DList b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder a -> DList a
forall el. Builder el -> DList el
runToDList

-- | Intersperse table with blank rows, this is useful for
-- clarity (with some backends) when using multiline cells.
-- This is exposed as a modifier, because there are already
-- too many ways to construct a table.
intersperseTablesWithBlankRows :: Builder Block -> Builder Block
intersperseTablesWithBlankRows :: Builder Block -> Builder Block
intersperseTablesWithBlankRows = (Block -> Block) -> Builder Block -> Builder Block
forall a b. (a -> b) -> Builder a -> Builder b
mapBuilder Block -> Block
updateBlock
  where
    updateBlock :: Block -> Block
    updateBlock :: Block -> Block
updateBlock Block
block = case Block
block of
      Table Attr
attr Caption
caption [ColSpec]
colspec TableHead
tableHead [TableBody]
tableBodies TableFoot
tableFoot ->
        Attr
-> Caption
-> [ColSpec]
-> TableHead
-> [TableBody]
-> TableFoot
-> Block
Table Attr
attr Caption
caption [ColSpec]
colspec TableHead
tableHead (TableBody -> TableBody
updateBody (TableBody -> TableBody) -> [TableBody] -> [TableBody]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [TableBody]
tableBodies) TableFoot
tableFoot
      Block
a -> Block
a

    updateBody :: TableBody -> TableBody
    updateBody :: TableBody -> TableBody
updateBody (TableBody Attr
attr RowHeadColumns
rowHeadCols [Row]
headRows [Row]
rows)
      = Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody
TableBody Attr
attr RowHeadColumns
rowHeadCols [Row]
headRows ([Row] -> TableBody) -> [Row] -> TableBody
forall a b. (a -> b) -> a -> b
$ Row -> [Row] -> [Row]
forall a. a -> [a] -> [a]
intersperse Row
blankRow [Row]
rows

    blankRow :: Row
    blankRow :: Row
blankRow = Attr -> [Cell] -> Row
Row Attr
nullAttr [Cell]
forall a. Monoid a => a
mempty

-- | Vertical space - a paragraph containing a non-breaking space
vspace :: Builder Block
vspace :: Builder Block
vspace = Builder Inline -> Builder Block
para Builder Inline
"\x00A0"