{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Text.Pandoc.Writers.XWiki ( writeXWiki ) where
import Prelude
import Control.Monad.Reader (ReaderT, asks, local, runReaderT)
import qualified Data.Set as Set
import qualified Data.Text as Text
import Data.Text (Text, intercalate, pack, replace, split)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Shared (escapeURI, isURI, linesToPara)
import Text.Pandoc.Writers.MediaWiki (highlightingLangs)
data WriterState = WriterState {
listLevel :: Text
}
type XWikiReader m = ReaderT WriterState m
writeXWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeXWiki _ (Pandoc _ blocks) = do
let env = WriterState { listLevel = "" }
body <- runReaderT (blockListToXWiki blocks) env
return $ body
vcat :: [Text] -> Text
vcat = intercalate "\n"
genAnchor :: String -> Text
genAnchor id' = if null id'
then ""
else pack $ "{{id name=\"" ++ id' ++ "\" /}}"
blockListToXWiki :: PandocMonad m => [Block] -> XWikiReader m Text
blockListToXWiki blocks =
fmap vcat $ mapM blockToXWiki blocks
blockToXWiki :: PandocMonad m => Block -> XWikiReader m Text
blockToXWiki Null = return ""
blockToXWiki (Div (id', _, _) blocks) = do
content <- blockListToXWiki blocks
return $ (genAnchor id') <> content
blockToXWiki (Plain inlines) =
inlineListToXWiki inlines
blockToXWiki (Para inlines) = do
contents <- inlineListToXWiki inlines
return $ contents <> "\n"
blockToXWiki (LineBlock lns) =
blockToXWiki $ linesToPara lns
blockToXWiki b@(RawBlock f str)
| f == Format "xwiki" = return $ pack str
| otherwise = "" <$ report (BlockNotRendered b)
blockToXWiki HorizontalRule = return "\n----\n"
blockToXWiki (Header level (id', _, _) inlines) = do
contents <- inlineListToXWiki inlines
let eqs = Text.replicate level "="
return $ eqs <> " " <> contents <> " " <> (genAnchor id') <> eqs <> "\n"
blockToXWiki (CodeBlock attrs str) = do
contents <- inlineToXWiki (Code attrs ("\n" <> str <> "\n"))
return $ "\n" <> contents <> "\n"
blockToXWiki (BlockQuote blocks) = do
blockText <- blockListToXWiki blocks
let quoteLines = split (== '\n') blockText
let prefixed = map (">" <>) quoteLines
return $ vcat prefixed
blockToXWiki (BulletList contents) = blockToXWikiList "*" $ contents
blockToXWiki (OrderedList _ contents) = blockToXWikiList "1" $ contents
blockToXWiki (DefinitionList items) = do
lev <- asks listLevel
contents <- local (\s -> s { listLevel = listLevel s <> ";" }) $ mapM definitionListItemToMediaWiki items
return $ vcat contents <> if Text.null lev then "\n" else ""
blockToXWiki (Table _ _ _ headers rows') = do
headers' <- mapM (tableCellXWiki True) headers
otherRows <- mapM formRow rows'
return $ Text.unlines (Text.unwords headers':otherRows)
formRow :: PandocMonad m => [[Block]] -> XWikiReader m Text
formRow row = do
cellStrings <- mapM (tableCellXWiki False) row
return $ Text.unwords cellStrings
tableCellXWiki :: PandocMonad m => Bool -> [Block] -> XWikiReader m Text
tableCellXWiki isHeader cell = do
contents <- blockListToXWiki cell
let cellBorder = if isHeader then "|=" else "|"
return $ cellBorder <> contents
inlineListToXWiki :: PandocMonad m => [Inline] -> XWikiReader m Text
inlineListToXWiki lst =
mconcat <$> mapM inlineToXWiki lst
inlineToXWiki :: PandocMonad m => Inline -> XWikiReader m Text
inlineToXWiki (Str str) = return $ escapeXWikiString $ pack str
inlineToXWiki Space = return " "
inlineToXWiki LineBreak = return "\\\\"
inlineToXWiki SoftBreak = return " "
inlineToXWiki (Emph lst) = do
contents <- inlineListToXWiki lst
return $ "//" <> contents <> "//"
inlineToXWiki (Strong lst) = do
contents <- inlineListToXWiki lst
return $ "**" <> contents <> "**"
inlineToXWiki (Strikeout lst) = do
contents <- inlineListToXWiki lst
return $ "--" <> contents <> "--"
inlineToXWiki (Superscript lst) = do
contents <- inlineListToXWiki lst
return $ "^^" <> contents <> "^^"
inlineToXWiki (Subscript lst) = do
contents <- inlineListToXWiki lst
return $ ",," <> contents <> ",,"
inlineToXWiki (SmallCaps lst) = do
contents <- inlineListToXWiki lst
return contents
inlineToXWiki (Quoted SingleQuote lst) = do
contents <- inlineListToXWiki lst
return $ "‘" <> contents <> "’"
inlineToXWiki (Quoted DoubleQuote lst) = do
contents <- inlineListToXWiki lst
return $ "“" <> contents <> "”"
inlineToXWiki (Code (_,classes,_) contents') = do
let at = Set.fromList classes `Set.intersection` highlightingLangs
let contents = pack contents'
return $
case Set.toList at of
[] -> "{{code}}" <> contents <> "{{/code}}"
(l:_) -> "{{code language=\"" <> (pack l) <> "\"}}" <> contents <> "{{/code}}"
inlineToXWiki (Cite _ lst) = inlineListToXWiki lst
inlineToXWiki (Math _ str) = return $ "{{formula}}" <> (pack str) <> "{{/formula}}"
inlineToXWiki il@(RawInline frmt str)
| frmt == Format "xwiki" = return $ pack str
| otherwise = "" <$ report (InlineNotRendered il)
inlineToXWiki (Link (id', _, _) txt (src, _)) = do
label <- inlineListToXWiki txt
case txt of
[Str s] | isURI src && escapeURI s == src -> return $ (pack src) <> (genAnchor id')
_ -> return $ "[[" <> label <> ">>" <> (pack src) <> "]]" <> (genAnchor id')
inlineToXWiki (Image _ alt (source, tit)) = do
alt' <- inlineListToXWiki alt
let
titText = pack tit
params = intercalate " " $ filter (not . Text.null) [
if Text.null alt' then "" else "alt=\"" <> alt' <> "\"",
if Text.null titText then "" else "title=\"" <> titText <> "\""
]
return $ "[[image:" <> (pack source) <> (if Text.null params then "" else "||" <> params) <> "]]"
inlineToXWiki (Note contents) = do
contents' <- blockListToXWiki contents
return $ "{{footnote}}" <> (Text.strip contents') <> "{{/footnote}}"
inlineToXWiki (Span (id', _, _) contents) = do
contents' <- inlineListToXWiki contents
return $ (genAnchor id') <> contents'
blockToXWikiList :: PandocMonad m => Text -> [[Block]] -> XWikiReader m Text
blockToXWikiList marker contents = do
lev <- asks listLevel
contents' <- local (\s -> s { listLevel = listLevel s <> marker } ) $ mapM listItemToXWiki contents
return $ vcat contents' <> if Text.null lev then "\n" else ""
listItemToXWiki :: PandocMonad m => [Block] -> XWikiReader m Text
listItemToXWiki contents = do
marker <- asks listLevel
contents' <- blockListToXWiki contents
return $ marker <> ". " <> (Text.strip contents')
definitionListItemToMediaWiki :: PandocMonad m
=> ([Inline],[[Block]])
-> XWikiReader m Text
definitionListItemToMediaWiki (label, items) = do
labelText <- inlineListToXWiki label
contents <- mapM blockListToXWiki items
marker <- asks listLevel
return $ marker <> " " <> labelText <> "\n" <>
intercalate "\n" (map (\d -> (Text.init marker) <> ": " <> d) contents)
escapeXWikiString :: Text -> Text
escapeXWikiString s = foldr (uncurry replace) s $ zip ["--", "**", "//", "^^", ",,", "~"] ["~-~-", "~*~*", "~/~/", "~^~^", "~,~,", "~~"]