    {-# LANGUAGE OverloadedStrings #-}
    {- |
       Module      : Text.Pandoc.Writers.DokuWiki
       Copyright   : Copyright (C) 2008-2024 John MacFarlane
       License     : GNU GPL, version 2 or above

       Maintainer  : Clare Macrae <clare.macrae@googlemail.com>
       Stability   : alpha
       Portability : portable

    Conversion of 'Pandoc' documents to DokuWiki markup.

    DokuWiki:  <https://www.dokuwiki.org/dokuwiki>
    -}

    {-
        [x] Implement nested blockquotes (currently only ever does one level)
        [x] Implement alignment of text in tables
        [ ] Implement comments
        [ ] Work through the Dokuwiki spec, and check I've not missed anything out
        [ ] Remove dud/duplicate code
    -}

    module Text.Pandoc.Writers.DokuWiki ( writeDokuWiki ) where
    import Control.Monad (zipWithM)
    import Control.Monad.Reader (ReaderT, asks, local, runReaderT)
    import Control.Monad.State.Strict (StateT, evalStateT)
    import Data.Default (Default (..))
    import Data.List (transpose)
    import Data.List.NonEmpty (nonEmpty)
    import Data.Text (Text)
    import qualified Data.Text as T
    import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
    import Text.Pandoc.Definition
    import Text.Pandoc.Extensions
    import Text.Pandoc.ImageSize
    import Text.Pandoc.Logging
    import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents,
                                writerTemplate, writerWrapText), isEnabled)
    import Text.Pandoc.Shared (figureDiv, linesToPara, removeFormatting, trimr)
    import Text.Pandoc.URI (escapeURI, isURI)
    import Text.Pandoc.Templates (renderTemplate)
    import Text.DocLayout (render, literal)
    import Text.Pandoc.Writers.Shared (defField, metaToContext, toLegacyTable)
    import Data.Maybe (fromMaybe)
    import qualified Data.Map as M

    data WriterState = WriterState {
      }

    data WriterEnvironment = WriterEnvironment {
        WriterEnvironment -> Text
    stIndent      :: Text          -- Indent after the marker at the beginning of list items
      , WriterEnvironment -> Bool
    stBackSlashLB :: Bool     -- True if we should produce formatted strings with newlines (as in a table cell)
      , WriterEnvironment -> Int
    stBlockQuoteLevel :: Int   -- Block quote level
      }

    instance Default WriterState where
      def :: WriterState
    def = WriterState {}

    instance Default WriterEnvironment where
      def :: WriterEnvironment
    def = WriterEnvironment { stIndent :: Text
    stIndent = Text
    ""
                              , stBackSlashLB :: Bool
    stBackSlashLB = Bool
    False
                              , stBlockQuoteLevel :: Int
    stBlockQuoteLevel = Int
    0 }

    type DokuWiki m = ReaderT WriterEnvironment (StateT WriterState m)

    -- | Convert Pandoc to DokuWiki.
    writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
    writeDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Pandoc -> m Text
    writeDokuWiki WriterOptions
    opts Pandoc
    document =
      DokuWiki m Text -> m Text
    forall (m :: * -> *) a. PandocMonad m => DokuWiki m a -> m a
    runDokuWiki (WriterOptions -> Pandoc -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Pandoc -> DokuWiki m Text
    pandocToDokuWiki WriterOptions
    opts Pandoc
    document)

    runDokuWiki :: PandocMonad m => DokuWiki m a -> m a
    runDokuWiki :: forall (m :: * -> *) a. PandocMonad m => DokuWiki m a -> m a
    runDokuWiki = (StateT WriterState m a -> WriterState -> m a)
    -> WriterState -> StateT WriterState m a -> m a
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip StateT WriterState m a -> WriterState -> m a
    forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
    evalStateT WriterState
    forall a. Default a => a
    def (StateT WriterState m a -> m a)
    -> (DokuWiki m a -> StateT WriterState m a) -> DokuWiki m a -> m a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (DokuWiki m a -> WriterEnvironment -> StateT WriterState m a)
    -> WriterEnvironment -> DokuWiki m a -> StateT WriterState m a
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip DokuWiki m a -> WriterEnvironment -> StateT WriterState m a
    forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
    runReaderT WriterEnvironment
    forall a. Default a => a
    def

    -- | Return DokuWiki representation of document.
    pandocToDokuWiki :: PandocMonad m
                     => WriterOptions -> Pandoc -> DokuWiki m Text
    pandocToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Pandoc -> DokuWiki m Text
    pandocToDokuWiki WriterOptions
    opts (Pandoc Meta
    meta [Block]
    blocks) = do
      metadata <- WriterOptions
    -> ([Block]
        -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text))
    -> ([Inline]
        -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text))
    -> Meta
    -> ReaderT WriterEnvironment (StateT WriterState m) (Context Text)
    forall (m :: * -> *) a.
    (Monad m, TemplateTarget a) =>
    WriterOptions
    -> ([Block] -> m (Doc a))
    -> ([Inline] -> m (Doc a))
    -> Meta
    -> m (Context a)
    metaToContext WriterOptions
    opts
                  ((Text -> Doc Text)
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text)
    forall a b.
    (a -> b)
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    -> ReaderT WriterEnvironment (StateT WriterState m) b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Text -> Doc Text
    forall a. HasChars a => a -> Doc a
    literal (Text -> Doc Text) -> (Text -> Text) -> Text -> Doc Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    trimr) (ReaderT WriterEnvironment (StateT WriterState m) Text
     -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text))
    -> ([Block]
        -> ReaderT WriterEnvironment (StateT WriterState m) Text)
    -> [Block]
    -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . WriterOptions
    -> [Block] -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts)
                  ((Text -> Doc Text)
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text)
    forall a b.
    (a -> b)
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    -> ReaderT WriterEnvironment (StateT WriterState m) b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Text -> Doc Text
    forall a. HasChars a => a -> Doc a
    literal (Text -> Doc Text) -> (Text -> Text) -> Text -> Doc Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    trimr) (ReaderT WriterEnvironment (StateT WriterState m) Text
     -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text))
    -> ([Inline]
        -> ReaderT WriterEnvironment (StateT WriterState m) Text)
    -> [Inline]
    -> ReaderT WriterEnvironment (StateT WriterState m) (Doc Text)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . WriterOptions
    -> [Inline]
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts)
                  Meta
    meta
      body <- blockListToDokuWiki opts blocks
      let context = Text -> Text -> Context Text -> Context Text
    forall a b. ToContext a b => Text -> b -> Context a -> Context a
    defField Text
    "body" Text
    body
                  (Context Text -> Context Text) -> Context Text -> Context Text
    forall a b. (a -> b) -> a -> b
    $ Text -> Bool -> Context Text -> Context Text
    forall a b. ToContext a b => Text -> b -> Context a -> Context a
    defField Text
    "toc" (WriterOptions -> Bool
    writerTableOfContents WriterOptions
    opts) Context Text
    metadata
      return $
        case writerTemplate opts of
           Maybe (Template Text)
    Nothing  -> Text
    body
           Just Template Text
    tpl -> Maybe Int -> Doc Text -> Text
    forall a. HasChars a => Maybe Int -> Doc a -> a
    render Maybe Int
    forall a. Maybe a
    Nothing (Doc Text -> Text) -> Doc Text -> Text
    forall a b. (a -> b) -> a -> b
    $ Template Text -> Context Text -> Doc Text
    forall a b.
    (TemplateTarget a, ToContext a b) =>
    Template a -> b -> Doc a
    renderTemplate Template Text
    tpl Context Text
    context

    -- | Escape special characters for DokuWiki.
    escapeString :: Text -> Text
    escapeString :: Text -> Text
    escapeString = HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "__" Text
    "%%__%%" (Text -> Text) -> (Text -> Text) -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                   HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "**" Text
    "%%**%%" (Text -> Text) -> (Text -> Text) -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                   HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "//" Text
    "%%//%%"

    -- | Convert Pandoc block element to DokuWiki.
    blockToDokuWiki :: PandocMonad m
                    => WriterOptions -- ^ Options
                    -> Block         -- ^ Block element
                    -> DokuWiki m Text

    blockToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Block -> DokuWiki m Text
    blockToDokuWiki WriterOptions
    opts (Div Attr
    _attrs [Block]
    bs) = do
      contents <- WriterOptions -> [Block] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts [Block]
    bs
      indent <- asks stIndent
      return $ contents <> if T.null indent then "\n" else ""

    blockToDokuWiki WriterOptions
    opts (Plain [Inline]
    inlines) =
      WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    inlines

    blockToDokuWiki WriterOptions
    opts (Para [Inline]
    inlines) = do
      bqLevel <- (WriterEnvironment -> Int)
    -> ReaderT WriterEnvironment (StateT WriterState m) Int
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Int
    stBlockQuoteLevel
      let bqPrefix = case Int
    bqLevel of
                        Int
    0 -> Text
    ""
                        Int
    n -> Int -> Text -> Text
    T.replicate Int
    n Text
    ">" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    " "
      indent <- asks stIndent
      contents <- inlineListToDokuWiki opts inlines
      return $ bqPrefix <> contents <> if T.null indent then "\n" else ""

    blockToDokuWiki WriterOptions
    opts (LineBlock [[Inline]]
    lns) =
      WriterOptions -> Block -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Block -> DokuWiki m Text
    blockToDokuWiki WriterOptions
    opts (Block -> DokuWiki m Text) -> Block -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ [[Inline]] -> Block
    linesToPara [[Inline]]
    lns

    blockToDokuWiki WriterOptions
    opts b :: Block
    b@(RawBlock Format
    f Text
    str)
      | Format
    f Format -> Format -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Format
    Format Text
    "dokuwiki" = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    str
      -- See https://www.dokuwiki.org/wiki:syntax
      -- use uppercase HTML tag for block-level content:
      | Format
    f Format -> Format -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Format
    Format Text
    "html"
      , Extension -> WriterOptions -> Bool
    forall a. HasSyntaxExtensions a => Extension -> a -> Bool
    isEnabled Extension
    Ext_raw_html WriterOptions
    opts = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "<HTML>\n" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    str Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "\n</HTML>"
      | Bool
    otherwise              = Text
    "" Text
    -> ReaderT WriterEnvironment (StateT WriterState m) ()
    -> DokuWiki m Text
    forall a b.
    a
    -> ReaderT WriterEnvironment (StateT WriterState m) b
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$
             LogMessage -> ReaderT WriterEnvironment (StateT WriterState m) ()
    forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
    report (Block -> LogMessage
    BlockNotRendered Block
    b)

    blockToDokuWiki WriterOptions
    _ Block
    HorizontalRule = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    "\n----\n"

    blockToDokuWiki WriterOptions
    opts (Header Int
    level Attr
    _ [Inline]
    inlines) = do
      -- emphasis, links etc. not allowed in headers, apparently,
      -- so we remove formatting:
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts ([Inline] -> DokuWiki m Text) -> [Inline] -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ [Inline] -> [Inline]
    forall a. Walkable Inline a => a -> [Inline]
    removeFormatting [Inline]
    inlines
      let eqs = Int -> Text -> Text
    T.replicate ( Int
    7 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    level ) Text
    "="
      return $ eqs <> " " <> contents <> " " <> eqs <> "\n"

    blockToDokuWiki WriterOptions
    _ (CodeBlock (Text
    _,[Text]
    classes,[(Text, Text)]
    _) Text
    str) = do
      bqLevel <- (WriterEnvironment -> Int)
    -> ReaderT WriterEnvironment (StateT WriterState m) Int
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Int
    stBlockQuoteLevel
      let bqPrefix = case Int
    bqLevel of
                        Int
    0 -> Text
    ""
                        Int
    n -> Int -> Text -> Text
    T.replicate Int
    n Text
    ">" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    " "
      return $ bqPrefix <>
               "<code" <>
               (case classes of
                   []    -> Text
    ""
                   (Text
    x:[Text]
    _) -> Text
    " " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe Text
    x (Text -> Map Text Text -> Maybe Text
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup Text
    x Map Text Text
    languageNames)) <>
               ">\n" <> str <>
               (if "\n" `T.isSuffixOf` str then "" else "\n") <> "</code>\n"

    blockToDokuWiki WriterOptions
    opts (BlockQuote [Block]
    blocks) =
      (WriterEnvironment -> WriterEnvironment)
    -> DokuWiki m Text -> DokuWiki m Text
    forall a.
    (WriterEnvironment -> WriterEnvironment)
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
    local (\WriterEnvironment
    st -> WriterEnvironment
    st{ stBlockQuoteLevel = stBlockQuoteLevel st + 1 })
                   (WriterOptions -> [Block] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts [Block]
    blocks)

    blockToDokuWiki WriterOptions
    opts (Table Attr
    _ Caption
    blkCapt [ColSpec]
    specs TableHead
    thead [TableBody]
    tbody TableFoot
    tfoot) = do
      let ([Inline]
    capt, [Alignment]
    aligns, [Double]
    _, [[Block]]
    headers, [[[Block]]]
    rows) = Caption
    -> [ColSpec]
    -> TableHead
    -> [TableBody]
    -> TableFoot
    -> ([Inline], [Alignment], [Double], [[Block]], [[[Block]]])
    toLegacyTable Caption
    blkCapt [ColSpec]
    specs TableHead
    thead [TableBody]
    tbody TableFoot
    tfoot
      captionDoc <- if [Inline] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Inline]
    capt
                       then Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    ""
                       else do
                          c <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    capt
                          return $ "" <> c <> "\n"
      headers' <- if all null headers
                     then return []
                     else zipWithM (tableItemToDokuWiki opts) aligns headers
      rows' <- mapM (zipWithM (tableItemToDokuWiki opts) aligns) rows
      let widths = ([Text] -> Int) -> [[Text]] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> (NonEmpty Int -> Int) -> Maybe (NonEmpty Int) -> Int
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Int
    0 NonEmpty Int -> Int
    forall a. Ord a => NonEmpty a -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum (Maybe (NonEmpty Int) -> Int)
    -> ([Text] -> Maybe (NonEmpty Int)) -> [Text] -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Int] -> Maybe (NonEmpty Int)
    forall a. [a] -> Maybe (NonEmpty a)
    nonEmpty ([Int] -> Maybe (NonEmpty Int))
    -> ([Text] -> [Int]) -> [Text] -> Maybe (NonEmpty Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Int) -> [Text] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Int
    T.length)
                       ([[Text]] -> [Int]) -> [[Text]] -> [Int]
    forall a b. (a -> b) -> a -> b
    $ [[Text]] -> [[Text]]
    forall a. [[a]] -> [[a]]
    transpose ([Text]
    headers'[Text] -> [[Text]] -> [[Text]]
    forall a. a -> [a] -> [a]
    :[[Text]]
    rows')
      let padTo (Int
    width, Alignment
    al) Text
    s =
              case Int
    width Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Text -> Int
    T.length Text
    s of
                   Int
    x | Int
    x Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0 ->
                     if Alignment
    al Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignLeft Bool -> Bool -> Bool
    || Alignment
    al Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignDefault
                        then Text
    s Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Int -> Text -> Text
    T.replicate Int
    x Text
    " "
                        else if Alignment
    al Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignRight
                                then Int -> Text -> Text
    T.replicate Int
    x Text
    " " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    s
                                else Int -> Text -> Text
    T.replicate (Int
    x Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    2) Text
    " " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>
                                     Text
    s Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Int -> Text -> Text
    T.replicate (Int
    x Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    x Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    2) Text
    " "
                     | Bool
    otherwise -> Text
    s
      let renderRow Text
    sep [Text]
    cells = Text
    sep Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>
              Text -> [Text] -> Text
    T.intercalate Text
    sep (((Int, Alignment) -> Text -> Text)
    -> [(Int, Alignment)] -> [Text] -> [Text]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (Int, Alignment) -> Text -> Text
    padTo ([Int] -> [Alignment] -> [(Int, Alignment)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Int]
    widths [Alignment]
    aligns) [Text]
    cells) Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    sep
      return $ captionDoc <>
               (if null headers' then "" else renderRow "^" headers' <> "\n") <>
               T.unlines (map (renderRow "|") rows')

    blockToDokuWiki WriterOptions
    opts (BulletList [[Block]]
    items) = do
      indent <- (WriterEnvironment -> Text) -> DokuWiki m Text
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Text
    stIndent
      backSlash <- asks stBackSlashLB
      contents <- local (\WriterEnvironment
    s -> WriterEnvironment
    s { stIndent = stIndent s <> "  "
                                 , stBackSlashLB = backSlash})
                          (mapM (listItemToDokuWiki opts) items)
      return $ vcat contents <> if T.null indent then "\n" else ""

    blockToDokuWiki WriterOptions
    opts (OrderedList ListAttributes
    _attribs [[Block]]
    items) = do
      indent <- (WriterEnvironment -> Text) -> DokuWiki m Text
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Text
    stIndent
      backSlash <- asks stBackSlashLB
      contents <- local (\WriterEnvironment
    s -> WriterEnvironment
    s { stIndent = stIndent s <> "  "
                                 , stBackSlashLB = backSlash})
                    (mapM (orderedListItemToDokuWiki opts) items)
      return $ vcat contents <> if T.null indent then "\n" else ""

    blockToDokuWiki WriterOptions
    opts (Figure Attr
    attr Caption
    capt [Block]
    body) =
      WriterOptions -> Block -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Block -> DokuWiki m Text
    blockToDokuWiki WriterOptions
    opts (Block -> DokuWiki m Text) -> Block -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Attr -> Caption -> [Block] -> Block
    figureDiv Attr
    attr Caption
    capt [Block]
    body

    -- TODO Need to decide how to make definition lists work on dokuwiki - I don't think there
    --      is a specific representation of them.
    -- TODO This creates double '; ; ' if there is a bullet or ordered list inside a definition list
    blockToDokuWiki WriterOptions
    opts (DefinitionList [([Inline], [[Block]])]
    items) = do
      indent <- (WriterEnvironment -> Text) -> DokuWiki m Text
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Text
    stIndent
      backSlash <- asks stBackSlashLB
      contents <- local (\WriterEnvironment
    s -> WriterEnvironment
    s { stIndent = stIndent s <> "  "
                                 , stBackSlashLB = backSlash})
                    (mapM (definitionListItemToDokuWiki opts) items)
      return $ vcat contents <> if T.null indent then "\n" else ""

    -- Auxiliary functions for lists:

    -- | Convert bullet list item (list of blocks) to DokuWiki.
    listItemToDokuWiki :: PandocMonad m
                       => WriterOptions -> [Block] -> DokuWiki m Text
    listItemToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    listItemToDokuWiki WriterOptions
    opts [Block]
    items = do
      bqLevel <- (WriterEnvironment -> Int)
    -> ReaderT WriterEnvironment (StateT WriterState m) Int
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Int
    stBlockQuoteLevel
      let bqPrefix = case Int
    bqLevel of
                        Int
    0 -> Text
    ""
                        Int
    n -> Int -> Text -> Text
    T.replicate Int
    n Text
    ">" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    " "
      let useWrap = Bool -> Bool
    not ([Block] -> Bool
    isSimpleListItem [Block]
    items)
      bs <- mapM (blockToDokuWiki opts) items
      let contents = case [Block]
    items of
                          [Block
    _, CodeBlock Attr
    _ Text
    _] -> [Text] -> Text
    T.concat [Text]
    bs
                          [Block]
    _                  -> [Text] -> Text
    vcat [Text]
    bs
      indent <- asks stIndent
      backSlash <- asks stBackSlashLB
      let indent' = if Bool
    backSlash then Int -> Text -> Text
    T.drop Int
    2 Text
    indent else Text
    indent
      return $ bqPrefix <> indent' <> "* " <>
        if useWrap
           then "<WRAP>\n" <> contents <> "\n</WRAP>"
           else contents

    -- | Convert ordered list item (list of blocks) to DokuWiki.
    -- | TODO Emiminate dreadful duplication of text from listItemToDokuWiki
    orderedListItemToDokuWiki :: PandocMonad m => WriterOptions -> [Block] -> DokuWiki m Text
    orderedListItemToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    orderedListItemToDokuWiki WriterOptions
    opts [Block]
    items = do
      bqLevel <- (WriterEnvironment -> Int)
    -> ReaderT WriterEnvironment (StateT WriterState m) Int
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Int
    stBlockQuoteLevel
      let bqPrefix = case Int
    bqLevel of
                        Int
    0 -> Text
    ""
                        Int
    n -> Int -> Text -> Text
    T.replicate Int
    n Text
    ">" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    " "
      let useWrap = Bool -> Bool
    not ([Block] -> Bool
    isSimpleListItem [Block]
    items)
      contents <- local (\WriterEnvironment
    st -> WriterEnvironment
    st{ stBlockQuoteLevel = 0 })
                   (blockListToDokuWiki opts items)
      indent <- asks stIndent
      backSlash <- asks stBackSlashLB
      let indent' = if Bool
    backSlash then Int -> Text -> Text
    T.drop Int
    2 Text
    indent else Text
    indent
      return $ bqPrefix <> indent' <> "- " <>
        if useWrap
           then "<WRAP>\n" <> contents <> "\n</WRAP>"
           else contents

    -- | Convert definition list item (label, list of blocks) to DokuWiki.
    definitionListItemToDokuWiki :: PandocMonad m
                                 => WriterOptions
                                 -> ([Inline],[[Block]])
                                 -> DokuWiki m Text
    definitionListItemToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> ([Inline], [[Block]]) -> DokuWiki m Text
    definitionListItemToDokuWiki WriterOptions
    opts ([Inline]
    label, [[Block]]
    items) = do
      let useWrap :: Bool
    useWrap = Bool -> Bool
    not (([Block] -> Bool) -> [[Block]] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all [Block] -> Bool
    isSimpleListItem [[Block]]
    items)
      bqLevel <- (WriterEnvironment -> Int)
    -> ReaderT WriterEnvironment (StateT WriterState m) Int
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Int
    stBlockQuoteLevel
      let bqPrefix = case Int
    bqLevel of
                        Int
    0 -> Text
    ""
                        Int
    n -> Int -> Text -> Text
    T.replicate Int
    n Text
    ">" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    " "
      labelText <- inlineListToDokuWiki opts label
      contents <- local (\WriterEnvironment
    st -> WriterEnvironment
    st{ stBlockQuoteLevel = 0 })
                   (mapM (blockListToDokuWiki opts) items)
      indent <- asks stIndent
      backSlash <- asks stBackSlashLB
      let indent' = if Bool
    backSlash then Int -> Text -> Text
    T.drop Int
    2 Text
    indent else Text
    indent
      return $ bqPrefix <> indent' <> "* **" <> labelText <> "** " <>
        if useWrap
           then "<WRAP>\n" <> vcat contents <> "\n</WRAP>"
           else T.intercalate "; " contents

    -- | True if list item can be handled with the simple wiki syntax.  False if
    --   WRAP tags will be needed.
    isSimpleListItem :: [Block] -> Bool
    isSimpleListItem :: [Block] -> Bool
    isSimpleListItem []  = Bool
    True
    isSimpleListItem [Block
    x, CodeBlock{}] | Block -> Bool
    isPlainOrPara Block
    x = Bool
    True
    isSimpleListItem (Div Attr
    _ [Block]
    bs : [Block]
    ys) = -- see #8920
      [Block] -> Bool
    isSimpleListItem [Block]
    bs Bool -> Bool -> Bool
    && (Block -> Bool) -> [Block] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Block -> Bool
    isSimpleList [Block]
    ys
    isSimpleListItem (Block
    x:[Block]
    ys) | Block -> Bool
    isPlainOrPara Block
    x = (Block -> Bool) -> [Block] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Block -> Bool
    isSimpleList [Block]
    ys
    isSimpleListItem [Block]
    _ = Bool
    False
    --- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.

    isSimpleList :: Block -> Bool
    isSimpleList :: Block -> Bool
    isSimpleList Block
    x =
      case Block
    x of
           BulletList [[Block]]
    items            -> ([Block] -> Bool) -> [[Block]] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all [Block] -> Bool
    isSimpleListItem [[Block]]
    items
           OrderedList (Int
    1, ListNumberStyle
    _, ListNumberDelim
    _) [[Block]]
    items -> ([Block] -> Bool) -> [[Block]] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all [Block] -> Bool
    isSimpleListItem [[Block]]
    items
           DefinitionList [([Inline], [[Block]])]
    items        -> (([Inline], [[Block]]) -> Bool) -> [([Inline], [[Block]])] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (([Block] -> Bool) -> [[Block]] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all [Block] -> Bool
    isSimpleListItem ([[Block]] -> Bool)
    -> (([Inline], [[Block]]) -> [[Block]])
    -> ([Inline], [[Block]])
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Inline], [[Block]]) -> [[Block]]
    forall a b. (a, b) -> b
    snd) [([Inline], [[Block]])]
    items
           Block
    _                           -> Bool
    False

    isPlainOrPara :: Block -> Bool
    isPlainOrPara :: Block -> Bool
    isPlainOrPara (Plain [Inline]
    _) = Bool
    True
    isPlainOrPara (Para  [Inline]
    _) = Bool
    True
    isPlainOrPara Block
    _         = Bool
    False

    -- | Concatenates strings with line breaks between them.
    vcat :: [Text] -> Text
    vcat :: [Text] -> Text
    vcat = Text -> [Text] -> Text
    T.intercalate Text
    "\n"

    -- | For each string in the input list, convert all newlines to
    -- dokuwiki escaped newlines. Then concat the list using double linebreaks.
    backSlashLineBreaks :: [Text] -> Text
    backSlashLineBreaks :: [Text] -> Text
    backSlashLineBreaks [Text]
    ls = [Text] -> Text
    vcatBackSlash ([Text] -> Text) -> [Text] -> Text
    forall a b. (a -> b) -> a -> b
    $ (Text -> Text) -> [Text] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> Text
    T.pack (String -> Text) -> (Text -> String) -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String
    escape (String -> String) -> (Text -> String) -> Text -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack) [Text]
    ls
      where
        vcatBackSlash :: [Text] -> Text
    vcatBackSlash = Text -> [Text] -> Text
    T.intercalate Text
    "\\\\ \\\\ " -- simulate paragraphs.
        escape :: String -> String
    escape [Char
    '\n']    = String
    "" -- remove trailing newlines
        escape (Char
    '\n':String
    cs) = String
    "\\\\ " String -> String -> String
    forall a. Semigroup a => a -> a -> a
    <> String -> String
    escape String
    cs
        escape (Char
    c:String
    cs)    = Char
    c Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    escape String
    cs
        escape []        = []

    -- Auxiliary functions for tables:

    tableItemToDokuWiki :: PandocMonad m
                        => WriterOptions
                        -> Alignment
                        -> [Block]
                        -> DokuWiki m Text
    tableItemToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Alignment -> [Block] -> DokuWiki m Text
    tableItemToDokuWiki WriterOptions
    opts Alignment
    align' [Block]
    item = do
      let mkcell :: a -> a
    mkcell a
    x = (if Alignment
    align' Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignRight Bool -> Bool -> Bool
    || Alignment
    align' Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignCenter
                         then a
    "  "
                         else a
    "") a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    x a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <>
                     (if Alignment
    align' Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignLeft Bool -> Bool -> Bool
    || Alignment
    align' Alignment -> Alignment -> Bool
    forall a. Eq a => a -> a -> Bool
    == Alignment
    AlignCenter
                         then a
    "  "
                         else a
    "")
      contents <- (WriterEnvironment -> WriterEnvironment)
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall a.
    (WriterEnvironment -> WriterEnvironment)
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
    local (\WriterEnvironment
    s -> WriterEnvironment
    s { stBackSlashLB = True
                                 , stBlockQuoteLevel = 0 }) (ReaderT WriterEnvironment (StateT WriterState m) Text
     -> ReaderT WriterEnvironment (StateT WriterState m) Text)
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall a b. (a -> b) -> a -> b
    $
                    WriterOptions
    -> [Block] -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts [Block]
    item
      return $ mkcell contents

    -- | Convert list of Pandoc block elements to DokuWiki.
    blockListToDokuWiki :: PandocMonad m
                        => WriterOptions -- ^ Options
                        -> [Block]       -- ^ List of block elements
                        -> DokuWiki m Text
    blockListToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts [Block]
    blocks = do
      backSlash <- (WriterEnvironment -> Bool)
    -> ReaderT WriterEnvironment (StateT WriterState m) Bool
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Bool
    stBackSlashLB
      let blocks' = [Block] -> [Block]
    consolidateRawBlocks [Block]
    blocks
      if backSlash
        then backSlashLineBreaks <$> mapM (blockToDokuWiki opts) blocks'
        else vcat <$> mapM (blockToDokuWiki opts) blocks'

    consolidateRawBlocks :: [Block] -> [Block]
    consolidateRawBlocks :: [Block] -> [Block]
    consolidateRawBlocks [] = []
    consolidateRawBlocks (RawBlock Format
    f1 Text
    b1 : RawBlock Format
    f2 Text
    b2 : [Block]
    xs)
      | Format
    f1 Format -> Format -> Bool
    forall a. Eq a => a -> a -> Bool
    == Format
    f2 = [Block] -> [Block]
    consolidateRawBlocks (Format -> Text -> Block
    RawBlock Format
    f1 (Text
    b1 Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "\n" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    b2) Block -> [Block] -> [Block]
    forall a. a -> [a] -> [a]
    : [Block]
    xs)
    consolidateRawBlocks (Block
    x:[Block]
    xs) = Block
    x Block -> [Block] -> [Block]
    forall a. a -> [a] -> [a]
    : [Block] -> [Block]
    consolidateRawBlocks [Block]
    xs

    -- | Convert list of Pandoc inline elements to DokuWiki.
    inlineListToDokuWiki :: PandocMonad m
                         => WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst =
      [Text] -> Text
    T.concat ([Text] -> Text)
    -> ReaderT WriterEnvironment (StateT WriterState m) [Text]
    -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Inline -> ReaderT WriterEnvironment (StateT WriterState m) Text)
    -> [Inline]
    -> ReaderT WriterEnvironment (StateT WriterState m) [Text]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM (WriterOptions
    -> Inline -> ReaderT WriterEnvironment (StateT WriterState m) Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Inline -> DokuWiki m Text
    inlineToDokuWiki WriterOptions
    opts) [Inline]
    lst

    -- | Convert Pandoc inline element to DokuWiki.
    inlineToDokuWiki :: PandocMonad m
                     => WriterOptions -> Inline -> DokuWiki m Text

    inlineToDokuWiki :: forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> Inline -> DokuWiki m Text
    inlineToDokuWiki WriterOptions
    opts (Span Attr
    _attrs [Inline]
    ils) =
      WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    ils

    inlineToDokuWiki WriterOptions
    opts (Emph [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "//" <> contents <> "//"

    inlineToDokuWiki WriterOptions
    opts (Underline [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "__" <> contents <> "__"

    inlineToDokuWiki WriterOptions
    opts (Strong [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "**" <> contents <> "**"

    inlineToDokuWiki WriterOptions
    opts (Strikeout [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "<del>" <> contents <> "</del>"

    inlineToDokuWiki WriterOptions
    opts (Superscript [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "<sup>" <> contents <> "</sup>"

    inlineToDokuWiki WriterOptions
    opts (Subscript [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "<sub>" <> contents <> "</sub>"

    inlineToDokuWiki WriterOptions
    opts (SmallCaps [Inline]
    lst) = WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst

    inlineToDokuWiki WriterOptions
    opts (Quoted QuoteType
    SingleQuote [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "\8216" <> contents <> "\8217"

    inlineToDokuWiki WriterOptions
    opts (Quoted QuoteType
    DoubleQuote [Inline]
    lst) = do
      contents <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst
      return $ "\8220" <> contents <> "\8221"

    inlineToDokuWiki WriterOptions
    opts (Cite [Citation]
    _  [Inline]
    lst) = WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    lst

    inlineToDokuWiki WriterOptions
    _ (Code Attr
    _ Text
    str) =
      -- In dokuwiki, text surrounded by '' is really just a font statement, i.e. <tt>,
      -- and so other formatting can be present inside.
      -- However, in pandoc, and markdown, inlined code doesn't contain formatting.
      -- So I have opted for using %% to disable all formatting inside inline code blocks.
      -- This gives the best results when converting from other formats to dokuwiki, even if
      -- the resultand code is a little ugly, for short strings that don't contain formatting
      -- characters.
      -- It does mean that if pandoc could ever read dokuwiki, and so round-trip the format,
      -- any formatting inside inlined code blocks would be lost, or presented incorrectly.
      Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "''%%" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    str Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "%%''"

    inlineToDokuWiki WriterOptions
    _ (Str Text
    str) = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text -> Text
    escapeString Text
    str

    inlineToDokuWiki WriterOptions
    _ (Math MathType
    mathType Text
    str) = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    delim Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    str Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    delim
                                     -- note:  str should NOT be escaped
      where delim :: Text
    delim = case MathType
    mathType of
                         MathType
    DisplayMath -> Text
    "$$"
                         MathType
    InlineMath  -> Text
    "$"

    inlineToDokuWiki WriterOptions
    opts il :: Inline
    il@(RawInline Format
    f Text
    str)
      | Format
    f Format -> Format -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Format
    Format Text
    "dokuwiki" = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    str
      | Format
    f Format -> Format -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Format
    Format Text
    "html"
      , Extension -> WriterOptions -> Bool
    forall a. HasSyntaxExtensions a => Extension -> a -> Bool
    isEnabled Extension
    Ext_raw_html WriterOptions
    opts = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "<html>" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    str Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "</html>"
      | Bool
    otherwise              = Text
    "" Text
    -> ReaderT WriterEnvironment (StateT WriterState m) ()
    -> DokuWiki m Text
    forall a b.
    a
    -> ReaderT WriterEnvironment (StateT WriterState m) b
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ LogMessage -> ReaderT WriterEnvironment (StateT WriterState m) ()
    forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
    report (Inline -> LogMessage
    InlineNotRendered Inline
    il)

    inlineToDokuWiki WriterOptions
    _ Inline
    LineBreak = do
      backSlash <- (WriterEnvironment -> Bool)
    -> ReaderT WriterEnvironment (StateT WriterState m) Bool
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks WriterEnvironment -> Bool
    stBackSlashLB
      return $ if backSlash
               then "\n"
               else "\\\\\n"

    inlineToDokuWiki WriterOptions
    opts Inline
    SoftBreak =
      case WriterOptions -> WrapOption
    writerWrapText WriterOptions
    opts of
           WrapOption
    WrapNone     -> Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    " "
           WrapOption
    WrapAuto     -> Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    " "
           WrapOption
    WrapPreserve -> Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    "\n"

    inlineToDokuWiki WriterOptions
    _ Inline
    Space = Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    " "

    inlineToDokuWiki WriterOptions
    opts (Link Attr
    _ [Inline]
    txt (Text
    src, Text
    _)) = do
      label <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    txt
      case txt of
         [Str Text
    s] | Text
    "mailto:" Text -> Text -> Bool
    `T.isPrefixOf` Text
    src -> Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "<" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    s Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    ">"
                 | Text -> Text
    escapeURI Text
    s Text -> Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text
    src -> Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    src
         [Inline]
    _  -> if Text -> Bool
    isURI Text
    src
                  then Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "[[" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    src  Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "|" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    label Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "]]"
                  else Text -> DokuWiki m Text
    forall a. a -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> DokuWiki m Text) -> Text -> DokuWiki m Text
    forall a b. (a -> b) -> a -> b
    $ Text
    "[[" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    src' Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "|" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    label Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "]]"
                         where src' :: Text
    src' = case Text -> Maybe (Char, Text)
    T.uncons Text
    src of
                                         Just (Char
    '/',Text
    xs) -> Text
    xs  -- with leading / it's a
                                         Maybe (Char, Text)
    _             -> Text
    src -- link to a help page
    inlineToDokuWiki WriterOptions
    opts (Image Attr
    attr [Inline]
    alt (Text
    source, Text
    tit)) = do
      alt' <- WriterOptions -> [Inline] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Inline] -> DokuWiki m Text
    inlineListToDokuWiki WriterOptions
    opts [Inline]
    alt
      let txt = case (Text
    tit, [Inline]
    alt) of
                  (Text
    "", []) -> Text
    ""
                  (Text
    "", [Inline]
    _ ) -> Text
    "|" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    alt'
                  (Text
    _ , [Inline]
    _ ) -> Text
    "|" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    tit
      return $ "{{" <> source <> imageDims opts attr <> txt <> "}}"

    inlineToDokuWiki WriterOptions
    opts (Note [Block]
    contents) = do
      contents' <- (WriterEnvironment -> WriterEnvironment)
    -> DokuWiki m Text -> DokuWiki m Text
    forall a.
    (WriterEnvironment -> WriterEnvironment)
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    -> ReaderT WriterEnvironment (StateT WriterState m) a
    forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
    local (\WriterEnvironment
    st -> WriterEnvironment
    st{ stBlockQuoteLevel = 0 })
                     (WriterOptions -> [Block] -> DokuWiki m Text
    forall (m :: * -> *).
    PandocMonad m =>
    WriterOptions -> [Block] -> DokuWiki m Text
    blockListToDokuWiki WriterOptions
    opts [Block]
    contents)
      return $ "((" <> contents' <> "))"
      -- note - may not work for notes with multiple blocks

    imageDims :: WriterOptions -> Attr -> Text
    imageDims :: WriterOptions -> Attr -> Text
    imageDims WriterOptions
    opts Attr
    attr = Maybe Text -> Maybe Text -> Text
    forall {a}. (Semigroup a, IsString a) => Maybe a -> Maybe a -> a
    go (Maybe Dimension -> Maybe Text
    toPx (Maybe Dimension -> Maybe Text) -> Maybe Dimension -> Maybe Text
    forall a b. (a -> b) -> a -> b
    $ Direction -> Attr -> Maybe Dimension
    dimension Direction
    Width Attr
    attr) (Maybe Dimension -> Maybe Text
    toPx (Maybe Dimension -> Maybe Text) -> Maybe Dimension -> Maybe Text
    forall a b. (a -> b) -> a -> b
    $ Direction -> Attr -> Maybe Dimension
    dimension Direction
    Height Attr
    attr)
      where
        toPx :: Maybe Dimension -> Maybe Text
    toPx = (Dimension -> Text) -> Maybe Dimension -> Maybe Text
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (WriterOptions -> Dimension -> Text
    showInPixel WriterOptions
    opts) (Maybe Dimension -> Maybe Text)
    -> (Maybe Dimension -> Maybe Dimension)
    -> Maybe Dimension
    -> Maybe Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Maybe Dimension -> Maybe Dimension
    checkPct
        checkPct :: Maybe Dimension -> Maybe Dimension
    checkPct (Just (Percent Double
    _)) = Maybe Dimension
    forall a. Maybe a
    Nothing
        checkPct Maybe Dimension
    maybeDim           = Maybe Dimension
    maybeDim
        go :: Maybe a -> Maybe a -> a
    go (Just a
    w) Maybe a
    Nothing  = a
    "?" a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    w
        go (Just a
    w) (Just a
    h) = a
    "?" a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    w a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    "x" a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    h
        go Maybe a
    Nothing  (Just a
    h) = a
    "?0x" a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    h
        go Maybe a
    Nothing  Maybe a
    Nothing  = a
    ""

    languageNames :: M.Map Text Text
    languageNames :: Map Text Text
    languageNames = [(Text, Text)] -> Map Text Text
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList
      [(Text
    "cs", Text
    "csharp")
      ,(Text
    "coffee", Text
    "cofeescript")
      ,(Text
    "commonlisp", Text
    "lisp")
      ,(Text
    "gcc", Text
    "c")
      ,(Text
    "html", Text
    "html5")
      ,(Text
    "makefile", Text
    "make")
      ,(Text
    "objectivec", Text
    "objc")
      ,(Text
    "r", Text
    "rsplus")
      ,(Text
    "sqlmysql", Text
    "mysql")
      ,(Text
    "sqlpostgresql", Text
    "postgresql")
      ,(Text
    "sci", Text
    "scilab")
      ,(Text
    "xorg", Text
    "xorgconf")
      ]