Convert all writers to use PandocMonad.

Since PandocMonad is an instance of MonadError, this will allow us, in a
future commit, to change all invocations of `error` to `throwError`,
which will be preferable for the pure versions. At the moment, we're
disabling the lua custom writers (this is temporary).

This requires changing the type of the Writer in Text.Pandoc. Right now,
we run `runIOorExplode` in pandoc.hs, to make the conversion easier. We
can switch it to the safer `runIO` in the future.

Note that this required a change to Text.Pandoc.PDF as well. Since
running an external program is necessarily IO, we can be clearer about
using PandocIO.
This commit is contained in:
Jesse Rosenthal 2016-11-26 08:46:28 -05:00 committed by John MacFarlane
parent b19f79f672
commit 04487779b2
25 changed files with 393 additions and 273 deletions

View file

@ -77,6 +77,7 @@ import Text.Printf (printf)
import System.Posix.Terminal (queryTerminal)
import System.Posix.IO (stdOutput)
#endif
import Text.Pandoc.Class (runIOorExplode, PandocIO)
type Transform = Pandoc -> Pandoc
@ -914,7 +915,7 @@ options =
let allopts = unwords (concatMap optnames options)
UTF8.hPutStrLn stdout $ printf tpl allopts
(unwords (map fst readers))
(unwords (map fst writers))
(unwords (map fst (writers' :: [(String, Writer' PandocIO)])))
(unwords $ map fst highlightingStyles)
ddir
exitSuccess ))
@ -931,7 +932,7 @@ options =
, Option "" ["list-output-formats"]
(NoArg
(\_ -> do
let writers'names = sort (map fst writers)
let writers'names = sort (map fst (writers' :: [(String, Writer' PandocIO)]))
mapM_ (UTF8.hPutStrLn stdout) writers'names
exitSuccess ))
""
@ -1268,10 +1269,12 @@ convertWithOpts opts args = do
let laTeXInput = "latex" `isPrefixOf` readerName' ||
"beamer" `isPrefixOf` readerName'
-- disabling the custom writer for now
writer <- if ".lua" `isSuffixOf` format
-- note: use non-lowercased version writerName
then return $ IOStringWriter $ writeCustom writerName
else case getWriter writerName' of
then error "custom writers disabled for now"
else case getWriter' writerName' of
Left e -> err 9 $
if format == "pdf"
then e ++
@ -1477,9 +1480,9 @@ convertWithOpts opts args = do
writerFn f = UTF8.writeFile f
case writer of
IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
IOByteStringWriter f -> f writerOptions doc' >>= writeFnBinary outputFile
PureStringWriter f
-- StringWriter f -> f writerOptions doc' >>= writerFn outputFile
ByteStringWriter' f -> (runIOorExplode $ f writerOptions doc') >>= writeFnBinary outputFile
StringWriter' f
| pdfOutput -> do
-- make sure writer is latex or beamer or context or html5
unless (laTeXOutput || conTeXtOutput || html5Output) $
@ -1503,14 +1506,14 @@ convertWithOpts opts args = do
B.hPutStr stderr err'
B.hPut stderr $ B.pack [10]
err 43 "Error producing PDF"
| otherwise -> selfcontain (f writerOptions doc' ++
['\n' | not standalone'])
>>= writerFn outputFile . handleEntities
where htmlFormat = format `elem`
["html","html5","s5","slidy","slideous","dzslides","revealjs"]
selfcontain = if selfContained && htmlFormat
then makeSelfContained writerOptions
else return
handleEntities = if htmlFormat && ascii
then toEntities
else id
| otherwise -> do
let htmlFormat = format `elem`
["html","html5","s5","slidy","slideous","dzslides","revealjs"]
selfcontain = if selfContained && htmlFormat
then makeSelfContained writerOptions
else return
handleEntities = if htmlFormat && ascii
then toEntities
else id
output <- runIOorExplode $ f writerOptions doc'
selfcontain (output ++ ['\n' | not standalone']) >>= writerFn outputFile . handleEntities

View file

@ -1,4 +1,4 @@
{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables, FlexibleInstances, GADTs #-}
{-
Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
@ -63,7 +63,8 @@ module Text.Pandoc
, module Text.Pandoc.Error
-- * Lists of readers and writers
, readers
, writers
-- , writers
, writers'
-- * Readers: converting /to/ Pandoc format
, Reader (..)
, mkStringReader
@ -87,7 +88,8 @@ module Text.Pandoc
, readTxt2TagsNoMacros
, readEPUB
-- * Writers: converting /from/ Pandoc format
, Writer (..)
-- , Writer (..)
, Writer'(..)
, writeNative
, writeJSON
, writeMarkdown
@ -122,7 +124,8 @@ module Text.Pandoc
, module Text.Pandoc.Templates
-- * Miscellaneous
, getReader
, getWriter
-- , getWriter
, getWriter'
, getDefaultExtensions
, ToJsonFilter(..)
, pandocVersion
@ -180,7 +183,7 @@ import Text.Pandoc.Options
import Text.Pandoc.Shared (safeRead, warn, mapLeft, pandocVersion)
import Text.Pandoc.MediaBag (MediaBag)
import Text.Pandoc.Error
import Text.Pandoc.Class (runIOorExplode)
import Text.Pandoc.Class (PandocMonad)
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
import Data.List (intercalate)
@ -262,74 +265,137 @@ readers = [ ("native" , StringReader $ \_ s -> return $ readNative s)
,("epub" , mkBSReader readEPUB)
]
data Writer = PureStringWriter (WriterOptions -> Pandoc -> String)
| IOStringWriter (WriterOptions -> Pandoc -> IO String)
| IOByteStringWriter (WriterOptions -> Pandoc -> IO BL.ByteString)
-- data Writer = PureStringWriter (WriterOptions -> Pandoc -> String)
-- | IOStringWriter (WriterOptions -> Pandoc -> IO String)
-- | IOByteStringWriter (WriterOptions -> Pandoc -> IO BL.ByteString)
-- -- | Association list of formats and writers.
-- writers :: [ ( String, Writer ) ]
-- writers = [
-- ("native" , PureStringWriter writeNative)
-- ,("json" , PureStringWriter writeJSON)
-- ,("docx" , IOByteStringWriter $ \o doc ->
-- runIOorExplode $ writeDocx o doc)
-- ,("odt" , IOByteStringWriter $ \o doc ->
-- runIOorExplode $ writeODT o doc)
-- ,("epub" , IOByteStringWriter $ \o doc ->
-- runIOorExplode $
-- writeEPUB o{ writerEpubVersion = Just EPUB2 } doc)
-- ,("epub3" , IOByteStringWriter $ \o doc ->
-- runIOorExplode $
-- writeEPUB o{ writerEpubVersion = Just EPUB3 } doc)
-- ,("fb2" , IOStringWriter $ \o doc ->
-- runIOorExplode $ writeFB2 o doc)
-- ,("html" , PureStringWriter writeHtmlString)
-- ,("html5" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerHtml5 = True })
-- ,("icml" , IOStringWriter $ \o doc ->
-- runIOorExplode $ writeICML o doc)
-- ,("s5" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerSlideVariant = S5Slides
-- , writerTableOfContents = False })
-- ,("slidy" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerSlideVariant = SlidySlides })
-- ,("slideous" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerSlideVariant = SlideousSlides })
-- ,("dzslides" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerSlideVariant = DZSlides
-- , writerHtml5 = True })
-- ,("revealjs" , PureStringWriter $ \o ->
-- writeHtmlString o{ writerSlideVariant = RevealJsSlides
-- , writerHtml5 = True })
-- ,("docbook" , PureStringWriter writeDocbook)
-- ,("docbook5" , PureStringWriter $ \o ->
-- writeDocbook o{ writerDocbook5 = True })
-- ,("opml" , PureStringWriter writeOPML)
-- ,("opendocument" , PureStringWriter writeOpenDocument)
-- ,("latex" , PureStringWriter writeLaTeX)
-- ,("beamer" , PureStringWriter $ \o ->
-- writeLaTeX o{ writerBeamer = True })
-- ,("context" , PureStringWriter writeConTeXt)
-- ,("texinfo" , PureStringWriter writeTexinfo)
-- ,("man" , PureStringWriter writeMan)
-- ,("markdown" , PureStringWriter writeMarkdown)
-- ,("markdown_strict" , PureStringWriter writeMarkdown)
-- ,("markdown_phpextra" , PureStringWriter writeMarkdown)
-- ,("markdown_github" , PureStringWriter writeMarkdown)
-- ,("markdown_mmd" , PureStringWriter writeMarkdown)
-- ,("plain" , PureStringWriter writePlain)
-- ,("rst" , PureStringWriter writeRST)
-- ,("mediawiki" , PureStringWriter writeMediaWiki)
-- ,("dokuwiki" , PureStringWriter writeDokuWiki)
-- ,("zimwiki" , PureStringWriter writeZimWiki)
-- ,("textile" , PureStringWriter writeTextile)
-- ,("rtf" , IOStringWriter $ \o doc ->
-- runIOorExplode $ writeRTFWithEmbeddedImages o doc)
-- ,("org" , PureStringWriter writeOrg)
-- ,("asciidoc" , PureStringWriter writeAsciiDoc)
-- ,("haddock" , PureStringWriter writeHaddock)
-- ,("commonmark" , PureStringWriter writeCommonMark)
-- ,("tei" , PureStringWriter writeTEI)
-- ]
data Writer' m = StringWriter' (WriterOptions -> Pandoc -> m String)
| ByteStringWriter' (WriterOptions -> Pandoc -> m BL.ByteString)
-- | Association list of formats and writers.
writers :: [ ( String, Writer ) ]
writers = [
("native" , PureStringWriter writeNative)
,("json" , PureStringWriter writeJSON)
,("docx" , IOByteStringWriter $ \o doc ->
runIOorExplode $ writeDocx o doc)
,("odt" , IOByteStringWriter $ \o doc ->
runIOorExplode $ writeODT o doc)
,("epub" , IOByteStringWriter $ \o doc ->
runIOorExplode $
writeEPUB o{ writerEpubVersion = Just EPUB2 } doc)
,("epub3" , IOByteStringWriter $ \o doc ->
runIOorExplode $
writeEPUB o{ writerEpubVersion = Just EPUB3 } doc)
,("fb2" , IOStringWriter $ \o doc ->
runIOorExplode $ writeFB2 o doc)
,("html" , PureStringWriter writeHtmlString)
,("html5" , PureStringWriter $ \o ->
writers' :: PandocMonad m => [ ( String, Writer' m) ]
writers' = [
("native" , StringWriter' writeNative)
,("json" , StringWriter' $ \o d -> return $ writeJSON o d)
,("docx" , ByteStringWriter' writeDocx)
,("odt" , ByteStringWriter' writeODT)
,("epub" , ByteStringWriter' $ \o ->
writeEPUB o{ writerEpubVersion = Just EPUB2 })
,("epub3" , ByteStringWriter' $ \o ->
writeEPUB o{ writerEpubVersion = Just EPUB3 })
,("fb2" , StringWriter' writeFB2)
,("html" , StringWriter' writeHtmlString)
,("html5" , StringWriter' $ \o ->
writeHtmlString o{ writerHtml5 = True })
,("icml" , IOStringWriter $ \o doc ->
runIOorExplode $ writeICML o doc)
,("s5" , PureStringWriter $ \o ->
,("icml" , StringWriter' writeICML)
,("s5" , StringWriter' $ \o ->
writeHtmlString o{ writerSlideVariant = S5Slides
, writerTableOfContents = False })
,("slidy" , PureStringWriter $ \o ->
,("slidy" , StringWriter' $ \o ->
writeHtmlString o{ writerSlideVariant = SlidySlides })
,("slideous" , PureStringWriter $ \o ->
,("slideous" , StringWriter' $ \o ->
writeHtmlString o{ writerSlideVariant = SlideousSlides })
,("dzslides" , PureStringWriter $ \o ->
,("dzslides" , StringWriter' $ \o ->
writeHtmlString o{ writerSlideVariant = DZSlides
, writerHtml5 = True })
,("revealjs" , PureStringWriter $ \o ->
,("revealjs" , StringWriter' $ \o ->
writeHtmlString o{ writerSlideVariant = RevealJsSlides
, writerHtml5 = True })
,("docbook" , PureStringWriter writeDocbook)
,("docbook5" , PureStringWriter $ \o ->
,("docbook" , StringWriter' writeDocbook)
,("docbook5" , StringWriter' $ \o ->
writeDocbook o{ writerDocbook5 = True })
,("opml" , PureStringWriter writeOPML)
,("opendocument" , PureStringWriter writeOpenDocument)
,("latex" , PureStringWriter writeLaTeX)
,("beamer" , PureStringWriter $ \o ->
,("opml" , StringWriter' writeOPML)
,("opendocument" , StringWriter' writeOpenDocument)
,("latex" , StringWriter' writeLaTeX)
,("beamer" , StringWriter' $ \o ->
writeLaTeX o{ writerBeamer = True })
,("context" , PureStringWriter writeConTeXt)
,("texinfo" , PureStringWriter writeTexinfo)
,("man" , PureStringWriter writeMan)
,("markdown" , PureStringWriter writeMarkdown)
,("markdown_strict" , PureStringWriter writeMarkdown)
,("markdown_phpextra" , PureStringWriter writeMarkdown)
,("markdown_github" , PureStringWriter writeMarkdown)
,("markdown_mmd" , PureStringWriter writeMarkdown)
,("plain" , PureStringWriter writePlain)
,("rst" , PureStringWriter writeRST)
,("mediawiki" , PureStringWriter writeMediaWiki)
,("dokuwiki" , PureStringWriter writeDokuWiki)
,("zimwiki" , PureStringWriter writeZimWiki)
,("textile" , PureStringWriter writeTextile)
,("rtf" , IOStringWriter $ \o doc ->
runIOorExplode $ writeRTFWithEmbeddedImages o doc)
,("org" , PureStringWriter writeOrg)
,("asciidoc" , PureStringWriter writeAsciiDoc)
,("haddock" , PureStringWriter writeHaddock)
,("commonmark" , PureStringWriter writeCommonMark)
,("tei" , PureStringWriter writeTEI)
,("context" , StringWriter' writeConTeXt)
,("texinfo" , StringWriter' writeTexinfo)
,("man" , StringWriter' writeMan)
,("markdown" , StringWriter' writeMarkdown)
,("markdown_strict" , StringWriter' writeMarkdown)
,("markdown_phpextra" , StringWriter' writeMarkdown)
,("markdown_github" , StringWriter' writeMarkdown)
,("markdown_mmd" , StringWriter' writeMarkdown)
,("plain" , StringWriter' writePlain)
,("rst" , StringWriter' writeRST)
,("mediawiki" , StringWriter' writeMediaWiki)
,("dokuwiki" , StringWriter' writeDokuWiki)
,("zimwiki" , StringWriter' writeZimWiki)
,("textile" , StringWriter' writeTextile)
,("rtf" , StringWriter' $ \o ->
writeRTFWithEmbeddedImages o)
,("org" , StringWriter' writeOrg)
,("asciidoc" , StringWriter' writeAsciiDoc)
,("haddock" , StringWriter' writeHaddock)
,("commonmark" , StringWriter' writeCommonMark)
,("tei" , StringWriter' writeTEI)
]
getDefaultExtensions :: String -> Set Extension
@ -368,20 +434,34 @@ getReader s =
getDefaultExtensions readerName }
-- | Retrieve writer based on formatSpec (format+extensions).
getWriter :: String -> Either String Writer
getWriter s
-- getWriter :: String -> Either String Writer
-- getWriter s
-- = case parseFormatSpec s of
-- Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
-- Right (writerName, setExts) ->
-- case lookup writerName writers of
-- Nothing -> Left $ "Unknown writer: " ++ writerName
-- Just (PureStringWriter r) -> Right $ PureStringWriter $
-- \o -> r o{ writerExtensions = setExts $
-- getDefaultExtensions writerName }
-- Just (IOStringWriter r) -> Right $ IOStringWriter $
-- \o -> r o{ writerExtensions = setExts $
-- getDefaultExtensions writerName }
-- Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $
-- \o -> r o{ writerExtensions = setExts $
-- getDefaultExtensions writerName }
getWriter' :: PandocMonad m => String -> Either String (Writer' m)
getWriter' s
= case parseFormatSpec s of
Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
Right (writerName, setExts) ->
case lookup writerName writers of
case lookup writerName writers' of
Nothing -> Left $ "Unknown writer: " ++ writerName
Just (PureStringWriter r) -> Right $ PureStringWriter $
Just (StringWriter' r) -> Right $ StringWriter' $
\o -> r o{ writerExtensions = setExts $
getDefaultExtensions writerName }
Just (IOStringWriter r) -> Right $ IOStringWriter $
\o -> r o{ writerExtensions = setExts $
getDefaultExtensions writerName }
Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $
Just (ByteStringWriter' r) -> Right $ ByteStringWriter' $
\o -> r o{ writerExtensions = setExts $
getDefaultExtensions writerName }

View file

@ -60,6 +60,7 @@ import qualified Codec.Picture as JP
#ifdef _WINDOWS
import Data.List (intercalate)
#endif
import Text.Pandoc.Class (PandocIO, runIOorExplode)
#ifdef _WINDOWS
changePathSeparators :: FilePath -> FilePath
@ -68,7 +69,7 @@ changePathSeparators = intercalate "/" . splitDirectories
makePDF :: String -- ^ pdf creator (pdflatex, lualatex,
-- xelatex, context, wkhtmltopdf)
-> (WriterOptions -> Pandoc -> String) -- ^ writer
-> (WriterOptions -> Pandoc -> PandocIO String) -- ^ writer
-> WriterOptions -- ^ options
-> Pandoc -- ^ document
-> IO (Either ByteString ByteString)
@ -93,12 +94,12 @@ makePDF "wkhtmltopdf" writer opts doc@(Pandoc meta _) = do
,("margin-left", fromMaybe (Just "1.25in")
(getField "margin-left" meta'))
]
let source = writer opts doc
source <- runIOorExplode $ writer opts doc
html2pdf (writerVerbose opts) args source
makePDF program writer opts doc = withTempDir "tex2pdf." $ \tmpdir -> do
doc' <- handleImages opts tmpdir doc
let source = writer opts doc'
args = writerLaTeXArgs opts
source <- runIOorExplode $ writer opts doc'
let args = writerLaTeXArgs opts
case takeBaseName program of
"context" -> context2pdf (writerVerbose opts) tmpdir source
prog | prog `elem` ["pdflatex", "lualatex", "xelatex"]

View file

@ -52,6 +52,7 @@ import qualified Data.Map as M
import Data.Aeson (Value(String), fromJSON, toJSON, Result(..))
import qualified Data.Text as T
import Data.Char (isSpace, isPunctuation)
import Text.Pandoc.Class (PandocMonad)
data WriterState = WriterState { defListMarker :: String
, orderedListLevel :: Int
@ -60,8 +61,8 @@ data WriterState = WriterState { defListMarker :: String
}
-- | Convert Pandoc to AsciiDoc.
writeAsciiDoc :: WriterOptions -> Pandoc -> String
writeAsciiDoc opts document =
writeAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeAsciiDoc opts document = return $
evalState (pandocToAsciiDoc opts document) WriterState{
defListMarker = "::"
, orderedListLevel = 1

View file

@ -39,26 +39,27 @@ import Text.Pandoc.Writers.Shared
import Text.Pandoc.Options
import CMark
import qualified Data.Text as T
import Control.Monad.Identity (runIdentity, Identity)
import Control.Monad.State (runState, State, modify, get)
import Text.Pandoc.Walk (walkM)
import Text.Pandoc.Class (PandocMonad)
import Data.Foldable (foldrM)
-- | Convert Pandoc to CommonMark.
writeCommonMark :: WriterOptions -> Pandoc -> String
writeCommonMark opts (Pandoc meta blocks) = rendered
where main = runIdentity $ blocksToCommonMark opts (blocks' ++ notes')
(blocks', notes) = runState (walkM processNotes blocks) []
notes' = if null notes
then []
else [OrderedList (1, Decimal, Period) $ reverse notes]
metadata = runIdentity $ metaToJSON opts
(blocksToCommonMark opts)
(inlinesToCommonMark opts)
meta
context = defField "body" main $ metadata
rendered = case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate' tpl context
writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeCommonMark opts (Pandoc meta blocks) = do
let (blocks', notes) = runState (walkM processNotes blocks) []
notes' = if null notes
then []
else [OrderedList (1, Decimal, Period) $ reverse notes]
main <- blocksToCommonMark opts (blocks' ++ notes')
metadata <- metaToJSON opts
(blocksToCommonMark opts)
(inlinesToCommonMark opts)
meta
let context = defField "body" main $ metadata
return $ case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate' tpl context
processNotes :: Inline -> State [[Block]] Inline
processNotes (Note bs) = do
@ -70,16 +71,19 @@ processNotes x = return x
node :: NodeType -> [Node] -> Node
node = Node Nothing
blocksToCommonMark :: WriterOptions -> [Block] -> Identity String
blocksToCommonMark opts bs = return $
T.unpack $ nodeToCommonmark cmarkOpts colwidth
$ node DOCUMENT (blocksToNodes bs)
where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m String
blocksToCommonMark opts bs = do
let cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
nodes <- blocksToNodes bs
return $
T.unpack $
nodeToCommonmark cmarkOpts colwidth $
node DOCUMENT nodes
inlinesToCommonMark :: WriterOptions -> [Inline] -> Identity String
inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m String
inlinesToCommonMark opts ils = return $
T.unpack $ nodeToCommonmark cmarkOpts colwidth
$ node PARAGRAPH (inlinesToNodes ils)
@ -88,39 +92,44 @@ inlinesToCommonMark opts ils = return $
then Just $ writerColumns opts
else Nothing
blocksToNodes :: [Block] -> [Node]
blocksToNodes = foldr blockToNodes []
blocksToNodes :: PandocMonad m => [Block] -> m [Node]
blocksToNodes = foldrM blockToNodes []
blockToNodes :: Block -> [Node] -> [Node]
blockToNodes (Plain xs) = (node PARAGRAPH (inlinesToNodes xs) :)
blockToNodes (Para xs) = (node PARAGRAPH (inlinesToNodes xs) :)
blockToNodes (LineBlock lns) = blockToNodes $ linesToPara lns
blockToNodes (CodeBlock (_,classes,_) xs) =
(node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] :)
blockToNodes (RawBlock fmt xs)
| fmt == Format "html" = (node (HTML_BLOCK (T.pack xs)) [] :)
| otherwise = (node (CUSTOM_BLOCK (T.pack xs) (T.empty)) [] :)
blockToNodes (BlockQuote bs) =
(node BLOCK_QUOTE (blocksToNodes bs) :)
blockToNodes (BulletList items) =
(node (LIST ListAttributes{
listType = BULLET_LIST,
listDelim = PERIOD_DELIM,
listTight = isTightList items,
listStart = 1 }) (map (node ITEM . blocksToNodes) items) :)
blockToNodes (OrderedList (start, _sty, delim) items) =
(node (LIST ListAttributes{
listType = ORDERED_LIST,
listDelim = case delim of
OneParen -> PAREN_DELIM
TwoParens -> PAREN_DELIM
_ -> PERIOD_DELIM,
listTight = isTightList items,
listStart = start }) (map (node ITEM . blocksToNodes) items) :)
blockToNodes HorizontalRule = (node THEMATIC_BREAK [] :)
blockToNodes (Header lev _ ils) = (node (HEADING lev) (inlinesToNodes ils) :)
blockToNodes (Div _ bs) = (blocksToNodes bs ++)
blockToNodes (DefinitionList items) = blockToNodes (BulletList items')
blockToNodes :: PandocMonad m => Block -> [Node] -> m [Node]
blockToNodes (Plain xs) ns = return (node PARAGRAPH (inlinesToNodes xs) : ns)
blockToNodes (Para xs) ns = return (node PARAGRAPH (inlinesToNodes xs) : ns)
blockToNodes (LineBlock lns) ns = blockToNodes (linesToPara lns) ns
blockToNodes (CodeBlock (_,classes,_) xs) ns = return $
(node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] : ns)
blockToNodes (RawBlock fmt xs) ns
| fmt == Format "html" = return (node (HTML_BLOCK (T.pack xs)) [] : ns)
| otherwise = return (node (CUSTOM_BLOCK (T.pack xs) (T.empty)) [] : ns)
blockToNodes (BlockQuote bs) ns = do
nodes <- blocksToNodes bs
return (node BLOCK_QUOTE nodes : ns)
blockToNodes (BulletList items) ns = do
nodes <- mapM blocksToNodes items
return (node (LIST ListAttributes{
listType = BULLET_LIST,
listDelim = PERIOD_DELIM,
listTight = isTightList items,
listStart = 1 }) (map (node ITEM) nodes) : ns)
blockToNodes (OrderedList (start, _sty, delim) items) ns = do
nodes <- mapM blocksToNodes items
return (node (LIST ListAttributes{
listType = ORDERED_LIST,
listDelim = case delim of
OneParen -> PAREN_DELIM
TwoParens -> PAREN_DELIM
_ -> PERIOD_DELIM,
listTight = isTightList items,
listStart = start }) (map (node ITEM) nodes) : ns)
blockToNodes HorizontalRule ns = return (node THEMATIC_BREAK [] : ns)
blockToNodes (Header lev _ ils) ns = return (node (HEADING lev) (inlinesToNodes ils) : ns)
blockToNodes (Div _ bs) ns = do
nodes <- blocksToNodes bs
return (nodes ++ ns)
blockToNodes (DefinitionList items) ns = blockToNodes (BulletList items') ns
where items' = map dlToBullet items
dlToBullet (term, ((Para xs : ys) : zs)) =
Para (term ++ [LineBreak] ++ xs) : ys ++ concat zs
@ -128,9 +137,10 @@ blockToNodes (DefinitionList items) = blockToNodes (BulletList items')
Plain (term ++ [LineBreak] ++ xs) : ys ++ concat zs
dlToBullet (term, xs) =
Para term : concat xs
blockToNodes t@(Table _ _ _ _ _) =
(node (HTML_BLOCK (T.pack $! writeHtmlString def $! Pandoc nullMeta [t])) [] :)
blockToNodes Null = id
blockToNodes t@(Table _ _ _ _ _) ns = do
s <- writeHtmlString def $! Pandoc nullMeta [t]
return (node (HTML_BLOCK (T.pack $! s)) [] : ns)
blockToNodes Null ns = return ns
inlinesToNodes :: [Inline] -> [Node]
inlinesToNodes = foldr inlineToNodes []

View file

@ -43,6 +43,7 @@ import Text.Pandoc.Pretty
import Text.Pandoc.ImageSize
import Text.Pandoc.Templates ( renderTemplate' )
import Network.URI ( isURI, unEscapeString )
import Text.Pandoc.Class (PandocMonad)
data WriterState =
WriterState { stNextRef :: Int -- number of next URL reference
@ -54,8 +55,8 @@ orderedListStyles :: [Char]
orderedListStyles = cycle "narg"
-- | Convert Pandoc to ConTeXt.
writeConTeXt :: WriterOptions -> Pandoc -> String
writeConTeXt options document =
writeConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeConTeXt options document = return $
let defaultWriterState = WriterState { stNextRef = 1
, stOrderedListLevel = 0
, stOptions = options

View file

@ -47,6 +47,7 @@ import qualified Text.Pandoc.Builder as B
import Text.TeXMath
import qualified Text.XML.Light as Xml
import Data.Generics (everywhere, mkT)
import Text.Pandoc.Class (PandocMonad)
-- | Convert list of authors to a docbook <author> section
authorToDocbook :: WriterOptions -> [Inline] -> B.Inlines
@ -73,8 +74,8 @@ authorToDocbook opts name' =
inTagsSimple "surname" (text $ escapeStringForXML lastname)
-- | Convert Pandoc document to string in Docbook format.
writeDocbook :: WriterOptions -> Pandoc -> String
writeDocbook opts (Pandoc meta blocks) =
writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeDocbook opts (Pandoc meta blocks) = return $
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts

View file

@ -55,6 +55,7 @@ import Network.URI ( isURI )
import Control.Monad ( zipWithM )
import Control.Monad.State ( modify, State, get, evalState )
import Control.Monad.Reader ( ReaderT, runReaderT, ask, local )
import Text.Pandoc.Class (PandocMonad)
data WriterState = WriterState {
stNotes :: Bool -- True if there are notes
@ -77,8 +78,8 @@ instance Default WriterEnvironment where
type DokuWiki = ReaderT WriterEnvironment (State WriterState)
-- | Convert Pandoc to DokuWiki.
writeDokuWiki :: WriterOptions -> Pandoc -> String
writeDokuWiki opts document =
writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeDokuWiki opts document = return $
runDokuWiki (pandocToDokuWiki opts $ normalize document)
runDokuWiki :: DokuWiki a -> a

View file

@ -55,7 +55,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Walk (walk, walkM, query)
import Text.Pandoc.UUID (getUUID)
import Control.Monad.State (modify, get, gets, State, StateT, put, evalState, evalStateT, lift)
import Control.Monad (mplus, when)
import Control.Monad (mplus, when, zipWithM)
import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs
, strContent, lookupAttr, Node(..), QName(..), parseXML
, onlyElems, node, ppElement)
@ -374,17 +374,17 @@ pandocToEPUB opts doc@(Pandoc meta _) = do
Nothing -> return ([],[])
Just img -> do
let coverImage = "media/" ++ takeFileName img
let cpContent = renderHtml $ writeHtml
cpContent <- renderHtml <$> (lift $ writeHtml
opts'{ writerVariables = ("coverpage","true"):vars }
(Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
(Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"]))
imgContent <- lift $ P.readFileLazy img
return ( [mkEntry "cover.xhtml" cpContent]
, [mkEntry coverImage imgContent] )
-- title page
let tpContent = renderHtml $ writeHtml opts'{
writerVariables = ("titlepage","true"):vars }
(Pandoc meta [])
tpContent <- renderHtml <$> (lift $ writeHtml opts'{
writerVariables = ("titlepage","true"):vars }
(Pandoc meta []))
let tpEntry = mkEntry "title_page.xhtml" tpContent
-- handle pictures
@ -482,20 +482,20 @@ pandocToEPUB opts doc@(Pandoc meta _) = do
Chapter mbnum $ walk fixInternalReferences bs)
chapters'
let chapToEntry :: Int -> Chapter -> Entry
chapToEntry num (Chapter mbnum bs) = mkEntry (showChapter num)
$ renderHtml
$ writeHtml opts'{ writerNumberOffset =
fromMaybe [] mbnum }
$ case bs of
(Header _ _ xs : _) ->
-- remove notes or we get doubled footnotes
Pandoc (setMeta "title" (walk removeNote $ fromList xs)
nullMeta) bs
_ ->
Pandoc nullMeta bs
let chapToEntry :: PandocMonad m => Int -> Chapter -> m Entry
chapToEntry num (Chapter mbnum bs) =
(mkEntry (showChapter num) . renderHtml) <$>
(writeHtml opts'{ writerNumberOffset =
fromMaybe [] mbnum }
$ case bs of
(Header _ _ xs : _) ->
-- remove notes or we get doubled footnotes
Pandoc (setMeta "title" (walk removeNote $ fromList xs)
nullMeta) bs
_ ->
Pandoc nullMeta bs)
let chapterEntries = zipWith chapToEntry [1..] chapters
chapterEntries <- lift $ zipWithM chapToEntry [1..] chapters
-- incredibly inefficient (TODO):
let containsMathML ent = epub3 &&
@ -679,11 +679,11 @@ pandocToEPUB opts doc@(Pandoc meta _) = do
]
]
else []
let navData = renderHtml $ writeHtml
navData <- renderHtml <$> (lift $ writeHtml
opts'{ writerVariables = ("navpage","true"):vars }
(Pandoc (setMeta "title"
(walk removeNote $ fromList $ docTitle' meta) nullMeta)
(navBlocks ++ landmarks))
(navBlocks ++ landmarks)))
let navEntry = mkEntry "nav.xhtml" navData
-- mimetype

View file

@ -68,6 +68,7 @@ import Text.XML.Light (unode, elChildren, unqual)
import qualified Text.XML.Light as XML
import System.FilePath (takeExtension)
import Data.Aeson (Value)
import Text.Pandoc.Class (PandocMonad)
data WriterState = WriterState
{ stNotes :: [Html] -- ^ List of notes
@ -99,8 +100,8 @@ nl opts = if writerWrapText opts == WrapNone
else preEscapedString "\n"
-- | Convert Pandoc document to Html string.
writeHtmlString :: WriterOptions -> Pandoc -> String
writeHtmlString opts d =
writeHtmlString :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeHtmlString opts d = return $
let (body, context) = evalState (pandocToHtml opts d) defaultWriterState
in case writerTemplate opts of
Nothing -> renderHtml body
@ -108,8 +109,8 @@ writeHtmlString opts d =
defField "body" (renderHtml body) context
-- | Convert Pandoc document to Html structure.
writeHtml :: WriterOptions -> Pandoc -> Html
writeHtml opts d =
writeHtml :: PandocMonad m => WriterOptions -> Pandoc -> m Html
writeHtml opts d = return $
let (body, context) = evalState (pandocToHtml opts d) defaultWriterState
in case writerTemplate opts of
Nothing -> body

View file

@ -42,6 +42,7 @@ import Control.Monad.State
import Text.Pandoc.Readers.TeXMath (texMathToInlines)
import Network.URI (isURI)
import Data.Default
import Text.Pandoc.Class (PandocMonad)
type Notes = [[Block]]
data WriterState = WriterState { stNotes :: Notes }
@ -49,8 +50,8 @@ instance Default WriterState
where def = WriterState{ stNotes = [] }
-- | Convert Pandoc to Haddock.
writeHaddock :: WriterOptions -> Pandoc -> String
writeHaddock opts document =
writeHaddock :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeHaddock opts document = return $
evalState (pandocToHaddock opts{
writerWrapText = writerWrapText opts } document) def

View file

@ -54,6 +54,7 @@ import Text.Pandoc.Slides
import Text.Pandoc.Highlighting (highlight, styleToLaTeX,
formatLaTeXInline, formatLaTeXBlock,
toListingsLanguage)
import Text.Pandoc.Class (PandocMonad)
data WriterState =
WriterState { stInNote :: Bool -- true if we're in a note
@ -78,8 +79,8 @@ data WriterState =
}
-- | Convert Pandoc to LaTeX.
writeLaTeX :: WriterOptions -> Pandoc -> String
writeLaTeX options document =
writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeLaTeX options document = return $
evalState (pandocToLaTeX options document) $
WriterState { stInNote = False, stInQuote = False,
stInMinipage = False, stInHeading = False,

View file

@ -41,14 +41,15 @@ import Data.Maybe (fromMaybe)
import Text.Pandoc.Pretty
import Text.Pandoc.Builder (deleteMeta)
import Control.Monad.State
import Text.Pandoc.Class (PandocMonad)
type Notes = [[Block]]
data WriterState = WriterState { stNotes :: Notes
, stHasTables :: Bool }
-- | Convert Pandoc to Man.
writeMan :: WriterOptions -> Pandoc -> String
writeMan opts document = evalState (pandocToMan opts document) (WriterState [] False)
writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeMan opts document = return $ evalState (pandocToMan opts document) (WriterState [] False)
-- | Return groff man representation of document.
pandocToMan :: WriterOptions -> Pandoc -> State WriterState String

View file

@ -57,15 +57,16 @@ import qualified Data.Vector as V
import qualified Data.Text as T
import qualified Data.Set as Set
import Network.HTTP ( urlEncode )
import Text.Pandoc.Class (PandocMonad)
type Notes = [[Block]]
type Ref = ([Inline], Target, Attr)
type Refs = [Ref]
type MD = ReaderT WriterEnv (State WriterState)
type MD m = ReaderT WriterEnv (StateT WriterState m)
evalMD :: MD a -> WriterEnv -> WriterState -> a
evalMD md env st = evalState (runReaderT md env) st
evalMD :: PandocMonad m => MD m a -> WriterEnv -> WriterState -> m a
evalMD md env st = evalStateT (runReaderT md env) st
data WriterEnv = WriterEnv { envInList :: Bool
, envPlain :: Bool
@ -96,7 +97,7 @@ instance Default WriterState
}
-- | Convert Pandoc to Markdown.
writeMarkdown :: WriterOptions -> Pandoc -> String
writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeMarkdown opts document =
evalMD (pandocToMarkdown opts{
writerWrapText = if isEnabled Ext_hard_line_breaks opts
@ -106,7 +107,7 @@ writeMarkdown opts document =
-- | Convert Pandoc to plain text (like markdown, but without links,
-- pictures, or inline formatting).
writePlain :: WriterOptions -> Pandoc -> String
writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m String
writePlain opts document =
evalMD (pandocToMarkdown opts document) def{ envPlain = True } def
@ -171,7 +172,7 @@ jsonToYaml (Number n) = text $ show n
jsonToYaml _ = empty
-- | Return markdown representation of document.
pandocToMarkdown :: WriterOptions -> Pandoc -> MD String
pandocToMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> MD m String
pandocToMarkdown opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
@ -196,9 +197,9 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
| otherwise -> empty
Nothing -> empty
let headerBlocks = filter isHeaderBlock blocks
let toc = if writerTableOfContents opts
then tableOfContents opts headerBlocks
else empty
toc <- if writerTableOfContents opts
then lift $ lift $ tableOfContents opts headerBlocks
else return empty
-- Strip off final 'references' header if markdown citations enabled
let blocks' = if isEnabled Ext_citations opts
then case reverse blocks of
@ -221,13 +222,14 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
Just tpl -> return $ renderTemplate' tpl context
-- | Return markdown representation of reference key table.
refsToMarkdown :: WriterOptions -> Refs -> MD Doc
refsToMarkdown :: PandocMonad m => WriterOptions -> Refs -> MD m Doc
refsToMarkdown opts refs = mapM (keyToMarkdown opts) refs >>= return . vcat
-- | Return markdown representation of a reference key.
keyToMarkdown :: WriterOptions
keyToMarkdown :: PandocMonad m
=> WriterOptions
-> Ref
-> MD Doc
-> MD m Doc
keyToMarkdown opts (label, (src, tit), attr) = do
label' <- inlineListToMarkdown opts label
let tit' = if null tit
@ -238,7 +240,7 @@ keyToMarkdown opts (label, (src, tit), attr) = do
<> linkAttributes opts attr
-- | Return markdown representation of notes.
notesToMarkdown :: WriterOptions -> [[Block]] -> MD Doc
notesToMarkdown :: PandocMonad m => WriterOptions -> [[Block]] -> MD m Doc
notesToMarkdown opts notes = do
n <- gets stNoteNum
notes' <- mapM (\(num, note) -> noteToMarkdown opts num note) (zip [n..] notes)
@ -246,7 +248,7 @@ notesToMarkdown opts notes = do
return $ vsep notes'
-- | Return markdown representation of a note.
noteToMarkdown :: WriterOptions -> Int -> [Block] -> MD Doc
noteToMarkdown :: PandocMonad m => WriterOptions -> Int -> [Block] -> MD m Doc
noteToMarkdown opts num blocks = do
contents <- blockListToMarkdown opts blocks
let num' = text $ writerIdentifierPrefix opts ++ show num
@ -279,7 +281,7 @@ escapeString opts = escapeStringUsing markdownEscapes
"\\`*_[]#"
-- | Construct table of contents from list of header blocks.
tableOfContents :: WriterOptions -> [Block] -> Doc
tableOfContents :: PandocMonad m => WriterOptions -> [Block] -> m Doc
tableOfContents opts headers =
let opts' = opts { writerIgnoreNotes = True }
contents = BulletList $ map (elementToListItem opts) $ hierarchicalize headers
@ -334,7 +336,7 @@ beginsWithOrderedListMarker str =
Left _ -> False
Right _ -> True
notesAndRefs :: WriterOptions -> MD Doc
notesAndRefs :: PandocMonad m => WriterOptions -> MD m Doc
notesAndRefs opts = do
notes' <- reverse <$> gets stNotes >>= notesToMarkdown opts
modify $ \s -> s { stNotes = [] }
@ -352,9 +354,10 @@ notesAndRefs opts = do
endSpacing
-- | Convert Pandoc block element to markdown.
blockToMarkdown :: WriterOptions -- ^ Options
blockToMarkdown :: PandocMonad m
=> WriterOptions -- ^ Options
-> Block -- ^ Block element
-> MD Doc
-> MD m Doc
blockToMarkdown opts blk =
local (\env -> env {envBlockLevel = envBlockLevel env + 1}) $
do doc <- blockToMarkdown' opts blk
@ -363,9 +366,10 @@ blockToMarkdown opts blk =
then notesAndRefs opts >>= (\d -> return $ doc <> d)
else return doc
blockToMarkdown' :: WriterOptions -- ^ Options
-> Block -- ^ Block element
-> MD Doc
blockToMarkdown' :: PandocMonad m
=> WriterOptions -- ^ Options
-> Block -- ^ Block element
-> MD m Doc
blockToMarkdown' _ Null = return empty
blockToMarkdown' opts (Div attrs ils) = do
contents <- blockListToMarkdown opts ils
@ -526,8 +530,8 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do
gridTable opts (all null headers) aligns widths
rawHeaders rawRows
| isEnabled Ext_raw_html opts -> fmap (id,) $
return $ text $ writeHtmlString def
$ Pandoc nullMeta [t]
text <$>
(lift $ lift $ writeHtmlString def $ Pandoc nullMeta [t])
| otherwise -> return $ (id, text "[TABLE]")
return $ nst $ tbl $$ blankline $$ caption'' $$ blankline
blockToMarkdown' opts (BulletList items) = do
@ -550,7 +554,7 @@ blockToMarkdown' opts (DefinitionList items) = do
contents <- inList $ mapM (definitionListItemToMarkdown opts) items
return $ cat contents <> blankline
inList :: MD a -> MD a
inList :: Monad m => MD m a -> MD m a
inList p = local (\env -> env {envInList = True}) p
addMarkdownAttribute :: String -> String
@ -562,7 +566,7 @@ addMarkdownAttribute s =
x /= "markdown"]
_ -> s
pipeTable :: Bool -> [Alignment] -> [Doc] -> [[Doc]] -> MD Doc
pipeTable :: PandocMonad m => Bool -> [Alignment] -> [Doc] -> [[Doc]] -> MD m Doc
pipeTable headless aligns rawHeaders rawRows = do
let sp = text " "
let blockFor AlignLeft x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
@ -590,8 +594,8 @@ pipeTable headless aligns rawHeaders rawRows = do
let body = vcat $ map torow rawRows
return $ header $$ border $$ body
pandocTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
-> [Doc] -> [[Doc]] -> MD Doc
pandocTable :: PandocMonad m => WriterOptions -> Bool -> [Alignment] -> [Double]
-> [Doc] -> [[Doc]] -> MD m Doc
pandocTable opts headless aligns widths rawHeaders rawRows = do
let isSimple = all (==0) widths
let alignHeader alignment = case alignment of
@ -642,8 +646,8 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
else border
return $ head'' $$ underline $$ body $$ bottom
gridTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
-> [Doc] -> [[Doc]] -> MD Doc
gridTable :: PandocMonad m => WriterOptions -> Bool -> [Alignment] -> [Double]
-> [Doc] -> [[Doc]] -> MD m Doc
gridTable opts headless aligns widths headers' rawRows = do
let numcols = length headers'
let widths' = if all (==0) widths
@ -697,7 +701,7 @@ itemEndsWithTightList bs =
_ -> False
-- | Convert bullet list item (list of blocks) to markdown.
bulletListItemToMarkdown :: WriterOptions -> [Block] -> MD Doc
bulletListItemToMarkdown :: PandocMonad m => WriterOptions -> [Block] -> MD m Doc
bulletListItemToMarkdown opts bs = do
contents <- blockListToMarkdown opts bs
let sps = replicate (writerTabStop opts - 2) ' '
@ -709,10 +713,11 @@ bulletListItemToMarkdown opts bs = do
return $ hang (writerTabStop opts) start $ contents' <> cr
-- | Convert ordered list item (a list of blocks) to markdown.
orderedListItemToMarkdown :: WriterOptions -- ^ options
orderedListItemToMarkdown :: PandocMonad m
=> WriterOptions -- ^ options
-> String -- ^ list item marker
-> [Block] -- ^ list item (list of blocks)
-> MD Doc
-> MD m Doc
orderedListItemToMarkdown opts marker bs = do
contents <- blockListToMarkdown opts bs
let sps = case length marker - writerTabStop opts of
@ -726,9 +731,10 @@ orderedListItemToMarkdown opts marker bs = do
return $ hang (writerTabStop opts) start $ contents' <> cr
-- | Convert definition list item (label, list of blocks) to markdown.
definitionListItemToMarkdown :: WriterOptions
definitionListItemToMarkdown :: PandocMonad m
=> WriterOptions
-> ([Inline],[[Block]])
-> MD Doc
-> MD m Doc
definitionListItemToMarkdown opts (label, defs) = do
labelText <- inlineListToMarkdown opts label
defs' <- mapM (mapM (blockToMarkdown opts)) defs
@ -758,9 +764,10 @@ definitionListItemToMarkdown opts (label, defs) = do
vsep (map vsep defs') <> blankline
-- | Convert list of Pandoc block elements to markdown.
blockListToMarkdown :: WriterOptions -- ^ Options
blockListToMarkdown :: PandocMonad m
=> WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
-> MD Doc
-> MD m Doc
blockListToMarkdown opts blocks =
mapM (blockToMarkdown opts) (fixBlocks blocks) >>= return . cat
-- insert comment between list and indented code block, or the
@ -787,7 +794,7 @@ blockListToMarkdown opts blocks =
-- | Get reference for target; if none exists, create unique one and return.
-- Prefer label if possible; otherwise, generate a unique key.
getReference :: Attr -> [Inline] -> Target -> MD [Inline]
getReference :: PandocMonad m => Attr -> [Inline] -> Target -> MD m [Inline]
getReference attr label target = do
st <- get
case find (\(_,t,a) -> t == target && a == attr) (stRefs st) of
@ -805,7 +812,7 @@ getReference attr label target = do
return label'
-- | Convert list of Pandoc inline elements to markdown.
inlineListToMarkdown :: WriterOptions -> [Inline] -> MD Doc
inlineListToMarkdown :: PandocMonad m => WriterOptions -> [Inline] -> MD m Doc
inlineListToMarkdown opts lst = do
inlist <- asks envInList
go (if inlist then avoidBadWrapsInList lst else lst)
@ -866,7 +873,7 @@ isRight (Right _) = True
isRight (Left _) = False
-- | Convert Pandoc inline element to markdown.
inlineToMarkdown :: WriterOptions -> Inline -> MD Doc
inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m Doc
inlineToMarkdown opts (Span attrs ils) = do
plain <- asks envPlain
contents <- inlineListToMarkdown opts ils
@ -1053,7 +1060,7 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
return $ text $ trim $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]]
(text . trim) <$> (lift $ lift $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]])
| otherwise = do
plain <- asks envPlain
linktext <- inlineListToMarkdown opts txt
@ -1092,7 +1099,7 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
return $ text $ trim $ writeHtmlString def $ Pandoc nullMeta [Plain [img]]
(text . trim) <$> (lift $ lift $ writeHtmlString def $ Pandoc nullMeta [Plain [img]])
| otherwise = do
plain <- asks envPlain
let txt = if null alternate || alternate == [Str source]

View file

@ -42,6 +42,7 @@ import Data.List ( intersect, intercalate )
import Network.URI ( isURI )
import Control.Monad.Reader
import Control.Monad.State
import Text.Pandoc.Class (PandocMonad)
data WriterState = WriterState {
stNotes :: Bool -- True if there are notes
@ -57,8 +58,8 @@ data WriterReader = WriterReader {
type MediaWikiWriter = ReaderT WriterReader (State WriterState)
-- | Convert Pandoc to MediaWiki.
writeMediaWiki :: WriterOptions -> Pandoc -> String
writeMediaWiki opts document =
writeMediaWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeMediaWiki opts document = return $
let initialState = WriterState { stNotes = False, stOptions = opts }
env = WriterReader { options = opts, listLevel = [], useTags = False }
in evalState (runReaderT (pandocToMediaWiki document) env) initialState

View file

@ -34,6 +34,7 @@ import Text.Pandoc.Options ( WriterOptions(..), WrapOption(..) )
import Data.List ( intersperse )
import Text.Pandoc.Definition
import Text.Pandoc.Pretty
import Text.Pandoc.Class (PandocMonad)
prettyList :: [Doc] -> Doc
prettyList ds =
@ -66,8 +67,8 @@ prettyBlock (Div attr blocks) =
prettyBlock block = text $ show block
-- | Prettyprint Pandoc document.
writeNative :: WriterOptions -> Pandoc -> String
writeNative opts (Pandoc meta blocks) =
writeNative :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeNative opts (Pandoc meta blocks) = return $
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing

View file

@ -83,7 +83,7 @@ pandocToODT opts doc@(Pandoc meta _) = do
-- handle formulas and pictures
-- picEntriesRef <- P.newIORef ([] :: [Entry])
doc' <- walkM (transformPicMath opts) $ walk fixDisplayMath doc
let newContents = writeOpenDocument opts{writerWrapText = WrapNone} doc'
newContents <- lift $ writeOpenDocument opts{writerWrapText = WrapNone} doc'
epochtime <- floor `fmap` (lift P.getPOSIXTime)
let contentEntry = toEntry "content.xml" epochtime
$ fromStringLazy newContents

View file

@ -40,29 +40,30 @@ import Text.Pandoc.Writers.Markdown (writeMarkdown)
import Text.Pandoc.Pretty
import Text.Pandoc.Compat.Time
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
-- | Convert Pandoc document to string in OPML format.
writeOPML :: WriterOptions -> Pandoc -> String
writeOPML opts (Pandoc meta blocks) =
writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeOPML opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
meta' = B.setMeta "date" (B.str $ convertDate $ docDate meta) meta
Just metadata = metaToJSON opts
(Just . writeMarkdown def . Pandoc nullMeta)
(Just . trimr . writeMarkdown def . Pandoc nullMeta .
(\ils -> [Plain ils]))
meta'
main = render colwidth $ vcat (map (elementToOPML opts) elements)
context = defField "body" main metadata
in case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate' tpl context
metadata <- metaToJSON opts
(writeMarkdown def . Pandoc nullMeta)
(\ils -> trimr <$> (writeMarkdown def $ Pandoc nullMeta [Plain ils]))
meta'
main <- (render colwidth . vcat) <$> (mapM (elementToOPML opts) elements)
let context = defField "body" main metadata
return $ case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate' tpl context
writeHtmlInlines :: [Inline] -> String
writeHtmlInlines ils = trim $ writeHtmlString def
$ Pandoc nullMeta [Plain ils]
writeHtmlInlines :: PandocMonad m => [Inline] -> m String
writeHtmlInlines ils =
trim <$> (writeHtmlString def $ Pandoc nullMeta [Plain ils])
-- date format: RFC 822: Thu, 14 Jul 2005 23:41:05 GMT
showDateTimeRFC822 :: UTCTime -> String
@ -78,17 +79,18 @@ convertDate ils = maybe "" showDateTimeRFC822 $
defaultTimeLocale "%F" =<< (normalizeDate $ stringify ils)
-- | Convert an Element to OPML.
elementToOPML :: WriterOptions -> Element -> Doc
elementToOPML _ (Blk _) = empty
elementToOPML opts (Sec _ _num _ title elements) =
elementToOPML :: PandocMonad m => WriterOptions -> Element -> m Doc
elementToOPML _ (Blk _) = return empty
elementToOPML opts (Sec _ _num _ title elements) = do
let isBlk (Blk _) = True
isBlk _ = False
fromBlk (Blk x) = x
fromBlk _ = error "fromBlk called on non-block"
(blocks, rest) = span isBlk elements
attrs = [("text", writeHtmlInlines title)] ++
[("_note", writeMarkdown def (Pandoc nullMeta
(map fromBlk blocks)))
| not (null blocks)]
in inTags True "outline" attrs $
vcat (map (elementToOPML opts) rest)
htmlIls <- writeHtmlInlines title
md <- if null blocks
then return []
else writeMarkdown def $ Pandoc nullMeta $ map fromBlk blocks
let attrs = [("text", htmlIls)] ++ [("_note", md)]
o <- mapM (elementToOPML opts) rest
return $ inTags True "outline" attrs $ vcat o

View file

@ -47,6 +47,7 @@ import qualified Data.Map as Map
import Text.Pandoc.Writers.Shared
import Data.List (sortBy)
import Data.Ord (comparing)
import Text.Pandoc.Class (PandocMonad)
-- | Auxiliary function to convert Plain block to Para.
plainToPara :: Block -> Block
@ -190,8 +191,8 @@ handleSpaces s
rm [] = empty
-- | Convert Pandoc document to string in OpenDocument format.
writeOpenDocument :: WriterOptions -> Pandoc -> String
writeOpenDocument opts (Pandoc meta blocks) =
writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeOpenDocument opts (Pandoc meta blocks) = return $
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing

View file

@ -42,6 +42,7 @@ import Text.Pandoc.Templates (renderTemplate')
import Data.Char ( isAlphaNum, toLower )
import Data.List ( isPrefixOf, intersect, intersperse, partition, transpose )
import Control.Monad.State
import Text.Pandoc.Class (PandocMonad)
data WriterState =
WriterState { stNotes :: [[Block]]
@ -52,8 +53,8 @@ data WriterState =
}
-- | Convert Pandoc to Org.
writeOrg :: WriterOptions -> Pandoc -> String
writeOrg opts document =
writeOrg :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeOrg opts document = return $
let st = WriterState { stNotes = [], stLinks = False,
stImages = False, stHasMath = False,
stOptions = opts }

View file

@ -44,6 +44,7 @@ import Network.URI (isURI)
import Text.Pandoc.Pretty
import Control.Monad.State
import Data.Char (isSpace, toLower)
import Text.Pandoc.Class (PandocMonad)
type Refs = [([Inline], Target)]
@ -58,8 +59,8 @@ data WriterState =
}
-- | Convert Pandoc to RST.
writeRST :: WriterOptions -> Pandoc -> String
writeRST opts document =
writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeRST opts document = return $
let st = WriterState { stNotes = [], stLinks = [],
stImages = [], stHasMath = False,
stHasRawTeX = False, stOptions = opts,

View file

@ -41,6 +41,7 @@ import Text.Pandoc.Highlighting ( languages, languagesByExtension )
import Text.Pandoc.Pretty
import Text.Pandoc.ImageSize
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class ( PandocMonad )
-- | Convert list of authors to a docbook <author> section
authorToTEI :: WriterOptions -> [Inline] -> B.Inlines
@ -53,8 +54,8 @@ authorToTEI opts name' =
inTagsSimple "author" (text $ escapeStringForXML name)
-- | Convert Pandoc document to string in Docbook format.
writeTEI :: WriterOptions -> Pandoc -> String
writeTEI opts (Pandoc meta blocks) =
writeTEI :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeTEI opts (Pandoc meta blocks) = return $
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts

View file

@ -44,6 +44,7 @@ import Text.Pandoc.ImageSize
import Network.URI ( isURI, unEscapeString )
import System.FilePath
import qualified Data.Set as Set
import Text.Pandoc.Class ( PandocMonad )
data WriterState =
WriterState { stStrikeout :: Bool -- document contains strikeout
@ -60,8 +61,8 @@ data WriterState =
-}
-- | Convert Pandoc to Texinfo.
writeTexinfo :: WriterOptions -> Pandoc -> String
writeTexinfo options document =
writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeTexinfo options document = return $
evalState (pandocToTexinfo options $ wrapTop document) $
WriterState { stStrikeout = False, stSuperscript = False,
stEscapeComma = False, stSubscript = False,

View file

@ -41,6 +41,7 @@ import Text.Pandoc.XML ( escapeStringForXML )
import Data.List ( intercalate )
import Control.Monad.State
import Data.Char ( isSpace )
import Text.Pandoc.Class ( PandocMonad )
data WriterState = WriterState {
stNotes :: [String] -- Footnotes
@ -50,8 +51,8 @@ data WriterState = WriterState {
}
-- | Convert Pandoc to Textile.
writeTextile :: WriterOptions -> Pandoc -> String
writeTextile opts document =
writeTextile :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeTextile opts document = return $
evalState (pandocToTextile opts document)
WriterState { stNotes = [], stListLevel = [], stStartNum = Nothing,
stUseTags = False }

View file

@ -45,6 +45,7 @@ import Network.URI ( isURI )
import Control.Monad ( zipWithM )
import Control.Monad.State ( modify, State, get, evalState )
--import Control.Monad.Reader ( ReaderT, runReaderT, ask, local )
import Text.Pandoc.Class ( PandocMonad )
data WriterState = WriterState {
stItemNum :: Int,
@ -55,8 +56,8 @@ instance Default WriterState where
def = WriterState { stItemNum = 1, stIndent = "" }
-- | Convert Pandoc to ZimWiki.
writeZimWiki :: WriterOptions -> Pandoc -> String
writeZimWiki opts document = evalState (pandocToZimWiki opts document) (WriterState 1 "")
writeZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
writeZimWiki opts document = return $ evalState (pandocToZimWiki opts document) (WriterState 1 "")
-- | Return ZimWiki representation of document.
pandocToZimWiki :: WriterOptions -> Pandoc -> State WriterState String