packages feed

pandoc-utils-0.4.0: README.md

# pandoc-utils

This package contains some useful functions for writing
[Pandoc](https://pandoc.org/) filters and integrating Pandoc into Haskell
applications such as [Hakyll](https://jaspervdj.be/hakyll/). It provides a
composable wrapper for filters acting on nodes of the [Pandoc
AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html).

## Filter conversion/composition

As an example, let us look at the `behead` and `delink` filter from [Pandoc's
tutorial](https://pandoc.org/filters.html).
```haskell
behead :: Block -> Block
behead (Header n _ xs) | n >= 2 = Para [Emph xs]
behead x = x

delink :: Inline -> [Inline]
delink (Link _ txt _) = txt
delink x = [x]
```

Since `behead` has type `Block -> Block`, while `delink` has type `Inline ->
[Inline]`, they are not naturally composable. However, this package provides a
utility function `mkFilter` to convert them into a `PandocFilter`.
```haskell
import Text.Pandoc.Filter.Utils

beheadFilter :: PandocFilter
beheadFilter = mkFilter behead

delinkFilter :: PandocFilter
delinkFilter = mkFilter delink
```
`PandocFilter` is an alias for `PartialFilter Pandoc`, so you can also have
`PartialFilter Inline`, etc. There is also a monadic version called
`PartialFilterM` for encapsulating monadic filters.

The `PandocFilter` is a monoid so you can do something like,
```haskell
myFilter :: PandocFilter
myFilter = beheadFilter <> delinkFilter
```
where `myFilter` would apply `beheadFilter` first, then the `delinkFilter`. You
can apply the filter using `applyFilter`,
```haskell
import Text.Pandoc
import Data.Default (def)

mdToHtml
  :: Text                    -- ^ Input markdown string
  -> Either PandocError Text -- ^ Html string or error
mdToHtml md = runPure $ do
  doc <- readMarkdown def md
  let doc' = applyFilter myFilter doc
  writeHtml5String def doc'
```
or get an unwrapped `Pandoc -> Pandoc` filter using `getFilter` (this function
is also capable of doing implicit conversion from `PartialFilter a` to `b ->
b`).
```haskell
myPandocFilter :: Pandoc -> Pandoc
myPandocFilter = getFilter myFilter
```

For applying multiple filters, there is also a function called `applyFilters`,
which takes a list of filters and apply it to a `Pandoc` document (or subnode)
sequentially, from left to right.
```haskell
myFilters :: [PandocFilter]
myFilters =
  [ beheadFilter
  , delinkFilter
  ]

mdToHtml'
  :: Text                    -- ^ Input markdown string
  -> Either PandocError Text -- ^ Html string or error
mdToHtml' md = runPure $ do
  doc <- readMarkdown def md
  let doc' = applyFilters myFilters doc
  writeHtml5String def doc'
```

## Attribute builder

pandoc-utils also provides an attribute builder for handling attributes. You
can create a new attributes by
```haskell
ghci> import Text.Pandoc.Filter.Utils.AttrBuilder
ghci> import Text.Pandoc.Definition
ghci> nullAttr `setId` "id" `addClass` "class" `addKVPair` ("key","value")
("id",["class"],[("key","value")])
```
or modifying an existing attributes by
```haskell
ghci> attr = ("id",[],[])
ghci> attr `setId` "newId"
("newId",[],[])
```

For more examples, please read the
[spec](https://github.com/Krasjet/pandoc-utils/blob/master/test/Spec.hs).