packages feed

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

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

-- We define some instances for Builder here, because this is where we
-- have functions to implement them.
{-# OPTIONS_GHC -Wno-orphans #-}

-- We use named parameters as a form of documentation.
{- HLINT ignore "Eta reduce" -}

-- | This module exports a 1:1 monadic version of pandoc-types' 'Text.Pandoc.Builder'.

module Text.Pandoc.Builder.Monadic.Verbatim
  ( module Text.Pandoc.Definition
  , Builder
  , URL
  , Title
  , Raw

  -- * Top-level
  , doc
  , setTitle
  , setAuthors
  , setDate
  , setMeta

  -- * Inline builders
  , text
  , str
  , emph
  , underline
  , strong
  , strikeout
  , superscript
  , subscript
  , smallcaps
  , singleQuoted
  , doubleQuoted
  , cite
  , code
  , codeWith
  , space
  , softbreak
  , linebreak
  , math
  , displayMath
  , rawInline
  , link
  , linkWith
  , image
  , imageWith
  , note
  , spanWith
  , trimInlines

  -- * Block builders
  , para
  , plain
  , lineBlock
  , codeBlockWith
  , codeBlock
  , rawBlock
  , blockQuote
  , bulletList
  , orderedListWith
  , orderedList
  , definitionList
  , header
  , headerWith
  , horizontalRule
  , cell
  , simpleCell
  , emptyCell
  , cellWith
  , table
  , simpleTable
  , tableWith
#if MIN_VERSION_pandoc_types(1,23,0)
  , figure
  , figureWith
#endif
  , caption
  , simpleCaption
  , emptyCaption
#if MIN_VERSION_pandoc_types(1,22,1)
  , simpleFigureWith
  , simpleFigure
#endif
  , divWith

  -- * Table processing
  , B.normalizeTableHead
  , B.normalizeTableBody
  , B.normalizeTableFoot
  , B.placeRowSection
  , B.clipRows
  ) where

import Control.Arrow               ((***))
import Data.Text                   (Text)

import Text.Pandoc.Definition
import Data.String (IsString(..))

import Text.Pandoc.Builder.Monadic.Internal
  ( Builder
  , buildMany
  , runToMany
  , runToList
  , tellOne
  )

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

-- | Type alias for raw output.
type Raw = Text

-- | Type alias for URLs.
type URL = Text

-- | Type alias for Titles.
type Title = Text

instance IsString (Builder Inline) where
  fromString = str . Text.pack

instance IsString (Builder Block) where
  fromString = plain . str . Text.pack

-- | Lifts something (usually a Pandoc data constructor), into
-- a builder which takes a builder.
liftWrapper :: ([a] -> b) -> Builder a -> Builder b
liftWrapper f = tellOne . f . runToList

liftWrapper' :: (B.Many a -> B.Many b) -> Builder a -> Builder b
liftWrapper' f = buildMany . f . runToMany

-- | Build a pandoc document from a 'Builder' of top-level elements.
doc :: Builder Block -> Pandoc
doc = B.Pandoc mempty . runToList

-- | Set the document's title in the metadata.
setTitle :: Builder Inline -> Pandoc -> Pandoc
setTitle = B.setTitle . runToMany

-- | Set the document's authors in the metadata.
setAuthors :: [Builder Inline] -> Pandoc -> Pandoc
setAuthors = B.setAuthors . fmap runToMany

-- | Set the document's date in the metadata.
setDate :: Builder Inline -> Pandoc -> Pandoc
setDate = B.setDate . runToMany

-- | Set a value in the document's metadata.
setMeta :: (B.HasMeta a, B.ToMetaValue b) => Text -> b -> a -> a 
setMeta = B.setMeta

-- | Convert a 'Text' to a 'Builder' 'Inline', treating interword spaces as 'B.Space's
-- or 'B.SoftBreak's. If you want a 'B.Str' with literal spaces, use 'str'.
text :: Text -> Builder Inline
text = buildMany . B.text

-- | Build a string.
str :: Text -> Builder Inline
str = tellOne . B.Str

-- | Build an emphasized (usually italicized) inline.
emph :: Builder Inline -> Builder Inline
emph = liftWrapper B.Emph

-- | Build an underlined inline.
underline :: Builder Inline -> Builder Inline
underline = liftWrapper B.Underline

-- | Build a strong (bold) inline.
strong :: Builder Inline -> Builder Inline
strong = liftWrapper B.Strong

-- | Build a strikeout (crossed out) inline.
strikeout :: Builder Inline -> Builder Inline
strikeout = liftWrapper B.Strikeout

-- | Build a superscripted inline.
superscript :: Builder Inline -> Builder Inline
superscript = liftWrapper B.Superscript

-- | Build a subscripted inline.
subscript :: Builder Inline -> Builder Inline
subscript = liftWrapper B.Subscript

-- | Build a smallcaps inline. See the example in the font-family [MDN page](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant#examples).
smallcaps :: Builder Inline -> Builder Inline
smallcaps = liftWrapper B.SmallCaps

-- | Build a single-quoted inline.
singleQuoted :: Builder Inline -> Builder Inline
singleQuoted = liftWrapper $ B.Quoted B.SingleQuote

-- | Build a double-quoted inline.
doubleQuoted :: Builder Inline -> Builder Inline
doubleQuoted = liftWrapper $ B.Quoted B.DoubleQuote

-- | Build a citation. See
-- [Citations in note style](https://pandoc.org/chunkedhtml-demo/9.3-citations-in-note-styles.html)
-- and [Specifying a citation style](https://pandoc.org/chunkedhtml-demo/9.2-specifying-a-citation-style.html).
cite :: [B.Citation] -> Builder Inline -> Builder Inline
cite citations = liftWrapper $ B.Cite citations

-- | Build some inline code.
code :: Text -> Builder Inline
code = codeWith B.nullAttr

-- | Build some inline code with attributes.
codeWith :: B.Attr -> Text -> Builder Inline
codeWith = (tellOne .) . B.Code

-- | Build an inter-word space.
space :: Builder Inline
space = tellOne B.Space

-- | Build a soft line-break.
softbreak :: Builder Inline
softbreak = tellOne B.SoftBreak

-- | Build a hard line-break.
linebreak :: Builder Inline
linebreak = tellOne B.LineBreak

-- | Build some inline TeX math.
math :: Text -> Builder Inline
math = tellOne . B.Math B.InlineMath

-- | Build some display-mode TeX math.
-- Display mode is for math that is set apart from the main text.
displayMath :: Text -> Builder Inline
displayMath = tellOne . B.Math B.DisplayMath

-- | Embed some of the output directly.
-- This is useful to gain access to features of the underlying
-- output which aren't supported by pandoc directly.
rawInline :: Format -> Raw -> Builder Inline
rawInline format = tellOne . B.RawInline format

-- | Build a link from a URL, a title, and some inline pandoc.
link :: URL -> Title -> Builder Inline -> Builder Inline
link url title = linkWith B.nullAttr url title

-- | Build a link from some attributes, a URL, a title, and some inline pandoc.
linkWith :: B.Attr -> URL -> Title -> Builder Inline -> Builder Inline
linkWith attr url title x = tellOne $ B.Link attr (runToList x) (url, title)

-- | Build an image from a URL, a title, and some inline pandoc.
image :: URL -> Title -> Builder Inline -> Builder Inline
image url title = imageWith B.nullAttr url title

-- | Build an image from some attributes, a URL, a title, and some inline pandoc.
imageWith :: B.Attr -> Text -> Text -> Builder Inline -> Builder Inline
imageWith attr url title x = tellOne $ B.Image attr (runToList x) (url, title)

-- | Build a footnote or endnote from some pandoc blocks.
note :: Builder B.Block -> Builder Inline
note = liftWrapper B.Note

-- | Build a generic inline container from attributes and more inline pandoc.
spanWith :: B.Attr -> Builder Inline -> Builder Inline
spanWith attr = liftWrapper $ B.Span attr

-- | Trim leading and trailing spaces and softbreaks from some inline pandoc.
trimInlines :: Builder Inline -> Builder Inline
trimInlines = liftWrapper' B.trimInlines

-- Block list builders

-- | Build a paragraph.
para :: Builder Inline -> Builder Block
para = liftWrapper B.Para

-- | Build some plain text (not a paragraph).
plain :: Builder Inline -> Builder Block
plain = liftWrapper' B.plain

-- | Build multiple non-breaking lines.
lineBlock :: [Builder Inline] -> Builder Block
lineBlock = tellOne . B.LineBlock . fmap runToList

-- | Build a code block.
codeBlock :: Text -> Builder Block
codeBlock = codeBlockWith B.nullAttr

-- | Build a code block with attributes.
codeBlockWith :: B.Attr -> Text -> Builder Block
codeBlockWith attrs = tellOne . B.CodeBlock attrs

-- | Embed some of the output directly.
-- This is useful to gain access to features of the underlying
-- output which aren't supported by pandoc directly.
rawBlock :: Format -> Raw -> Builder Block
rawBlock format = tellOne . B.RawBlock format

-- | Build a block quote.
blockQuote :: Builder Block -> Builder Block
blockQuote = liftWrapper B.BlockQuote

-- | Build an ordered list.
orderedList :: [Builder Block] -> Builder Block
orderedList = orderedListWith (1, B.DefaultStyle, B.DefaultDelim)

-- | Build an ordered list with attributes.
orderedListWith :: B.ListAttributes -> [Builder Block] -> Builder Block
orderedListWith attrs = tellOne . B.OrderedList attrs . fmap runToList

-- | Build a bullet list.
bulletList :: [Builder Block] -> Builder Block
bulletList = tellOne . B.BulletList . fmap runToList

-- | Build an definition list given a list of tuples, where the first element
-- of each tuple is a term, and the second element is the definition.
definitionList :: [(Builder Inline, [Builder Block])] -> Builder Block
definitionList = tellOne . B.DefinitionList . fmap (runToList *** fmap runToList)

-- | Build a header, given a level and some inline pandoc.
-- You may consider using 'Text.Pandoc.Builder.Monadic.h1' and friends,
-- for a more concise API.
header :: Int -> Builder Inline -> Builder Block
header level x = headerWith B.nullAttr level x

-- | Build a header from some attributes, a level and some inline pandoc.
headerWith :: B.Attr -> Int -> Builder Inline -> Builder Block
headerWith attr level = liftWrapper $ B.Header level attr

-- | Build a horizontal rule.
horizontalRule :: Builder Block
horizontalRule = tellOne B.HorizontalRule

-- | Build a 1x1 cell with default alignment, given some pandoc.
simpleCell :: Builder Block -> B.Cell
simpleCell = cell B.AlignDefault 1 1

-- | Build a cell of a table, full API excluding attributes.
cell
  :: B.Alignment
  -> B.RowSpan
  -> B.ColSpan
  -> Builder Block
  -> B.Cell
cell = cellWith B.nullAttr

-- | Build a cell of a table, full API including attributes.
cellWith
  :: B.Attr
  -> B.Alignment
  -> B.RowSpan
  -> B.ColSpan
  -> Builder Block
  -> B.Cell
cellWith attrs align rowspan colspan = B.Cell attrs align rowspan colspan . runToList

-- | Build a 1x1 empty cell.
emptyCell :: B.Cell
emptyCell = simpleCell $ pure ()

-- | Build a table, full API excluding attributes.
table :: B.Caption
      -> [B.ColSpec]
      -> B.TableHead
      -> [B.TableBody]
      -> B.TableFoot
      -> Builder Block
table = tableWith B.nullAttr

-- | Build a table, full API including attributes.
tableWith :: B.Attr
          -> B.Caption
          -> [B.ColSpec]
          -> B.TableHead
          -> [B.TableBody]
          -> B.TableFoot
          -> Builder Block
tableWith = (((((buildMany .) .) .) .) .) . B.tableWith

-- | Build a table, given a list of header cells, and a list of rows.
simpleTable :: [Builder Block] -> [[Builder Block]] -> Builder Block
simpleTable headers rows = buildMany $ B.simpleTable (fmap runToMany headers) (fmap runToMany <$> rows)

#if MIN_VERSION_pandoc_types(1,23,0)
-- | Build a captioned figure.
-- This is available in pandoc-types >= 1.23, which corresponds to pandoc >= 3.0.
figure :: B.Caption -> Builder Block -> Builder Block
figure = figureWith B.nullAttr

-- | Build a captioned figure, with attributes.
-- This is available in pandoc-types >= 1.23, which corresponds to pandoc >= 3.0.
figureWith :: B.Attr -> B.Caption -> Builder Block -> Builder Block
figureWith attr capt = liftWrapper $ B.Figure attr capt
#endif

-- | Make a caption, with an optional short version.
caption :: Maybe B.ShortCaption -> Builder Block -> B.Caption
caption x = B.Caption x . runToList

-- | Make a caption, without a short version.
simpleCaption :: Builder Block -> B.Caption
simpleCaption = caption Nothing

-- | Make an empty caption
emptyCaption :: B.Caption
emptyCaption = simpleCaption mempty

#if MIN_VERSION_pandoc_types(1,22,1)
-- | Build a captioned figure, containing an image.
-- This is available in pandoc-types >= 1.22.1, which corresponds to pandoc >= 2.15.
simpleFigure :: Builder Inline -> Text -> Text -> Builder Block
simpleFigure figureCaption url title = simpleFigureWith B.nullAttr figureCaption url title

-- | Build a captioned figure containing an image, with attributes.
-- This is available in pandoc-types >= 1.22.1, which corresponds to pandoc >= 2.15.
simpleFigureWith :: B.Attr -> Builder Inline -> URL -> Title-> Builder Block
simpleFigureWith attr figureCaption url title
  = buildMany $ B.simpleFigureWith attr (runToMany figureCaption) url title
#endif

-- | Build a generic block container with attributes.
divWith :: B.Attr -> Builder Block -> Builder Block
divWith attr = liftWrapper $ B.Div attr