From 30b3412857fc604656aac53d57730ad2442a3599 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 11 Nov 2016 13:07:50 +0100 Subject: Added page breaks into Pandoc. This requires an updated version of pandoc-types that introduces PageBreak definition. Not that this initial commit only introduces ODT pagebreaks and distinguishes for it page breaks before, after, or both, the paragraph, as read from the style definition. --- src/Text/Pandoc/Writers/OpenDocument.hs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 8f0e037c5..444a09587 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -36,6 +36,7 @@ import Text.Pandoc.XML import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Readers.Odt.StyleReader import Text.Pandoc.Pretty import Text.Printf ( printf ) import Control.Arrow ( (***), (>>>) ) @@ -307,9 +308,7 @@ blockToOpenDocument o bs else inParagraphTags =<< inlinesToOpenDocument o b | Para [Image attr c (s,'f':'i':'g':':':t)] <- bs = figure attr c s t - | Para b <- bs = if null b - then return empty - else inParagraphTags =<< inlinesToOpenDocument o b + | Para b <- bs = paragraph b | LineBlock b <- bs = blockToOpenDocument o $ linesToPara b | Div _ xs <- bs = blocksToOpenDocument o xs | Header i _ b <- bs = setFirstPara >> @@ -370,6 +369,22 @@ blockToOpenDocument o bs captionDoc <- withParagraphStyle o "FigureCaption" [Para caption] return $ imageDoc $$ captionDoc + endsWithPageBreak [] = False + endsWithPageBreak [PageBreak] = True + endsWithPageBreak (_ : xs) = endsWithPageBreak xs + + paragraph :: [Inline] -> State WriterState Doc + paragraph [] = return empty + paragraph (PageBreak : rest) | endsWithPageBreak rest = paraWithBreak PageBoth rest + paragraph (PageBreak : rest) = paraWithBreak PageBefore rest + paragraph inlines | endsWithPageBreak inlines = paraWithBreak PageAfter inlines + paragraph inlines = inParagraphTags =<< inlinesToOpenDocument o inlines + + paraWithBreak :: ParaBreak -> [Inline] -> State WriterState Doc + paraWithBreak breakKind bs = do + pn <- paraBreakStyle breakKind + withParagraphStyle o ("P" ++ show pn) [Para bs] + colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc colHeadsToOpenDocument o tn ns hs = inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$> @@ -562,6 +577,13 @@ paraStyle attrs = do addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) paraProps return pn +paraBreakStyle :: ParaBreak -> State WriterState Int +paraBreakStyle PageBefore = paraStyle "Text_20_body" [("fo:break-before", "page")] +paraBreakStyle PageAfter = paraStyle "Text_20_body" [("fo:break-after", "page")] +paraBreakStyle PageBoth = paraStyle "Text_20_body" [("fo:break-before", "page"), ("fo:break-after", "page")] +paraBreakStyle AutoNone = paraStyle "Text_20_body" [] + + paraListStyle :: Int -> State WriterState Int paraListStyle l = paraStyle [("style:parent-style-name","Text_20_body") -- cgit v1.2.3 From a6b469c02b3c21cfc1b5169ea3e75b7388f55691 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 11 Nov 2016 13:09:49 +0100 Subject: Adds support for pagebreaks (when it makes sense) Update all writers to take into account page breaks. A straightforwad, far from complete, implementation of page breaks in selected writers. Readers will have to follow in the future as well. --- src/Text/Pandoc/Writers/AsciiDoc.hs | 3 ++- src/Text/Pandoc/Writers/CommonMark.hs | 1 + src/Text/Pandoc/Writers/ConTeXt.hs | 1 + src/Text/Pandoc/Writers/Custom.hs | 2 ++ src/Text/Pandoc/Writers/Docbook.hs | 3 +++ src/Text/Pandoc/Writers/Docx.hs | 9 ++++++++- src/Text/Pandoc/Writers/DokuWiki.hs | 4 +++- src/Text/Pandoc/Writers/FB2.hs | 2 ++ src/Text/Pandoc/Writers/HTML.hs | 1 + src/Text/Pandoc/Writers/Haddock.hs | 3 ++- src/Text/Pandoc/Writers/ICML.hs | 1 + src/Text/Pandoc/Writers/LaTeX.hs | 1 + src/Text/Pandoc/Writers/Man.hs | 3 ++- src/Text/Pandoc/Writers/Markdown.hs | 3 ++- src/Text/Pandoc/Writers/MediaWiki.hs | 4 +++- src/Text/Pandoc/Writers/Org.hs | 3 ++- src/Text/Pandoc/Writers/RST.hs | 1 + src/Text/Pandoc/Writers/RTF.hs | 3 ++- src/Text/Pandoc/Writers/TEI.hs | 1 + src/Text/Pandoc/Writers/Texinfo.hs | 2 ++ src/Text/Pandoc/Writers/Textile.hs | 4 +++- src/Text/Pandoc/Writers/ZimWiki.hs | 4 +++- 22 files changed, 48 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs index e9d3dccf1..88fab171f 100644 --- a/src/Text/Pandoc/Writers/AsciiDoc.hs +++ b/src/Text/Pandoc/Writers/AsciiDoc.hs @@ -411,7 +411,8 @@ inlineToAsciiDoc _ (Math DisplayMath str) = inlineToAsciiDoc _ (RawInline f s) | f == "asciidoc" = return $ text s | otherwise = return empty -inlineToAsciiDoc _ (LineBreak) = return $ " +" <> cr +inlineToAsciiDoc _ LineBreak = return $ " +" <> cr +inlineToAsciiDoc _ PageBreak = return empty inlineToAsciiDoc _ Space = return space inlineToAsciiDoc opts SoftBreak = case writerWrapText opts of diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index 88a92eb47..e0591de83 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -139,6 +139,7 @@ inlineToNodes :: Inline -> [Node] -> [Node] inlineToNodes (Str s) = (node (TEXT (T.pack s)) [] :) inlineToNodes Space = (node (TEXT (T.pack " ")) [] :) inlineToNodes LineBreak = (node LINEBREAK [] :) +inlineToNodes PageBreak = id inlineToNodes SoftBreak = (node SOFTBREAK [] :) inlineToNodes (Emph xs) = (node EMPH (inlinesToNodes xs) :) inlineToNodes (Strong xs) = (node STRONG (inlinesToNodes xs) :) diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index c663c75ce..ee2cc3f34 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -346,6 +346,7 @@ inlineToConTeXt SoftBreak = do WrapAuto -> space WrapNone -> space WrapPreserve -> cr +inlineToConTeXt PageBreak = return empty inlineToConTeXt Space = return space -- Handle HTML-like internal document references to sections inlineToConTeXt (Link _ txt (('#' : ref), _)) = do diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index cf641dcd6..371dd21c3 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -310,6 +310,8 @@ inlineToCustom lua (RawInline format str) = inlineToCustom lua (LineBreak) = callfunc lua "LineBreak" +inlineToCustom lua (PageBreak) = callfunc lua "PageBreak" + inlineToCustom lua (Link attr txt (src,tit)) = callfunc lua "Link" txt src tit (attrToMap attr) diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index 44f96d700..5c03d449d 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -356,6 +356,9 @@ inlineToDocbook opts (Math t str) inlineToDocbook _ (RawInline f x) | f == "html" || f == "docbook" = text x | otherwise = empty inlineToDocbook _ LineBreak = text "\n" +-- currently ignore, would require the option to add custom +-- styles to the document +inlineToDocbook _ PageBreak = empty inlineToDocbook _ Space = space -- because we use \n for LineBreak, we can't do soft breaks: inlineToDocbook _ SoftBreak = space diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 3fc5d22a2..d425bbbca 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1100,6 +1100,7 @@ inlineToOpenXML' opts (Strikeout lst) = withTextProp (mknode "w:strike" [] ()) $ inlinesToOpenXML opts lst inlineToOpenXML' _ LineBreak = return [br] +inlineToOpenXML' _ PageBreak = return [pageBreak] inlineToOpenXML' _ (RawInline f str) | f == Format "openxml" = return [ x | Elem x <- parseXML str ] | otherwise = return [] @@ -1247,7 +1248,13 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do return [imgElt] br :: Element -br = mknode "w:r" [] [mknode "w:br" [("w:type","textWrapping")] () ] +br = breakElement "textWrapping" + +pageBreak :: Element +pageBreak = breakElement "page" + +breakElement :: String -> Element +breakElement kind = mknode "w:r" [] [mknode "w:br" [("w:type",kind)] () ] -- Word will insert these footnotes into the settings.xml file -- (whether or not they're visible in the document). If they're in the diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs index 7459f1b42..c90dc9078 100644 --- a/src/Text/Pandoc/Writers/DokuWiki.hs +++ b/src/Text/Pandoc/Writers/DokuWiki.hs @@ -465,7 +465,9 @@ inlineToDokuWiki _ (RawInline f str) | f == Format "html" = return $ "" ++ str ++ "" | otherwise = return "" -inlineToDokuWiki _ (LineBreak) = return "\\\\\n" +inlineToDokuWiki _ LineBreak = return "\\\\\n" + +inlineToDokuWiki _ PageBreak = return mempty inlineToDokuWiki opts SoftBreak = case writerWrapText opts of diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 5538ca061..8c4817ac6 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -443,6 +443,7 @@ toXml (Code _ s) = return [el "code" s] toXml Space = return [txt " "] toXml SoftBreak = return [txt " "] toXml LineBreak = return [el "empty-line" ()] +toXml PageBreak = return [] toXml (Math _ formula) = insertMath InlineImage formula toXml (RawInline _ _) = return [] -- raw TeX and raw HTML are suppressed toXml (Link _ text (url,ttl)) = do @@ -574,6 +575,7 @@ plain (Code _ s) = s plain Space = " " plain SoftBreak = " " plain LineBreak = "\n" +plain PageBreak = "\n" plain (Math _ s) = s plain (RawInline _ s) = s plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"]) diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 3c8c264d2..e0b0234fb 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -705,6 +705,7 @@ inlineToHtml opts inline = WrapPreserve -> preEscapedString "\n" (LineBreak) -> return $ (if writerHtml5 opts then H5.br else H.br) <> strToHtml "\n" + (PageBreak) -> return mempty (Span (id',classes,kvs) ils) -> inlineListToHtml opts ils >>= return . addAttrs opts attr' . H.span diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 29fdafe15..4e93cc4e4 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -326,7 +326,8 @@ inlineToHaddock _ (RawInline f str) | f == "haddock" = return $ text str | otherwise = return empty -- no line break in haddock (see above on CodeBlock) -inlineToHaddock _ (LineBreak) = return cr +inlineToHaddock _ LineBreak = return cr +inlineToHaddock _ PageBreak = return empty inlineToHaddock opts SoftBreak = case writerWrapText opts of WrapAuto -> return space diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 8f0d21cf5..e2c123fc2 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -432,6 +432,7 @@ inlineToICML opts style SoftBreak = WrapNone -> charStyle style space WrapPreserve -> charStyle style cr inlineToICML _ style LineBreak = charStyle style $ text lineSeparator +inlineToICML _ _ PageBreak = return empty inlineToICML opts style (Math mt str) = cat <$> mapM (inlineToICML opts style) (texMathToInlines mt str) inlineToICML _ _ (RawInline f str) diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 88934eb44..50e99fe15 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -960,6 +960,7 @@ inlineToLaTeX SoftBreak = do WrapAuto -> return space WrapNone -> return space WrapPreserve -> return cr +inlineToLaTeX PageBreak = return $ "\\clearpage{}" inlineToLaTeX Space = return space inlineToLaTeX (Link _ txt ('#':ident, _)) = do contents <- inlineListToLaTeX txt diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index 98b08b08b..304995ec8 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -342,8 +342,9 @@ inlineToMan opts (Math DisplayMath str) = do inlineToMan _ (RawInline f str) | f == Format "man" = return $ text str | otherwise = return empty -inlineToMan _ (LineBreak) = return $ +inlineToMan _ LineBreak = return $ cr <> text ".PD 0" $$ text ".P" $$ text ".PD" <> cr +inlineToMan _ PageBreak = return empty inlineToMan _ SoftBreak = return space inlineToMan _ Space = return space inlineToMan opts (Link _ txt (src, _)) = do diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index e3bb3eea0..f9c7c326e 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -345,7 +345,7 @@ notesAndRefs opts = do if | writerReferenceLocation opts == EndOfDocument -> empty | isEmpty notes' && isEmpty refs' -> empty | otherwise -> blankline - + return $ (if isEmpty notes' then empty else blankline <> notes') <> (if isEmpty refs' then empty else blankline <> refs') <> @@ -1018,6 +1018,7 @@ inlineToMarkdown opts SoftBreak = do WrapNone -> space' WrapAuto -> space' WrapPreserve -> cr +inlineToMarkdown _ PageBreak = return empty inlineToMarkdown opts (Cite [] lst) = inlineListToMarkdown opts lst inlineToMarkdown opts (Cite (c:cs) lst) | not (isEnabled Ext_citations opts) = inlineListToMarkdown opts lst diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs index 78d4651e7..95b649dd2 100644 --- a/src/Text/Pandoc/Writers/MediaWiki.hs +++ b/src/Text/Pandoc/Writers/MediaWiki.hs @@ -402,7 +402,9 @@ inlineToMediaWiki (RawInline f str) | f == Format "html" = return str | otherwise = return "" -inlineToMediaWiki (LineBreak) = return "
\n" +inlineToMediaWiki LineBreak = return "
\n" + +inlineToMediaWiki PageBreak = return mempty inlineToMediaWiki SoftBreak = do wrapText <- gets (writerWrapText . stOptions) diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs index 4302459cc..330f24b0b 100644 --- a/src/Text/Pandoc/Writers/Org.hs +++ b/src/Text/Pandoc/Writers/Org.hs @@ -349,7 +349,8 @@ inlineToOrg (RawInline f@(Format f') str) = return $ if isRawFormat f then text str else "@@" <> text f' <> ":" <> text str <> "@@" -inlineToOrg (LineBreak) = return (text "\\\\" <> cr) +inlineToOrg LineBreak = return (text "\\\\" <> cr) +inlineToOrg PageBreak = return empty inlineToOrg Space = return space inlineToOrg SoftBreak = do wrapText <- gets (writerWrapText . stOptions) diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 064434483..c170889cc 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -461,6 +461,7 @@ inlineToRST SoftBreak = do WrapPreserve -> return cr WrapAuto -> return space WrapNone -> return space +inlineToRST PageBreak = return $ ".. pagebreak::" -- autolink inlineToRST (Link _ [Str str] (src, _)) | isURI src && diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 8f942b4d0..6ca749a10 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -350,8 +350,9 @@ inlineToRTF (Cite _ lst) = inlineListToRTF lst inlineToRTF (RawInline f str) | f == Format "rtf" = str | otherwise = "" -inlineToRTF (LineBreak) = "\\line " +inlineToRTF LineBreak = "\\line " inlineToRTF SoftBreak = " " +inlineToRTF PageBreak = "\\page " inlineToRTF Space = " " inlineToRTF (Link _ text (src, _)) = "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++ diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs index 9bd23ac3b..27a2819a0 100644 --- a/src/Text/Pandoc/Writers/TEI.hs +++ b/src/Text/Pandoc/Writers/TEI.hs @@ -284,6 +284,7 @@ inlineToTEI _ (Math t str) = inlineToTEI _ (RawInline f x) | f == "tei" = text x | otherwise = empty inlineToTEI _ LineBreak = selfClosingTag "lb" [] +inlineToTEI _ PageBreak = selfClosingTag "pb" [] inlineToTEI _ Space = space -- because we use \n for LineBreak, we can't do soft breaks: inlineToTEI _ SoftBreak = space diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index f2b9aa15f..993e6fbfd 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -437,6 +437,8 @@ inlineToTexinfo SoftBreak = do WrapPreserve -> return cr inlineToTexinfo Space = return space +inlineToTexinfo PageBreak = return $ text "@page" + inlineToTexinfo (Link _ txt (src@('#':_), _)) = do contents <- escapeCommas $ inlineListToTexinfo txt return $ text "@ref" <> diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs index f73876fd2..4283e29cc 100644 --- a/src/Text/Pandoc/Writers/Textile.hs +++ b/src/Text/Pandoc/Writers/Textile.hs @@ -435,7 +435,9 @@ inlineToTextile opts (RawInline f str) isEnabled Ext_raw_tex opts = return str | otherwise = return "" -inlineToTextile _ (LineBreak) = return "\n" +inlineToTextile _ LineBreak = return "\n" + +inlineToTextile _ PageBreak = return mempty inlineToTextile _ SoftBreak = return " " diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs index 423928c8a..56a5d5455 100644 --- a/src/Text/Pandoc/Writers/ZimWiki.hs +++ b/src/Text/Pandoc/Writers/ZimWiki.hs @@ -317,7 +317,9 @@ inlineToZimWiki opts (RawInline f str) | f == Format "html" = do cont <- indentFromHTML opts str; return cont | otherwise = return "" -inlineToZimWiki _ (LineBreak) = return "\n" -- was \\\\ +inlineToZimWiki _ LineBreak = return "\n" -- was \\\\ + +inlineToZimWiki _ PageBreak = return mempty inlineToZimWiki opts SoftBreak = case writerWrapText opts of -- cgit v1.2.3 From 32c68dada92eb142949c5be5224a3ddf20fcf484 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 24 Sep 2016 17:52:25 -0400 Subject: Introduce pure versions of IO Writers. Using Text.Pandoc.Free, introduce pure versions of Docx, EPUB, ICML, and ODT writers. Each of the pure versions is exported along with the IO version (produced by running `runIO` on the pure reader). Ideally, this should make the writers easier to test. --- src/Text/Pandoc/Writers/Docx.hs | 66 +++++++++++++++++++-------------- src/Text/Pandoc/Writers/EPUB.hs | 81 ++++++++++++++++++++++------------------- src/Text/Pandoc/Writers/ICML.hs | 19 +++++++--- src/Text/Pandoc/Writers/ODT.hs | 48 ++++++++++++++---------- 4 files changed, 124 insertions(+), 90 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index d425bbbca..cecee7e9e 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE ScopedTypeVariables, PatternGuards, ViewPatterns #-} +{-# LANGUAGE ScopedTypeVariables, PatternGuards, ViewPatterns, DeriveFunctor #-} {- Copyright (C) 2012-2015 John MacFarlane @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to docx. -} -module Text.Pandoc.Writers.Docx ( writeDocx ) where +module Text.Pandoc.Writers.Docx ( writeDocx, writeDocxPure ) where import Data.List ( intercalate, isPrefixOf, isSuffixOf ) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL @@ -38,7 +38,6 @@ import qualified Data.Set as Set import qualified Text.Pandoc.UTF8 as UTF8 import Codec.Archive.Zip import Data.Time.Clock.POSIX -import System.Environment import Text.Pandoc.Compat.Time import Text.Pandoc.Definition import Text.Pandoc.Generic @@ -57,7 +56,7 @@ import Control.Monad.Reader import Control.Monad.State import Skylighting import Data.Unique (hashUnique, newUnique) -import System.Random (randomRIO) +import System.Random (randomR) import Text.Printf (printf) import qualified Control.Exception as E import Data.Monoid ((<>)) @@ -67,6 +66,10 @@ import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef, import Control.Applicative ((<|>)) import Data.Maybe (fromMaybe, mapMaybe, maybeToList, isNothing) import Data.Char (ord, isSpace, toLower) +import Text.Pandoc.Free (PandocAction, runIO) +import qualified Text.Pandoc.Free as P + +type DocxAction = PandocAction () data ListMarker = NoMarker | BulletMarker @@ -146,7 +149,7 @@ defaultWriterState = WriterState{ , stDynamicTextProps = [] } -type WS = ReaderT WriterEnv (StateT WriterState IO) +type WS = ReaderT WriterEnv (StateT WriterState (DocxAction)) mknode :: Node t => String -> [(String,String)] -> t -> Element mknode s attrs = @@ -213,19 +216,27 @@ metaValueToInlines (MetaBlocks bs) = query return bs metaValueToInlines (MetaBool b) = [Str $ show b] metaValueToInlines _ = [] --- | Produce an Docx file from a Pandoc document. + + writeDocx :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert -> IO BL.ByteString -writeDocx opts doc@(Pandoc meta _) = do +writeDocx opts doc = runIO $ writeDocxPure opts doc + + +-- | Produce an Docx file from a Pandoc document. +writeDocxPure :: WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> DocxAction BL.ByteString +writeDocxPure opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let doc' = walk fixDisplayMath $ doc - username <- lookup "USERNAME" <$> getEnvironment - utctime <- getCurrentTime - distArchive <- getDefaultReferenceDocx datadir + username <- P.lookupEnv "USERNAME" + utctime <- P.getCurrentTime + distArchive <- P.getDefaultReferenceDocx datadir refArchive <- case writerReferenceDocx opts of - Just f -> liftM (toArchive . toLazy) $ B.readFile f - Nothing -> getDefaultReferenceDocx datadir + Just f -> liftM (toArchive . toLazy) $ P.readFileStrict f + Nothing -> P.getDefaultReferenceDocx datadir parsedDoc <- parseXml refArchive distArchive "word/document.xml" let wname f qn = qPrefix qn == Just "w" && f (qName qn) @@ -603,7 +614,7 @@ styleToOpenXml sm style = $ backgroundColor style ) ] -copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> IO Entry +copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> DocxAction Entry copyChildren refArchive distArchive path timestamp elNames = do ref <- parseXml refArchive distArchive path dist <- parseXml distArchive distArchive path @@ -622,7 +633,7 @@ copyChildren refArchive distArchive path timestamp elNames = do baseListId :: Int baseListId = 1000 -mkNumbering :: [ListMarker] -> IO [Element] +mkNumbering :: [ListMarker] -> DocxAction [Element] mkNumbering lists = do elts <- mapM mkAbstractNum (ordNub lists) return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)] @@ -638,9 +649,10 @@ mkNum marker numid = map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))] $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6] -mkAbstractNum :: ListMarker -> IO Element +mkAbstractNum :: ListMarker -> DocxAction Element mkAbstractNum marker = do - nsid <- randomRIO (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) + gen <- P.newStdGen + let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen return $ mknode "w:abstractNum" [("w:abstractNumId",listMarkerToId marker)] $ mknode "w:nsid" [("w:val", printf "%8x" nsid)] () : mknode "w:multiLevelType" [("w:val","multilevel")] () @@ -695,6 +707,7 @@ mkLvl marker lvl = getNumId :: WS Int getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists + makeTOC :: WriterOptions -> WS [Element] makeTOC opts | writerTableOfContents opts = do let depth = "1-"++(show (writerTOCDepth opts)) @@ -781,10 +794,10 @@ rStyleM styleName = do let sty' = getStyleId styleName $ sCharStyleMap styleMaps return $ mknode "w:rStyle" [("w:val",sty')] () -getUniqueId :: MonadIO m => m String +getUniqueId :: DocxAction String -- the + 20 is to ensure that there are no clashes with the rIds -- already in word/document.xml.rel -getUniqueId = liftIO $ (show . (+ 20) . hashUnique) `fmap` newUnique +getUniqueId = (show . (+ 20) . hashUnique) <$> P.newUnique -- | Key for specifying user-defined docx styles. dynamicStyleKey :: String @@ -825,7 +838,7 @@ blockToOpenXML' opts (Header lev (ident,_,_) lst) = do then uniqueIdent lst usedIdents else ident modify $ \s -> s{ stSectionIds = Set.insert bookmarkName $ stSectionIds s } - id' <- getUniqueId + id' <- (lift . lift) getUniqueId let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id') ,("w:name",bookmarkName)] () let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] () @@ -1137,7 +1150,7 @@ inlineToOpenXML' opts (Code attrs str) = do else unhighlighted inlineToOpenXML' opts (Note bs) = do notes <- gets stFootnotes - notenum <- getUniqueId + notenum <- (lift . lift) getUniqueId footnoteStyle <- rStyleM "Footnote Reference" let notemarker = mknode "w:r" [] [ mknode "w:rPr" [] footnoteStyle @@ -1168,7 +1181,7 @@ inlineToOpenXML' opts (Link _ txt (src,_)) = do id' <- case M.lookup src extlinks of Just i -> return i Nothing -> do - i <- ("rId"++) `fmap` getUniqueId + i <- ("rId"++) `fmap` ((lift . lift) getUniqueId) modify $ \st -> st{ stExternalLinks = M.insert src i extlinks } return i @@ -1180,15 +1193,14 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do case M.lookup src imgs of Just (_,_,_,elt,_) -> return [elt] Nothing -> do - res <- liftIO $ - fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + res <- (lift . lift) $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - warn $ "Could not find image `" ++ src ++ "', skipping..." + (lift . lift) $ P.warn ("Could not find image `" ++ src ++ "', skipping...") -- emit alt text inlinesToOpenXML opts alt Right (img, mt) -> do - ident <- ("rId"++) `fmap` getUniqueId + ident <- ("rId"++) `fmap` ((lift . lift) getUniqueId) let (xpt,ypt) = desiredSizeInPoints opts attr (either (const def) id (imageSize img)) -- 12700 emu = 1 pt @@ -1272,13 +1284,13 @@ defaultFootnotes = [ mknode "w:footnote" [ mknode "w:r" [] $ [ mknode "w:continuationSeparator" [] ()]]]] -parseXml :: Archive -> Archive -> String -> IO Element +parseXml :: Archive -> Archive -> String -> DocxAction Element parseXml refArchive distArchive relpath = case findEntryByPath relpath refArchive `mplus` findEntryByPath relpath distArchive of Nothing -> fail $ relpath ++ " missing in reference docx" Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of - Nothing -> fail $ relpath ++ " corrupt in reference docx" + Nothing -> P.fail $ relpath ++ " corrupt in reference docx" Just d -> return d -- | Scales the image to fit the page diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 00bf4a81c..4a93d52e2 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -28,26 +28,23 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to EPUB. -} -module Text.Pandoc.Writers.EPUB ( writeEPUB ) where -import Data.IORef ( IORef, newIORef, readIORef, modifyIORef ) +module Text.Pandoc.Writers.EPUB ( writeEPUB, writeEPUBPure ) where +import Data.IORef ( IORef ) import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe ( fromMaybe, catMaybes ) import Data.List ( isPrefixOf, isInfixOf, intercalate ) -import System.Environment ( getEnv ) import Text.Printf (printf) import System.FilePath ( takeExtension, takeFileName ) -import System.FilePath.Glob ( namesMatching ) import Network.HTTP ( urlEncode ) import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy.Char8 as B8 import qualified Text.Pandoc.UTF8 as UTF8 import Codec.Archive.Zip ( emptyArchive, addEntryToArchive, eRelativePath, fromEntry , Entry, toEntry, fromArchive) -import Data.Time.Clock.POSIX ( getPOSIXTime ) import Text.Pandoc.Compat.Time import Text.Pandoc.Shared ( renderTags', safeRead, uniqueIdent, trim - , normalizeDate, readDataFile, stringify, warn - , hierarchicalize, fetchItem' ) + , normalizeDate, stringify + , hierarchicalize ) import qualified Text.Pandoc.Shared as S (Element(..)) import Text.Pandoc.Builder (fromList, setMeta) import Text.Pandoc.Options ( WriterOptions(..) @@ -58,17 +55,19 @@ import Text.Pandoc.Options ( WriterOptions(..) import Text.Pandoc.Definition import Text.Pandoc.Walk (walk, walkM, query) import Control.Monad.State (modify, get, State, put, evalState) -import Control.Monad (mplus, liftM, when) +import Control.Monad (mplus, when) import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs , strContent, lookupAttr, Node(..), QName(..), parseXML , onlyElems, node, ppElement) -import Text.Pandoc.UUID (getRandomUUID) import Text.Pandoc.Writers.HTML ( writeHtml ) import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) -import qualified Control.Exception as E import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) +import Text.Pandoc.Free (PandocAction, runIO) +import qualified Text.Pandoc.Free as P + +type EPUBAction = PandocAction [(FilePath, (FilePath, Maybe Entry))] -- A Chapter includes a list of blocks and maybe a section -- number offset. Note, some chapters are unnumbered. The section @@ -143,7 +142,7 @@ removeNote :: Inline -> Inline removeNote (Note _) = Str "" removeNote x = x -getEPUBMetadata :: WriterOptions -> Meta -> IO EPUBMetadata +getEPUBMetadata :: WriterOptions -> Meta -> EPUBAction EPUBMetadata getEPUBMetadata opts meta = do let md = metadataFromMeta opts meta let elts = onlyElems $ parseXML $ writerEpubMetadata opts @@ -151,7 +150,7 @@ getEPUBMetadata opts meta = do let addIdentifier m = if null (epubIdentifier m) then do - randomId <- fmap show getRandomUUID + randomId <- fmap show P.newUUID return $ m{ epubIdentifier = [Identifier randomId Nothing] } else return m let addLanguage m = @@ -159,16 +158,19 @@ getEPUBMetadata opts meta = do then case lookup "lang" (writerVariables opts) of Just x -> return m{ epubLanguage = x } Nothing -> do - localeLang <- E.catch (liftM - (map (\c -> if c == '_' then '-' else c) . - takeWhile (/='.')) $ getEnv "LANG") - (\e -> let _ = (e :: E.SomeException) in return "en-US") + mLang <- P.lookupEnv "LANG" + let localeLang = + case mLang of + Just lang -> + map (\c -> if c == '_' then '-' else c) $ + takeWhile (/='.') lang + Nothing -> "en-US" return m{ epubLanguage = localeLang } else return m let fixDate m = if null (epubDate m) then do - currentTime <- getCurrentTime + currentTime <- P.getCurrentTime return $ m{ epubDate = [ Date{ dateText = showDateTimeISO8601 currentTime , dateEvent = Nothing } ] } @@ -333,10 +335,15 @@ metadataFromMeta opts meta = EPUBMetadata{ writeEPUB :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert -> IO B.ByteString -writeEPUB opts doc@(Pandoc meta _) = do +writeEPUB opts doc = runIO $ writeEPUBPure opts doc + +writeEPUBPure :: WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> EPUBAction B.ByteString +writeEPUBPure opts doc@(Pandoc meta _) = do let version = fromMaybe EPUB2 (writerEpubVersion opts) let epub3 = version == EPUB3 - epochtime <- floor `fmap` getPOSIXTime + epochtime <- floor <$> P.getPOSIXTime let mkEntry path content = toEntry path epochtime content let vars = ("epub3", if epub3 then "true" else "false") : ("css", "stylesheet.css") @@ -361,7 +368,7 @@ writeEPUB opts doc@(Pandoc meta _) = do let cpContent = renderHtml $ writeHtml opts'{ writerVariables = ("coverpage","true"):vars } (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"]) - imgContent <- B.readFile img + imgContent <- P.readFileLazy img return ( [mkEntry "cover.xhtml" cpContent] , [mkEntry coverImage imgContent] ) @@ -372,18 +379,18 @@ writeEPUB opts doc@(Pandoc meta _) = do let tpEntry = mkEntry "title_page.xhtml" tpContent -- handle pictures - mediaRef <- newIORef [] + mediaRef <- P.newIORef [] Pandoc _ blocks <- walkM (transformInline opts' mediaRef) doc >>= walkM (transformBlock opts' mediaRef) - picEntries <- (catMaybes . map (snd . snd)) <$> readIORef mediaRef + picEntries <- (catMaybes . map (snd . snd)) <$> P.readIORef mediaRef -- handle fonts let matchingGlob f = do - xs <- namesMatching f + xs <- P.namesMatching f when (null xs) $ - warn $ f ++ " did not match any font files." + P.warn $ f ++ " did not match any font files." return xs - let mkFontEntry f = mkEntry (takeFileName f) `fmap` B.readFile f + let mkFontEntry f = mkEntry (takeFileName f) `fmap` P.readFileLazy f fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts') fontEntries <- mapM mkFontEntry fontFiles @@ -520,7 +527,7 @@ writeEPUB opts doc@(Pandoc meta _) = do let uuid = case epubIdentifier metadata of (x:_) -> identifierText x -- use first identifier as UUID [] -> error "epubIdentifier is null" -- shouldn't happen - currentTime <- getCurrentTime + currentTime <- P.getCurrentTime let contentsData = UTF8.fromStringLazy $ ppTopElement $ unode "package" ! [("version", case version of EPUB2 -> "2.0" @@ -692,10 +699,10 @@ writeEPUB opts doc@(Pandoc meta _) = do -- stylesheet stylesheet <- case epubStylesheet metadata of - Just (StylesheetPath fp) -> UTF8.readFile fp + Just (StylesheetPath fp) -> P.readFileUTF8 fp Just (StylesheetContents s) -> return s Nothing -> UTF8.toString `fmap` - readDataFile (writerUserDataDir opts) "epub.css" + P.readDataFile (writerUserDataDir opts) "epub.css" let stylesheetEntry = mkEntry "stylesheet.css" $ UTF8.fromStringLazy stylesheet -- construct archive @@ -814,7 +821,7 @@ showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ" transformTag :: WriterOptions -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Tag String - -> IO (Tag String) + -> EPUBAction (Tag String) transformTag opts mediaRef tag@(TagOpen name attr) | name `elem` ["video", "source", "img", "audio"] && lookup "data-external" attr == Nothing = do @@ -831,34 +838,34 @@ transformTag _ _ tag = return tag modifyMediaRef :: WriterOptions -> IORef [(FilePath, (FilePath, Maybe Entry))] -> FilePath - -> IO FilePath + -> EPUBAction FilePath modifyMediaRef _ _ "" = return "" modifyMediaRef opts mediaRef oldsrc = do - media <- readIORef mediaRef + media <- P.readIORef mediaRef case lookup oldsrc media of Just (n,_) -> return n Nothing -> do - res <- fetchItem' (writerMediaBag opts) + res <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) oldsrc (new, mbEntry) <- case res of Left _ -> do - warn $ "Could not find media `" ++ oldsrc ++ "', skipping..." + P.warn $ "Could not find media `" ++ oldsrc ++ "', skipping..." return (oldsrc, Nothing) Right (img,mbMime) -> do let new = "media/file" ++ show (length media) ++ fromMaybe (takeExtension (takeWhile (/='?') oldsrc)) (('.':) <$> (mbMime >>= extensionFromMimeType)) - epochtime <- floor `fmap` getPOSIXTime + epochtime <- floor `fmap` P.getPOSIXTime let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img return (new, Just entry) - modifyIORef mediaRef ( (oldsrc, (new, mbEntry)): ) + P.modifyIORef mediaRef ( (oldsrc, (new, mbEntry)): ) return new transformBlock :: WriterOptions -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Block - -> IO Block + -> EPUBAction Block transformBlock opts mediaRef (RawBlock fmt raw) | fmt == Format "html" = do let tags = parseTags raw @@ -869,7 +876,7 @@ transformBlock _ _ b = return b transformInline :: WriterOptions -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media -> Inline - -> IO Inline + -> EPUBAction Inline transformInline opts mediaRef (Image attr lab (src,tit)) = do newsrc <- modifyMediaRef opts mediaRef src return $ Image attr lab (newsrc, tit) diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index e2c123fc2..3a1e772ce 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -18,7 +18,7 @@ import Text.Pandoc.Definition import Text.Pandoc.XML import Text.Pandoc.Readers.TeXMath (texMathToInlines) import Text.Pandoc.Writers.Shared -import Text.Pandoc.Shared (linesToPara, splitBy, fetchItem, warn) +import Text.Pandoc.Shared (linesToPara, splitBy, warn) import Text.Pandoc.Options import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Pretty @@ -28,6 +28,10 @@ import Data.Text as Text (breakOnAll, pack) import Control.Monad.State import Network.URI (isURI) import qualified Data.Set as Set +import Text.Pandoc.Free (runIO) +import qualified Text.Pandoc.Free as P + +type ICMLAction = P.PandocAction () type Style = [String] type Hyperlink = [(Int, String)] @@ -40,7 +44,7 @@ data WriterState = WriterState{ , maxListDepth :: Int } -type WS a = StateT WriterState IO a +type WS a = StateT WriterState ICMLAction a defaultWriterState :: WriterState defaultWriterState = WriterState{ @@ -121,10 +125,13 @@ subListParName = "subParagraph" footnoteName = "Footnote" citeName = "Cite" - -- | Convert Pandoc document to string in ICML format. writeICML :: WriterOptions -> Pandoc -> IO String -writeICML opts (Pandoc meta blocks) = do +writeICML opts doc = runIO $ writeICMLPure opts doc + +-- | Convert Pandoc document to string in ICML format. +writeICMLPure :: WriterOptions -> Pandoc -> ICMLAction String +writeICMLPure opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing @@ -532,10 +539,10 @@ styleToStrAttr style = -- | Assemble an ICML Image. imageICML :: WriterOptions -> Style -> Attr -> Target -> WS Doc imageICML opts style attr (src, _) = do - res <- liftIO $ fetchItem (writerSourceURL opts) src + res <- lift $ P.fetchItem (writerSourceURL opts) src imgS <- case res of Left (_) -> do - warn $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.warn $ "Could not find image `" ++ src ++ "', skipping..." return def Right (img, _) -> do case imageSize img of diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index ce4d456a3..0f1dd7cd3 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to ODT. -} -module Text.Pandoc.Writers.ODT ( writeODT ) where +module Text.Pandoc.Writers.ODT ( writeODTPure, writeODT ) where import Data.IORef import Data.List ( isPrefixOf ) import Data.Maybe ( fromMaybe ) @@ -38,8 +38,7 @@ import qualified Data.ByteString.Lazy as B import Text.Pandoc.UTF8 ( fromStringLazy ) import Codec.Archive.Zip import Text.Pandoc.Options ( WriterOptions(..), WrapOption(..) ) -import Text.Pandoc.Shared ( stringify, fetchItem', warn, - getDefaultReferenceODT ) +import Text.Pandoc.Shared ( stringify ) import Text.Pandoc.ImageSize import Text.Pandoc.MIME ( getMimeType, extensionFromMimeType ) import Text.Pandoc.Definition @@ -50,28 +49,37 @@ import Control.Monad (liftM) import Text.Pandoc.XML import Text.Pandoc.Pretty import qualified Control.Exception as E -import Data.Time.Clock.POSIX ( getPOSIXTime ) import System.FilePath ( takeExtension, takeDirectory, (<.>)) +import Text.Pandoc.Free ( PandocAction, runIO ) +import qualified Text.Pandoc.Free as P + +type ODTAction = PandocAction [Entry] -- | Produce an ODT file from a Pandoc document. writeODT :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert -> IO B.ByteString -writeODT opts doc@(Pandoc meta _) = do +writeODT opts doc = runIO $ writeODTPure opts doc + +-- | Produce an ODT file from a Pandoc document. +writeODTPure :: WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> ODTAction B.ByteString +writeODTPure opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let title = docTitle meta refArchive <- case writerReferenceODT opts of - Just f -> liftM toArchive $ B.readFile f - Nothing -> getDefaultReferenceODT datadir + Just f -> liftM toArchive $ P.readFileLazy f + Nothing -> P.getDefaultReferenceODT datadir -- handle formulas and pictures - picEntriesRef <- newIORef ([] :: [Entry]) + picEntriesRef <- P.newIORef ([] :: [Entry]) doc' <- walkM (transformPicMath opts picEntriesRef) $ walk fixDisplayMath doc let newContents = writeOpenDocument opts{writerWrapText = WrapNone} doc' - epochtime <- floor `fmap` getPOSIXTime + epochtime <- floor `fmap` P.getPOSIXTime let contentEntry = toEntry "content.xml" epochtime $ fromStringLazy newContents - picEntries <- readIORef picEntriesRef + picEntries <- P.readIORef picEntriesRef let archive = foldr addEntryToArchive refArchive $ contentEntry : picEntries -- construct META-INF/manifest.xml based on archive @@ -126,18 +134,18 @@ writeODT opts doc@(Pandoc meta _) = do return $ fromArchive archive'' -- | transform both Image and Math elements -transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> IO Inline +transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> ODTAction Inline transformPicMath opts entriesRef (Image attr@(id', cls, _) lab (src,t)) = do - res <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + res <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - warn $ "Could not find image `" ++ src ++ "', skipping..." + P.warn $ "Could not find image `" ++ src ++ "', skipping..." return $ Emph lab Right (img, mbMimeType) -> do (ptX, ptY) <- case imageSize img of Right s -> return $ sizeInPoints s Left msg -> do - warn $ "Could not determine image size in `" ++ + P.warn $ "Could not determine image size in `" ++ src ++ "': " ++ msg return (100, 100) let dims = @@ -155,28 +163,28 @@ transformPicMath opts entriesRef (Image attr@(id', cls, _) lab (src,t)) = do Just dim -> Just $ Inch $ inInch opts dim Nothing -> Nothing let newattr = (id', cls, dims) - entries <- readIORef entriesRef + entries <- P.readIORef entriesRef let extension = fromMaybe (takeExtension $ takeWhile (/='?') src) (mbMimeType >>= extensionFromMimeType) let newsrc = "Pictures/" ++ show (length entries) <.> extension let toLazy = B.fromChunks . (:[]) - epochtime <- floor `fmap` getPOSIXTime + epochtime <- floor `fmap` P.getPOSIXTime let entry = toEntry newsrc epochtime $ toLazy img - modifyIORef entriesRef (entry:) + P.modifyIORef entriesRef (entry:) return $ Image newattr lab (newsrc, t) transformPicMath _ entriesRef (Math t math) = do - entries <- readIORef entriesRef + entries <- P.readIORef entriesRef let dt = if t == InlineMath then DisplayInline else DisplayBlock case writeMathML dt <$> readTeX math of Left _ -> return $ Math t math Right r -> do let conf = useShortEmptyTags (const False) defaultConfigPP let mathml = ppcTopElement conf r - epochtime <- floor `fmap` getPOSIXTime + epochtime <- floor `fmap` P.getPOSIXTime let dirname = "Formula-" ++ show (length entries) ++ "/" let fname = dirname ++ "content.xml" let entry = toEntry fname epochtime (fromStringLazy mathml) - modifyIORef entriesRef (entry:) + P.modifyIORef entriesRef (entry:) return $ RawInline (Format "opendocument") $ render Nothing $ inTags False "draw:frame" [("text:anchor-type", if t == DisplayMath -- cgit v1.2.3 From 8d1d0eb9a509543c724292438e185e6ed24996b5 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Thu, 17 Nov 2016 08:04:25 -0500 Subject: Remove IORef from ODT writer. We want pure writers, so IORef shouldn't be in there. We switch to using a normal State Monad. If this produces performance problems, we can look into trying STRefs, but that seems like unnecessary complication at the moment. --- src/Text/Pandoc/Writers/ODT.hs | 62 ++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 24 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 0f1dd7cd3..b139695db 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -29,7 +29,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to ODT. -} module Text.Pandoc.Writers.ODT ( writeODTPure, writeODT ) where -import Data.IORef import Data.List ( isPrefixOf ) import Data.Maybe ( fromMaybe ) import Text.XML.Light.Output @@ -46,6 +45,7 @@ import Text.Pandoc.Walk import Text.Pandoc.Writers.Shared ( fixDisplayMath ) import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) import Control.Monad (liftM) +import Control.Monad.State import Text.Pandoc.XML import Text.Pandoc.Pretty import qualified Control.Exception as E @@ -55,31 +55,45 @@ import qualified Text.Pandoc.Free as P type ODTAction = PandocAction [Entry] +data ODTState = ODTState { stEntries :: [Entry] + } + +type O = StateT ODTState ODTAction + -- | Produce an ODT file from a Pandoc document. writeODT :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert -> IO B.ByteString writeODT opts doc = runIO $ writeODTPure opts doc --- | Produce an ODT file from a Pandoc document. -writeODTPure :: WriterOptions -- ^ Writer options - -> Pandoc -- ^ Document to convert +writeODTPure :: WriterOptions + -> Pandoc -> ODTAction B.ByteString -writeODTPure opts doc@(Pandoc meta _) = do +writeODTPure opts doc = + let initState = ODTState{ stEntries = [] + } + in + evalStateT (pandocToODT opts doc) initState + +-- | Produce an ODT file from a Pandoc document. +pandocToODT :: WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> O B.ByteString +pandocToODT opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let title = docTitle meta refArchive <- case writerReferenceODT opts of - Just f -> liftM toArchive $ P.readFileLazy f - Nothing -> P.getDefaultReferenceODT datadir + Just f -> liftM toArchive $ lift $ P.readFileLazy f + Nothing -> lift $ P.getDefaultReferenceODT datadir -- handle formulas and pictures - picEntriesRef <- P.newIORef ([] :: [Entry]) - doc' <- walkM (transformPicMath opts picEntriesRef) $ walk fixDisplayMath doc + -- picEntriesRef <- P.newIORef ([] :: [Entry]) + doc' <- walkM (transformPicMath opts) $ walk fixDisplayMath doc let newContents = writeOpenDocument opts{writerWrapText = WrapNone} doc' - epochtime <- floor `fmap` P.getPOSIXTime + epochtime <- floor `fmap` (lift P.getPOSIXTime) let contentEntry = toEntry "content.xml" epochtime $ fromStringLazy newContents - picEntries <- P.readIORef picEntriesRef + picEntries <- gets stEntries let archive = foldr addEntryToArchive refArchive $ contentEntry : picEntries -- construct META-INF/manifest.xml based on archive @@ -134,18 +148,18 @@ writeODTPure opts doc@(Pandoc meta _) = do return $ fromArchive archive'' -- | transform both Image and Math elements -transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> ODTAction Inline -transformPicMath opts entriesRef (Image attr@(id', cls, _) lab (src,t)) = do - res <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src +transformPicMath :: WriterOptions ->Inline -> O Inline +transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do + res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - P.warn $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.warn $ "Could not find image `" ++ src ++ "', skipping..." return $ Emph lab Right (img, mbMimeType) -> do (ptX, ptY) <- case imageSize img of Right s -> return $ sizeInPoints s Left msg -> do - P.warn $ "Could not determine image size in `" ++ + lift $ P.warn $ "Could not determine image size in `" ++ src ++ "': " ++ msg return (100, 100) let dims = @@ -163,28 +177,28 @@ transformPicMath opts entriesRef (Image attr@(id', cls, _) lab (src,t)) = do Just dim -> Just $ Inch $ inInch opts dim Nothing -> Nothing let newattr = (id', cls, dims) - entries <- P.readIORef entriesRef + entries <- gets stEntries let extension = fromMaybe (takeExtension $ takeWhile (/='?') src) (mbMimeType >>= extensionFromMimeType) let newsrc = "Pictures/" ++ show (length entries) <.> extension let toLazy = B.fromChunks . (:[]) - epochtime <- floor `fmap` P.getPOSIXTime + epochtime <- floor `fmap` (lift P.getPOSIXTime) let entry = toEntry newsrc epochtime $ toLazy img - P.modifyIORef entriesRef (entry:) + modify $ \st -> st{ stEntries = entry : entries } return $ Image newattr lab (newsrc, t) -transformPicMath _ entriesRef (Math t math) = do - entries <- P.readIORef entriesRef +transformPicMath _ (Math t math) = do + entries <- gets stEntries let dt = if t == InlineMath then DisplayInline else DisplayBlock case writeMathML dt <$> readTeX math of Left _ -> return $ Math t math Right r -> do let conf = useShortEmptyTags (const False) defaultConfigPP let mathml = ppcTopElement conf r - epochtime <- floor `fmap` P.getPOSIXTime + epochtime <- floor `fmap` (lift $ P.getPOSIXTime) let dirname = "Formula-" ++ show (length entries) ++ "/" let fname = dirname ++ "content.xml" let entry = toEntry fname epochtime (fromStringLazy mathml) - P.modifyIORef entriesRef (entry:) + modify $ \st -> st{ stEntries = entry : entries } return $ RawInline (Format "opendocument") $ render Nothing $ inTags False "draw:frame" [("text:anchor-type", if t == DisplayMath @@ -197,4 +211,4 @@ transformPicMath _ entriesRef (Math t math) = do , ("xlink:show", "embed") , ("xlink:actuate", "onLoad")] -transformPicMath _ _ x = return x +transformPicMath _ x = return x -- cgit v1.2.3 From 072107d1a2300afc7fb99263cc464048291d16d1 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Thu, 17 Nov 2016 09:04:44 -0500 Subject: Remove IORef from EPUB writer. --- src/Text/Pandoc/Writers/EPUB.hs | 113 ++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 51 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 4a93d52e2..8e283a66a 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -29,7 +29,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to EPUB. -} module Text.Pandoc.Writers.EPUB ( writeEPUB, writeEPUBPure ) where -import Data.IORef ( IORef ) import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe ( fromMaybe, catMaybes ) @@ -54,7 +53,7 @@ import Text.Pandoc.Options ( WriterOptions(..) , ObfuscationMethod(NoObfuscation) ) import Text.Pandoc.Definition import Text.Pandoc.Walk (walk, walkM, query) -import Control.Monad.State (modify, get, State, put, evalState) +import Control.Monad.State (modify, get, gets, State, StateT, put, evalState, evalStateT, lift) import Control.Monad (mplus, when) import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs , strContent, lookupAttr, Node(..), QName(..), parseXML @@ -75,6 +74,11 @@ type EPUBAction = PandocAction [(FilePath, (FilePath, Maybe Entry))] -- in filenames, chapter0003.xhtml. data Chapter = Chapter (Maybe [Int]) [Block] +data EPUBState = EPUBState { stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))] + } + +type E = StateT EPUBState EPUBAction + data EPUBMetadata = EPUBMetadata{ epubIdentifier :: [Identifier] , epubTitle :: [Title] @@ -142,7 +146,7 @@ removeNote :: Inline -> Inline removeNote (Note _) = Str "" removeNote x = x -getEPUBMetadata :: WriterOptions -> Meta -> EPUBAction EPUBMetadata +getEPUBMetadata :: WriterOptions -> Meta -> E EPUBMetadata getEPUBMetadata opts meta = do let md = metadataFromMeta opts meta let elts = onlyElems $ parseXML $ writerEpubMetadata opts @@ -150,7 +154,7 @@ getEPUBMetadata opts meta = do let addIdentifier m = if null (epubIdentifier m) then do - randomId <- fmap show P.newUUID + randomId <- fmap show (lift P.newUUID) return $ m{ epubIdentifier = [Identifier randomId Nothing] } else return m let addLanguage m = @@ -158,7 +162,7 @@ getEPUBMetadata opts meta = do then case lookup "lang" (writerVariables opts) of Just x -> return m{ epubLanguage = x } Nothing -> do - mLang <- P.lookupEnv "LANG" + mLang <- lift $ P.lookupEnv "LANG" let localeLang = case mLang of Just lang -> @@ -170,7 +174,7 @@ getEPUBMetadata opts meta = do let fixDate m = if null (epubDate m) then do - currentTime <- P.getCurrentTime + currentTime <- lift P.getCurrentTime return $ m{ epubDate = [ Date{ dateText = showDateTimeISO8601 currentTime , dateEvent = Nothing } ] } @@ -338,12 +342,21 @@ writeEPUB :: WriterOptions -- ^ Writer options writeEPUB opts doc = runIO $ writeEPUBPure opts doc writeEPUBPure :: WriterOptions -- ^ Writer options - -> Pandoc -- ^ Document to convert - -> EPUBAction B.ByteString -writeEPUBPure opts doc@(Pandoc meta _) = do + -> Pandoc -- ^ Document to convert + -> EPUBAction B.ByteString +writeEPUBPure opts doc = + let initState = EPUBState { stMediaPaths = [] + } + in + evalStateT (pandocToEPUB opts doc) initState + +pandocToEPUB :: WriterOptions + -> Pandoc + -> E B.ByteString +pandocToEPUB opts doc@(Pandoc meta _) = do let version = fromMaybe EPUB2 (writerEpubVersion opts) let epub3 = version == EPUB3 - epochtime <- floor <$> P.getPOSIXTime + epochtime <- floor <$> lift P.getPOSIXTime let mkEntry path content = toEntry path epochtime content let vars = ("epub3", if epub3 then "true" else "false") : ("css", "stylesheet.css") @@ -368,7 +381,7 @@ writeEPUBPure opts doc@(Pandoc meta _) = do let cpContent = renderHtml $ writeHtml opts'{ writerVariables = ("coverpage","true"):vars } (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"]) - imgContent <- P.readFileLazy img + imgContent <- lift $ P.readFileLazy img return ( [mkEntry "cover.xhtml" cpContent] , [mkEntry coverImage imgContent] ) @@ -379,18 +392,17 @@ writeEPUBPure opts doc@(Pandoc meta _) = do let tpEntry = mkEntry "title_page.xhtml" tpContent -- handle pictures - mediaRef <- P.newIORef [] - Pandoc _ blocks <- walkM (transformInline opts' mediaRef) doc >>= - walkM (transformBlock opts' mediaRef) - picEntries <- (catMaybes . map (snd . snd)) <$> P.readIORef mediaRef - + -- mediaRef <- P.newIORef [] + Pandoc _ blocks <- walkM (transformInline opts') doc >>= + walkM (transformBlock opts') + picEntries <- (catMaybes . map (snd . snd)) <$> (gets stMediaPaths) -- handle fonts let matchingGlob f = do - xs <- P.namesMatching f + xs <- lift $ P.namesMatching f when (null xs) $ - P.warn $ f ++ " did not match any font files." + lift $ P.warn $ f ++ " did not match any font files." return xs - let mkFontEntry f = mkEntry (takeFileName f) `fmap` P.readFileLazy f + let mkFontEntry f = mkEntry (takeFileName f) `fmap` (lift $ P.readFileLazy f) fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts') fontEntries <- mapM mkFontEntry fontFiles @@ -527,7 +539,7 @@ writeEPUBPure opts doc@(Pandoc meta _) = do let uuid = case epubIdentifier metadata of (x:_) -> identifierText x -- use first identifier as UUID [] -> error "epubIdentifier is null" -- shouldn't happen - currentTime <- P.getCurrentTime + currentTime <- lift $ P.getCurrentTime let contentsData = UTF8.fromStringLazy $ ppTopElement $ unode "package" ! [("version", case version of EPUB2 -> "2.0" @@ -699,10 +711,10 @@ writeEPUBPure opts doc@(Pandoc meta _) = do -- stylesheet stylesheet <- case epubStylesheet metadata of - Just (StylesheetPath fp) -> P.readFileUTF8 fp + Just (StylesheetPath fp) -> lift $ P.readFileUTF8 fp Just (StylesheetContents s) -> return s Nothing -> UTF8.toString `fmap` - P.readDataFile (writerUserDataDir opts) "epub.css" + (lift $ P.readDataFile (writerUserDataDir opts) "epub.css") let stylesheetEntry = mkEntry "stylesheet.css" $ UTF8.fromStringLazy stylesheet -- construct archive @@ -819,78 +831,77 @@ showDateTimeISO8601 :: UTCTime -> String showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ" transformTag :: WriterOptions - -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media + -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Tag String - -> EPUBAction (Tag String) -transformTag opts mediaRef tag@(TagOpen name attr) + -> E (Tag String) +transformTag opts tag@(TagOpen name attr) | name `elem` ["video", "source", "img", "audio"] && lookup "data-external" attr == Nothing = do let src = fromAttrib "src" tag let poster = fromAttrib "poster" tag - newsrc <- modifyMediaRef opts mediaRef src - newposter <- modifyMediaRef opts mediaRef poster + newsrc <- modifyMediaRef opts src + newposter <- modifyMediaRef opts poster let attr' = filter (\(x,_) -> x /= "src" && x /= "poster") attr ++ [("src", newsrc) | not (null newsrc)] ++ [("poster", newposter) | not (null newposter)] return $ TagOpen name attr' -transformTag _ _ tag = return tag +transformTag _ tag = return tag modifyMediaRef :: WriterOptions - -> IORef [(FilePath, (FilePath, Maybe Entry))] -> FilePath - -> EPUBAction FilePath -modifyMediaRef _ _ "" = return "" -modifyMediaRef opts mediaRef oldsrc = do - media <- P.readIORef mediaRef + -> E FilePath +modifyMediaRef _ "" = return "" +modifyMediaRef opts oldsrc = do + media <- gets stMediaPaths case lookup oldsrc media of Just (n,_) -> return n Nothing -> do - res <- P.fetchItem' (writerMediaBag opts) + res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) oldsrc (new, mbEntry) <- case res of Left _ -> do - P.warn $ "Could not find media `" ++ oldsrc ++ "', skipping..." + lift $ P.warn $ "Could not find media `" ++ oldsrc ++ "', skipping..." return (oldsrc, Nothing) Right (img,mbMime) -> do let new = "media/file" ++ show (length media) ++ fromMaybe (takeExtension (takeWhile (/='?') oldsrc)) (('.':) <$> (mbMime >>= extensionFromMimeType)) - epochtime <- floor `fmap` P.getPOSIXTime + epochtime <- floor `fmap` lift P.getPOSIXTime let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img return (new, Just entry) - P.modifyIORef mediaRef ( (oldsrc, (new, mbEntry)): ) + modify $ \st -> st{ stMediaPaths = (oldsrc, (new, mbEntry)):media} return new transformBlock :: WriterOptions - -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media + -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Block - -> EPUBAction Block -transformBlock opts mediaRef (RawBlock fmt raw) + -> E Block +transformBlock opts (RawBlock fmt raw) | fmt == Format "html" = do let tags = parseTags raw - tags' <- mapM (transformTag opts mediaRef) tags + tags' <- mapM (transformTag opts) tags return $ RawBlock fmt (renderTags' tags') -transformBlock _ _ b = return b +transformBlock _ b = return b transformInline :: WriterOptions - -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media + -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media -> Inline - -> EPUBAction Inline -transformInline opts mediaRef (Image attr lab (src,tit)) = do - newsrc <- modifyMediaRef opts mediaRef src + -> E Inline +transformInline opts (Image attr lab (src,tit)) = do + newsrc <- modifyMediaRef opts src return $ Image attr lab (newsrc, tit) -transformInline opts mediaRef (x@(Math t m)) +transformInline opts (x@(Math t m)) | WebTeX url <- writerHTMLMathMethod opts = do - newsrc <- modifyMediaRef opts mediaRef (url ++ urlEncode m) + newsrc <- modifyMediaRef opts (url ++ urlEncode m) let mathclass = if t == DisplayMath then "display" else "inline" return $ Span ("",["math",mathclass],[]) [Image nullAttr [x] (newsrc, "")] -transformInline opts mediaRef (RawInline fmt raw) +transformInline opts (RawInline fmt raw) | fmt == Format "html" = do let tags = parseTags raw - tags' <- mapM (transformTag opts mediaRef) tags + tags' <- mapM (transformTag opts) tags return $ RawInline fmt (renderTags' tags') -transformInline _ _ x = return x +transformInline _ x = return x (!) :: (t -> Element) -> [(String, String)] -> t -> Element (!) f attrs n = add_attrs (map (\(k,v) -> Attr (unqual k) v) attrs) (f n) -- cgit v1.2.3 From e24d5a56a7d0b26b9f15185bb570836878927d16 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Wed, 16 Nov 2016 20:49:17 -0500 Subject: Implement runTest functions. These work with a State monad and a Reader monad to produce deterministic results. It can probably be simplified somewhat. --- pandoc.cabal | 2 +- src/Text/Pandoc/Free.hs | 217 +++++++++++++++++++++++++++++----------- src/Text/Pandoc/UUID.hs | 2 +- src/Text/Pandoc/Writers/Docx.hs | 19 ++-- src/Text/Pandoc/Writers/EPUB.hs | 8 +- src/Text/Pandoc/Writers/ICML.hs | 8 +- src/Text/Pandoc/Writers/ODT.hs | 6 +- 7 files changed, 177 insertions(+), 85 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.cabal b/pandoc.cabal index a33b8571f..d1fc56bed 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -290,7 +290,7 @@ Library old-time, deepseq >= 1.3 && < 1.5, JuicyPixels >= 3.1.6.1 && < 3.3, - filemanip >= 0.3 && < 0.4, + Glob >= 0.7 && < 0.8, cmark >= 0.5 && < 0.6, doctemplates >= 0.1 && < 0.2, free >= 4 diff --git a/src/Text/Pandoc/Free.hs b/src/Text/Pandoc/Free.hs index d6a28e87f..eb42b45c2 100644 --- a/src/Text/Pandoc/Free.hs +++ b/src/Text/Pandoc/Free.hs @@ -33,6 +33,7 @@ Pure implementations of the IO monads used in Pandoc's readers and writers. module Text.Pandoc.Free ( PandocActionF(..) , PandocAction , runIO + , runTest , liftF -- , lookupEnv @@ -41,7 +42,7 @@ module Text.Pandoc.Free ( PandocActionF(..) , getDefaultReferenceDocx , getDefaultReferenceODT , newStdGen - , newUnique + , newUniqueHash , newUUID , readFileStrict , readFileLazy @@ -51,18 +52,15 @@ module Text.Pandoc.Free ( PandocActionF(..) , fetchItem' , warn , fail - , newIORef - , modifyIORef - , readIORef - , namesMatching + , glob ) where import Prelude hiding (readFile, fail) import qualified Control.Monad as M (fail) -import System.Random (StdGen) +import System.Random (StdGen, next) import qualified System.Random as IO (newStdGen) -import Codec.Archive.Zip (Archive) -import Data.Unique (Unique) +import Codec.Archive.Zip (Archive, fromArchive) +import Data.Unique (Unique, hashUnique, newUnique) import qualified Data.Unique as IO (newUnique) import qualified Text.Pandoc.Shared as IO ( fetchItem , fetchItem' @@ -70,32 +68,35 @@ import qualified Text.Pandoc.Shared as IO ( fetchItem , getDefaultReferenceODT , warn , readDataFile) -import Text.Pandoc.MediaBag (MediaBag) -import Data.Time.Clock.POSIX (POSIXTime) +import Text.Pandoc.MediaBag (MediaBag, lookupMedia) +import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds) import qualified Data.Time.Clock.POSIX as IO (getPOSIXTime) import Text.Pandoc.Compat.Time (UTCTime) import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime) -import Text.Pandoc.MIME (MimeType) +import Text.Pandoc.MIME (MimeType, getMimeType) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL import Control.Monad.Free import qualified Control.Exception as E import qualified System.Environment as IO (lookupEnv) -import Data.IORef (IORef) -import qualified Data.IORef as IO (newIORef, modifyIORef, readIORef) -import Text.Pandoc.UUID (UUID) +import Text.Pandoc.UUID import qualified Text.Pandoc.UUID as IO (getRandomUUID) -import qualified Text.Pandoc.UTF8 as UTF8 (readFile) -import qualified System.FilePath.Glob as IO (namesMatching) - -data PandocActionF ref nxt = +import qualified Text.Pandoc.UTF8 as UTF8 (readFile, toString) +import System.FilePath.Glob (match, compile) +import System.FilePath (()) +import qualified System.FilePath.Glob as IO (glob) +import Control.Monad.State hiding (fail) +import Control.Monad.Reader hiding (fail) +import Data.Word (Word8) + +data PandocActionF nxt = LookupEnv String (Maybe String -> nxt) | GetCurrentTime (UTCTime -> nxt) | GetPOSIXTime (POSIXTime -> nxt) | GetDefaultReferenceDocx (Maybe FilePath) (Archive -> nxt) | GetDefaultReferenceODT (Maybe FilePath) (Archive -> nxt) | NewStdGen (StdGen -> nxt) - | NewUnique (Unique -> nxt) + | NewUniqueHash (Int -> nxt) | NewUUID (UUID -> nxt) | ReadFileStrict FilePath (B.ByteString -> nxt) | ReadFileLazy FilePath (BL.ByteString -> nxt) @@ -105,83 +106,71 @@ data PandocActionF ref nxt = (Either E.SomeException (B.ByteString, Maybe MimeType) -> nxt) | FetchItem' MediaBag (Maybe String) (String) (Either E.SomeException (B.ByteString, Maybe MimeType) -> nxt) - | NewIORef ref (IORef ref -> nxt) - | ModifyIORef (IORef ref) (ref -> ref) nxt - | ReadIORef (IORef ref) (ref -> nxt) - | NamesMatching String ([FilePath] -> nxt) + | Glob String ([FilePath] -> nxt) | Warn String nxt | Fail String deriving Functor -type PandocAction a = Free (PandocActionF a) +type PandocAction = Free PandocActionF -lookupEnv :: String -> PandocAction a (Maybe String) +lookupEnv :: String -> PandocAction (Maybe String) lookupEnv s = liftF $ LookupEnv s id -getCurrentTime :: PandocAction a UTCTime +getCurrentTime :: PandocAction UTCTime getCurrentTime = liftF $ GetCurrentTime id -getPOSIXTime :: PandocAction a POSIXTime +getPOSIXTime :: PandocAction POSIXTime getPOSIXTime = liftF $ GetPOSIXTime id -getDefaultReferenceDocx :: Maybe FilePath -> PandocAction a Archive +getDefaultReferenceDocx :: Maybe FilePath -> PandocAction Archive getDefaultReferenceDocx fp = liftF $ GetDefaultReferenceDocx fp id -getDefaultReferenceODT :: Maybe FilePath -> PandocAction a Archive +getDefaultReferenceODT :: Maybe FilePath -> PandocAction Archive getDefaultReferenceODT fp = liftF $ GetDefaultReferenceODT fp id -newStdGen :: PandocAction a StdGen +newStdGen :: PandocAction StdGen newStdGen = liftF $ NewStdGen id -newUnique :: PandocAction a Unique -newUnique = liftF $ NewUnique id +newUniqueHash :: PandocAction Int +newUniqueHash = liftF $ NewUniqueHash id -newUUID :: PandocAction a UUID +newUUID :: PandocAction UUID newUUID = liftF $ NewUUID id -readFileStrict :: FilePath -> PandocAction a B.ByteString +readFileStrict :: FilePath -> PandocAction B.ByteString readFileStrict fp = liftF $ ReadFileStrict fp id -readFileLazy :: FilePath -> PandocAction a BL.ByteString +readFileLazy :: FilePath -> PandocAction BL.ByteString readFileLazy fp = liftF $ ReadFileLazy fp id -readFileUTF8 :: FilePath -> PandocAction a String +readFileUTF8 :: FilePath -> PandocAction String readFileUTF8 fp = liftF $ ReadFileUTF8 fp id -readDataFile :: Maybe FilePath -> FilePath -> PandocAction a B.ByteString +readDataFile :: Maybe FilePath -> FilePath -> PandocAction B.ByteString readDataFile mfp fp = liftF $ ReadDataFile mfp fp id fetchItem :: Maybe String -> String -> - PandocAction a (Either E.SomeException (B.ByteString, Maybe MimeType)) + PandocAction (Either E.SomeException (B.ByteString, Maybe MimeType)) fetchItem ms s = liftF $ FetchItem ms s id fetchItem' :: MediaBag -> Maybe String -> String -> - PandocAction a (Either E.SomeException (B.ByteString, Maybe MimeType)) + PandocAction (Either E.SomeException (B.ByteString, Maybe MimeType)) fetchItem' mb ms s = liftF $ FetchItem' mb ms s id -warn :: String -> PandocAction a () +warn :: String -> PandocAction () warn s = liftF $ Warn s () -fail :: String -> PandocAction a b +fail :: String -> PandocAction b fail s = liftF $ Fail s -newIORef :: a -> PandocAction a (IORef a) -newIORef v = liftF $ NewIORef v id - -modifyIORef :: (IORef a) -> (a -> a) -> PandocAction a () -modifyIORef ref f = liftF $ ModifyIORef ref f () - -readIORef :: (IORef a) -> PandocAction a a -readIORef ref = liftF $ ReadIORef ref id - -namesMatching :: String -> PandocAction a [FilePath] -namesMatching s = liftF $ NamesMatching s id +glob :: String -> PandocAction [FilePath] +glob s = liftF $ Glob s id -runIO :: PandocAction ref nxt -> IO nxt +runIO :: PandocAction nxt -> IO nxt runIO (Free (LookupEnv s f)) = IO.lookupEnv s >>= runIO . f runIO (Free (GetCurrentTime f)) = IO.getCurrentTime >>= runIO . f runIO (Free (GetPOSIXTime f)) = IO.getPOSIXTime >>= runIO . f @@ -190,7 +179,7 @@ runIO (Free (GetDefaultReferenceDocx mfp f)) = runIO (Free (GetDefaultReferenceODT mfp f)) = IO.getDefaultReferenceODT mfp >>= runIO . f runIO (Free (NewStdGen f)) = IO.newStdGen >>= runIO . f -runIO (Free (NewUnique f)) = IO.newUnique >>= runIO . f +runIO (Free (NewUniqueHash f)) = hashUnique <$> IO.newUnique >>= runIO . f runIO (Free (NewUUID f)) = IO.getRandomUUID >>= runIO . f runIO (Free (ReadFileStrict fp f)) = B.readFile fp >>= runIO . f runIO (Free (ReadFileLazy fp f)) = BL.readFile fp >>= runIO . f @@ -202,8 +191,120 @@ runIO (Free (FetchItem sourceUrl nm f)) = runIO (Free (FetchItem' media sourceUrl nm f)) = IO.fetchItem' media sourceUrl nm >>= runIO . f runIO (Free (Warn s nxt)) = IO.warn s >> runIO nxt -runIO (Free (NewIORef v f)) = IO.newIORef v >>= runIO . f -runIO (Free (ModifyIORef ref f nxt)) = IO.modifyIORef ref f >> runIO nxt -runIO (Free (ReadIORef ref f)) = IO.readIORef ref >>= runIO . f -runIO (Free (NamesMatching s f)) = IO.namesMatching s >>= runIO . f +runIO (Free (Glob s f)) = IO.glob s >>= runIO . f runIO (Pure r) = return r + +data TestState = TestState { stStdGen :: StdGen + , stWord8Store :: [Word8] -- should be + -- inifinite, + -- i.e. [1..] + , stWarnings :: [String] + , stUniqStore :: [Int] -- should be + -- inifinite and + -- contain every + -- element at most + -- once, e.g. [1..] + } + +data TestEnv = TestEnv { envEnv :: [(String, String)] + , envTime :: UTCTime + , envReferenceDocx :: Archive + , envReferenceODT :: Archive + , envFiles :: [(FilePath, B.ByteString)] + , envUserDataDir :: [(FilePath, B.ByteString)] + , envCabalDataDir :: [(FilePath, B.ByteString)] + , envFontFiles :: [FilePath] + } + +data TestException = TestException + deriving (Show) + +instance E.Exception TestException + +type Testing = ReaderT TestEnv (State TestState) + +runTest :: PandocAction nxt -> Testing nxt +runTest (Free (LookupEnv s f)) = do + env <- asks envEnv + return (lookup s env) >>= runTest . f +runTest (Free (GetCurrentTime f)) = + asks envTime >>= runTest . f +runTest (Free (GetPOSIXTime f)) = + (utcTimeToPOSIXSeconds <$> asks envTime) >>= runTest . f +runTest (Free (GetDefaultReferenceDocx _ f)) = + asks envReferenceDocx >>= runTest . f +runTest (Free (GetDefaultReferenceODT _ f)) = + asks envReferenceODT >>= runTest . f +runTest (Free (NewStdGen f)) = do + g <- gets stStdGen + let (_, nxtGen) = next g + modify $ \st -> st { stStdGen = nxtGen } + return g >>= runTest . f +runTest (Free (NewUniqueHash f)) = do + uniqs <- gets stUniqStore + case uniqs of + u : us -> do + modify $ \st -> st { stUniqStore = us } + return u >>= runTest . f + _ -> M.fail "uniq store ran out of elements" +runTest (Free (NewUUID f)) = do + word8s <- gets stWord8Store + case word8s of + -- note we use f' because f is a param of the function + a:b:c:d:e:f':g:h:i:j:k:l:m:n:o:p:remaining -> do + modify $ \st -> st { stWord8Store = remaining } + return (UUID a b c d e f' g h i j k l m n o p) >>= runTest . f + _ -> M.fail "word8 supply was not infinite" +runTest (Free (ReadFileStrict fp f)) = do + fps <- asks envFiles + case lookup fp fps of + Just bs -> return bs >>= runTest . f + Nothing -> error "openFile: does not exist" +runTest (Free (ReadFileLazy fp f)) = do + fps <- asks envFiles + case lookup fp fps of + Just bs -> return (BL.fromStrict bs) >>= runTest . f + Nothing -> error "openFile: does not exist" +runTest (Free (ReadFileUTF8 fp f)) = do + fps <- asks envFiles + case lookup fp fps of + Just bs -> return (UTF8.toString bs) >>= runTest . f + Nothing -> error "openFile: does not exist" +-- A few different cases of readDataFile to reimplement, for when +-- there is no filepath and it falls through to readDefaultDataFile +runTest (Free (ReadDataFile Nothing "reference.docx" f)) = do + (B.concat . BL.toChunks . fromArchive) <$> + (runTest $ getDefaultReferenceDocx Nothing) >>= + runTest . f +runTest (Free (ReadDataFile Nothing "reference.odt" f)) = do + (B.concat . BL.toChunks . fromArchive) <$> + (runTest $ getDefaultReferenceODT Nothing) >>= + runTest . f +runTest (Free (ReadDataFile Nothing fname f)) = do + let fname' = if fname == "MANUAL.txt" then fname else "data" fname + runTest (readFileStrict fname') >>= runTest . f +runTest (Free (ReadDataFile (Just userDir) fname f)) = do + userDirFiles <- asks envUserDataDir + case lookup (userDir fname) userDirFiles of + Just bs -> return bs >>= runTest . f + Nothing -> runTest (readDataFile Nothing fname) >>= runTest . f +runTest (Free (Fail s)) = M.fail s +runTest (Free (FetchItem _ fp f)) = do + fps <- asks envFiles + case lookup fp fps of + Just bs -> return (Right (bs, getMimeType fp)) >>= runTest . f + Nothing -> return (Left $ E.toException TestException) >>= runTest . f +runTest (Free (FetchItem' media sourceUrl nm f)) = do + case lookupMedia nm media of + Nothing -> runTest (fetchItem sourceUrl nm) >>= runTest . f + Just (mime, bs) -> return (Right (B.concat $ BL.toChunks bs, Just mime)) >>= runTest . f +runTest (Free (Warn s nxt)) = do + modify $ \st -> st { stWarnings = s : stWarnings st } + runTest nxt +runTest (Free (Glob s f)) = do + fontFiles <- asks envFontFiles + return (filter (match (compile s)) fontFiles) >>= runTest . f +runTest (Pure r) = return r + + + diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs index 5d05fa303..6d6e22944 100644 --- a/src/Text/Pandoc/UUID.hs +++ b/src/Text/Pandoc/UUID.hs @@ -29,7 +29,7 @@ UUID generation using Version 4 (random method) described in RFC4122. See http://tools.ietf.org/html/rfc4122 -} -module Text.Pandoc.UUID ( UUID, getRandomUUID ) where +module Text.Pandoc.UUID ( UUID(..), getRandomUUID ) where import Text.Printf ( printf ) import System.Random ( randomIO ) diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index cecee7e9e..3f380a3ee 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -55,7 +55,6 @@ import Text.Pandoc.Readers.Docx.Util (elemName) import Control.Monad.Reader import Control.Monad.State import Skylighting -import Data.Unique (hashUnique, newUnique) import System.Random (randomR) import Text.Printf (printf) import qualified Control.Exception as E @@ -69,8 +68,6 @@ import Data.Char (ord, isSpace, toLower) import Text.Pandoc.Free (PandocAction, runIO) import qualified Text.Pandoc.Free as P -type DocxAction = PandocAction () - data ListMarker = NoMarker | BulletMarker | NumberMarker ListNumberStyle ListNumberDelim Int @@ -149,7 +146,7 @@ defaultWriterState = WriterState{ , stDynamicTextProps = [] } -type WS = ReaderT WriterEnv (StateT WriterState (DocxAction)) +type WS = ReaderT WriterEnv (StateT WriterState (PandocAction)) mknode :: Node t => String -> [(String,String)] -> t -> Element mknode s attrs = @@ -227,7 +224,7 @@ writeDocx opts doc = runIO $ writeDocxPure opts doc -- | Produce an Docx file from a Pandoc document. writeDocxPure :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> DocxAction BL.ByteString + -> PandocAction BL.ByteString writeDocxPure opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let doc' = walk fixDisplayMath $ doc @@ -614,7 +611,7 @@ styleToOpenXml sm style = $ backgroundColor style ) ] -copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> DocxAction Entry +copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> PandocAction Entry copyChildren refArchive distArchive path timestamp elNames = do ref <- parseXml refArchive distArchive path dist <- parseXml distArchive distArchive path @@ -633,7 +630,7 @@ copyChildren refArchive distArchive path timestamp elNames = do baseListId :: Int baseListId = 1000 -mkNumbering :: [ListMarker] -> DocxAction [Element] +mkNumbering :: [ListMarker] -> PandocAction [Element] mkNumbering lists = do elts <- mapM mkAbstractNum (ordNub lists) return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)] @@ -649,7 +646,7 @@ mkNum marker numid = map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))] $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6] -mkAbstractNum :: ListMarker -> DocxAction Element +mkAbstractNum :: ListMarker -> PandocAction Element mkAbstractNum marker = do gen <- P.newStdGen let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen @@ -794,10 +791,10 @@ rStyleM styleName = do let sty' = getStyleId styleName $ sCharStyleMap styleMaps return $ mknode "w:rStyle" [("w:val",sty')] () -getUniqueId :: DocxAction String +getUniqueId :: PandocAction String -- the + 20 is to ensure that there are no clashes with the rIds -- already in word/document.xml.rel -getUniqueId = (show . (+ 20) . hashUnique) <$> P.newUnique +getUniqueId = (show . (+ 20)) <$> P.newUniqueHash -- | Key for specifying user-defined docx styles. dynamicStyleKey :: String @@ -1284,7 +1281,7 @@ defaultFootnotes = [ mknode "w:footnote" [ mknode "w:r" [] $ [ mknode "w:continuationSeparator" [] ()]]]] -parseXml :: Archive -> Archive -> String -> DocxAction Element +parseXml :: Archive -> Archive -> String -> PandocAction Element parseXml refArchive distArchive relpath = case findEntryByPath relpath refArchive `mplus` findEntryByPath relpath distArchive of diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 8e283a66a..435893443 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -66,8 +66,6 @@ import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) import Text.Pandoc.Free (PandocAction, runIO) import qualified Text.Pandoc.Free as P -type EPUBAction = PandocAction [(FilePath, (FilePath, Maybe Entry))] - -- A Chapter includes a list of blocks and maybe a section -- number offset. Note, some chapters are unnumbered. The section -- number is different from the index number, which will be used @@ -77,7 +75,7 @@ data Chapter = Chapter (Maybe [Int]) [Block] data EPUBState = EPUBState { stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))] } -type E = StateT EPUBState EPUBAction +type E = StateT EPUBState PandocAction data EPUBMetadata = EPUBMetadata{ epubIdentifier :: [Identifier] @@ -343,7 +341,7 @@ writeEPUB opts doc = runIO $ writeEPUBPure opts doc writeEPUBPure :: WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> EPUBAction B.ByteString + -> PandocAction B.ByteString writeEPUBPure opts doc = let initState = EPUBState { stMediaPaths = [] } @@ -398,7 +396,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do picEntries <- (catMaybes . map (snd . snd)) <$> (gets stMediaPaths) -- handle fonts let matchingGlob f = do - xs <- lift $ P.namesMatching f + xs <- lift $ P.glob f when (null xs) $ lift $ P.warn $ f ++ " did not match any font files." return xs diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 3a1e772ce..186bf0c8d 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -28,11 +28,9 @@ import Data.Text as Text (breakOnAll, pack) import Control.Monad.State import Network.URI (isURI) import qualified Data.Set as Set -import Text.Pandoc.Free (runIO) +import Text.Pandoc.Free (runIO, PandocAction) import qualified Text.Pandoc.Free as P -type ICMLAction = P.PandocAction () - type Style = [String] type Hyperlink = [(Int, String)] @@ -44,7 +42,7 @@ data WriterState = WriterState{ , maxListDepth :: Int } -type WS a = StateT WriterState ICMLAction a +type WS a = StateT WriterState PandocAction a defaultWriterState :: WriterState defaultWriterState = WriterState{ @@ -130,7 +128,7 @@ writeICML :: WriterOptions -> Pandoc -> IO String writeICML opts doc = runIO $ writeICMLPure opts doc -- | Convert Pandoc document to string in ICML format. -writeICMLPure :: WriterOptions -> Pandoc -> ICMLAction String +writeICMLPure :: WriterOptions -> Pandoc -> PandocAction String writeICMLPure opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index b139695db..561230b15 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -53,12 +53,10 @@ import System.FilePath ( takeExtension, takeDirectory, (<.>)) import Text.Pandoc.Free ( PandocAction, runIO ) import qualified Text.Pandoc.Free as P -type ODTAction = PandocAction [Entry] - data ODTState = ODTState { stEntries :: [Entry] } -type O = StateT ODTState ODTAction +type O = StateT ODTState PandocAction -- | Produce an ODT file from a Pandoc document. writeODT :: WriterOptions -- ^ Writer options @@ -68,7 +66,7 @@ writeODT opts doc = runIO $ writeODTPure opts doc writeODTPure :: WriterOptions -> Pandoc - -> ODTAction B.ByteString + -> PandocAction B.ByteString writeODTPure opts doc = let initState = ODTState{ stEntries = [] } -- cgit v1.2.3 From 9ac1303660bc271054137d313b2c54bae60a59d4 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Thu, 17 Nov 2016 13:22:39 -0500 Subject: Make pure rtf writer using free. --- src/Text/Pandoc/Writers/RTF.hs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 6ca749a10..8d7c643e0 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -27,7 +27,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to RTF (rich text format). -} -module Text.Pandoc.Writers.RTF ( writeRTF, writeRTFWithEmbeddedImages ) where +module Text.Pandoc.Writers.RTF ( writeRTF + , writeRTFWithEmbeddedImages + , writeRTFWithEmbeddedImagesPure + ) where import Text.Pandoc.Definition import Text.Pandoc.Options import Text.Pandoc.Shared @@ -41,13 +44,15 @@ import qualified Data.ByteString as B import qualified Data.Map as M import Text.Printf ( printf ) import Text.Pandoc.ImageSize +import Text.Pandoc.Free (PandocAction, runIO) +import qualified Text.Pandoc.Free as P -- | Convert Image inlines into a raw RTF embedded image, read from a file, -- or a MediaBag, or the internet. -- If file not found or filetype not jpeg or png, leave the inline unchanged. -rtfEmbedImage :: WriterOptions -> Inline -> IO Inline +rtfEmbedImage :: WriterOptions -> Inline -> PandocAction Inline rtfEmbedImage opts x@(Image attr _ (src,_)) = do - result <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + result <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case result of Right (imgdata, Just mime) | mime == "image/jpeg" || mime == "image/png" -> do @@ -58,7 +63,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do _ -> error "Unknown file type" sizeSpec <- case imageSize imgdata of Left msg -> do - warn $ "Could not determine image size in `" ++ + P.warn $ "Could not determine image size in `" ++ src ++ "': " ++ msg return "" Right sz -> return $ "\\picw" ++ show xpx ++ @@ -80,6 +85,10 @@ rtfEmbedImage _ x = return x -- images embedded as encoded binary data. writeRTFWithEmbeddedImages :: WriterOptions -> Pandoc -> IO String writeRTFWithEmbeddedImages options doc = + runIO $ writeRTF options `fmap` walkM (rtfEmbedImage options) doc + +writeRTFWithEmbeddedImagesPure :: WriterOptions -> Pandoc -> PandocAction String +writeRTFWithEmbeddedImagesPure options doc = writeRTF options `fmap` walkM (rtfEmbedImage options) doc -- | Convert Pandoc to a string in rich text format. -- cgit v1.2.3 From d97fb5f3c600e9171bb80a7dde358282580da9ea Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 18 Nov 2016 06:18:12 -0500 Subject: FB2 writer: bring functions to toplevel. This is the first of a number of changes to bring the FB2 writer a bit closer to the idioms used elsewhere in pandoc, so it can be more easily converted to using the pure functions from Free. --- src/Text/Pandoc/Writers/FB2.hs | 100 ++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 47 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 8c4817ac6..70044bd96 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -94,53 +94,59 @@ writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do xlink = "http://www.w3.org/1999/xlink" in [ uattr "xmlns" xmlns , attr ("xmlns", "l") xlink ] - -- - frontpage :: Meta -> FBM [Content] - frontpage meta' = do - t <- cMapM toXml . docTitle $ meta' - return $ - [ el "title" (el "p" t) - , el "annotation" (map (el "p" . cMap plain) - (docAuthors meta' ++ [docDate meta'])) - ] - description :: Meta -> FBM Content - description meta' = do - bt <- booktitle meta' - let as = authors meta' - dd <- docdate meta' - return $ el "description" - [ el "title-info" (bt ++ as ++ dd) - , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version - ] - booktitle :: Meta -> FBM [Content] - booktitle meta' = do - t <- cMapM toXml . docTitle $ meta' - return $ if null t - then [] - else [ el "book-title" t ] - authors :: Meta -> [Content] - authors meta' = cMap author (docAuthors meta') - author :: [Inline] -> [Content] - author ss = - let ws = words . cMap plain $ ss - email = (el "email") `fmap` (take 1 $ filter ('@' `elem`) ws) - ws' = filter ('@' `notElem`) ws - names = case ws' of - (nickname:[]) -> [ el "nickname" nickname ] - (fname:lname:[]) -> [ el "first-name" fname - , el "last-name" lname ] - (fname:rest) -> [ el "first-name" fname - , el "middle-name" (concat . init $ rest) - , el "last-name" (last rest) ] - ([]) -> [] - in list $ el "author" (names ++ email) - docdate :: Meta -> FBM [Content] - docdate meta' = do - let ss = docDate meta' - d <- cMapM toXml ss - return $ if null d - then [] - else [el "date" d] + + +frontpage :: Meta -> FBM [Content] +frontpage meta' = do + t <- cMapM toXml . docTitle $ meta' + return $ + [ el "title" (el "p" t) + , el "annotation" (map (el "p" . cMap plain) + (docAuthors meta' ++ [docDate meta'])) + ] + +description :: Meta -> FBM Content +description meta' = do + bt <- booktitle meta' + let as = authors meta' + dd <- docdate meta' + return $ el "description" + [ el "title-info" (bt ++ as ++ dd) + , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version + ] + +booktitle :: Meta -> FBM [Content] +booktitle meta' = do + t <- cMapM toXml . docTitle $ meta' + return $ if null t + then [] + else [ el "book-title" t ] + +authors :: Meta -> [Content] +authors meta' = cMap author (docAuthors meta') + +author :: [Inline] -> [Content] +author ss = + let ws = words . cMap plain $ ss + email = (el "email") `fmap` (take 1 $ filter ('@' `elem`) ws) + ws' = filter ('@' `notElem`) ws + names = case ws' of + (nickname:[]) -> [ el "nickname" nickname ] + (fname:lname:[]) -> [ el "first-name" fname + , el "last-name" lname ] + (fname:rest) -> [ el "first-name" fname + , el "middle-name" (concat . init $ rest) + , el "last-name" (last rest) ] + ([]) -> [] + in list $ el "author" (names ++ email) + +docdate :: Meta -> FBM [Content] +docdate meta' = do + let ss = docDate meta' + d <- cMapM toXml ss + return $ if null d + then [] + else [el "date" d] -- | Divide the stream of blocks into sections and convert to XML -- representation. -- cgit v1.2.3 From 30cfda7a71cd8397dc8d19c9b53bed39d5c1afa1 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 18 Nov 2016 09:41:36 -0500 Subject: Continue refactoring FB2 writer. --- src/Text/Pandoc/Writers/FB2.hs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 70044bd96..41ad9bb2d 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -76,8 +76,13 @@ instance Show ImageMode where writeFB2 :: WriterOptions -- ^ conversion options -> Pandoc -- ^ document to convert -> IO String -- ^ FictionBook2 document (not encoded yet) -writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do - modify (\s -> s { writerOptions = opts }) +writeFB2 opts doc = flip evalStateT newFB $ pandocToFB2 opts doc + +pandocToFB2 :: WriterOptions + -> Pandoc + -> FBM String +pandocToFB2 opts (Pandoc meta blocks) = do + modify (\s -> s { writerOptions = opts { writerOptions = opts } }) desc <- description meta fp <- frontpage meta secs <- renderSections 1 blocks @@ -95,7 +100,6 @@ writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do in [ uattr "xmlns" xmlns , attr ("xmlns", "l") xlink ] - frontpage :: Meta -> FBM [Content] frontpage meta' = do t <- cMapM toXml . docTitle $ meta' @@ -250,11 +254,13 @@ fetchImage href link = do , uattr "content-type" imgtype] , txt imgdata ) _ -> return (Left ('#':href)) - where - nothingOnError :: (IO B.ByteString) -> (IO (Maybe B.ByteString)) - nothingOnError action = liftM Just action `E.catch` omnihandler - omnihandler :: E.SomeException -> IO (Maybe B.ByteString) - omnihandler _ = return Nothing + + +nothingOnError :: (IO B.ByteString) -> (IO (Maybe B.ByteString)) +nothingOnError action = liftM Just action `E.catch` omnihandler + +omnihandler :: E.SomeException -> IO (Maybe B.ByteString) +omnihandler _ = return Nothing -- | Extract mime type and encoded data from the Data URI. readDataURI :: String -- ^ URI -- cgit v1.2.3 From e711043dee212ced02323591623261ef743c5f2a Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 18 Nov 2016 16:35:36 -0500 Subject: FB2 writer: Rewrite image-fetching to use fetchItem. This uses the function from shared, which will allow us to convert it over to the free monad. --- src/Text/Pandoc/Writers/FB2.hs | 54 +++++++++--------------------------------- 1 file changed, 11 insertions(+), 43 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 41ad9bb2d..f03fe5c7e 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -28,26 +28,23 @@ FictionBook is an XML-based e-book format. For more information see: module Text.Pandoc.Writers.FB2 (writeFB2) where import Control.Monad.State (StateT, evalStateT, get, modify) -import Control.Monad.State (liftM, liftM2, liftIO) +import Control.Monad.State (liftM, liftIO) import Data.ByteString.Base64 (encode) import Data.Char (toLower, isSpace, isAscii, isControl) import Data.List (intersperse, intercalate, isPrefixOf, stripPrefix) import Data.Either (lefts, rights) -import Network.Browser (browse, request, setAllowRedirects, setOutHandler) -import Network.HTTP (catchIO_, getRequest, getHeaders, getResponseBody) -import Network.HTTP (lookupHeader, HeaderName(..), urlEncode) -import Network.URI (isURI, unEscapeString) -import System.FilePath (takeExtension) +import Network.HTTP (urlEncode) +import Network.URI (isURI) import Text.XML.Light -import qualified Control.Exception as E -import qualified Data.ByteString as B import qualified Text.XML.Light as X import qualified Text.XML.Light.Cursor as XC +import qualified Data.ByteString.Char8 as B8 + import Text.Pandoc.Definition import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def) import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize, - linesToPara) + linesToPara, fetchItem) -- | Data to be written at the end of the document: -- (foot)notes, URLs, references, images. @@ -237,16 +234,11 @@ fetchImage href link = do then return (Just (mime',base64)) else return Nothing (True, Just _) -> return Nothing -- not base64-encoded - (True, Nothing) -> fetchURL link - (False, _) -> do - d <- nothingOnError $ B.readFile (unEscapeString link) - let t = case map toLower (takeExtension link) of - ".png" -> Just "image/png" - ".jpg" -> Just "image/jpeg" - ".jpeg" -> Just "image/jpeg" - ".jpe" -> Just "image/jpeg" - _ -> Nothing -- only PNG and JPEG are supported in FB2 - return $ liftM2 (,) t (liftM (toStr . encode) d) + _ -> do + response <- fetchItem Nothing link + case response of + Right (bs, Just mime) -> return $ Just (mime, B8.unpack $ encode bs) + _ -> return $ Nothing case mbimg of Just (imgtype, imgdata) -> do return . Right $ el "binary" @@ -256,12 +248,6 @@ fetchImage href link = do _ -> return (Left ('#':href)) -nothingOnError :: (IO B.ByteString) -> (IO (Maybe B.ByteString)) -nothingOnError action = liftM Just action `E.catch` omnihandler - -omnihandler :: E.SomeException -> IO (Maybe B.ByteString) -omnihandler _ = return Nothing - -- | Extract mime type and encoded data from the Data URI. readDataURI :: String -- ^ URI -> Maybe (String,String,Bool,String) @@ -298,24 +284,6 @@ isMimeType s = valid c = isAscii c && not (isControl c) && not (isSpace c) && c `notElem` "()<>@,;:\\\"/[]?=" --- | Fetch URL, return its Content-Type and binary data on success. -fetchURL :: String -> IO (Maybe (String, String)) -fetchURL url = do - flip catchIO_ (return Nothing) $ do - r <- browse $ do - setOutHandler (const (return ())) - setAllowRedirects True - liftM snd . request . getRequest $ url - let content_type = lookupHeader HdrContentType (getHeaders r) - content <- liftM (Just . toStr . encode . toBS) . getResponseBody $ Right r - return $ liftM2 (,) content_type content - -toBS :: String -> B.ByteString -toBS = B.pack . map (toEnum . fromEnum) - -toStr :: B.ByteString -> String -toStr = map (toEnum . fromEnum) . B.unpack - footnoteID :: Int -> String footnoteID i = "n" ++ (show i) -- cgit v1.2.3 From 2ea3e77172837505f021ae014c898a244bd9c436 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 18 Nov 2016 16:54:15 -0500 Subject: Finish pure writer of FB2. --- src/Text/Pandoc/Writers/FB2.hs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index f03fe5c7e..3c4970e75 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -25,10 +25,10 @@ FictionBook is an XML-based e-book format. For more information see: -} -module Text.Pandoc.Writers.FB2 (writeFB2) where +module Text.Pandoc.Writers.FB2 (writeFB2, writeFB2Pure) where -import Control.Monad.State (StateT, evalStateT, get, modify) -import Control.Monad.State (liftM, liftIO) +import Control.Monad.State (StateT, evalStateT, get, modify, lift) +import Control.Monad.State (liftM) import Data.ByteString.Base64 (encode) import Data.Char (toLower, isSpace, isAscii, isControl) import Data.List (intersperse, intercalate, isPrefixOf, stripPrefix) @@ -44,7 +44,9 @@ import qualified Data.ByteString.Char8 as B8 import Text.Pandoc.Definition import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def) import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize, - linesToPara, fetchItem) + linesToPara) +import Text.Pandoc.Free (PandocAction, runIO) +import qualified Text.Pandoc.Free as P -- | Data to be written at the end of the document: -- (foot)notes, URLs, references, images. @@ -57,7 +59,7 @@ data FbRenderState = FbRenderState } deriving (Show) -- | FictionBook building monad. -type FBM = StateT FbRenderState IO +type FBM = StateT FbRenderState PandocAction newFB :: FbRenderState newFB = FbRenderState { footnotes = [], imagesToFetch = [] @@ -73,7 +75,12 @@ instance Show ImageMode where writeFB2 :: WriterOptions -- ^ conversion options -> Pandoc -- ^ document to convert -> IO String -- ^ FictionBook2 document (not encoded yet) -writeFB2 opts doc = flip evalStateT newFB $ pandocToFB2 opts doc +writeFB2 opts doc = runIO $ writeFB2Pure opts doc + +writeFB2Pure :: WriterOptions + -> Pandoc + -> PandocAction String +writeFB2Pure opts doc = flip evalStateT newFB $ pandocToFB2 opts doc pandocToFB2 :: WriterOptions -> Pandoc @@ -85,7 +92,7 @@ pandocToFB2 opts (Pandoc meta blocks) = do secs <- renderSections 1 blocks let body = el "body" $ fp ++ secs notes <- renderFootnotes - (imgs,missing) <- liftM imagesToFetch get >>= \s -> liftIO (fetchImages s) + (imgs,missing) <- liftM imagesToFetch get >>= \s -> lift (fetchImages s) let body' = replaceImagesWithAlt missing body let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs) return $ xml_head ++ (showContent fb2_xml) ++ "\n" @@ -217,14 +224,14 @@ renderFootnotes = do -- | Fetch images and encode them for the FictionBook XML. -- Return image data and a list of hrefs of the missing images. -fetchImages :: [(String,String)] -> IO ([Content],[String]) +fetchImages :: [(String,String)] -> PandocAction ([Content],[String]) fetchImages links = do imgs <- mapM (uncurry fetchImage) links return $ (rights imgs, lefts imgs) -- | Fetch image data from disk or from network and make a XML section. -- Return either (Left hrefOfMissingImage) or (Right xmlContent). -fetchImage :: String -> String -> IO (Either String Content) +fetchImage :: String -> String -> PandocAction (Either String Content) fetchImage href link = do mbimg <- case (isURI link, readDataURI link) of @@ -235,7 +242,7 @@ fetchImage href link = do else return Nothing (True, Just _) -> return Nothing -- not base64-encoded _ -> do - response <- fetchItem Nothing link + response <- P.fetchItem Nothing link case response of Right (bs, Just mime) -> return $ Just (mime, B8.unpack $ encode bs) _ -> return $ Nothing -- cgit v1.2.3 From 1c589c51b13aa6833cf6246b514ce8ddadf25dd5 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 18 Nov 2016 20:54:43 -0500 Subject: ODT Writer: fix compiler complaint. --- src/Text/Pandoc/Writers/ODT.hs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 561230b15..abd403cc9 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -44,7 +44,6 @@ import Text.Pandoc.Definition import Text.Pandoc.Walk import Text.Pandoc.Writers.Shared ( fixDisplayMath ) import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) -import Control.Monad (liftM) import Control.Monad.State import Text.Pandoc.XML import Text.Pandoc.Pretty -- cgit v1.2.3 From c9e67163fd08f7eb1ef18aed47d7fab4614653b6 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 19 Nov 2016 05:42:00 -0500 Subject: Remove IO UUID functions. --- src/Text/Pandoc/Free.hs | 16 ---------------- src/Text/Pandoc/Writers/EPUB.hs | 3 ++- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Free.hs b/src/Text/Pandoc/Free.hs index 33cb50c88..071482e32 100644 --- a/src/Text/Pandoc/Free.hs +++ b/src/Text/Pandoc/Free.hs @@ -45,7 +45,6 @@ module Text.Pandoc.Free ( PandocActionF(..) , getDefaultReferenceODT , newStdGen , newUniqueHash - , newUUID , readFileStrict , readFileLazy , readFileUTF8 @@ -81,8 +80,6 @@ import qualified Data.ByteString.Lazy as BL import Control.Monad.Free import qualified Control.Exception as E import qualified System.Environment as IO (lookupEnv) -import Text.Pandoc.UUID -import qualified Text.Pandoc.UUID as IO (getRandomUUID) import qualified Text.Pandoc.UTF8 as UTF8 (readFile, toString) import System.FilePath.Glob (match, compile) import System.FilePath (()) @@ -100,7 +97,6 @@ data PandocActionF nxt = | GetDefaultReferenceODT (Maybe FilePath) (Archive -> nxt) | NewStdGen (StdGen -> nxt) | NewUniqueHash (Int -> nxt) - | NewUUID (UUID -> nxt) | ReadFileStrict FilePath (B.ByteString -> nxt) | ReadFileLazy FilePath (BL.ByteString -> nxt) | ReadFileUTF8 FilePath (String -> nxt) @@ -137,9 +133,6 @@ newStdGen = liftF $ NewStdGen id newUniqueHash :: PandocAction Int newUniqueHash = liftF $ NewUniqueHash id -newUUID :: PandocAction UUID -newUUID = liftF $ NewUUID id - readFileStrict :: FilePath -> PandocAction B.ByteString readFileStrict fp = liftF $ ReadFileStrict fp id @@ -183,7 +176,6 @@ runIO (Free (GetDefaultReferenceODT mfp f)) = IO.getDefaultReferenceODT mfp >>= runIO . f runIO (Free (NewStdGen f)) = IO.newStdGen >>= runIO . f runIO (Free (NewUniqueHash f)) = hashUnique <$> IO.newUnique >>= runIO . f -runIO (Free (NewUUID f)) = IO.getRandomUUID >>= runIO . f runIO (Free (ReadFileStrict fp f)) = B.readFile fp >>= runIO . f runIO (Free (ReadFileLazy fp f)) = BL.readFile fp >>= runIO . f runIO (Free (ReadFileUTF8 fp f)) = UTF8.readFile fp >>= runIO . f @@ -250,14 +242,6 @@ runTest (Free (NewUniqueHash f)) = do modify $ \st -> st { stUniqStore = us } return u >>= runTest . f _ -> M.fail "uniq store ran out of elements" -runTest (Free (NewUUID f)) = do - word8s <- gets stWord8Store - case word8s of - -- note we use f' because f is a param of the function - a:b:c:d:e:f':g:h:i:j:k:l:m:n:o:p:remaining -> do - modify $ \st -> st { stWord8Store = remaining } - return (UUID a b c d e f' g h i j k l m n o p) >>= runTest . f - _ -> M.fail "word8 supply was not infinite" runTest (Free (ReadFileStrict fp f)) = do fps <- asks envFiles case lookup fp fps of diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 435893443..35724dfef 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -53,6 +53,7 @@ import Text.Pandoc.Options ( WriterOptions(..) , ObfuscationMethod(NoObfuscation) ) 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 Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs @@ -152,7 +153,7 @@ getEPUBMetadata opts meta = do let addIdentifier m = if null (epubIdentifier m) then do - randomId <- fmap show (lift P.newUUID) + randomId <- (show . getUUID) <$> lift P.newStdGen return $ m{ epubIdentifier = [Identifier randomId Nothing] } else return m let addLanguage m = -- cgit v1.2.3 From 314a4c7296029753872164428667c63642762901 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 19 Nov 2016 05:57:33 -0500 Subject: Remove readFileStrict. We only used it once, and then immediately converted to lazy. --- src/Text/Pandoc/Free.hs | 13 +------------ src/Text/Pandoc/Writers/Docx.hs | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Free.hs b/src/Text/Pandoc/Free.hs index 071482e32..4294384d4 100644 --- a/src/Text/Pandoc/Free.hs +++ b/src/Text/Pandoc/Free.hs @@ -45,7 +45,6 @@ module Text.Pandoc.Free ( PandocActionF(..) , getDefaultReferenceODT , newStdGen , newUniqueHash - , readFileStrict , readFileLazy , readFileUTF8 , readDataFile @@ -97,7 +96,6 @@ data PandocActionF nxt = | GetDefaultReferenceODT (Maybe FilePath) (Archive -> nxt) | NewStdGen (StdGen -> nxt) | NewUniqueHash (Int -> nxt) - | ReadFileStrict FilePath (B.ByteString -> nxt) | ReadFileLazy FilePath (BL.ByteString -> nxt) | ReadFileUTF8 FilePath (String -> nxt) | ReadDataFile (Maybe FilePath) FilePath (B.ByteString -> nxt) @@ -133,9 +131,6 @@ newStdGen = liftF $ NewStdGen id newUniqueHash :: PandocAction Int newUniqueHash = liftF $ NewUniqueHash id -readFileStrict :: FilePath -> PandocAction B.ByteString -readFileStrict fp = liftF $ ReadFileStrict fp id - readFileLazy :: FilePath -> PandocAction BL.ByteString readFileLazy fp = liftF $ ReadFileLazy fp id @@ -176,7 +171,6 @@ runIO (Free (GetDefaultReferenceODT mfp f)) = IO.getDefaultReferenceODT mfp >>= runIO . f runIO (Free (NewStdGen f)) = IO.newStdGen >>= runIO . f runIO (Free (NewUniqueHash f)) = hashUnique <$> IO.newUnique >>= runIO . f -runIO (Free (ReadFileStrict fp f)) = B.readFile fp >>= runIO . f runIO (Free (ReadFileLazy fp f)) = BL.readFile fp >>= runIO . f runIO (Free (ReadFileUTF8 fp f)) = UTF8.readFile fp >>= runIO . f runIO (Free (ReadDataFile mfp fp f)) = IO.readDataFile mfp fp >>= runIO . f @@ -242,11 +236,6 @@ runTest (Free (NewUniqueHash f)) = do modify $ \st -> st { stUniqStore = us } return u >>= runTest . f _ -> M.fail "uniq store ran out of elements" -runTest (Free (ReadFileStrict fp f)) = do - fps <- asks envFiles - case lookup fp fps of - Just bs -> return bs >>= runTest . f - Nothing -> error "openFile: does not exist" runTest (Free (ReadFileLazy fp f)) = do fps <- asks envFiles case lookup fp fps of @@ -269,7 +258,7 @@ runTest (Free (ReadDataFile Nothing "reference.odt" f)) = do runTest . f runTest (Free (ReadDataFile Nothing fname f)) = do let fname' = if fname == "MANUAL.txt" then fname else "data" fname - runTest (readFileStrict fname') >>= runTest . f + runTest (BL.toStrict <$> readFileLazy fname') >>= runTest . f runTest (Free (ReadDataFile (Just userDir) fname f)) = do userDirFiles <- asks envUserDataDir case lookup (userDir fname) userDirFiles of diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 3f380a3ee..07041f189 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -232,7 +232,7 @@ writeDocxPure opts doc@(Pandoc meta _) = do utctime <- P.getCurrentTime distArchive <- P.getDefaultReferenceDocx datadir refArchive <- case writerReferenceDocx opts of - Just f -> liftM (toArchive . toLazy) $ P.readFileStrict f + Just f -> toArchive <$> P.readFileLazy f Nothing -> P.getDefaultReferenceDocx datadir parsedDoc <- parseXml refArchive distArchive "word/document.xml" -- cgit v1.2.3 From 2ffd630a43749794bf72591f41d6b523676bd5b1 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 19 Nov 2016 06:03:54 -0500 Subject: Free: Remove readFileUTF8. This is just defined in term of a bytestring, so we convert when necessary. --- src/Text/Pandoc/Free.hs | 12 ------------ src/Text/Pandoc/Writers/EPUB.hs | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Free.hs b/src/Text/Pandoc/Free.hs index 4294384d4..3a62270a7 100644 --- a/src/Text/Pandoc/Free.hs +++ b/src/Text/Pandoc/Free.hs @@ -46,7 +46,6 @@ module Text.Pandoc.Free ( PandocActionF(..) , newStdGen , newUniqueHash , readFileLazy - , readFileUTF8 , readDataFile , fetchItem , fetchItem' @@ -79,7 +78,6 @@ import qualified Data.ByteString.Lazy as BL import Control.Monad.Free import qualified Control.Exception as E import qualified System.Environment as IO (lookupEnv) -import qualified Text.Pandoc.UTF8 as UTF8 (readFile, toString) import System.FilePath.Glob (match, compile) import System.FilePath (()) import qualified System.FilePath.Glob as IO (glob) @@ -97,7 +95,6 @@ data PandocActionF nxt = | NewStdGen (StdGen -> nxt) | NewUniqueHash (Int -> nxt) | ReadFileLazy FilePath (BL.ByteString -> nxt) - | ReadFileUTF8 FilePath (String -> nxt) | ReadDataFile (Maybe FilePath) FilePath (B.ByteString -> nxt) | FetchItem (Maybe String) (String) (Either E.SomeException (B.ByteString, Maybe MimeType) -> nxt) @@ -134,9 +131,6 @@ newUniqueHash = liftF $ NewUniqueHash id readFileLazy :: FilePath -> PandocAction BL.ByteString readFileLazy fp = liftF $ ReadFileLazy fp id -readFileUTF8 :: FilePath -> PandocAction String -readFileUTF8 fp = liftF $ ReadFileUTF8 fp id - readDataFile :: Maybe FilePath -> FilePath -> PandocAction B.ByteString readDataFile mfp fp = liftF $ ReadDataFile mfp fp id @@ -172,7 +166,6 @@ runIO (Free (GetDefaultReferenceODT mfp f)) = runIO (Free (NewStdGen f)) = IO.newStdGen >>= runIO . f runIO (Free (NewUniqueHash f)) = hashUnique <$> IO.newUnique >>= runIO . f runIO (Free (ReadFileLazy fp f)) = BL.readFile fp >>= runIO . f -runIO (Free (ReadFileUTF8 fp f)) = UTF8.readFile fp >>= runIO . f runIO (Free (ReadDataFile mfp fp f)) = IO.readDataFile mfp fp >>= runIO . f runIO (Free (Fail s)) = M.fail s runIO (Free (FetchItem sourceUrl nm f)) = @@ -241,11 +234,6 @@ runTest (Free (ReadFileLazy fp f)) = do case lookup fp fps of Just bs -> return (BL.fromStrict bs) >>= runTest . f Nothing -> error "openFile: does not exist" -runTest (Free (ReadFileUTF8 fp f)) = do - fps <- asks envFiles - case lookup fp fps of - Just bs -> return (UTF8.toString bs) >>= runTest . f - Nothing -> error "openFile: does not exist" -- A few different cases of readDataFile to reimplement, for when -- there is no filepath and it falls through to readDefaultDataFile runTest (Free (ReadDataFile Nothing "reference.docx" f)) = do diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 35724dfef..a0991e27b 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -710,7 +710,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do -- stylesheet stylesheet <- case epubStylesheet metadata of - Just (StylesheetPath fp) -> lift $ P.readFileUTF8 fp + Just (StylesheetPath fp) -> UTF8.toStringLazy <$> (lift $ P.readFileLazy fp) Just (StylesheetContents s) -> return s Nothing -> UTF8.toString `fmap` (lift $ P.readDataFile (writerUserDataDir opts) "epub.css") -- cgit v1.2.3 From 957eee24ec9037a31574503fa1ca939567f23a90 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Mon, 21 Nov 2016 10:12:42 -0500 Subject: Convert writers to use PandocMonad typeclass. Instead of Free Monad with runIO --- src/Text/Pandoc/Writers/Docx.hs | 82 +++++++++++++++++++---------------------- src/Text/Pandoc/Writers/EPUB.hs | 49 ++++++++++++------------ src/Text/Pandoc/Writers/FB2.hs | 57 ++++++++++++++-------------- src/Text/Pandoc/Writers/ICML.hs | 36 ++++++++---------- src/Text/Pandoc/Writers/ODT.hs | 27 ++++++-------- src/Text/Pandoc/Writers/RTF.hs | 13 ++----- 6 files changed, 122 insertions(+), 142 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 07041f189..36816eaa1 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to docx. -} -module Text.Pandoc.Writers.Docx ( writeDocx, writeDocxPure ) where +module Text.Pandoc.Writers.Docx ( writeDocx ) where import Data.List ( intercalate, isPrefixOf, isSuffixOf ) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL @@ -65,8 +65,8 @@ import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef, import Control.Applicative ((<|>)) import Data.Maybe (fromMaybe, mapMaybe, maybeToList, isNothing) import Data.Char (ord, isSpace, toLower) -import Text.Pandoc.Free (PandocAction, runIO) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class (PandocMonad) +import qualified Text.Pandoc.Class as P data ListMarker = NoMarker | BulletMarker @@ -146,7 +146,7 @@ defaultWriterState = WriterState{ , stDynamicTextProps = [] } -type WS = ReaderT WriterEnv (StateT WriterState (PandocAction)) +type WS m = ReaderT WriterEnv (StateT WriterState m) mknode :: Node t => String -> [(String,String)] -> t -> Element mknode s attrs = @@ -215,17 +215,11 @@ metaValueToInlines _ = [] -writeDocx :: WriterOptions -- ^ Writer options +writeDocx :: (PandocMonad m) + => WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> IO BL.ByteString -writeDocx opts doc = runIO $ writeDocxPure opts doc - - --- | Produce an Docx file from a Pandoc document. -writeDocxPure :: WriterOptions -- ^ Writer options - -> Pandoc -- ^ Document to convert - -> PandocAction BL.ByteString -writeDocxPure opts doc@(Pandoc meta _) = do + -> m BL.ByteString +writeDocx opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let doc' = walk fixDisplayMath $ doc username <- P.lookupEnv "USERNAME" @@ -611,7 +605,7 @@ styleToOpenXml sm style = $ backgroundColor style ) ] -copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> PandocAction Entry +copyChildren :: (PandocMonad m) => Archive -> Archive -> String -> Integer -> [String] -> m Entry copyChildren refArchive distArchive path timestamp elNames = do ref <- parseXml refArchive distArchive path dist <- parseXml distArchive distArchive path @@ -630,7 +624,7 @@ copyChildren refArchive distArchive path timestamp elNames = do baseListId :: Int baseListId = 1000 -mkNumbering :: [ListMarker] -> PandocAction [Element] +mkNumbering :: (PandocMonad m) => [ListMarker] -> m [Element] mkNumbering lists = do elts <- mapM mkAbstractNum (ordNub lists) return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)] @@ -646,7 +640,7 @@ mkNum marker numid = map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))] $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6] -mkAbstractNum :: ListMarker -> PandocAction Element +mkAbstractNum :: (PandocMonad m) => ListMarker -> m Element mkAbstractNum marker = do gen <- P.newStdGen let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen @@ -701,11 +695,11 @@ mkLvl marker lvl = patternFor TwoParens s = "(" ++ s ++ ")" patternFor _ s = s ++ "." -getNumId :: WS Int +getNumId :: (PandocMonad m) => WS m Int getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists -makeTOC :: WriterOptions -> WS [Element] +makeTOC :: (PandocMonad m) => WriterOptions -> WS m [Element] makeTOC opts | writerTableOfContents opts = do let depth = "1-"++(show (writerTOCDepth opts)) let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u" @@ -735,7 +729,7 @@ makeTOC _ = return [] -- | Convert Pandoc document to two lists of -- OpenXML elements (the main document and footnotes). -writeOpenXML :: WriterOptions -> Pandoc -> WS ([Element], [Element]) +writeOpenXML :: (PandocMonad m) => WriterOptions -> Pandoc -> WS m ([Element], [Element]) writeOpenXML opts (Pandoc meta blocks) = do let tit = docTitle meta ++ case lookupMeta "subtitle" meta of Just (MetaBlocks [Plain xs]) -> LineBreak : xs @@ -770,13 +764,13 @@ writeOpenXML opts (Pandoc meta blocks) = do return (meta' ++ doc', notes') -- | Convert a list of Pandoc blocks to OpenXML. -blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element] +blocksToOpenXML :: (PandocMonad m) => WriterOptions -> [Block] -> WS m [Element] blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls pCustomStyle :: String -> Element pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] () -pStyleM :: String -> WS XML.Element +pStyleM :: (PandocMonad m) => String -> WS m XML.Element pStyleM styleName = do styleMaps <- gets stStyleMaps let sty' = getStyleId styleName $ sParaStyleMap styleMaps @@ -785,13 +779,13 @@ pStyleM styleName = do rCustomStyle :: String -> Element rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] () -rStyleM :: String -> WS XML.Element +rStyleM :: (PandocMonad m) => String -> WS m XML.Element rStyleM styleName = do styleMaps <- gets stStyleMaps let sty' = getStyleId styleName $ sCharStyleMap styleMaps return $ mknode "w:rStyle" [("w:val",sty')] () -getUniqueId :: PandocAction String +getUniqueId :: (PandocMonad m) => m String -- the + 20 is to ensure that there are no clashes with the rIds -- already in word/document.xml.rel getUniqueId = (show . (+ 20)) <$> P.newUniqueHash @@ -801,10 +795,10 @@ dynamicStyleKey :: String dynamicStyleKey = "custom-style" -- | Convert a Pandoc block element to OpenXML. -blockToOpenXML :: WriterOptions -> Block -> WS [Element] +blockToOpenXML :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element] blockToOpenXML opts blk = withDirection $ blockToOpenXML' opts blk -blockToOpenXML' :: WriterOptions -> Block -> WS [Element] +blockToOpenXML' :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element] blockToOpenXML' _ Null = return [] blockToOpenXML' opts (Div (ident,classes,kvs) bs) | Just sty <- lookup dynamicStyleKey kvs = do @@ -955,7 +949,7 @@ blockToOpenXML' opts (DefinitionList items) = do setFirstPara return l -definitionListItemToOpenXML :: WriterOptions -> ([Inline],[[Block]]) -> WS [Element] +definitionListItemToOpenXML :: (PandocMonad m) => WriterOptions -> ([Inline],[[Block]]) -> WS m [Element] definitionListItemToOpenXML opts (term,defs) = do term' <- withParaProp (pCustomStyle "DefinitionTerm") $ blockToOpenXML opts (Para term) @@ -963,12 +957,12 @@ definitionListItemToOpenXML opts (term,defs) = do $ concat `fmap` mapM (blocksToOpenXML opts) defs return $ term' ++ defs' -addList :: ListMarker -> WS () +addList :: (PandocMonad m) => ListMarker -> WS m () addList marker = do lists <- gets stLists modify $ \st -> st{ stLists = lists ++ [marker] } -listItemToOpenXML :: WriterOptions -> Int -> [Block] -> WS [Element] +listItemToOpenXML :: (PandocMonad m) => WriterOptions -> Int -> [Block] -> WS m [Element] listItemToOpenXML _ _ [] = return [] listItemToOpenXML opts numid (first:rest) = do first' <- withNumId numid $ blockToOpenXML opts first @@ -984,30 +978,30 @@ alignmentToString alignment = case alignment of AlignDefault -> "left" -- | Convert a list of inline elements to OpenXML. -inlinesToOpenXML :: WriterOptions -> [Inline] -> WS [Element] +inlinesToOpenXML :: (PandocMonad m) => WriterOptions -> [Inline] -> WS m [Element] inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst -withNumId :: Int -> WS a -> WS a +withNumId :: (PandocMonad m) => Int -> WS m a -> WS m a withNumId numid = local $ \env -> env{ envListNumId = numid } -asList :: WS a -> WS a +asList :: (PandocMonad m) => WS m a -> WS m a asList = local $ \env -> env{ envListLevel = envListLevel env + 1 } -getTextProps :: WS [Element] +getTextProps :: (PandocMonad m) => WS m [Element] getTextProps = do props <- asks envTextProperties return $ if null props then [] else [mknode "w:rPr" [] props] -withTextProp :: Element -> WS a -> WS a +withTextProp :: PandocMonad m => Element -> WS m a -> WS m a withTextProp d p = local (\env -> env {envTextProperties = d : envTextProperties env}) p -withTextPropM :: WS Element -> WS a -> WS a +withTextPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a withTextPropM = (. flip withTextProp) . (>>=) -getParaProps :: Bool -> WS [Element] +getParaProps :: PandocMonad m => Bool -> WS m [Element] getParaProps displayMathPara = do props <- asks envParaProperties listLevel <- asks envListLevel @@ -1022,14 +1016,14 @@ getParaProps displayMathPara = do [] -> [] ps -> [mknode "w:pPr" [] ps] -withParaProp :: Element -> WS a -> WS a +withParaProp :: PandocMonad m => Element -> WS m a -> WS m a withParaProp d p = local (\env -> env {envParaProperties = d : envParaProperties env}) p -withParaPropM :: WS Element -> WS a -> WS a +withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a withParaPropM = (. flip withParaProp) . (>>=) -formattedString :: String -> WS [Element] +formattedString :: PandocMonad m => String -> WS m [Element] formattedString str = do props <- getTextProps inDel <- asks envInDel @@ -1038,14 +1032,14 @@ formattedString str = do [ mknode (if inDel then "w:delText" else "w:t") [("xml:space","preserve")] (stripInvalidChars str) ] ] -setFirstPara :: WS () +setFirstPara :: PandocMonad m => WS m () setFirstPara = modify $ \s -> s { stFirstPara = True } -- | Convert an inline element to OpenXML. -inlineToOpenXML :: WriterOptions -> Inline -> WS [Element] +inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Element] inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il -inlineToOpenXML' :: WriterOptions -> Inline -> WS [Element] +inlineToOpenXML' :: PandocMonad m => WriterOptions -> Inline -> WS m [Element] inlineToOpenXML' _ (Str str) = formattedString str inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ") inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ") @@ -1281,7 +1275,7 @@ defaultFootnotes = [ mknode "w:footnote" [ mknode "w:r" [] $ [ mknode "w:continuationSeparator" [] ()]]]] -parseXml :: Archive -> Archive -> String -> PandocAction Element +parseXml :: (PandocMonad m) => Archive -> Archive -> String -> m Element parseXml refArchive distArchive relpath = case findEntryByPath relpath refArchive `mplus` findEntryByPath relpath distArchive of @@ -1299,7 +1293,7 @@ fitToPage (x, y) pageWidth (pageWidth, floor $ ((fromIntegral pageWidth) / x) * y) | otherwise = (floor x, floor y) -withDirection :: WS a -> WS a +withDirection :: PandocMonad m => WS m a -> WS m a withDirection x = do isRTL <- asks envRTL paraProps <- asks envParaProperties diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index a0991e27b..397aa5847 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to EPUB. -} -module Text.Pandoc.Writers.EPUB ( writeEPUB, writeEPUBPure ) where +module Text.Pandoc.Writers.EPUB ( writeEPUB ) where import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe ( fromMaybe, catMaybes ) @@ -64,8 +64,8 @@ import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) -import Text.Pandoc.Free (PandocAction, runIO) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class (PandocMonad) +import qualified Text.Pandoc.Class as P -- A Chapter includes a list of blocks and maybe a section -- number offset. Note, some chapters are unnumbered. The section @@ -76,7 +76,7 @@ data Chapter = Chapter (Maybe [Int]) [Block] data EPUBState = EPUBState { stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))] } -type E = StateT EPUBState PandocAction +type E m = StateT EPUBState m data EPUBMetadata = EPUBMetadata{ epubIdentifier :: [Identifier] @@ -145,7 +145,7 @@ removeNote :: Inline -> Inline removeNote (Note _) = Str "" removeNote x = x -getEPUBMetadata :: WriterOptions -> Meta -> E EPUBMetadata +getEPUBMetadata :: PandocMonad m => WriterOptions -> Meta -> E m EPUBMetadata getEPUBMetadata opts meta = do let md = metadataFromMeta opts meta let elts = onlyElems $ parseXML $ writerEpubMetadata opts @@ -335,23 +335,20 @@ metadataFromMeta opts meta = EPUBMetadata{ _ -> Nothing -- | Produce an EPUB file from a Pandoc document. -writeEPUB :: WriterOptions -- ^ Writer options +writeEPUB :: PandocMonad m + => WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> IO B.ByteString -writeEPUB opts doc = runIO $ writeEPUBPure opts doc - -writeEPUBPure :: WriterOptions -- ^ Writer options - -> Pandoc -- ^ Document to convert - -> PandocAction B.ByteString -writeEPUBPure opts doc = + -> m B.ByteString +writeEPUB opts doc = let initState = EPUBState { stMediaPaths = [] } in evalStateT (pandocToEPUB opts doc) initState -pandocToEPUB :: WriterOptions - -> Pandoc - -> E B.ByteString +pandocToEPUB :: PandocMonad m + => WriterOptions + -> Pandoc + -> E m B.ByteString pandocToEPUB opts doc@(Pandoc meta _) = do let version = fromMaybe EPUB2 (writerEpubVersion opts) let epub3 = version == EPUB3 @@ -829,10 +826,11 @@ metadataElement version md currentTime = showDateTimeISO8601 :: UTCTime -> String showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ" -transformTag :: WriterOptions +transformTag :: PandocMonad m + => WriterOptions -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Tag String - -> E (Tag String) + -> E m (Tag String) transformTag opts tag@(TagOpen name attr) | name `elem` ["video", "source", "img", "audio"] && lookup "data-external" attr == Nothing = do @@ -846,9 +844,10 @@ transformTag opts tag@(TagOpen name attr) return $ TagOpen name attr' transformTag _ tag = return tag -modifyMediaRef :: WriterOptions +modifyMediaRef :: PandocMonad m + => WriterOptions -> FilePath - -> E FilePath + -> E m FilePath modifyMediaRef _ "" = return "" modifyMediaRef opts oldsrc = do media <- gets stMediaPaths @@ -872,10 +871,11 @@ modifyMediaRef opts oldsrc = do modify $ \st -> st{ stMediaPaths = (oldsrc, (new, mbEntry)):media} return new -transformBlock :: WriterOptions +transformBlock :: PandocMonad m + => WriterOptions -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media -> Block - -> E Block + -> E m Block transformBlock opts (RawBlock fmt raw) | fmt == Format "html" = do let tags = parseTags raw @@ -883,10 +883,11 @@ transformBlock opts (RawBlock fmt raw) return $ RawBlock fmt (renderTags' tags') transformBlock _ b = return b -transformInline :: WriterOptions +transformInline :: PandocMonad m + => WriterOptions -- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media -> Inline - -> E Inline + -> E m Inline transformInline opts (Image attr lab (src,tit)) = do newsrc <- modifyMediaRef opts src return $ Image attr lab (newsrc, tit) diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 3c4970e75..58bfe7615 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -25,7 +25,7 @@ FictionBook is an XML-based e-book format. For more information see: -} -module Text.Pandoc.Writers.FB2 (writeFB2, writeFB2Pure) where +module Text.Pandoc.Writers.FB2 (writeFB2) where import Control.Monad.State (StateT, evalStateT, get, modify, lift) import Control.Monad.State (liftM) @@ -45,8 +45,8 @@ import Text.Pandoc.Definition import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def) import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize, linesToPara) -import Text.Pandoc.Free (PandocAction, runIO) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class (PandocMonad) +import qualified Text.Pandoc.Class as P -- | Data to be written at the end of the document: -- (foot)notes, URLs, references, images. @@ -59,7 +59,7 @@ data FbRenderState = FbRenderState } deriving (Show) -- | FictionBook building monad. -type FBM = StateT FbRenderState PandocAction +type FBM m = StateT FbRenderState m newFB :: FbRenderState newFB = FbRenderState { footnotes = [], imagesToFetch = [] @@ -72,19 +72,16 @@ instance Show ImageMode where show InlineImage = "inlineImageType" -- | Produce an FB2 document from a 'Pandoc' document. -writeFB2 :: WriterOptions -- ^ conversion options +writeFB2 :: PandocMonad m + => WriterOptions -- ^ conversion options -> Pandoc -- ^ document to convert - -> IO String -- ^ FictionBook2 document (not encoded yet) -writeFB2 opts doc = runIO $ writeFB2Pure opts doc + -> m String -- ^ FictionBook2 document (not encoded yet) +writeFB2 opts doc = flip evalStateT newFB $ pandocToFB2 opts doc -writeFB2Pure :: WriterOptions - -> Pandoc - -> PandocAction String -writeFB2Pure opts doc = flip evalStateT newFB $ pandocToFB2 opts doc - -pandocToFB2 :: WriterOptions +pandocToFB2 :: PandocMonad m + => WriterOptions -> Pandoc - -> FBM String + -> FBM m String pandocToFB2 opts (Pandoc meta blocks) = do modify (\s -> s { writerOptions = opts { writerOptions = opts } }) desc <- description meta @@ -104,7 +101,7 @@ pandocToFB2 opts (Pandoc meta blocks) = do in [ uattr "xmlns" xmlns , attr ("xmlns", "l") xlink ] -frontpage :: Meta -> FBM [Content] +frontpage :: PandocMonad m => Meta -> FBM m [Content] frontpage meta' = do t <- cMapM toXml . docTitle $ meta' return $ @@ -113,7 +110,7 @@ frontpage meta' = do (docAuthors meta' ++ [docDate meta'])) ] -description :: Meta -> FBM Content +description :: PandocMonad m => Meta -> FBM m Content description meta' = do bt <- booktitle meta' let as = authors meta' @@ -123,7 +120,7 @@ description meta' = do , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version ] -booktitle :: Meta -> FBM [Content] +booktitle :: PandocMonad m => Meta -> FBM m [Content] booktitle meta' = do t <- cMapM toXml . docTitle $ meta' return $ if null t @@ -148,7 +145,7 @@ author ss = ([]) -> [] in list $ el "author" (names ++ email) -docdate :: Meta -> FBM [Content] +docdate :: PandocMonad m => Meta -> FBM m [Content] docdate meta' = do let ss = docDate meta' d <- cMapM toXml ss @@ -158,12 +155,12 @@ docdate meta' = do -- | Divide the stream of blocks into sections and convert to XML -- representation. -renderSections :: Int -> [Block] -> FBM [Content] +renderSections :: PandocMonad m => Int -> [Block] -> FBM m [Content] renderSections level blocks = do let secs = splitSections level blocks mapM (renderSection level) secs -renderSection :: Int -> ([Inline], [Block]) -> FBM Content +renderSection :: PandocMonad m => Int -> ([Inline], [Block]) -> FBM m Content renderSection level (ttl, body) = do title <- if null ttl then return [] @@ -210,7 +207,7 @@ splitSections level blocks = reverse $ revSplit (reverse blocks) sameLevel _ = False -- | Make another FictionBook body with footnotes. -renderFootnotes :: FBM [Content] +renderFootnotes :: PandocMonad m => FBM m [Content] renderFootnotes = do fns <- footnotes `liftM` get if null fns @@ -224,14 +221,14 @@ renderFootnotes = do -- | Fetch images and encode them for the FictionBook XML. -- Return image data and a list of hrefs of the missing images. -fetchImages :: [(String,String)] -> PandocAction ([Content],[String]) +fetchImages :: PandocMonad m => [(String,String)] -> m ([Content],[String]) fetchImages links = do imgs <- mapM (uncurry fetchImage) links return $ (rights imgs, lefts imgs) -- | Fetch image data from disk or from network and make a XML section. -- Return either (Left hrefOfMissingImage) or (Right xmlContent). -fetchImage :: String -> String -> PandocAction (Either String Content) +fetchImage :: PandocMonad m => String -> String -> m (Either String Content) fetchImage href link = do mbimg <- case (isURI link, readDataURI link) of @@ -298,7 +295,7 @@ linkID :: Int -> String linkID i = "l" ++ (show i) -- | Convert a block-level Pandoc's element to FictionBook XML representation. -blockToXml :: Block -> FBM [Content] +blockToXml :: PandocMonad m => Block -> FBM m [Content] blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2 blockToXml (Para [Math DisplayMath formula]) = insertMath NormalImage formula -- title beginning with fig: indicates that the image is a figure @@ -362,11 +359,11 @@ blockToXml (Table caption aligns _ headers rows) = do c <- return . el "emphasis" =<< cMapM toXml caption return [el "table" (hd : bd), el "p" c] where - mkrow :: String -> [TableCell] -> [Alignment] -> FBM Content + mkrow :: PandocMonad m => String -> [TableCell] -> [Alignment] -> FBM m Content mkrow tag cells aligns' = (el "tr") `liftM` (mapM (mkcell tag) (zip cells aligns')) -- - mkcell :: String -> (TableCell, Alignment) -> FBM Content + mkcell :: PandocMonad m => String -> (TableCell, Alignment) -> FBM m Content mkcell tag (cell, align) = do cblocks <- cMapM blockToXml cell return $ el tag ([align_attr align], cblocks) @@ -410,7 +407,7 @@ indent = indentBlock in intercalate [LineBreak] $ map ((Str spacer):) lns -- | Convert a Pandoc's Inline element to FictionBook XML representation. -toXml :: Inline -> FBM [Content] +toXml :: PandocMonad m => Inline -> FBM m [Content] toXml (Str s) = return [txt s] toXml (Span _ ils) = cMapM toXml ils toXml (Emph ss) = list `liftM` wrap "emphasis" ss @@ -462,7 +459,7 @@ toXml (Note bs) = do , uattr "type" "note" ] , fn_ref ) -insertMath :: ImageMode -> String -> FBM [Content] +insertMath :: PandocMonad m => ImageMode -> String -> FBM m [Content] insertMath immode formula = do htmlMath <- return . writerHTMLMathMethod . writerOptions =<< get case htmlMath of @@ -473,7 +470,7 @@ insertMath immode formula = do insertImage immode img _ -> return [el "code" formula] -insertImage :: ImageMode -> Inline -> FBM [Content] +insertImage :: PandocMonad m => ImageMode -> Inline -> FBM m [Content] insertImage immode (Image _ alt (url,ttl)) = do images <- imagesToFetch `liftM` get let n = 1 + length images @@ -539,7 +536,7 @@ replaceImagesWithAlt missingHrefs body = -- | Wrap all inlines with an XML tag (given its unqualified name). -wrap :: String -> [Inline] -> FBM Content +wrap :: PandocMonad m => String -> [Inline] -> FBM m Content wrap tagname inlines = el tagname `liftM` cMapM toXml inlines -- " Create a singleton list. diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 186bf0c8d..c82a77452 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -28,8 +28,8 @@ import Data.Text as Text (breakOnAll, pack) import Control.Monad.State import Network.URI (isURI) import qualified Data.Set as Set -import Text.Pandoc.Free (runIO, PandocAction) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class (PandocMonad) +import qualified Text.Pandoc.Class as P type Style = [String] type Hyperlink = [(Int, String)] @@ -42,7 +42,7 @@ data WriterState = WriterState{ , maxListDepth :: Int } -type WS a = StateT WriterState PandocAction a +type WS m = StateT WriterState m defaultWriterState :: WriterState defaultWriterState = WriterState{ @@ -124,12 +124,8 @@ footnoteName = "Footnote" citeName = "Cite" -- | Convert Pandoc document to string in ICML format. -writeICML :: WriterOptions -> Pandoc -> IO String -writeICML opts doc = runIO $ writeICMLPure opts doc - --- | Convert Pandoc document to string in ICML format. -writeICMLPure :: WriterOptions -> Pandoc -> PandocAction String -writeICMLPure opts (Pandoc meta blocks) = do +writeICML :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeICML opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing @@ -288,13 +284,13 @@ hyperlinksToDoc (x:xs) = hyp x $$ hyperlinksToDoc xs -- | Convert a list of Pandoc blocks to ICML. -blocksToICML :: WriterOptions -> Style -> [Block] -> WS Doc +blocksToICML :: PandocMonad m => WriterOptions -> Style -> [Block] -> WS m Doc blocksToICML opts style lst = do docs <- mapM (blockToICML opts style) lst return $ intersperseBrs docs -- | Convert a Pandoc block element to ICML. -blockToICML :: WriterOptions -> Style -> Block -> WS Doc +blockToICML :: PandocMonad m => WriterOptions -> Style -> Block -> WS m Doc blockToICML opts style (Plain lst) = parStyle opts style lst -- title beginning with fig: indicates that the image is a figure blockToICML opts style (Para img@[Image _ txt (_,'f':'i':'g':':':_)]) = do @@ -364,7 +360,7 @@ blockToICML opts style (Div _ lst) = blocksToICML opts style lst blockToICML _ _ Null = return empty -- | Convert a list of lists of blocks to ICML list items. -listItemsToICML :: WriterOptions -> String -> Style -> Maybe ListAttributes -> [[Block]] -> WS Doc +listItemsToICML :: PandocMonad m => WriterOptions -> String -> Style -> Maybe ListAttributes -> [[Block]] -> WS m Doc listItemsToICML _ _ _ _ [] = return empty listItemsToICML opts listType style attribs (first:rest) = do st <- get @@ -379,7 +375,7 @@ listItemsToICML opts listType style attribs (first:rest) = do return $ intersperseBrs docs -- | Convert a list of blocks to ICML list items. -listItemToICML :: WriterOptions -> Style -> Bool-> Maybe ListAttributes -> [Block] -> WS Doc +listItemToICML :: PandocMonad m => WriterOptions -> Style -> Bool-> Maybe ListAttributes -> [Block] -> WS m Doc listItemToICML opts style isFirst attribs item = let makeNumbStart (Just (beginsWith, numbStl, _)) = let doN DefaultStyle = [] @@ -406,7 +402,7 @@ listItemToICML opts style isFirst attribs item = return $ intersperseBrs (f : r) else blocksToICML opts stl' item -definitionListItemToICML :: WriterOptions -> Style -> ([Inline],[[Block]]) -> WS Doc +definitionListItemToICML :: PandocMonad m => WriterOptions -> Style -> ([Inline],[[Block]]) -> WS m Doc definitionListItemToICML opts style (term,defs) = do term' <- parStyle opts (defListTermName:style) term defs' <- mapM (blocksToICML opts (defListDefName:style)) defs @@ -414,11 +410,11 @@ definitionListItemToICML opts style (term,defs) = do -- | Convert a list of inline elements to ICML. -inlinesToICML :: WriterOptions -> Style -> [Inline] -> WS Doc +inlinesToICML :: PandocMonad m => WriterOptions -> Style -> [Inline] -> WS m Doc inlinesToICML opts style lst = vcat `fmap` mapM (inlineToICML opts style) (mergeSpaces lst) -- | Convert an inline element to ICML. -inlineToICML :: WriterOptions -> Style -> Inline -> WS Doc +inlineToICML :: PandocMonad m => WriterOptions -> Style -> Inline -> WS m Doc inlineToICML _ style (Str str) = charStyle style $ text $ escapeStringForXML str inlineToICML opts style (Emph lst) = inlinesToICML opts (emphName:style) lst inlineToICML opts style (Strong lst) = inlinesToICML opts (strongName:style) lst @@ -458,7 +454,7 @@ inlineToICML opts style (Note lst) = footnoteToICML opts style lst inlineToICML opts style (Span _ lst) = inlinesToICML opts style lst -- | Convert a list of block elements to an ICML footnote. -footnoteToICML :: WriterOptions -> Style -> [Block] -> WS Doc +footnoteToICML :: PandocMonad m => WriterOptions -> Style -> [Block] -> WS m Doc footnoteToICML opts style lst = let insertTab (Para ls) = blockToICML opts (footnoteName:style) $ Para $ (Str "\t"):ls insertTab block = blockToICML opts (footnoteName:style) block @@ -489,7 +485,7 @@ intersperseBrs :: [Doc] -> Doc intersperseBrs = vcat . intersperse (selfClosingTag "Br" []) . filter (not . isEmpty) -- | Wrap a list of inline elements in an ICML Paragraph Style -parStyle :: WriterOptions -> Style -> [Inline] -> WS Doc +parStyle :: PandocMonad m => WriterOptions -> Style -> [Inline] -> WS m Doc parStyle opts style lst = let slipIn x y = if null y then x @@ -513,7 +509,7 @@ parStyle opts style lst = state $ \st -> (cont, st{ blockStyles = Set.insert stlStr $ blockStyles st }) -- | Wrap a Doc in an ICML Character Style. -charStyle :: Style -> Doc -> WS Doc +charStyle :: PandocMonad m => Style -> Doc -> WS m Doc charStyle style content = let (stlStr, attrs) = styleToStrAttr style doc = inTags True "CharacterStyleRange" attrs $ inTagsSimple "Content" $ flush content @@ -535,7 +531,7 @@ styleToStrAttr style = in (stlStr, attrs) -- | Assemble an ICML Image. -imageICML :: WriterOptions -> Style -> Attr -> Target -> WS Doc +imageICML :: PandocMonad m => WriterOptions -> Style -> Attr -> Target -> WS m Doc imageICML opts style attr (src, _) = do res <- lift $ P.fetchItem (writerSourceURL opts) src imgS <- case res of diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index abd403cc9..8013763c2 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to ODT. -} -module Text.Pandoc.Writers.ODT ( writeODTPure, writeODT ) where +module Text.Pandoc.Writers.ODT ( writeODT ) where import Data.List ( isPrefixOf ) import Data.Maybe ( fromMaybe ) import Text.XML.Light.Output @@ -49,33 +49,30 @@ import Text.Pandoc.XML import Text.Pandoc.Pretty import qualified Control.Exception as E import System.FilePath ( takeExtension, takeDirectory, (<.>)) -import Text.Pandoc.Free ( PandocAction, runIO ) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class ( PandocMonad ) +import qualified Text.Pandoc.Class as P data ODTState = ODTState { stEntries :: [Entry] } -type O = StateT ODTState PandocAction +type O m = StateT ODTState m -- | Produce an ODT file from a Pandoc document. -writeODT :: WriterOptions -- ^ Writer options +writeODT :: PandocMonad m + => WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> IO B.ByteString -writeODT opts doc = runIO $ writeODTPure opts doc - -writeODTPure :: WriterOptions - -> Pandoc - -> PandocAction B.ByteString -writeODTPure opts doc = + -> m B.ByteString +writeODT opts doc = let initState = ODTState{ stEntries = [] } in evalStateT (pandocToODT opts doc) initState -- | Produce an ODT file from a Pandoc document. -pandocToODT :: WriterOptions -- ^ Writer options +pandocToODT :: PandocMonad m + => WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert - -> O B.ByteString + -> O m B.ByteString pandocToODT opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let title = docTitle meta @@ -145,7 +142,7 @@ pandocToODT opts doc@(Pandoc meta _) = do return $ fromArchive archive'' -- | transform both Image and Math elements -transformPicMath :: WriterOptions ->Inline -> O Inline +transformPicMath :: PandocMonad m => WriterOptions ->Inline -> O m Inline transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 8d7c643e0..75b97a648 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -29,7 +29,6 @@ Conversion of 'Pandoc' documents to RTF (rich text format). -} module Text.Pandoc.Writers.RTF ( writeRTF , writeRTFWithEmbeddedImages - , writeRTFWithEmbeddedImagesPure ) where import Text.Pandoc.Definition import Text.Pandoc.Options @@ -44,13 +43,13 @@ import qualified Data.ByteString as B import qualified Data.Map as M import Text.Printf ( printf ) import Text.Pandoc.ImageSize -import Text.Pandoc.Free (PandocAction, runIO) -import qualified Text.Pandoc.Free as P +import Text.Pandoc.Class (PandocMonad) +import qualified Text.Pandoc.Class as P -- | Convert Image inlines into a raw RTF embedded image, read from a file, -- or a MediaBag, or the internet. -- If file not found or filetype not jpeg or png, leave the inline unchanged. -rtfEmbedImage :: WriterOptions -> Inline -> PandocAction Inline +rtfEmbedImage :: PandocMonad m => WriterOptions -> Inline -> m Inline rtfEmbedImage opts x@(Image attr _ (src,_)) = do result <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case result of @@ -83,12 +82,8 @@ rtfEmbedImage _ x = return x -- | Convert Pandoc to a string in rich text format, with -- images embedded as encoded binary data. -writeRTFWithEmbeddedImages :: WriterOptions -> Pandoc -> IO String +writeRTFWithEmbeddedImages :: PandocMonad m => WriterOptions -> Pandoc -> m String writeRTFWithEmbeddedImages options doc = - runIO $ writeRTF options `fmap` walkM (rtfEmbedImage options) doc - -writeRTFWithEmbeddedImagesPure :: WriterOptions -> Pandoc -> PandocAction String -writeRTFWithEmbeddedImagesPure options doc = writeRTF options `fmap` walkM (rtfEmbedImage options) doc -- | Convert Pandoc to a string in rich text format. -- cgit v1.2.3 From 04487779b26458597fb751325b24c576b5088662 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 26 Nov 2016 08:46:28 -0500 Subject: 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. --- pandoc.hs | 39 +++--- src/Text/Pandoc.hs | 216 ++++++++++++++++++++++---------- src/Text/Pandoc/PDF.hs | 9 +- src/Text/Pandoc/Writers/AsciiDoc.hs | 5 +- src/Text/Pandoc/Writers/CommonMark.hs | 134 +++++++++++--------- src/Text/Pandoc/Writers/ConTeXt.hs | 5 +- src/Text/Pandoc/Writers/Docbook.hs | 5 +- src/Text/Pandoc/Writers/DokuWiki.hs | 5 +- src/Text/Pandoc/Writers/EPUB.hs | 44 +++---- src/Text/Pandoc/Writers/HTML.hs | 9 +- src/Text/Pandoc/Writers/Haddock.hs | 5 +- src/Text/Pandoc/Writers/LaTeX.hs | 5 +- src/Text/Pandoc/Writers/Man.hs | 5 +- src/Text/Pandoc/Writers/Markdown.hs | 89 +++++++------ src/Text/Pandoc/Writers/MediaWiki.hs | 5 +- src/Text/Pandoc/Writers/Native.hs | 5 +- src/Text/Pandoc/Writers/ODT.hs | 2 +- src/Text/Pandoc/Writers/OPML.hs | 50 ++++---- src/Text/Pandoc/Writers/OpenDocument.hs | 5 +- src/Text/Pandoc/Writers/Org.hs | 5 +- src/Text/Pandoc/Writers/RST.hs | 5 +- src/Text/Pandoc/Writers/TEI.hs | 5 +- src/Text/Pandoc/Writers/Texinfo.hs | 5 +- src/Text/Pandoc/Writers/Textile.hs | 5 +- src/Text/Pandoc/Writers/ZimWiki.hs | 5 +- 25 files changed, 396 insertions(+), 276 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.hs b/pandoc.hs index a032922be..662dd3e3b 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -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 diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index 703d0a002..5bb015fc2 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-} +{-# LANGUAGE ScopedTypeVariables, FlexibleInstances, GADTs #-} {- Copyright (C) 2006-2016 John MacFarlane @@ -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 $ - \o -> r o{ writerExtensions = setExts $ - getDefaultExtensions writerName } - Just (IOStringWriter r) -> Right $ IOStringWriter $ + Just (StringWriter' r) -> Right $ StringWriter' $ \o -> r o{ writerExtensions = setExts $ getDefaultExtensions writerName } - Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $ + Just (ByteStringWriter' r) -> Right $ ByteStringWriter' $ \o -> r o{ writerExtensions = setExts $ getDefaultExtensions writerName } diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 9faff1816..7aaa257fa 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -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"] diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs index 88fab171f..eed6183b4 100644 --- a/src/Text/Pandoc/Writers/AsciiDoc.hs +++ b/src/Text/Pandoc/Writers/AsciiDoc.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index e0591de83..b6ff35bbe 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -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 - -inlinesToCommonMark :: WriterOptions -> [Inline] -> Identity String +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 :: 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 [] - -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') +blocksToNodes :: PandocMonad m => [Block] -> m [Node] +blocksToNodes = foldrM blockToNodes [] + +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 [] diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index ee2cc3f34..c8a4abfd5 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index 5c03d449d..74e3bff3d 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -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 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 diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs index c90dc9078..c7a09fe50 100644 --- a/src/Text/Pandoc/Writers/DokuWiki.hs +++ b/src/Text/Pandoc/Writers/DokuWiki.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 397aa5847..298561db6 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -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") $ "
\n\"cover\n
"]) + (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"])) 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 chapterEntries = zipWith chapToEntry [1..] chapters + 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) + + 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 diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index e0b0234fb..6f25939f0 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 4e93cc4e4..03ce8c0eb 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 50e99fe15..dbb8e4326 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -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, diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index 304995ec8..75c026463 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index f9c7c326e..787db10f9 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -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] diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs index 95b649dd2..774139c43 100644 --- a/src/Text/Pandoc/Writers/MediaWiki.hs +++ b/src/Text/Pandoc/Writers/MediaWiki.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/Native.hs b/src/Text/Pandoc/Writers/Native.hs index 87e23aeeb..2421fd94d 100644 --- a/src/Text/Pandoc/Writers/Native.hs +++ b/src/Text/Pandoc/Writers/Native.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 8013763c2..02e84e26e 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index 20c2c5cbc..ce415264d 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 444a09587..903c94828 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -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 diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs index 330f24b0b..febb2e98f 100644 --- a/src/Text/Pandoc/Writers/Org.hs +++ b/src/Text/Pandoc/Writers/Org.hs @@ -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 } diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index c170889cc..438407cce 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -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, diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs index 27a2819a0..0a22ae085 100644 --- a/src/Text/Pandoc/Writers/TEI.hs +++ b/src/Text/Pandoc/Writers/TEI.hs @@ -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 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 diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 993e6fbfd..fac7f02ab 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -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, diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs index 4283e29cc..9691b7705 100644 --- a/src/Text/Pandoc/Writers/Textile.hs +++ b/src/Text/Pandoc/Writers/Textile.hs @@ -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 } diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs index 56a5d5455..f15b290e4 100644 --- a/src/Text/Pandoc/Writers/ZimWiki.hs +++ b/src/Text/Pandoc/Writers/ZimWiki.hs @@ -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 -- cgit v1.2.3 From 23c5b0d0f1901aa3ab68391f927de4f5278b5942 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Sat, 26 Nov 2016 23:43:54 -0500 Subject: Implement Errors in PandocMonad Errors can be thrown purely with `throwError`. At the moment there are only three kinds of errors: 1. PandocFileReadError FilePath (for problems reading a file from the filesystem) 2. PandocShouldNeverHappenError String (for stuff that should never happen but we need to pattern-match anyway) 3. PandocSomeError String (a grab bag of everything else) Of course, we need to subdivide the third item in this list. --- src/Text/Pandoc/Class.hs | 18 +++++--- src/Text/Pandoc/Writers/EPUB.hs | 28 +++++++----- src/Text/Pandoc/Writers/FB2.hs | 5 ++- src/Text/Pandoc/Writers/HTML.hs | 70 ++++++++++++++++------------- src/Text/Pandoc/Writers/Man.hs | 57 +++++++++++++----------- src/Text/Pandoc/Writers/Markdown.hs | 19 ++++---- src/Text/Pandoc/Writers/OPML.hs | 16 ++++--- src/Text/Pandoc/Writers/RTF.hs | 11 ++--- src/Text/Pandoc/Writers/Texinfo.hs | 89 ++++++++++++++++++++++--------------- 9 files changed, 179 insertions(+), 134 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 64fd7e907..69d2bb761 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -107,8 +107,10 @@ getPOSIXTime = utcTimeToPOSIXSeconds <$> getCurrentTime -- We can add to this as we go -data PandocExecutionError = PandocFileReadError String - deriving (Show, Typeable) +data PandocExecutionError = PandocFileReadError FilePath + | PandocShouldNeverHappenError String + | PandocSomeError String + deriving (Show, Typeable) -- Nothing in this for now, but let's put it there anyway. data PandocStateIO = PandocStateIO @@ -125,7 +127,9 @@ runIOorExplode ma = do eitherVal <- runIO ma case eitherVal of Right x -> return x - Left (PandocFileReadError s) -> error s + Left (PandocFileReadError fp) -> error $ "promple reading " ++ fp + Left (PandocShouldNeverHappenError s) -> error s + Left (PandocSomeError s) -> error s newtype PandocIO a = PandocIO { unPandocIO :: ExceptT PandocExecutionError (StateT PandocStateIO IO) a @@ -142,13 +146,13 @@ instance PandocMonad PandocIO where eitherBS <- liftIO (tryIOError $ BL.readFile s) case eitherBS of Right bs -> return bs - Left _ -> throwError $ PandocFileReadError $ "file not found: " ++ s + Left _ -> throwError $ PandocFileReadError s -- TODO: Make this more sensitive to the different sorts of failure readDataFile mfp fname = do eitherBS <- liftIO (tryIOError $ IO.readDataFile mfp fname) case eitherBS of Right bs -> return bs - Left _ -> throwError $ PandocFileReadError $ "file not found: " ++ fname + Left _ -> throwError $ PandocFileReadError fname fail = M.fail fetchItem ms s = liftIO $ IO.fetchItem ms s fetchItem' mb ms s = liftIO $ IO.fetchItem' mb ms s @@ -235,7 +239,7 @@ instance PandocMonad PandocPure where fps <- asks envFiles case lookup fp fps of Just bs -> return (BL.fromStrict bs) - Nothing -> throwError $ PandocFileReadError "file not in state" + Nothing -> throwError $ PandocFileReadError fp readDataFile Nothing "reference.docx" = do (B.concat . BL.toChunks . fromArchive) <$> (getDefaultReferenceDocx Nothing) readDataFile Nothing "reference.odt" = do @@ -253,7 +257,7 @@ instance PandocMonad PandocPure where fps <- asks envFiles case lookup fp fps of Just bs -> return (Right (bs, getMimeType fp)) - Nothing -> return (Left $ E.toException $ PandocFileReadError "oops") + Nothing -> return (Left $ E.toException $ PandocFileReadError fp) fetchItem' media sourceUrl nm = do case lookupMedia nm media of diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 298561db6..580b12210 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -64,7 +64,8 @@ import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) -import Text.Pandoc.Class (PandocMonad) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) import qualified Text.Pandoc.Class as P -- A Chapter includes a list of blocks and maybe a section @@ -532,9 +533,9 @@ pandocToEPUB opts doc@(Pandoc meta _) = do let tocTitle = fromMaybe plainTitle $ metaValueToString <$> lookupMeta "toc-title" meta - let uuid = case epubIdentifier metadata of - (x:_) -> identifierText x -- use first identifier as UUID - [] -> error "epubIdentifier is null" -- shouldn't happen + uuid <- case epubIdentifier metadata of + (x:_) -> return $ identifierText x -- use first identifier as UUID + [] -> throwError $ PandocShouldNeverHappenError "epubIdentifier is null" -- shouldn't happen currentTime <- lift $ P.getCurrentTime let contentsData = UTF8.fromStringLazy $ ppTopElement $ unode "package" ! [("version", case version of @@ -590,8 +591,9 @@ pandocToEPUB opts doc@(Pandoc meta _) = do let tocLevel = writerTOCDepth opts - let navPointNode :: (Int -> String -> String -> [Element] -> Element) - -> S.Element -> State Int Element + let navPointNode :: PandocMonad m + => (Int -> String -> String -> [Element] -> Element) + -> S.Element -> StateT Int m Element navPointNode formatter (S.Sec _ nums (ident,_,_) ils children) = do n <- get modify (+1) @@ -601,15 +603,15 @@ pandocToEPUB opts doc@(Pandoc meta _) = do let tit = if writerNumberSections opts && not (null nums) then showNums nums ++ " " ++ tit' else tit' - let src = case lookup ident reftable of - Just x -> x - Nothing -> error (ident ++ " not found in reftable") + src <- case lookup ident reftable of + Just x -> return x + Nothing -> throwError $ PandocSomeError $ ident ++ " not found in reftable" let isSec (S.Sec lev _ _ _ _) = lev <= tocLevel isSec _ = False let subsecs = filter isSec children subs <- mapM (navPointNode formatter) subsecs return $ formatter n tit src subs - navPointNode _ (S.Blk _) = error "navPointNode encountered Blk" + navPointNode _ (S.Blk _) = throwError $ PandocSomeError "navPointNode encountered Blk" let navMapFormatter :: Int -> String -> String -> [Element] -> Element navMapFormatter n tit src subs = unode "navPoint" ! @@ -622,6 +624,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do [ unode "navLabel" $ unode "text" (stringify $ docTitle' meta) , unode "content" ! [("src","title_page.xhtml")] $ () ] + navMap <- lift $ evalStateT (mapM (navPointNode navMapFormatter) secs) 1 let tocData = UTF8.fromStringLazy $ ppTopElement $ unode "ncx" ! [("version","2005-1") ,("xmlns","http://www.daisy.org/z3986/2005/ncx/")] $ @@ -640,7 +643,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do ("content", toId img)] $ ()] , unode "docTitle" $ unode "text" $ plainTitle , unode "navMap" $ - tpNode : evalState (mapM (navPointNode navMapFormatter) secs) 1 + tpNode : navMap ] let tocEntry = mkEntry "toc.ncx" tocData @@ -654,11 +657,12 @@ pandocToEPUB opts doc@(Pandoc meta _) = do (_:_) -> [unode "ol" ! [("class","toc")] $ subs] let navtag = if epub3 then "nav" else "div" + tocBlocks <- lift $ evalStateT (mapM (navPointNode navXhtmlFormatter) secs) 1 let navBlocks = [RawBlock (Format "html") $ ppElement $ unode navtag ! ([("epub:type","toc") | epub3] ++ [("id","toc")]) $ [ unode "h1" ! [("id","toc-title")] $ tocTitle - , unode "ol" ! [("class","toc")] $ evalState (mapM (navPointNode navXhtmlFormatter) secs) 1]] + , unode "ol" ! [("class","toc")] $ tocBlocks ]] let landmarks = if epub3 then [RawBlock (Format "html") $ ppElement $ unode "nav" ! [("epub:type","landmarks") diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 58bfe7615..5c22c8586 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -39,13 +39,14 @@ import Text.XML.Light import qualified Text.XML.Light as X import qualified Text.XML.Light.Cursor as XC import qualified Data.ByteString.Char8 as B8 +import Control.Monad.Except (throwError) import Text.Pandoc.Definition import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def) import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize, linesToPara) -import Text.Pandoc.Class (PandocMonad) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) import qualified Text.Pandoc.Class as P -- | Data to be written at the end of the document: @@ -348,7 +349,7 @@ blockToXml (DefinitionList defs) = needsBreak (Plain ins) = LineBreak `notElem` ins needsBreak _ = True blockToXml (Header _ _ _) = -- should never happen, see renderSections - error "unexpected header in section text" + throwError $ PandocShouldNeverHappenError "unexpected header in section text" blockToXml HorizontalRule = return [ el "empty-line" () , el "p" (txt (replicate 10 '—')) diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 6f25939f0..4520708e4 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -68,7 +68,8 @@ 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) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) data WriterState = WriterState { stNotes :: [Html] -- ^ List of notes @@ -101,26 +102,27 @@ nl opts = if writerWrapText opts == WrapNone -- | Convert Pandoc document to Html string. 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 - Just tpl -> renderTemplate' tpl $ - defField "body" (renderHtml body) context +writeHtmlString opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) defaultWriterState + return $ case writerTemplate opts of + Nothing -> renderHtml body + Just tpl -> renderTemplate' tpl $ + defField "body" (renderHtml body) context -- | Convert Pandoc document to Html structure. 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 - Just tpl -> renderTemplate' tpl $ - defField "body" (renderHtml body) context +writeHtml opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) defaultWriterState + return $ case writerTemplate opts of + Nothing -> renderHtml body + Just tpl -> renderTemplate' tpl $ + defField "body" (renderHtml body) context -- result is (title, authors, date, toc, body, new variables) -pandocToHtml :: WriterOptions +pandocToHtml :: PandocMonad m + => WriterOptions -> Pandoc - -> State WriterState (Html, Value) + -> StateT WriterState m (Html, Value) pandocToHtml opts (Pandoc meta blocks) = do metadata <- metaToJSON opts (fmap renderHtml . blockListToHtml opts) @@ -222,7 +224,7 @@ defList :: WriterOptions -> [Html] -> Html defList opts items = toList H.dl opts (items ++ [nl opts]) -- | Construct table of contents from list of elements. -tableOfContents :: WriterOptions -> [Element] -> State WriterState (Maybe Html) +tableOfContents :: PandocMonad m => WriterOptions -> [Element] -> StateT WriterState m (Maybe Html) tableOfContents _ [] = return Nothing tableOfContents opts sects = do let opts' = opts { writerIgnoreNotes = True } @@ -238,7 +240,7 @@ showSecNum = concat . intersperse "." . map show -- | Converts an Element to a list item for a table of contents, -- retrieving the appropriate identifier from state. -elementToListItem :: WriterOptions -> Element -> State WriterState (Maybe Html) +elementToListItem :: PandocMonad m => WriterOptions -> Element -> StateT WriterState m (Maybe Html) -- Don't include the empty headers created in slide shows -- shows when an hrule is used to separate slides without a new title: elementToListItem _ (Sec _ _ _ [Str "\0"] _) = return Nothing @@ -266,7 +268,7 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs) elementToListItem _ _ = return Nothing -- | Convert an Element to Html. -elementToHtml :: Int -> WriterOptions -> Element -> State WriterState Html +elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element -> StateT WriterState m Html elementToHtml _slideLevel opts (Blk block) = blockToHtml opts block elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elements) = do let slide = writerSlideVariant opts /= NoSlides && level <= slideLevel @@ -347,9 +349,9 @@ parseMailto s = do _ -> fail "not a mailto: URL" -- | Obfuscate a "mailto:" link. -obfuscateLink :: WriterOptions -> Attr -> Html -> String -> Html +obfuscateLink :: PandocMonad m => WriterOptions -> Attr -> Html -> String -> m Html obfuscateLink opts attr txt s | writerEmailObfuscation opts == NoObfuscation = - addAttrs opts attr $ H.a ! A.href (toValue s) $ txt + return $ addAttrs opts attr $ H.a ! A.href (toValue s) $ txt obfuscateLink opts attr (renderHtml -> txt) s = let meth = writerEmailObfuscation opts s' = map toLower (take 7 s) ++ drop 7 s @@ -365,9 +367,11 @@ obfuscateLink opts attr (renderHtml -> txt) s = in case meth of ReferenceObfuscation -> -- need to use preEscapedString or &'s are escaped to & in URL + return $ preEscapedString $ "" ++ (obfuscateString txt) ++ "" JavascriptObfuscation -> + return $ (H.script ! A.type_ "text/javascript" $ preEscapedString ("\n\n")) >> H.noscript (preEscapedString $ obfuscateString altText) - _ -> error $ "Unknown obfuscation method: " ++ show meth - _ -> addAttrs opts attr $ H.a ! A.href (toValue s) $ toHtml txt -- malformed email + _ -> throwError $ PandocSomeError $ "Unknown obfuscation method: " ++ show meth + _ -> return $ addAttrs opts attr $ H.a ! A.href (toValue s) $ toHtml txt -- malformed email -- | Obfuscate character as entity. obfuscateChar :: Char -> String @@ -435,7 +439,7 @@ treatAsImage fp = in null ext || ext `elem` imageExts -- | Convert Pandoc block element to HTML. -blockToHtml :: WriterOptions -> Block -> State WriterState Html +blockToHtml :: PandocMonad m => WriterOptions -> Block -> StateT WriterState m Html blockToHtml _ Null = return mempty blockToHtml opts (Plain lst) = inlineListToHtml opts lst -- title beginning with fig: indicates that the image is a figure @@ -625,11 +629,12 @@ blockToHtml opts (Table capt aligns widths headers rows') = do else tbl ! A.style (toValue $ "width:" ++ show (round (totalWidth * 100) :: Int) ++ "%;") -tableRowToHtml :: WriterOptions +tableRowToHtml :: PandocMonad m + => WriterOptions -> [Alignment] -> Int -> [[Block]] - -> State WriterState Html + -> StateT WriterState m Html tableRowToHtml opts aligns rownum cols' = do let mkcell = if rownum == 0 then H.th else H.td let rowclass = case rownum of @@ -649,11 +654,12 @@ alignmentToString alignment = case alignment of AlignCenter -> "center" AlignDefault -> "" -tableItemToHtml :: WriterOptions +tableItemToHtml :: PandocMonad m + => WriterOptions -> (Html -> Html) -> Alignment -> [Block] - -> State WriterState Html + -> StateT WriterState m Html tableItemToHtml opts tag' align' item = do contents <- blockListToHtml opts item let alignStr = alignmentToString align' @@ -671,12 +677,12 @@ toListItems opts items = map (toListItem opts) items ++ [nl opts] toListItem :: WriterOptions -> Html -> Html toListItem opts item = nl opts >> H.li item -blockListToHtml :: WriterOptions -> [Block] -> State WriterState Html +blockListToHtml :: PandocMonad m => WriterOptions -> [Block] -> StateT WriterState m Html blockListToHtml opts lst = fmap (mconcat . intersperse (nl opts)) $ mapM (blockToHtml opts) lst -- | Convert list of Pandoc inline elements to HTML. -inlineListToHtml :: WriterOptions -> [Inline] -> State WriterState Html +inlineListToHtml :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Html inlineListToHtml opts lst = mapM (inlineToHtml opts) lst >>= return . mconcat @@ -695,7 +701,7 @@ annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, -- | Convert Pandoc inline element to HTML. -inlineToHtml :: WriterOptions -> Inline -> State WriterState Html +inlineToHtml :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Html inlineToHtml opts inline = case inline of (Str str) -> return $ strToHtml str @@ -818,7 +824,7 @@ inlineToHtml opts inline = | otherwise -> return mempty (Link attr txt (s,_)) | "mailto:" `isPrefixOf` s -> do linkText <- inlineListToHtml opts txt - return $ obfuscateLink opts attr linkText s + lift $ obfuscateLink opts attr linkText s (Link attr txt (s,tit)) -> do linkText <- inlineListToHtml opts txt let s' = case s of @@ -878,7 +884,7 @@ inlineToHtml opts inline = then result ! customAttribute "data-cites" (toValue citationIds) else result -blockListToNote :: WriterOptions -> String -> [Block] -> State WriterState Html +blockListToNote :: PandocMonad m => WriterOptions -> String -> [Block] -> StateT WriterState m Html blockListToNote opts ref blocks = -- If last block is Para or Plain, include the backlink at the end of -- that block. Otherwise, insert a new Plain block with the backlink. diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index 75c026463..c9530e4e1 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -41,7 +41,8 @@ import Data.Maybe (fromMaybe) import Text.Pandoc.Pretty import Text.Pandoc.Builder (deleteMeta) import Control.Monad.State -import Text.Pandoc.Class (PandocMonad) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) type Notes = [[Block]] data WriterState = WriterState { stNotes :: Notes @@ -49,10 +50,10 @@ data WriterState = WriterState { stNotes :: Notes -- | Convert Pandoc to Man. writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeMan opts document = return $ evalState (pandocToMan opts document) (WriterState [] False) +writeMan opts document = evalStateT (pandocToMan opts document) (WriterState [] False) -- | Return groff man representation of document. -pandocToMan :: WriterOptions -> Pandoc -> State WriterState String +pandocToMan :: PandocMonad m => WriterOptions -> Pandoc -> StateT WriterState m String pandocToMan opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts @@ -94,7 +95,7 @@ pandocToMan opts (Pandoc meta blocks) = do Just tpl -> return $ renderTemplate' tpl context -- | Return man representation of notes. -notesToMan :: WriterOptions -> [[Block]] -> State WriterState Doc +notesToMan :: PandocMonad m => WriterOptions -> [[Block]] -> StateT WriterState m Doc notesToMan opts notes = if null notes then return empty @@ -102,7 +103,7 @@ notesToMan opts notes = return . (text ".SH NOTES" $$) . vcat -- | Return man representation of a note. -noteToMan :: WriterOptions -> Int -> [Block] -> State WriterState Doc +noteToMan :: PandocMonad m => WriterOptions -> Int -> [Block] -> StateT WriterState m Doc noteToMan opts num note = do contents <- blockListToMan opts note let marker = cr <> text ".SS " <> brackets (text (show num)) @@ -161,9 +162,10 @@ splitSentences xs = in if null rest then [sent] else sent : splitSentences rest -- | Convert Pandoc block element to man. -blockToMan :: WriterOptions -- ^ Options - -> Block -- ^ Block element - -> State WriterState Doc +blockToMan :: PandocMonad m + => WriterOptions -- ^ Options + -> Block -- ^ Block element + -> StateT WriterState m Doc blockToMan _ Null = return empty blockToMan opts (Div _ bs) = blockListToMan opts bs blockToMan opts (Plain inlines) = @@ -237,7 +239,7 @@ blockToMan opts (DefinitionList items) = do return (vcat contents) -- | Convert bullet list item (list of blocks) to man. -bulletListItemToMan :: WriterOptions -> [Block] -> State WriterState Doc +bulletListItemToMan :: PandocMonad m => WriterOptions -> [Block] -> StateT WriterState m Doc bulletListItemToMan _ [] = return empty bulletListItemToMan opts ((Para first):rest) = bulletListItemToMan opts ((Plain first):rest) @@ -255,11 +257,12 @@ bulletListItemToMan opts (first:rest) = do return $ text "\\[bu] .RS 2" $$ first' $$ rest' $$ text ".RE" -- | Convert ordered list item (a list of blocks) to man. -orderedListItemToMan :: WriterOptions -- ^ options - -> String -- ^ order marker for list item - -> Int -- ^ number of spaces to indent - -> [Block] -- ^ list item (list of blocks) - -> State WriterState Doc +orderedListItemToMan :: PandocMonad m + => WriterOptions -- ^ options + -> String -- ^ order marker for list item + -> Int -- ^ number of spaces to indent + -> [Block] -- ^ list item (list of blocks) + -> StateT WriterState m Doc orderedListItemToMan _ _ _ [] = return empty orderedListItemToMan opts num indent ((Para first):rest) = orderedListItemToMan opts num indent ((Plain first):rest) @@ -274,18 +277,19 @@ orderedListItemToMan opts num indent (first:rest) = do return $ first'' $$ rest'' -- | Convert definition list item (label, list of blocks) to man. -definitionListItemToMan :: WriterOptions - -> ([Inline],[[Block]]) - -> State WriterState Doc +definitionListItemToMan :: PandocMonad m + => WriterOptions + -> ([Inline],[[Block]]) + -> StateT WriterState m Doc definitionListItemToMan opts (label, defs) = do labelText <- inlineListToMan opts label contents <- if null defs then return empty else liftM vcat $ forM defs $ \blocks -> do - let (first, rest) = case blocks of - ((Para x):y) -> (Plain x,y) - (x:y) -> (x,y) - [] -> error "blocks is null" + (first, rest) <- case blocks of + ((Para x):y) -> return (Plain x,y) + (x:y) -> return (x,y) + [] -> throwError $ PandocSomeError "blocks is null" rest' <- liftM vcat $ mapM (\item -> blockToMan opts item) rest first' <- blockToMan opts first @@ -293,18 +297,19 @@ definitionListItemToMan opts (label, defs) = do return $ text ".TP" $$ nowrap (text ".B " <> labelText) $$ contents -- | Convert list of Pandoc block elements to man. -blockListToMan :: WriterOptions -- ^ Options - -> [Block] -- ^ List of block elements - -> State WriterState Doc +blockListToMan :: PandocMonad m + => WriterOptions -- ^ Options + -> [Block] -- ^ List of block elements + -> StateT WriterState m Doc blockListToMan opts blocks = mapM (blockToMan opts) blocks >>= (return . vcat) -- | Convert list of Pandoc inline elements to man. -inlineListToMan :: WriterOptions -> [Inline] -> State WriterState Doc +inlineListToMan :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Doc inlineListToMan opts lst = mapM (inlineToMan opts) lst >>= (return . hcat) -- | Convert Pandoc inline element to man. -inlineToMan :: WriterOptions -> Inline -> State WriterState Doc +inlineToMan :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Doc inlineToMan opts (Span _ ils) = inlineListToMan opts ils inlineToMan opts (Emph lst) = do contents <- inlineListToMan opts lst diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 787db10f9..4c33de65d 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -46,6 +46,7 @@ import Data.Ord ( comparing ) import Text.Pandoc.Pretty import Control.Monad.Reader import Control.Monad.State +import Control.Monad.Except (throwError) import Text.Pandoc.Writers.HTML (writeHtmlString) import Text.Pandoc.Readers.TeXMath (texMathToInlines) import Text.HTML.TagSoup (parseTags, isTagText, Tag(..)) @@ -57,7 +58,7 @@ 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) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) type Notes = [[Block]] type Ref = ([Inline], Target, Attr) @@ -800,14 +801,14 @@ getReference attr label target = do case find (\(_,t,a) -> t == target && a == attr) (stRefs st) of Just (ref, _, _) -> return ref Nothing -> do - let label' = case find (\(l,_,_) -> l == label) (stRefs st) of - Just _ -> -- label is used; generate numerical label - case find (\n -> notElem [Str (show n)] - (map (\(l,_,_) -> l) (stRefs st))) - [1..(10000 :: Integer)] of - Just x -> [Str (show x)] - Nothing -> error "no unique label" - Nothing -> label + label' <- case find (\(l,_,_) -> l == label) (stRefs st) of + Just _ -> -- label is used; generate numerical label + case find (\n -> notElem [Str (show n)] + (map (\(l,_,_) -> l) (stRefs st))) + [1..(10000 :: Integer)] of + Just x -> return [Str (show x)] + Nothing -> throwError $ PandocSomeError "no unique label" + Nothing -> return label modify (\s -> s{ stRefs = (label', target, attr) : stRefs st }) return label' diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index ce415264d..4f832f962 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -40,7 +40,8 @@ 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) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) -- | Convert Pandoc document to string in OPML format. writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m String @@ -82,15 +83,20 @@ convertDate ils = maybe "" showDateTimeRFC822 $ elementToOPML :: PandocMonad m => WriterOptions -> Element -> m Doc elementToOPML _ (Blk _) = return empty elementToOPML opts (Sec _ _num _ title elements) = do - let isBlk (Blk _) = True + let isBlk :: Element -> Bool + isBlk (Blk _) = True isBlk _ = False - fromBlk (Blk x) = x - fromBlk _ = error "fromBlk called on non-block" + + fromBlk :: PandocMonad m => Element -> m Block + fromBlk (Blk x) = return x + fromBlk _ = throwError $ PandocSomeError "fromBlk called on non-block" + (blocks, rest) = span isBlk elements htmlIls <- writeHtmlInlines title md <- if null blocks then return [] - else writeMarkdown def $ Pandoc nullMeta $ map fromBlk blocks + else do blks <- mapM fromBlk blocks + writeMarkdown def $ Pandoc nullMeta blks let attrs = [("text", htmlIls)] ++ [("_note", md)] o <- mapM (elementToOPML opts) rest return $ inTags True "outline" attrs $ vcat o diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 75b97a648..1ac906756 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -43,7 +43,8 @@ import qualified Data.ByteString as B import qualified Data.Map as M import Text.Printf ( printf ) import Text.Pandoc.ImageSize -import Text.Pandoc.Class (PandocMonad) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) import qualified Text.Pandoc.Class as P -- | Convert Image inlines into a raw RTF embedded image, read from a file, @@ -56,10 +57,10 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do Right (imgdata, Just mime) | mime == "image/jpeg" || mime == "image/png" -> do let bytes = map (printf "%02x") $ B.unpack imgdata - let filetype = case mime of - "image/jpeg" -> "\\jpegblip" - "image/png" -> "\\pngblip" - _ -> error "Unknown file type" + filetype <- case mime of + "image/jpeg" -> return "\\jpegblip" + "image/png" -> return "\\pngblip" + _ -> throwError $ PandocSomeError "Unknown file type" sizeSpec <- case imageSize imgdata of Left msg -> do P.warn $ "Could not determine image size in `" ++ diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index fac7f02ab..dd5d5ee5d 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -44,7 +44,8 @@ import Text.Pandoc.ImageSize import Network.URI ( isURI, unEscapeString ) import System.FilePath import qualified Data.Set as Set -import Text.Pandoc.Class ( PandocMonad ) +import Control.Monad.Except (throwError) +import Text.Pandoc.Class ( PandocMonad, PandocExecutionError(..) ) data WriterState = WriterState { stStrikeout :: Bool -- document contains strikeout @@ -60,10 +61,12 @@ data WriterState = - generated .texi files don't work when run through texi2dvi -} +type TI m = StateT WriterState m + -- | Convert Pandoc to Texinfo. writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeTexinfo options document = return $ - evalState (pandocToTexinfo options $ wrapTop document) $ +writeTexinfo options document = + evalStateT (pandocToTexinfo options $ wrapTop document) $ WriterState { stStrikeout = False, stSuperscript = False, stEscapeComma = False, stSubscript = False, stIdentifiers = Set.empty, stOptions = options} @@ -73,7 +76,7 @@ wrapTop :: Pandoc -> Pandoc wrapTop (Pandoc meta blocks) = Pandoc meta (Header 0 nullAttr (docTitle meta) : blocks) -pandocToTexinfo :: WriterOptions -> Pandoc -> State WriterState String +pandocToTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> TI m String pandocToTexinfo options (Pandoc meta blocks) = do let titlePage = not $ all null $ docTitle meta : docDate meta : docAuthors meta @@ -111,7 +114,7 @@ stringToTexinfo = escapeStringUsing texinfoEscapes , ('\x2019', "'") ] -escapeCommas :: State WriterState Doc -> State WriterState Doc +escapeCommas :: PandocMonad m => TI m Doc -> TI m Doc escapeCommas parser = do oldEscapeComma <- gets stEscapeComma modify $ \st -> st{ stEscapeComma = True } @@ -124,8 +127,9 @@ inCmd :: String -> Doc -> Doc inCmd cmd contents = char '@' <> text cmd <> braces contents -- | Convert Pandoc block element to Texinfo. -blockToTexinfo :: Block -- ^ Block to convert - -> State WriterState Doc +blockToTexinfo :: PandocMonad m + => Block -- ^ Block to convert + -> TI m Doc blockToTexinfo Null = return empty @@ -221,17 +225,19 @@ blockToTexinfo (Header level _ lst) = do idsUsed <- gets stIdentifiers let id' = uniqueIdent lst idsUsed modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed } + sec <- seccmd level return $ if (level > 0) && (level <= 4) then blankline <> text "@node " <> node $$ - text (seccmd level) <> txt $$ + text sec <> txt $$ text "@anchor" <> braces (text $ '#':id') else txt where - seccmd 1 = "@chapter " - seccmd 2 = "@section " - seccmd 3 = "@subsection " - seccmd 4 = "@subsubsection " - seccmd _ = error "illegal seccmd level" + seccmd :: PandocMonad m => Int -> TI m String + seccmd 1 = return "@chapter " + seccmd 2 = return "@section " + seccmd 3 = return "@subsection " + seccmd 4 = return "@subsubsection " + seccmd _ = throwError $ PandocSomeError "illegal seccmd level" blockToTexinfo (Table caption aligns widths heads rows) = do headers <- if all null heads @@ -257,28 +263,32 @@ blockToTexinfo (Table caption aligns widths heads rows) = do inCmd "caption" captionText $$ text "@end float" -tableHeadToTexinfo :: [Alignment] +tableHeadToTexinfo :: PandocMonad m + => [Alignment] -> [[Block]] - -> State WriterState Doc + -> TI m Doc tableHeadToTexinfo = tableAnyRowToTexinfo "@headitem " -tableRowToTexinfo :: [Alignment] +tableRowToTexinfo :: PandocMonad m + => [Alignment] -> [[Block]] - -> State WriterState Doc + -> TI m Doc tableRowToTexinfo = tableAnyRowToTexinfo "@item " -tableAnyRowToTexinfo :: String +tableAnyRowToTexinfo :: PandocMonad m + => String -> [Alignment] -> [[Block]] - -> State WriterState Doc + -> TI m Doc tableAnyRowToTexinfo itemtype aligns cols = zipWithM alignedBlock aligns cols >>= return . (text itemtype $$) . foldl (\row item -> row $$ (if isEmpty row then empty else text " @tab ") <> item) empty -alignedBlock :: Alignment +alignedBlock :: PandocMonad m + => Alignment -> [Block] - -> State WriterState Doc + -> TI m Doc -- XXX @flushleft and @flushright text won't get word wrapped. Since word -- wrapping is more important than alignment, we ignore the alignment. alignedBlock _ = blockListToTexinfo @@ -293,8 +303,9 @@ alignedBlock _ col = blockListToTexinfo col -} -- | Convert Pandoc block elements to Texinfo. -blockListToTexinfo :: [Block] - -> State WriterState Doc +blockListToTexinfo :: PandocMonad m + => [Block] + -> TI m Doc blockListToTexinfo [] = return empty blockListToTexinfo (x:xs) = do x' <- blockToTexinfo x @@ -336,15 +347,17 @@ collectNodes level (x:xs) = _ -> collectNodes level xs -makeMenuLine :: Block - -> State WriterState Doc +makeMenuLine :: PandocMonad m + => Block + -> TI m Doc makeMenuLine (Header _ _ lst) = do txt <- inlineListForNode lst return $ text "* " <> txt <> text "::" -makeMenuLine _ = error "makeMenuLine called with non-Header block" +makeMenuLine _ = throwError $ PandocSomeError "makeMenuLine called with non-Header block" -listItemToTexinfo :: [Block] - -> State WriterState Doc +listItemToTexinfo :: PandocMonad m + => [Block] + -> TI m Doc listItemToTexinfo lst = do contents <- blockListToTexinfo lst let spacer = case reverse lst of @@ -352,8 +365,9 @@ listItemToTexinfo lst = do _ -> empty return $ text "@item" $$ contents <> spacer -defListItemToTexinfo :: ([Inline], [[Block]]) - -> State WriterState Doc +defListItemToTexinfo :: PandocMonad m + => ([Inline], [[Block]]) + -> TI m Doc defListItemToTexinfo (term, defs) = do term' <- inlineListToTexinfo term let defToTexinfo bs = do d <- blockListToTexinfo bs @@ -364,13 +378,15 @@ defListItemToTexinfo (term, defs) = do return $ text "@item " <> term' $+$ vcat defs' -- | Convert list of inline elements to Texinfo. -inlineListToTexinfo :: [Inline] -- ^ Inlines to convert - -> State WriterState Doc +inlineListToTexinfo :: PandocMonad m + => [Inline] -- ^ Inlines to convert + -> TI m Doc inlineListToTexinfo lst = mapM inlineToTexinfo lst >>= return . hcat -- | Convert list of inline elements to Texinfo acceptable for a node name. -inlineListForNode :: [Inline] -- ^ Inlines to convert - -> State WriterState Doc +inlineListForNode :: PandocMonad m + => [Inline] -- ^ Inlines to convert + -> TI m Doc inlineListForNode = return . text . stringToTexinfo . filter (not . disallowedInNode) . stringify @@ -379,8 +395,9 @@ disallowedInNode :: Char -> Bool disallowedInNode c = c `elem` (".,:()" :: String) -- | Convert inline element to Texinfo -inlineToTexinfo :: Inline -- ^ Inline to convert - -> State WriterState Doc +inlineToTexinfo :: PandocMonad m + => Inline -- ^ Inline to convert + -> TI m Doc inlineToTexinfo (Span _ lst) = inlineListToTexinfo lst -- cgit v1.2.3 From 33af62acc5f2219cb093b83694cd73dec33f210b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 27 Nov 2016 11:52:32 +0100 Subject: Fixes to compile after rebase. --- src/Text/Pandoc/Writers/Docx.hs | 3 ++- src/Text/Pandoc/Writers/ICML.hs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 36816eaa1..cc0c180f2 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1121,7 +1121,8 @@ inlineToOpenXML' opts (Math mathType str) = do case writeOMML displayType <$> readTeX str of Right r -> return [r] Left e -> do - warn $ "Cannot convert the following TeX math, skipping:\n" ++ str ++ + (lift . lift) $ P.warn $ + "Cannot convert the following TeX math, skipping:\n" ++ str ++ "\n" ++ e inlinesToOpenXML opts (texMathToInlines mathType str) inlineToOpenXML' opts (Cite _ lst) = inlinesToOpenXML opts lst diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index c82a77452..f624b7dec 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -18,7 +18,7 @@ import Text.Pandoc.Definition import Text.Pandoc.XML import Text.Pandoc.Readers.TeXMath (texMathToInlines) import Text.Pandoc.Writers.Shared -import Text.Pandoc.Shared (linesToPara, splitBy, warn) +import Text.Pandoc.Shared (linesToPara, splitBy) import Text.Pandoc.Options import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Pretty @@ -542,7 +542,7 @@ imageICML opts style attr (src, _) = do case imageSize img of Right size -> return size Left msg -> do - warn $ "Could not determine image size in `" ++ + lift $ P.warn $ "Could not determine image size in `" ++ src ++ "': " ++ msg return def let (ow, oh) = sizeInPoints imgS -- cgit v1.2.3 From 22ffbad9e8e99a59f24997d09d04b28c87d5ecba Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 27 Nov 2016 15:33:44 +0100 Subject: Texinfo writer: restore former behavior for headers level > 4. The recent changes made the writer fail with an error if it encountered a header with level 5. Better to do as we did before and just print a paragraph in that case. Eventually we should emit a warning here. --- src/Text/Pandoc/Writers/Texinfo.hs | 40 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index dd5d5ee5d..9d5c80534 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -219,25 +219,27 @@ blockToTexinfo (Header 0 _ lst) = do return $ text "@node Top" $$ text "@top " <> txt <> blankline -blockToTexinfo (Header level _ lst) = do - node <- inlineListForNode lst - txt <- inlineListToTexinfo lst - idsUsed <- gets stIdentifiers - let id' = uniqueIdent lst idsUsed - modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed } - sec <- seccmd level - return $ if (level > 0) && (level <= 4) - then blankline <> text "@node " <> node $$ - text sec <> txt $$ - text "@anchor" <> braces (text $ '#':id') - else txt - where - seccmd :: PandocMonad m => Int -> TI m String - seccmd 1 = return "@chapter " - seccmd 2 = return "@section " - seccmd 3 = return "@subsection " - seccmd 4 = return "@subsubsection " - seccmd _ = throwError $ PandocSomeError "illegal seccmd level" +blockToTexinfo (Header level _ lst) + | level < 1 || level > 4 = blockToTexinfo (Para lst) + | otherwise = do + node <- inlineListForNode lst + txt <- inlineListToTexinfo lst + idsUsed <- gets stIdentifiers + let id' = uniqueIdent lst idsUsed + modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed } + sec <- seccmd level + return $ if (level > 0) && (level <= 4) + then blankline <> text "@node " <> node $$ + text sec <> txt $$ + text "@anchor" <> braces (text $ '#':id') + else txt + where + seccmd :: PandocMonad m => Int -> TI m String + seccmd 1 = return "@chapter " + seccmd 2 = return "@section " + seccmd 3 = return "@subsection " + seccmd 4 = return "@subsubsection " + seccmd _ = throwError $ PandocSomeError "illegal seccmd level" blockToTexinfo (Table caption aligns widths heads rows) = do headers <- if all null heads -- cgit v1.2.3 From 0e4f95998140c70b8eb77f636f81f10de0db4788 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 27 Nov 2016 15:41:55 +0100 Subject: Fixed regression in OPML writer. OPML writer should note include `_notes` attribute when there's no content. --- src/Text/Pandoc/Writers/OPML.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index 4f832f962..dee3a029c 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -97,6 +97,6 @@ elementToOPML opts (Sec _ _num _ title elements) = do then return [] else do blks <- mapM fromBlk blocks writeMarkdown def $ Pandoc nullMeta blks - let attrs = [("text", htmlIls)] ++ [("_note", md)] + let attrs = [("text", htmlIls)] ++ [("_note", md) | not (null blocks)] o <- mapM (elementToOPML opts) rest return $ inTags True "outline" attrs $ vcat o -- cgit v1.2.3 From 300d94ac249e7e70fb92fb21f6426d894fce61ce Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 27 Nov 2016 15:45:08 +0100 Subject: Deleted whitespace at end of source lines. --- pandoc.hs | 2 +- src/Text/Pandoc.hs | 2 +- src/Text/Pandoc/Class.hs | 2 +- src/Text/Pandoc/Readers/Docx.hs | 4 ++-- src/Text/Pandoc/Readers/Docx/Parse.hs | 2 +- src/Text/Pandoc/UUID.hs | 2 +- src/Text/Pandoc/Writers/CommonMark.hs | 2 +- src/Text/Pandoc/Writers/EPUB.hs | 4 ++-- src/Text/Pandoc/Writers/Texinfo.hs | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.hs b/pandoc.hs index baea94e6c..258b0c735 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -1269,7 +1269,7 @@ 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 diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index 0a6b67f02..b5e5bebcd 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -282,7 +282,7 @@ readers = [ ("native" , StringReader $ \_ s -> return $ readNative s) -- runIOorExplode $ -- writeEPUB o{ writerEpubVersion = Just EPUB2 } doc) -- ,("epub3" , IOByteStringWriter $ \o doc -> --- runIOorExplode $ +-- runIOorExplode $ -- writeEPUB o{ writerEpubVersion = Just EPUB3 } doc) -- ,("fb2" , IOStringWriter $ \o doc -> -- runIOorExplode $ writeFB2 o doc) diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 69d2bb761..279770e97 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -135,7 +135,7 @@ newtype PandocIO a = PandocIO { unPandocIO :: ExceptT PandocExecutionError (StateT PandocStateIO IO) a } deriving (MonadIO, Functor, Applicative, Monad, MonadError PandocExecutionError) -instance PandocMonad PandocIO where +instance PandocMonad PandocIO where lookupEnv = liftIO . IO.lookupEnv getCurrentTime = liftIO IO.getCurrentTime getDefaultReferenceDocx = liftIO . IO.getDefaultReferenceDocx diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 595c805bf..a43043d84 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -64,7 +64,7 @@ implemented, [-] means partially implemented): - [X] Math - [X] Link (links to an arbitrary bookmark create a span with the target as id and "anchor" class) - - [X] Image + - [X] Image - [X] Note (Footnotes and Endnotes are silently combined.) -} @@ -559,7 +559,7 @@ bodyPartToBlocks (ListItem pPr numId lvl (Just levelInfo) parparts) = do ] blks <- bodyPartToBlocks (Paragraph pPr parparts) return $ divWith ("", ["list-item"], kvs) blks -bodyPartToBlocks (ListItem pPr _ _ _ parparts) = +bodyPartToBlocks (ListItem pPr _ _ _ parparts) = let pPr' = pPr {pStyle = "ListParagraph": (pStyle pPr)} in bodyPartToBlocks $ Paragraph pPr' parparts diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs index deb2caccf..6cd3a49b6 100644 --- a/src/Text/Pandoc/Readers/Docx/Parse.hs +++ b/src/Text/Pandoc/Readers/Docx/Parse.hs @@ -690,7 +690,7 @@ elemToParPart ns element , Just drawingElem <- findChild (elemName ns "w" "drawing") element , c_ns <- "http://schemas.openxmlformats.org/drawingml/2006/chart" , Just _ <- findElement (QName "chart" (Just c_ns) (Just "c")) drawingElem - = return Chart + = return Chart elemToParPart ns element | isElem ns "w" "r" element = elemToRun ns element >>= (\r -> return $ PlainRun r) diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs index 9d8cd4434..8de102742 100644 --- a/src/Text/Pandoc/UUID.hs +++ b/src/Text/Pandoc/UUID.hs @@ -64,7 +64,7 @@ instance Show UUID where printf "%02x" p getUUID :: RandomGen g => g -> UUID -getUUID gen = +getUUID gen = let [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = take 16 $ randoms gen :: [Word8] -- set variant i' = i `setBit` 7 `clearBit` 6 diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index b6ff35bbe..c1963a9a8 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -51,7 +51,7 @@ writeCommonMark opts (Pandoc meta blocks) = do notes' = if null notes then [] else [OrderedList (1, Decimal, Period) $ reverse notes] - main <- blocksToCommonMark opts (blocks' ++ notes') + main <- blocksToCommonMark opts (blocks' ++ notes') metadata <- metaToJSON opts (blocksToCommonMark opts) (inlinesToCommonMark opts) diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 580b12210..f0dce739e 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -347,8 +347,8 @@ writeEPUB opts doc = evalStateT (pandocToEPUB opts doc) initState pandocToEPUB :: PandocMonad m - => WriterOptions - -> Pandoc + => WriterOptions + -> Pandoc -> E m B.ByteString pandocToEPUB opts doc@(Pandoc meta _) = do let version = fromMaybe EPUB2 (writerEpubVersion opts) diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 9d5c80534..44a1fffd8 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -65,7 +65,7 @@ type TI m = StateT WriterState m -- | Convert Pandoc to Texinfo. writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeTexinfo options document = +writeTexinfo options document = evalStateT (pandocToTexinfo options $ wrapTop document) $ WriterState { stStrikeout = False, stSuperscript = False, stEscapeComma = False, stSubscript = False, -- cgit v1.2.3 From 3574b98f81c2c24f7ef31f8251ba88792a2c06f0 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Thu, 1 Dec 2016 12:13:51 -0500 Subject: Unify Errors. --- src/Text/Pandoc.hs | 4 ++-- src/Text/Pandoc/Class.hs | 41 ++++++++++++++---------------------- src/Text/Pandoc/Error.hs | 26 ++++++++++++++++------- src/Text/Pandoc/Parsing.hs | 2 +- src/Text/Pandoc/Readers/Docx.hs | 3 ++- src/Text/Pandoc/Readers/EPUB.hs | 3 ++- src/Text/Pandoc/Readers/HTML.hs | 3 ++- src/Text/Pandoc/Readers/Haddock.hs | 5 +++-- src/Text/Pandoc/Readers/LaTeX.hs | 4 ++-- src/Text/Pandoc/Readers/Markdown.hs | 3 ++- src/Text/Pandoc/Readers/MediaWiki.hs | 3 ++- src/Text/Pandoc/Readers/Native.hs | 2 +- src/Text/Pandoc/Readers/OPML.hs | 4 ++-- src/Text/Pandoc/Readers/Odt.hs | 6 +++--- src/Text/Pandoc/Readers/Org.hs | 3 ++- src/Text/Pandoc/Readers/RST.hs | 3 ++- src/Text/Pandoc/Readers/TWiki.hs | 2 +- src/Text/Pandoc/Readers/Textile.hs | 3 ++- src/Text/Pandoc/Readers/Txt2Tags.hs | 3 ++- src/Text/Pandoc/Writers/EPUB.hs | 3 ++- src/Text/Pandoc/Writers/FB2.hs | 3 ++- src/Text/Pandoc/Writers/HTML.hs | 3 ++- src/Text/Pandoc/Writers/Man.hs | 3 ++- src/Text/Pandoc/Writers/Markdown.hs | 3 ++- src/Text/Pandoc/Writers/OPML.hs | 3 ++- src/Text/Pandoc/Writers/RTF.hs | 3 ++- src/Text/Pandoc/Writers/Texinfo.hs | 3 ++- 27 files changed, 83 insertions(+), 64 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index a49d52e25..036d3cdf5 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -180,7 +180,7 @@ import Text.Pandoc.Templates import Text.Pandoc.Options import Text.Pandoc.Shared (safeRead, mapLeft, pandocVersion) import Text.Pandoc.Error -import Text.Pandoc.Class (PandocMonad, runIOorExplode, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad, runIOorExplode) import Data.Aeson import qualified Data.ByteString.Lazy as BL import Data.List (intercalate) @@ -387,7 +387,7 @@ class ToJSONFilter a => ToJsonFilter a toJsonFilter = toJSONFilter readJSON :: ReaderOptions -> String -> Either PandocError Pandoc -readJSON _ = mapLeft ParseFailure . eitherDecode' . UTF8.fromStringLazy +readJSON _ = mapLeft PandocParseError . eitherDecode' . UTF8.fromStringLazy writeJSON :: WriterOptions -> Pandoc -> String writeJSON _ = UTF8.toStringLazy . encode diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 12566a51c..b3bbc04bc 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -39,7 +39,6 @@ module Text.Pandoc.Class ( PandocMonad(..) , addWarningWithPos , PandocIO(..) , PandocPure(..) - , PandocExecutionError(..) , FileInfo(..) , runIO , runIOorExplode @@ -83,12 +82,12 @@ import Control.Monad.State hiding (fail) import Control.Monad.Reader hiding (fail) import Control.Monad.Except hiding (fail) import Data.Word (Word8) -import Data.Typeable import Data.Default import System.IO.Error import qualified Data.Map as M +import Text.Pandoc.Error -class (Functor m, Applicative m, Monad m, MonadError PandocExecutionError m) => PandocMonad m where +class (Functor m, Applicative m, Monad m, MonadError PandocError m) => PandocMonad m where lookupEnv :: String -> m (Maybe String) getCurrentTime :: m UTCTime getCurrentTimeZone :: m TimeZone @@ -143,12 +142,6 @@ addWarningWithPos mbpos msg = warn $ msg ++ maybe "" (\pos -> " " ++ show pos) mbpos --- We can add to this as we go -data PandocExecutionError = PandocFileReadError FilePath - | PandocShouldNeverHappenError String - | PandocParseError String - | PandocSomeError String - deriving (Show, Typeable) -- Nothing in this for now, but let's put it there anyway. data PandocStateIO = PandocStateIO { ioStWarnings :: [String] @@ -168,35 +161,35 @@ instance Default PandocEnvIO where , ioEnvOutputFile = Nothing -- stdout } -runIO :: PandocIO a -> IO (Either PandocExecutionError a) +runIO :: PandocIO a -> IO (Either PandocError a) runIO ma = flip evalStateT def $ flip runReaderT def $ runExceptT $ unPandocIO ma withMediaBag :: PandocMonad m => m a -> m (a, MediaBag) withMediaBag ma = ((,)) <$> ma <*> getMediaBag runIOorExplode :: PandocIO a -> IO a -runIOorExplode ma = do - eitherVal <- runIO ma - case eitherVal of - Right x -> return x - Left (PandocFileReadError fp) -> error $ "problem reading " ++ fp - Left (PandocShouldNeverHappenError s) -> error s - Left (PandocParseError s) -> error $ "parse error" ++ s - Left (PandocSomeError s) -> error s +runIOorExplode ma = handleError <$> runIO ma + -- eitherVal <- runIO ma + -- case eitherVal of + -- Right x -> return x + -- Left (PandocFileReadError fp) -> error $ "problem reading " ++ fp + -- Left (PandocShouldNeverHappenError s) -> error s + -- Left (PandocParseError s) -> error $ "parse error" ++ s + -- Left (PandocSomeError s) -> error s newtype PandocIO a = PandocIO { - unPandocIO :: ExceptT PandocExecutionError (ReaderT PandocEnvIO (StateT PandocStateIO IO)) a + unPandocIO :: ExceptT PandocError (ReaderT PandocEnvIO (StateT PandocStateIO IO)) a } deriving ( MonadIO , Functor , Applicative , Monad , MonadReader PandocEnvIO , MonadState PandocStateIO - , MonadError PandocExecutionError + , MonadError PandocError ) instance PandocMonad PandocIO where @@ -303,20 +296,18 @@ instance Default PureEnv where , envOutputFile = Nothing } -instance E.Exception PandocExecutionError - newtype PandocPure a = PandocPure { - unPandocPure :: ExceptT PandocExecutionError + unPandocPure :: ExceptT PandocError (ReaderT PureEnv (State PureState)) a } deriving ( Functor , Applicative , Monad , MonadReader PureEnv , MonadState PureState - , MonadError PandocExecutionError + , MonadError PandocError ) -runPure :: PandocPure a -> Either PandocExecutionError a +runPure :: PandocPure a -> Either PandocError a runPure x = flip evalState def $ flip runReaderT def $ runExceptT $ unPandocPure x instance PandocMonad PandocPure where diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs index 5e26771fe..c001b279a 100644 --- a/src/Text/Pandoc/Error.hs +++ b/src/Text/Pandoc/Error.hs @@ -33,17 +33,24 @@ module Text.Pandoc.Error (PandocError(..), handleError) where import Text.Parsec.Error import Text.Parsec.Pos hiding (Line) -import GHC.Generics (Generic) import Data.Generics (Typeable) import Control.Exception (Exception) type Input = String -data PandocError = -- | Generic parse failure - ParseFailure String - -- | Error thrown by a Parsec parser - | ParsecError Input ParseError - deriving (Show, Typeable, Generic) +data PandocError = PandocFileReadError FilePath + | PandocShouldNeverHappenError String + | PandocSomeError String + | PandocParseError String + | PandocParsecError Input ParseError + deriving (Show, Typeable) + + +-- data PandocError = -- | Generic parse failure +-- ParseFailure String +-- -- | Error thrown by a Parsec parser +-- | ParsecError Input ParseError +-- deriving (Show, Typeable, Generic) instance Exception PandocError @@ -52,8 +59,11 @@ handleError :: Either PandocError a -> a handleError (Right r) = r handleError (Left err) = case err of - ParseFailure string -> error string - ParsecError input err' -> + PandocFileReadError fp -> error $ "problem reading " ++ fp + PandocShouldNeverHappenError s -> error s + PandocSomeError s -> error s + PandocParseError s -> error s + PandocParsecError input err' -> let errPos = errorPos err' errLine = sourceLine errPos errColumn = sourceColumn errPos diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index 90cc20ab6..796d09632 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -885,7 +885,7 @@ readWithM :: (Monad m) -> String -- ^ input -> m (Either PandocError a) readWithM parser state input = - mapLeft (ParsecError input) `liftM` runParserT parser state "source" input + mapLeft (PandocParsecError input) `liftM` runParserT parser state "source" input -- | Parse a string with a given parser and state diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 87b64d544..37fe5c532 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -96,8 +96,9 @@ import qualified Data.Sequence as Seq (null) #if !(MIN_VERSION_base(4,8,0)) import Data.Traversable (traverse) #endif +import Text.Pandoc.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P readDocx :: PandocMonad m diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs index 0dbe87052..a76ed04ba 100644 --- a/src/Text/Pandoc/Readers/EPUB.hs +++ b/src/Text/Pandoc/Readers/EPUB.hs @@ -32,7 +32,8 @@ import Data.Maybe (mapMaybe, fromMaybe) import qualified Data.Map as M (Map, lookup, fromList, elems) import Data.Monoid ((<>)) import Control.DeepSeq (deepseq, NFData) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P import Debug.Trace (trace) diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs index ef28ff739..b66a712e0 100644 --- a/src/Text/Pandoc/Readers/HTML.hs +++ b/src/Text/Pandoc/Readers/HTML.hs @@ -68,7 +68,8 @@ import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps) import Data.Monoid ((<>)) import Text.Parsec.Error import qualified Data.Set as Set -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import Control.Monad.Except (throwError) diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs index 4d33f657c..987342bf7 100644 --- a/src/Text/Pandoc/Readers/Haddock.hs +++ b/src/Text/Pandoc/Readers/Haddock.hs @@ -25,8 +25,9 @@ import Text.Pandoc.Options import Documentation.Haddock.Parser import Documentation.Haddock.Types import Debug.Trace (trace) +import Text.Pandoc.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) -- | Parse Haddock markup and return a 'Pandoc' document. @@ -40,7 +41,7 @@ readHaddock opts s = case readHaddockEither opts s of readHaddockEither :: ReaderOptions -- ^ Reader options -> String -- ^ String to parse - -> Either PandocExecutionError Pandoc + -> Either PandocError Pandoc readHaddockEither opts = #if MIN_VERSION_haddock_library(1,2,0) Right . B.doc . docHToBlocks . trace' . _doc . parseParas diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 2506c17be..882777c0e 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -57,7 +57,7 @@ import Text.Pandoc.Highlighting (fromListingsLanguage) import Text.Pandoc.ImageSize (numUnit, showFl) import Text.Pandoc.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..), PandocPure) +import Text.Pandoc.Class (PandocMonad, PandocPure) -- | Parse LaTeX from string and return 'Pandoc' document. readLaTeX :: PandocMonad m @@ -939,7 +939,7 @@ type IncludeParser = ParserT String [String] IO String -- | Replace "include" commands with file contents. handleIncludes :: String -> IO (Either PandocError String) -handleIncludes s = mapLeft (ParsecError s) <$> runParserT includeParser' [] "input" s +handleIncludes s = mapLeft (PandocParsecError s) <$> runParserT includeParser' [] "input" s includeParser' :: IncludeParser includeParser' = diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index e5df065ff..0acfca980 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -68,7 +68,8 @@ import Debug.Trace (trace) import Data.Monoid ((<>)) import Control.Monad.Trans (lift) import Control.Monad.Except (throwError, catchError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P type MarkdownParser m = ParserT [Char] ParserState m diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs index 7f45cdb2a..e22e88bcb 100644 --- a/src/Text/Pandoc/Readers/MediaWiki.hs +++ b/src/Text/Pandoc/Readers/MediaWiki.hs @@ -58,7 +58,8 @@ import Data.Maybe (fromMaybe) import Text.Printf (printf) import Debug.Trace (trace) import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error(PandocError(..)) +import Text.Pandoc.Class (PandocMonad) -- | Read mediawiki from an input string and return a Pandoc document. readMediaWiki :: PandocMonad m diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs index 489ddcd4a..3e934e43f 100644 --- a/src/Text/Pandoc/Readers/Native.hs +++ b/src/Text/Pandoc/Readers/Native.hs @@ -65,5 +65,5 @@ readInlines :: String -> Either PandocError [Inline] readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead s) readInline :: String -> Either PandocError Inline -readInline s = maybe (Left . ParseFailure $ "Could not read: " ++ s) Right (safeRead s) +readInline s = maybe (Left . PandocParseError $ "Could not read: " ++ s) Right (safeRead s) diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs index 608e9ae0f..627566609 100644 --- a/src/Text/Pandoc/Readers/OPML.hs +++ b/src/Text/Pandoc/Readers/OPML.hs @@ -13,7 +13,7 @@ import Control.Monad.State import Data.Default import Control.Monad.Except import Text.Pandoc.Error -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) type OPML m = StateT OPMLState m @@ -65,7 +65,7 @@ attrValue attr elt = Just z -> z Nothing -> "" --- exceptT :: PandocMonad m => Either PandocExecutionError a -> OPML m a +-- exceptT :: PandocMonad m => Either PandocError a -> OPML m a -- exceptT = either throwError return asHtml :: PandocMonad m => String -> OPML m Inlines diff --git a/src/Text/Pandoc/Readers/Odt.hs b/src/Text/Pandoc/Readers/Odt.hs index 898dda077..9c8e76081 100644 --- a/src/Text/Pandoc/Readers/Odt.hs +++ b/src/Text/Pandoc/Readers/Odt.hs @@ -41,7 +41,7 @@ import System.FilePath import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P import Text.Pandoc.Definition import Text.Pandoc.Error @@ -78,7 +78,7 @@ readOdt' _ bytes = bytesToOdt bytes-- of bytesToOdt :: B.ByteString -> Either PandocError (Pandoc, MediaBag) bytesToOdt bytes = case toArchiveOrFail bytes of Right archive -> archiveToOdt archive - Left _ -> Left $ ParseFailure "Couldn't parse odt file." + Left _ -> Left $ PandocParseError "Couldn't parse odt file." -- archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag) @@ -99,7 +99,7 @@ archiveToOdt archive | otherwise -- Not very detailed, but I don't think more information would be helpful - = Left $ ParseFailure "Couldn't parse odt file." + = Left $ PandocParseError "Couldn't parse odt file." where filePathIsOdtMedia :: FilePath -> Bool filePathIsOdtMedia fp = diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs index 3a41ed317..c8dbbf45a 100644 --- a/src/Text/Pandoc/Readers/Org.hs +++ b/src/Text/Pandoc/Readers/Org.hs @@ -31,8 +31,9 @@ import Text.Pandoc.Readers.Org.Blocks ( blockList, meta ) import Text.Pandoc.Readers.Org.Parsing ( OrgParser, readWithM ) import Text.Pandoc.Readers.Org.ParserState ( optionsToParserState ) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) import Text.Pandoc.Definition +import Text.Pandoc.Error import Text.Pandoc.Options import Control.Monad.Except ( throwError ) diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 4232f1c90..a20e29e93 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -51,7 +51,8 @@ import Data.Char (toLower, isHexDigit, isSpace) import Data.Monoid ((<>)) import Control.Monad.Except (throwError) import Control.Monad.Trans (lift) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P -- | Parse reStructuredText string and return Pandoc document. diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs index 091dcd7b1..40ea8b75a 100644 --- a/src/Text/Pandoc/Readers/TWiki.hs +++ b/src/Text/Pandoc/Readers/TWiki.hs @@ -48,7 +48,7 @@ import qualified Data.Foldable as F import Text.Pandoc.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P -- | Read twiki from an input string and return a Pandoc document. diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs index 5494695f5..4b558b42e 100644 --- a/src/Text/Pandoc/Readers/Textile.hs +++ b/src/Text/Pandoc/Readers/Textile.hs @@ -68,7 +68,8 @@ import Control.Monad ( guard, liftM, when ) import Data.Monoid ((<>)) import Text.Printf import Debug.Trace (trace) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import Control.Monad.Except (throwError) -- | Parse a Textile text and return a Pandoc document. diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs index 29457ee6a..2769ecb42 100644 --- a/src/Text/Pandoc/Readers/Txt2Tags.hs +++ b/src/Text/Pandoc/Readers/Txt2Tags.hs @@ -50,7 +50,8 @@ import Control.Monad.Reader (Reader, runReader, asks) import Data.Time.Format (formatTime) import Text.Pandoc.Compat.Time (defaultTimeLocale) import Control.Monad.Except (throwError, catchError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P type T2T = ParserT String ParserState (Reader T2TMeta) diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index f0dce739e..e41aa96ad 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -65,7 +65,8 @@ import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P -- A Chapter includes a list of blocks and maybe a section diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 5c22c8586..2401d7eee 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -46,7 +46,8 @@ import Text.Pandoc.Definition import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def) import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize, linesToPara) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P -- | Data to be written at the end of the document: diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 4520708e4..4c8ccfe4a 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -69,7 +69,8 @@ import qualified Text.XML.Light as XML import System.FilePath (takeExtension) import Data.Aeson (Value) import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) data WriterState = WriterState { stNotes :: [Html] -- ^ List of notes diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index c9530e4e1..27cf22b41 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -41,8 +41,9 @@ import Data.Maybe (fromMaybe) import Text.Pandoc.Pretty import Text.Pandoc.Builder (deleteMeta) import Control.Monad.State +import Text.Pandoc.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) type Notes = [[Block]] data WriterState = WriterState { stNotes :: Notes diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 4c33de65d..092693ea4 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -58,7 +58,8 @@ 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, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) type Notes = [[Block]] type Ref = ([Inline], Target, Attr) diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index dee3a029c..38c96589a 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -40,8 +40,9 @@ 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.Error import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Class (PandocMonad) -- | Convert Pandoc document to string in OPML format. writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m String diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 1ac906756..f5d56d021 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -44,7 +44,8 @@ import qualified Data.Map as M import Text.Printf ( printf ) import Text.Pandoc.ImageSize import Control.Monad.Except (throwError) -import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..)) +import Text.Pandoc.Error +import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P -- | Convert Image inlines into a raw RTF embedded image, read from a file, diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 44a1fffd8..783a01063 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -45,7 +45,8 @@ import Network.URI ( isURI, unEscapeString ) import System.FilePath import qualified Data.Set as Set import Control.Monad.Except (throwError) -import Text.Pandoc.Class ( PandocMonad, PandocExecutionError(..) ) +import Text.Pandoc.Error +import Text.Pandoc.Class ( PandocMonad) data WriterState = WriterState { stStrikeout :: Bool -- document contains strikeout -- cgit v1.2.3 From c4c56b8c0471b5051d334e8ccc3f2e6cb1efbf13 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Fri, 2 Dec 2016 07:27:42 -0500 Subject: Fix rebasing errors. --- src/Text/Pandoc/Writers/FB2.hs | 2 +- src/Text/Pandoc/Writers/HTML.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 2401d7eee..20af67b62 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -85,7 +85,7 @@ pandocToFB2 :: PandocMonad m -> Pandoc -> FBM m String pandocToFB2 opts (Pandoc meta blocks) = do - modify (\s -> s { writerOptions = opts { writerOptions = opts } }) + modify (\s -> s { writerOptions = opts }) desc <- description meta fp <- frontpage meta secs <- renderSections 1 blocks diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 4c8ccfe4a..b2b0865bf 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -115,7 +115,7 @@ writeHtml :: PandocMonad m => WriterOptions -> Pandoc -> m Html writeHtml opts d = do (body, context) <- evalStateT (pandocToHtml opts d) defaultWriterState return $ case writerTemplate opts of - Nothing -> renderHtml body + Nothing -> body Just tpl -> renderTemplate' tpl $ defField "body" (renderHtml body) context -- cgit v1.2.3 From 830be4d63204b918afd15615d965bfbc40886cbe Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 3 Dec 2016 16:15:13 +0100 Subject: Refactored math conversion in writers. * Remove exported module `Text.Pandoc.Readers.TeXMath` * Add exported module `Text.Pandoc.Writers.Math` * The function `texMathToInlines` now lives in `Text.Pandoc.Writers.Math` * Export helper function `convertMath` from `Text.Pandoc.Writers.Math` * Use these functions in all writers that do math conversion. This ensures that warnings will always be issued for failed math conversions. --- pandoc.cabal | 2 +- src/Text/Pandoc/Readers/TeXMath.hs | 48 ------ src/Text/Pandoc/Writers/Docbook.hs | 285 +++++++++++++++++--------------- src/Text/Pandoc/Writers/Docx.hs | 18 +- src/Text/Pandoc/Writers/HTML.hs | 15 +- src/Text/Pandoc/Writers/Haddock.hs | 63 ++++--- src/Text/Pandoc/Writers/ICML.hs | 5 +- src/Text/Pandoc/Writers/Man.hs | 6 +- src/Text/Pandoc/Writers/Markdown.hs | 22 ++- src/Text/Pandoc/Writers/Math.hs | 47 ++++++ src/Text/Pandoc/Writers/OpenDocument.hs | 136 ++++++++------- src/Text/Pandoc/Writers/RTF.hs | 259 ++++++++++++++++------------- 12 files changed, 489 insertions(+), 417 deletions(-) delete mode 100644 src/Text/Pandoc/Readers/TeXMath.hs create mode 100644 src/Text/Pandoc/Writers/Math.hs (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.cabal b/pandoc.cabal index dbd0a4d1c..691c83099 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -341,7 +341,6 @@ Library Text.Pandoc.Readers.Org, Text.Pandoc.Readers.DocBook, Text.Pandoc.Readers.OPML, - Text.Pandoc.Readers.TeXMath, Text.Pandoc.Readers.Textile, Text.Pandoc.Readers.Native, Text.Pandoc.Readers.Haddock, @@ -377,6 +376,7 @@ Library Text.Pandoc.Writers.EPUB, Text.Pandoc.Writers.FB2, Text.Pandoc.Writers.TEI, + Text.Pandoc.Writers.Math, Text.Pandoc.PDF, Text.Pandoc.UTF8, Text.Pandoc.Templates, diff --git a/src/Text/Pandoc/Readers/TeXMath.hs b/src/Text/Pandoc/Readers/TeXMath.hs deleted file mode 100644 index e5778b123..000000000 --- a/src/Text/Pandoc/Readers/TeXMath.hs +++ /dev/null @@ -1,48 +0,0 @@ -{- -Copyright (C) 2007-2015 John MacFarlane - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --} - -{- | - Module : Text.Pandoc.Readers.TeXMath - Copyright : Copyright (C) 2007-2015 John MacFarlane - License : GNU GPL, version 2 or above - - Maintainer : John MacFarlane - Stability : alpha - Portability : portable - -Conversion of TeX math to a list of 'Pandoc' inline elements. --} -module Text.Pandoc.Readers.TeXMath ( texMathToInlines ) where - -import Text.Pandoc.Definition -import Text.TeXMath - --- | Converts a raw TeX math formula to a list of 'Pandoc' inlines. --- Defaults to raw formula between @$@ or @$$@ characters if entire formula --- can't be converted. -texMathToInlines :: MathType - -> String -- ^ String to parse (assumes @'\n'@ line endings) - -> [Inline] -texMathToInlines mt inp = - case writePandoc dt `fmap` readTeX inp of - Right (Just ils) -> ils - _ -> [Str (delim ++ inp ++ delim)] - where (dt, delim) = case mt of - DisplayMath -> (DisplayBlock, "$$") - InlineMath -> (DisplayInline, "$") - diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index 74e3bff3d..0ec7445be 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -36,7 +36,7 @@ import Text.Pandoc.Walk import Text.Pandoc.Writers.Shared import Text.Pandoc.Options import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Writers.Math import Data.List ( stripPrefix, isPrefixOf, intercalate, isSuffixOf ) import Data.Char ( toLower ) import Data.Monoid ( Any(..) ) @@ -50,13 +50,13 @@ import Data.Generics (everywhere, mkT) import Text.Pandoc.Class (PandocMonad) -- | Convert list of authors to a docbook section -authorToDocbook :: WriterOptions -> [Inline] -> B.Inlines -authorToDocbook opts name' = - let name = render Nothing $ inlinesToDocbook opts name' - colwidth = if writerWrapText opts == WrapAuto +authorToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> m B.Inlines +authorToDocbook opts name' = do + name <- render Nothing <$> inlinesToDocbook opts name' + let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing - in B.rawInline "docbook" $ render colwidth $ + return $ B.rawInline "docbook" $ render colwidth $ if ',' `elem` name then -- last name first let (lastname, rest) = break (==',') name @@ -75,44 +75,45 @@ authorToDocbook opts name' = -- | Convert Pandoc document to string in Docbook format. writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeDocbook opts (Pandoc meta blocks) = return $ +writeDocbook opts (Pandoc meta blocks) = do let elements = hierarchicalize blocks - colwidth = if writerWrapText opts == WrapAuto + let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing - render' = render colwidth - opts' = if (maybe False (("/book>" `isSuffixOf`) . trimr) + let render' = render colwidth + let opts' = if (maybe False (("/book>" `isSuffixOf`) . trimr) (writerTemplate opts) && TopLevelDefault == writerTopLevelDivision opts) then opts{ writerTopLevelDivision = TopLevelChapter } else opts - -- The numbering here follows LaTeX's internal numbering - startLvl = case writerTopLevelDivision opts' of + -- The numbering here follows LaTeX's internal numbering + let startLvl = case writerTopLevelDivision opts' of TopLevelPart -> -1 TopLevelChapter -> 0 TopLevelSection -> 1 TopLevelDefault -> 1 - auths' = map (authorToDocbook opts) $ docAuthors meta - meta' = B.setMeta "author" auths' meta - Just metadata = metaToJSON opts - (Just . render colwidth . (vcat . - (map (elementToDocbook opts' startLvl)) . hierarchicalize)) - (Just . render colwidth . inlinesToDocbook opts') + auths' <- mapM (authorToDocbook opts) $ docAuthors meta + let meta' = B.setMeta "author" auths' meta + metadata <- metaToJSON opts + (fmap (render colwidth . vcat) . + (mapM (elementToDocbook opts' startLvl) . + hierarchicalize)) + (fmap (render colwidth) . inlinesToDocbook opts') meta' - main = render' $ vcat (map (elementToDocbook opts' startLvl) elements) - context = defField "body" main + main <- (render' . vcat) <$> mapM (elementToDocbook opts' startLvl) elements + let context = defField "body" main $ defField "mathml" (case writerHTMLMathMethod opts of MathML _ -> True _ -> False) $ metadata - in case writerTemplate opts of + return $ case writerTemplate opts of Nothing -> main Just tpl -> renderTemplate' tpl context -- | Convert an Element to Docbook. -elementToDocbook :: WriterOptions -> Int -> Element -> Doc +elementToDocbook :: PandocMonad m => WriterOptions -> Int -> Element -> m Doc elementToDocbook opts _ (Blk block) = blockToDocbook opts block -elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = +elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = do -- Docbook doesn't allow sections with no content, so insert some if needed let elements' = if null elements then [Blk (Para [])] @@ -131,13 +132,14 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = nsAttr = if writerDocbook5 opts && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")] else [] attribs = nsAttr ++ idAttr - in inTags True tag attribs $ - inTagsSimple "title" (inlinesToDocbook opts title) $$ - vcat (map (elementToDocbook opts (lvl + 1)) elements') + contents <- mapM (elementToDocbook opts (lvl + 1)) elements' + title' <- inlinesToDocbook opts title + return $ inTags True tag attribs $ + inTagsSimple "title" title' $$ vcat contents -- | Convert a list of Pandoc blocks to Docbook. -blocksToDocbook :: WriterOptions -> [Block] -> Doc -blocksToDocbook opts = vcat . map (blockToDocbook opts) +blocksToDocbook :: PandocMonad m => WriterOptions -> [Block] -> m Doc +blocksToDocbook opts = fmap vcat . mapM (blockToDocbook opts) -- | Auxiliary function to convert Plain block to Para. plainToPara :: Block -> Block @@ -146,26 +148,29 @@ plainToPara x = x -- | Convert a list of pairs of terms and definitions into a list of -- Docbook varlistentrys. -deflistItemsToDocbook :: WriterOptions -> [([Inline],[[Block]])] -> Doc +deflistItemsToDocbook :: PandocMonad m + => WriterOptions -> [([Inline],[[Block]])] -> m Doc deflistItemsToDocbook opts items = - vcat $ map (\(term, defs) -> deflistItemToDocbook opts term defs) items + vcat <$> mapM (\(term, defs) -> deflistItemToDocbook opts term defs) items -- | Convert a term and a list of blocks into a Docbook varlistentry. -deflistItemToDocbook :: WriterOptions -> [Inline] -> [[Block]] -> Doc -deflistItemToDocbook opts term defs = - let def' = concatMap (map plainToPara) defs - in inTagsIndented "varlistentry" $ - inTagsIndented "term" (inlinesToDocbook opts term) $$ - inTagsIndented "listitem" (blocksToDocbook opts def') +deflistItemToDocbook :: PandocMonad m + => WriterOptions -> [Inline] -> [[Block]] -> m Doc +deflistItemToDocbook opts term defs = do + term' <- inlinesToDocbook opts term + def' <- blocksToDocbook opts $ concatMap (map plainToPara) defs + return $ inTagsIndented "varlistentry" $ + inTagsIndented "term" term' $$ + inTagsIndented "listitem" def' -- | Convert a list of lists of blocks to a list of Docbook list items. -listItemsToDocbook :: WriterOptions -> [[Block]] -> Doc -listItemsToDocbook opts items = vcat $ map (listItemToDocbook opts) items +listItemsToDocbook :: PandocMonad m => WriterOptions -> [[Block]] -> m Doc +listItemsToDocbook opts items = vcat <$> mapM (listItemToDocbook opts) items -- | Convert a list of blocks into a Docbook list item. -listItemToDocbook :: WriterOptions -> [Block] -> Doc +listItemToDocbook :: PandocMonad m => WriterOptions -> [Block] -> m Doc listItemToDocbook opts item = - inTagsIndented "listitem" $ blocksToDocbook opts $ map plainToPara item + inTagsIndented "listitem" <$> blocksToDocbook opts (map plainToPara item) imageToDocbook :: WriterOptions -> Attr -> String -> Doc imageToDocbook _ attr src = selfClosingTag "imagedata" $ @@ -177,43 +182,46 @@ imageToDocbook _ attr src = selfClosingTag "imagedata" $ Nothing -> [] -- | Convert a Pandoc block element to Docbook. -blockToDocbook :: WriterOptions -> Block -> Doc -blockToDocbook _ Null = empty +blockToDocbook :: PandocMonad m => WriterOptions -> Block -> m Doc +blockToDocbook _ Null = return empty -- Add ids to paragraphs in divs with ids - this is needed for -- pandoc-citeproc to get link anchors in bibliographies: blockToDocbook opts (Div (ident,_,_) [Para lst]) = let attribs = [("id", ident) | not (null ident)] in if hasLineBreaks lst - then flush $ nowrap $ inTags False "literallayout" attribs - $ inlinesToDocbook opts lst - else inTags True "para" attribs $ inlinesToDocbook opts lst -blockToDocbook opts (Div (ident,_,_) bs) = - (if null ident - then mempty - else selfClosingTag "anchor" [("id", ident)]) $$ - blocksToDocbook opts (map plainToPara bs) -blockToDocbook _ (Header _ _ _) = empty -- should not occur after hierarchicalize + then (flush . nowrap . inTags False "literallayout" attribs) + <$> inlinesToDocbook opts lst + else inTags True "para" attribs <$> inlinesToDocbook opts lst +blockToDocbook opts (Div (ident,_,_) bs) = do + contents <- blocksToDocbook opts (map plainToPara bs) + return $ + (if null ident + then mempty + else selfClosingTag "anchor" [("id", ident)]) $$ contents +blockToDocbook _ (Header _ _ _) = + return empty -- should not occur after hierarchicalize blockToDocbook opts (Plain lst) = inlinesToDocbook opts lst -- title beginning with fig: indicates that the image is a figure -blockToDocbook opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) = - let alt = inlinesToDocbook opts txt - capt = if null txt +blockToDocbook opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) = do + alt <- inlinesToDocbook opts txt + let capt = if null txt then empty else inTagsSimple "title" alt - in inTagsIndented "figure" $ + return $ inTagsIndented "figure" $ capt $$ (inTagsIndented "mediaobject" $ (inTagsIndented "imageobject" (imageToDocbook opts attr src)) $$ inTagsSimple "textobject" (inTagsSimple "phrase" alt)) blockToDocbook opts (Para lst) - | hasLineBreaks lst = flush $ nowrap $ inTagsSimple "literallayout" $ inlinesToDocbook opts lst - | otherwise = inTagsIndented "para" $ inlinesToDocbook opts lst + | hasLineBreaks lst = (flush . nowrap . inTagsSimple "literallayout") + <$> inlinesToDocbook opts lst + | otherwise = inTagsIndented "para" <$> inlinesToDocbook opts lst blockToDocbook opts (LineBlock lns) = blockToDocbook opts $ linesToPara lns blockToDocbook opts (BlockQuote blocks) = - inTagsIndented "blockquote" $ blocksToDocbook opts blocks -blockToDocbook _ (CodeBlock (_,classes,_) str) = + inTagsIndented "blockquote" <$> blocksToDocbook opts blocks +blockToDocbook _ (CodeBlock (_,classes,_) str) = return $ text ("") <> cr <> flush (text (escapeStringForXML str) <> cr <> text "") where lang = if null langs @@ -225,11 +233,11 @@ blockToDocbook _ (CodeBlock (_,classes,_) str) = then [s] else languagesByExtension . map toLower $ s langs = concatMap langsFrom classes -blockToDocbook opts (BulletList lst) = +blockToDocbook opts (BulletList lst) = do let attribs = [("spacing", "compact") | isTightList lst] - in inTags True "itemizedlist" attribs $ listItemsToDocbook opts lst -blockToDocbook _ (OrderedList _ []) = empty -blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = + inTags True "itemizedlist" attribs <$> listItemsToDocbook opts lst +blockToDocbook _ (OrderedList _ []) = return empty +blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = do let numeration = case numstyle of DefaultStyle -> [] Decimal -> [("numeration", "arabic")] @@ -240,39 +248,41 @@ blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = LowerRoman -> [("numeration", "lowerroman")] spacing = [("spacing", "compact") | isTightList (first:rest)] attribs = numeration ++ spacing - items = if start == 1 - then listItemsToDocbook opts (first:rest) - else (inTags True "listitem" [("override",show start)] - (blocksToDocbook opts $ map plainToPara first)) $$ - listItemsToDocbook opts rest - in inTags True "orderedlist" attribs items -blockToDocbook opts (DefinitionList lst) = + items <- if start == 1 + then listItemsToDocbook opts (first:rest) + else do + first' <- blocksToDocbook opts (map plainToPara first) + rest' <- listItemsToDocbook opts rest + return $ + (inTags True "listitem" [("override",show start)] first') $$ + rest' + return $ inTags True "orderedlist" attribs items +blockToDocbook opts (DefinitionList lst) = do let attribs = [("spacing", "compact") | isTightList $ concatMap snd lst] - in inTags True "variablelist" attribs $ deflistItemsToDocbook opts lst + inTags True "variablelist" attribs <$> deflistItemsToDocbook opts lst blockToDocbook opts (RawBlock f str) - | f == "docbook" = text str -- raw XML block + | f == "docbook" = return $ text str -- raw XML block | f == "html" = if writerDocbook5 opts - then empty -- No html in Docbook5 - else text str -- allow html for backwards compatibility - | otherwise = empty -blockToDocbook _ HorizontalRule = empty -- not semantic -blockToDocbook opts (Table caption aligns widths headers rows) = - let captionDoc = if null caption - then empty - else inTagsIndented "title" - (inlinesToDocbook opts caption) - tableType = if isEmpty captionDoc then "informaltable" else "table" + then return empty -- No html in Docbook5 + else return $ text str -- allow html for backwards compatibility + | otherwise = return empty +blockToDocbook _ HorizontalRule = return empty -- not semantic +blockToDocbook opts (Table caption aligns widths headers rows) = do + captionDoc <- if null caption + then return empty + else inTagsIndented "title" <$> + inlinesToDocbook opts caption + let tableType = if isEmpty captionDoc then "informaltable" else "table" percent w = show (truncate (100*w) :: Integer) ++ "*" coltags = vcat $ zipWith (\w al -> selfClosingTag "colspec" ([("colwidth", percent w) | w > 0] ++ [("align", alignmentToString al)])) widths aligns - head' = if all null headers - then empty - else inTagsIndented "thead" $ - tableRowToDocbook opts headers - body' = inTagsIndented "tbody" $ - vcat $ map (tableRowToDocbook opts) rows - in inTagsIndented tableType $ captionDoc $$ + head' <- if all null headers + then return empty + else inTagsIndented "thead" <$> tableRowToDocbook opts headers + body' <- (inTagsIndented "tbody" . vcat) <$> + mapM (tableRowToDocbook opts) rows + return $ inTagsIndented tableType $ captionDoc $$ (inTags True "tgroup" [("cols", show (length headers))] $ coltags $$ head' $$ body') @@ -293,92 +303,97 @@ alignmentToString alignment = case alignment of AlignCenter -> "center" AlignDefault -> "left" -tableRowToDocbook :: WriterOptions +tableRowToDocbook :: PandocMonad m + => WriterOptions -> [[Block]] - -> Doc + -> m Doc tableRowToDocbook opts cols = - inTagsIndented "row" $ vcat $ map (tableItemToDocbook opts) cols + (inTagsIndented "row" . vcat) <$> mapM (tableItemToDocbook opts) cols -tableItemToDocbook :: WriterOptions +tableItemToDocbook :: PandocMonad m + => WriterOptions -> [Block] - -> Doc + -> m Doc tableItemToDocbook opts item = - inTags True "entry" [] $ vcat $ map (blockToDocbook opts) item + (inTags True "entry" [] . vcat) <$> mapM (blockToDocbook opts) item -- | Convert a list of inline elements to Docbook. -inlinesToDocbook :: WriterOptions -> [Inline] -> Doc -inlinesToDocbook opts lst = hcat $ map (inlineToDocbook opts) lst +inlinesToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> m Doc +inlinesToDocbook opts lst = hcat <$> mapM (inlineToDocbook opts) lst -- | Convert an inline element to Docbook. -inlineToDocbook :: WriterOptions -> Inline -> Doc -inlineToDocbook _ (Str str) = text $ escapeStringForXML str +inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> m Doc +inlineToDocbook _ (Str str) = return $ text $ escapeStringForXML str inlineToDocbook opts (Emph lst) = - inTagsSimple "emphasis" $ inlinesToDocbook opts lst + inTagsSimple "emphasis" <$> inlinesToDocbook opts lst inlineToDocbook opts (Strong lst) = - inTags False "emphasis" [("role", "strong")] $ inlinesToDocbook opts lst + inTags False "emphasis" [("role", "strong")] <$> inlinesToDocbook opts lst inlineToDocbook opts (Strikeout lst) = - inTags False "emphasis" [("role", "strikethrough")] $ + inTags False "emphasis" [("role", "strikethrough")] <$> inlinesToDocbook opts lst inlineToDocbook opts (Superscript lst) = - inTagsSimple "superscript" $ inlinesToDocbook opts lst + inTagsSimple "superscript" <$> inlinesToDocbook opts lst inlineToDocbook opts (Subscript lst) = - inTagsSimple "subscript" $ inlinesToDocbook opts lst + inTagsSimple "subscript" <$> inlinesToDocbook opts lst inlineToDocbook opts (SmallCaps lst) = - inTags False "emphasis" [("role", "smallcaps")] $ + inTags False "emphasis" [("role", "smallcaps")] <$> inlinesToDocbook opts lst inlineToDocbook opts (Quoted _ lst) = - inTagsSimple "quote" $ inlinesToDocbook opts lst + inTagsSimple "quote" <$> inlinesToDocbook opts lst inlineToDocbook opts (Cite _ lst) = inlinesToDocbook opts lst inlineToDocbook opts (Span (ident,_,_) ils) = - (if null ident - then mempty - else selfClosingTag "anchor" [("id", ident)]) <> + ((if null ident + then mempty + else selfClosingTag "anchor" [("id", ident)]) <>) <$> inlinesToDocbook opts ils inlineToDocbook _ (Code _ str) = - inTagsSimple "literal" $ text (escapeStringForXML str) + return $ inTagsSimple "literal" $ text (escapeStringForXML str) inlineToDocbook opts (Math t str) - | isMathML (writerHTMLMathMethod opts) = - case writeMathML dt <$> readTeX str of - Right r -> inTagsSimple tagtype - $ text $ Xml.ppcElement conf - $ fixNS - $ removeAttr r - Left _ -> inlinesToDocbook opts - $ texMathToInlines t str - | otherwise = inlinesToDocbook opts $ texMathToInlines t str - where (dt, tagtype) = case t of - InlineMath -> (DisplayInline,"inlineequation") - DisplayMath -> (DisplayBlock,"informalequation") + | isMathML (writerHTMLMathMethod opts) = do + res <- convertMath writeMathML t str + case res of + Right r -> return $ inTagsSimple tagtype + $ text $ Xml.ppcElement conf + $ fixNS + $ removeAttr r + Left il -> inlineToDocbook opts il + | otherwise = + texMathToInlines t str >>= inlinesToDocbook opts + where tagtype = case t of + InlineMath -> "inlineequation" + DisplayMath -> "informalequation" conf = Xml.useShortEmptyTags (const False) Xml.defaultConfigPP removeAttr e = e{ Xml.elAttribs = [] } fixNS' qname = qname{ Xml.qPrefix = Just "mml" } fixNS = everywhere (mkT fixNS') -inlineToDocbook _ (RawInline f x) | f == "html" || f == "docbook" = text x - | otherwise = empty -inlineToDocbook _ LineBreak = text "\n" +inlineToDocbook _ (RawInline f x) + | f == "html" || f == "docbook" = return $ text x + | otherwise = return empty +inlineToDocbook _ LineBreak = return $ text "\n" -- currently ignore, would require the option to add custom -- styles to the document -inlineToDocbook _ PageBreak = empty -inlineToDocbook _ Space = space +inlineToDocbook _ PageBreak = return empty +inlineToDocbook _ Space = return space -- because we use \n for LineBreak, we can't do soft breaks: -inlineToDocbook _ SoftBreak = space +inlineToDocbook _ SoftBreak = return space inlineToDocbook opts (Link attr txt (src, _)) | Just email <- stripPrefix "mailto:" src = let emailLink = inTagsSimple "email" $ text $ escapeStringForXML $ email in case txt of - [Str s] | escapeURI s == email -> emailLink - _ -> inlinesToDocbook opts txt <+> - char '(' <> emailLink <> char ')' + [Str s] | escapeURI s == email -> return emailLink + _ -> do contents <- inlinesToDocbook opts txt + return $ contents <+> + char '(' <> emailLink <> char ')' | otherwise = (if isPrefixOf "#" src then inTags False "link" $ ("linkend", drop 1 src) : idAndRole attr else if writerDocbook5 opts then inTags False "link" $ ("xlink:href", src) : idAndRole attr - else inTags False "ulink" $ ("url", src) : idAndRole attr ) $ - inlinesToDocbook opts txt -inlineToDocbook opts (Image attr _ (src, tit)) = + else inTags False "ulink" $ ("url", src) : idAndRole attr ) + <$> inlinesToDocbook opts txt +inlineToDocbook opts (Image attr _ (src, tit)) = return $ let titleDoc = if null tit then empty else inTagsIndented "objectinfo" $ @@ -386,7 +401,7 @@ inlineToDocbook opts (Image attr _ (src, tit)) = in inTagsIndented "inlinemediaobject" $ inTagsIndented "imageobject" $ titleDoc $$ imageToDocbook opts attr src inlineToDocbook opts (Note contents) = - inTagsIndented "footnote" $ blocksToDocbook opts contents + inTagsIndented "footnote" <$> blocksToDocbook opts contents isMathML :: HTMLMathMethod -> Bool isMathML (MathML _) = True diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index cc0c180f2..90261dede 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -45,7 +45,7 @@ import Text.Pandoc.ImageSize import Text.Pandoc.Shared hiding (Element) import Text.Pandoc.Writers.Shared (fixDisplayMath) import Text.Pandoc.Options -import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Writers.Math import Text.Pandoc.Highlighting ( highlight ) import Text.Pandoc.Walk import Text.XML.Light as XML @@ -1114,17 +1114,11 @@ inlineToOpenXML' opts (Quoted quoteType lst) = SingleQuote -> ("\x2018", "\x2019") DoubleQuote -> ("\x201C", "\x201D") inlineToOpenXML' opts (Math mathType str) = do - let displayType = if mathType == DisplayMath - then DisplayBlock - else DisplayInline - when (displayType == DisplayBlock) setFirstPara - case writeOMML displayType <$> readTeX str of - Right r -> return [r] - Left e -> do - (lift . lift) $ P.warn $ - "Cannot convert the following TeX math, skipping:\n" ++ str ++ - "\n" ++ e - inlinesToOpenXML opts (texMathToInlines mathType str) + when (mathType == DisplayMath) setFirstPara + res <- (lift . lift) (convertMath writeOMML mathType str) + case res of + Right r -> return [r] + Left il -> inlineToOpenXML' opts il inlineToOpenXML' opts (Cite _ lst) = inlinesToOpenXML opts lst inlineToOpenXML' opts (Code attrs str) = do let unhighlighted = intercalate [br] `fmap` diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index b2b0865bf..40658eaa8 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -36,7 +36,7 @@ import Text.Pandoc.Writers.Shared import Text.Pandoc.Options import Text.Pandoc.ImageSize import Text.Pandoc.Templates -import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Writers.Math import Text.Pandoc.Slides import Text.Pandoc.Highlighting ( highlight, styleToCss, formatHtmlInline, formatHtmlBlock ) @@ -794,17 +794,14 @@ inlineToHtml opts inline = InlineMath -> preEscapedString $ "" ++ str ++ "" DisplayMath -> preEscapedString $ "" ++ str ++ "" MathML _ -> do - let dt = if t == InlineMath - then DisplayInline - else DisplayBlock let conf = useShortEmptyTags (const False) defaultConfigPP - case writeMathML dt <$> readTeX str of + res <- lift $ convertMath writeMathML t str + case res of Right r -> return $ preEscapedString $ ppcElement conf (annotateMML r str) - Left _ -> inlineListToHtml opts - (texMathToInlines t str) >>= - return . (H.span ! A.class_ mathClass) + Left il -> (H.span ! A.class_ mathClass) <$> + inlineToHtml opts il MathJax _ -> return $ H.span ! A.class_ mathClass $ toHtml $ case t of InlineMath -> "\\(" ++ str ++ "\\)" @@ -814,7 +811,7 @@ inlineToHtml opts inline = InlineMath -> str DisplayMath -> "\\displaystyle " ++ str) PlainMath -> do - x <- inlineListToHtml opts (texMathToInlines t str) + x <- lift (texMathToInlines t str) >>= inlineListToHtml opts let m = H.span ! A.class_ mathClass $ x let brtag = if writerHtml5 opts then H5.br else H.br return $ case t of diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 03ce8c0eb..115d5d8d8 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -39,7 +39,7 @@ import Text.Pandoc.Options import Data.List ( intersperse, transpose ) import Text.Pandoc.Pretty import Control.Monad.State -import Text.Pandoc.Readers.TeXMath (texMathToInlines) +import Text.Pandoc.Writers.Math (texMathToInlines) import Network.URI (isURI) import Data.Default import Text.Pandoc.Class (PandocMonad) @@ -51,12 +51,13 @@ instance Default WriterState -- | Convert Pandoc to Haddock. writeHaddock :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeHaddock opts document = return $ - evalState (pandocToHaddock opts{ +writeHaddock opts document = + evalStateT (pandocToHaddock opts{ writerWrapText = writerWrapText opts } document) def -- | Return haddock representation of document. -pandocToHaddock :: WriterOptions -> Pandoc -> State WriterState String +pandocToHaddock :: PandocMonad m + => WriterOptions -> Pandoc -> StateT WriterState m String pandocToHaddock opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts @@ -79,7 +80,8 @@ pandocToHaddock opts (Pandoc meta blocks) = do Just tpl -> return $ renderTemplate' tpl context -- | Return haddock representation of notes. -notesToHaddock :: WriterOptions -> [[Block]] -> State WriterState Doc +notesToHaddock :: PandocMonad m + => WriterOptions -> [[Block]] -> StateT WriterState m Doc notesToHaddock opts notes = if null notes then return empty @@ -93,9 +95,10 @@ escapeString = escapeStringUsing haddockEscapes where haddockEscapes = backslashEscapes "\\/'`\"@<" -- | Convert Pandoc block element to haddock. -blockToHaddock :: WriterOptions -- ^ Options - -> Block -- ^ Block element - -> State WriterState Doc +blockToHaddock :: PandocMonad m + => WriterOptions -- ^ Options + -> Block -- ^ Block element + -> StateT WriterState m Doc blockToHaddock _ Null = return empty blockToHaddock opts (Div _ ils) = do contents <- blockListToHaddock opts ils @@ -168,8 +171,9 @@ blockToHaddock opts (DefinitionList items) = do contents <- mapM (definitionListItemToHaddock opts) items return $ cat contents <> blankline -pandocTable :: WriterOptions -> Bool -> [Alignment] -> [Double] - -> [Doc] -> [[Doc]] -> State WriterState Doc +pandocTable :: PandocMonad m + => WriterOptions -> Bool -> [Alignment] -> [Double] + -> [Doc] -> [[Doc]] -> StateT WriterState m Doc pandocTable opts headless aligns widths rawHeaders rawRows = do let isSimple = all (==0) widths let alignHeader alignment = case alignment of @@ -208,8 +212,9 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do else border return $ head'' $$ underline $$ body $$ bottom -gridTable :: WriterOptions -> Bool -> [Alignment] -> [Double] - -> [Doc] -> [[Doc]] -> State WriterState Doc +gridTable :: PandocMonad m + => WriterOptions -> Bool -> [Alignment] -> [Double] + -> [Doc] -> [[Doc]] -> StateT WriterState m Doc gridTable opts headless _aligns widths headers' rawRows = do let numcols = length headers' let widths' = if all (==0) widths @@ -236,7 +241,8 @@ gridTable opts headless _aligns widths headers' rawRows = do return $ border '-' $$ head'' $$ body $$ border '-' -- | Convert bullet list item (list of blocks) to haddock -bulletListItemToHaddock :: WriterOptions -> [Block] -> State WriterState Doc +bulletListItemToHaddock :: PandocMonad m + => WriterOptions -> [Block] -> StateT WriterState m Doc bulletListItemToHaddock opts items = do contents <- blockListToHaddock opts items let sps = replicate (writerTabStop opts - 2) ' ' @@ -251,10 +257,11 @@ bulletListItemToHaddock opts items = do return $ hang (writerTabStop opts) start $ contents' <> cr -- | Convert ordered list item (a list of blocks) to haddock -orderedListItemToHaddock :: WriterOptions -- ^ options - -> String -- ^ list item marker - -> [Block] -- ^ list item (list of blocks) - -> State WriterState Doc +orderedListItemToHaddock :: PandocMonad m + => WriterOptions -- ^ options + -> String -- ^ list item marker + -> [Block] -- ^ list item (list of blocks) + -> StateT WriterState m Doc orderedListItemToHaddock opts marker items = do contents <- blockListToHaddock opts items let sps = case length marker - writerTabStop opts of @@ -264,9 +271,10 @@ orderedListItemToHaddock opts marker items = do return $ hang (writerTabStop opts) start $ contents <> cr -- | Convert definition list item (label, list of blocks) to haddock -definitionListItemToHaddock :: WriterOptions - -> ([Inline],[[Block]]) - -> State WriterState Doc +definitionListItemToHaddock :: PandocMonad m + => WriterOptions + -> ([Inline],[[Block]]) + -> StateT WriterState m Doc definitionListItemToHaddock opts (label, defs) = do labelText <- inlineListToHaddock opts label defs' <- mapM (mapM (blockToHaddock opts)) defs @@ -274,19 +282,22 @@ definitionListItemToHaddock opts (label, defs) = do return $ nowrap (brackets labelText) <> cr <> contents <> cr -- | Convert list of Pandoc block elements to haddock -blockListToHaddock :: WriterOptions -- ^ Options - -> [Block] -- ^ List of block elements - -> State WriterState Doc +blockListToHaddock :: PandocMonad m + => WriterOptions -- ^ Options + -> [Block] -- ^ List of block elements + -> StateT WriterState m Doc blockListToHaddock opts blocks = mapM (blockToHaddock opts) blocks >>= return . cat -- | Convert list of Pandoc inline elements to haddock. -inlineListToHaddock :: WriterOptions -> [Inline] -> State WriterState Doc +inlineListToHaddock :: PandocMonad m + => WriterOptions -> [Inline] -> StateT WriterState m Doc inlineListToHaddock opts lst = mapM (inlineToHaddock opts) lst >>= return . cat -- | Convert Pandoc inline element to haddock. -inlineToHaddock :: WriterOptions -> Inline -> State WriterState Doc +inlineToHaddock :: PandocMonad m + => WriterOptions -> Inline -> StateT WriterState m Doc inlineToHaddock opts (Span (ident,_,_) ils) = do contents <- inlineListToHaddock opts ils if not (null ident) && null ils @@ -322,7 +333,7 @@ inlineToHaddock opts (Math mt str) = do let adjust x = case mt of DisplayMath -> cr <> x <> cr InlineMath -> x - adjust `fmap` (inlineListToHaddock opts $ texMathToInlines mt str) + adjust <$> (lift (texMathToInlines mt str) >>= inlineListToHaddock opts) inlineToHaddock _ (RawInline f str) | f == "haddock" = return $ text str | otherwise = return empty diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index f624b7dec..7c42671f1 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -16,7 +16,7 @@ into InDesign with File -> Place. module Text.Pandoc.Writers.ICML (writeICML) where import Text.Pandoc.Definition import Text.Pandoc.XML -import Text.Pandoc.Readers.TeXMath (texMathToInlines) +import Text.Pandoc.Writers.Math (texMathToInlines) import Text.Pandoc.Writers.Shared import Text.Pandoc.Shared (linesToPara, splitBy) import Text.Pandoc.Options @@ -435,7 +435,8 @@ inlineToICML opts style SoftBreak = inlineToICML _ style LineBreak = charStyle style $ text lineSeparator inlineToICML _ _ PageBreak = return empty inlineToICML opts style (Math mt str) = - cat <$> mapM (inlineToICML opts style) (texMathToInlines mt str) + lift (texMathToInlines mt str) >>= + (fmap cat . mapM (inlineToICML opts style)) inlineToICML _ _ (RawInline f str) | f == Format "icml" = return $ text str | otherwise = return empty diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index 27cf22b41..a9a30fd45 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -34,7 +34,7 @@ import Text.Pandoc.Templates import Text.Pandoc.Shared import Text.Pandoc.Writers.Shared import Text.Pandoc.Options -import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Writers.Math import Text.Printf ( printf ) import Data.List ( stripPrefix, intersperse, intercalate ) import Data.Maybe (fromMaybe) @@ -342,9 +342,9 @@ inlineToMan _ (Str str@('.':_)) = return $ afterBreak "\\&" <> text (escapeString str) inlineToMan _ (Str str) = return $ text $ escapeString str inlineToMan opts (Math InlineMath str) = - inlineListToMan opts $ texMathToInlines InlineMath str + lift (texMathToInlines InlineMath str) >>= inlineListToMan opts inlineToMan opts (Math DisplayMath str) = do - contents <- inlineListToMan opts $ texMathToInlines DisplayMath str + contents <- lift (texMathToInlines DisplayMath str) >>= inlineListToMan opts return $ cr <> text ".RS" $$ contents $$ text ".RE" inlineToMan _ (RawInline f str) | f == Format "man" = return $ text str diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 092693ea4..66e0365d8 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -48,7 +48,7 @@ import Control.Monad.Reader import Control.Monad.State import Control.Monad.Except (throwError) import Text.Pandoc.Writers.HTML (writeHtmlString) -import Text.Pandoc.Readers.TeXMath (texMathToInlines) +import Text.Pandoc.Writers.Math (texMathToInlines) import Text.HTML.TagSoup (parseTags, isTagText, Tag(..)) import Network.URI (isURI) import Data.Default @@ -200,7 +200,7 @@ pandocToMarkdown opts (Pandoc meta blocks) = do Nothing -> empty let headerBlocks = filter isHeaderBlock blocks toc <- if writerTableOfContents opts - then lift $ lift $ tableOfContents opts headerBlocks + then liftPandoc $ tableOfContents opts headerBlocks else return empty -- Strip off final 'references' header if markdown citations enabled let blocks' = if isEnabled Ext_citations opts @@ -533,7 +533,7 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do rawHeaders rawRows | isEnabled Ext_raw_html opts -> fmap (id,) $ text <$> - (lift $ lift $ writeHtmlString def $ Pandoc nullMeta [t]) + (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [t]) | otherwise -> return $ (id, text "[TABLE]") return $ nst $ tbl $$ blankline $$ caption'' $$ blankline blockToMarkdown' opts (BulletList items) = do @@ -985,9 +985,9 @@ inlineToMarkdown opts (Math InlineMath str) = return $ "\\\\(" <> text str <> "\\\\)" | otherwise -> do plain <- asks envPlain - inlineListToMarkdown opts $ - (if plain then makeMathPlainer else id) $ - texMathToInlines InlineMath str + (liftPandoc (texMathToInlines InlineMath str)) >>= + inlineListToMarkdown opts . + (if plain then makeMathPlainer else id) inlineToMarkdown opts (Math DisplayMath str) = case writerHTMLMathMethod opts of WebTeX url -> (\x -> blankline <> x <> blankline) `fmap` @@ -1000,7 +1000,8 @@ inlineToMarkdown opts (Math DisplayMath str) = | isEnabled Ext_tex_math_double_backslash opts -> return $ "\\\\[" <> text str <> "\\\\]" | otherwise -> (\x -> cr <> x <> cr) `fmap` - inlineListToMarkdown opts (texMathToInlines DisplayMath str) + (liftPandoc (texMathToInlines DisplayMath str) >>= + inlineListToMarkdown opts) inlineToMarkdown opts (RawInline f str) = do plain <- asks envPlain if not plain && @@ -1062,7 +1063,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 - (text . trim) <$> (lift $ lift $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]]) + (text . trim) <$> (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]]) | otherwise = do plain <- asks envPlain linktext <- inlineListToMarkdown opts txt @@ -1101,7 +1102,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 - (text . trim) <$> (lift $ lift $ writeHtmlString def $ Pandoc nullMeta [Plain [img]]) + (text . trim) <$> (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [Plain [img]]) | otherwise = do plain <- asks envPlain let txt = if null alternate || alternate == [Str source] @@ -1125,3 +1126,6 @@ makeMathPlainer = walk go where go (Emph xs) = Span nullAttr xs go x = x + +liftPandoc :: PandocMonad m => m a -> MD m a +liftPandoc = lift . lift diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs new file mode 100644 index 000000000..4540a2479 --- /dev/null +++ b/src/Text/Pandoc/Writers/Math.hs @@ -0,0 +1,47 @@ +module Text.Pandoc.Writers.Math + ( texMathToInlines + , convertMath + ) +where + +import Text.Pandoc.Class +import Text.Pandoc.Definition +import Text.TeXMath (Exp, writePandoc, DisplayType(..), readTeX) + +-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines. +-- Defaults to raw formula between @$@ or @$$@ characters if entire formula +-- can't be converted. +texMathToInlines :: PandocMonad m + => MathType + -> String -- ^ String to parse (assumes @'\n'@ line endings) + -> m [Inline] +texMathToInlines mt inp = do + res <- convertMath writePandoc mt inp + case res of + Right (Just ils) -> return ils + Right (Nothing) -> return [mkFallback mt inp] + Left il -> return [il] + +mkFallback :: MathType -> String -> Inline +mkFallback mt str = Str (delim ++ str ++ delim) + where delim = case mt of + DisplayMath -> "$$" + InlineMath -> "$" + +-- | Converts a raw TeX math formula using a writer function, +-- issuing a warning and producing a fallback (a raw string) +-- on failure. +convertMath :: PandocMonad m + => (DisplayType -> [Exp] -> a) -> MathType -> String + -> m (Either Inline a) +convertMath writer mt str = do + case writer dt <$> readTeX str of + Right r -> return (Right r) + Left e -> do + warn $ "Could not convert TeX math, rendering as raw TeX:\n" ++ + str ++ "\n" ++ e + return (Left $ mkFallback mt str) + where dt = case mt of + DisplayMath -> DisplayBlock + InlineMath -> DisplayInline + diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 903c94828..1a758193a 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -35,8 +35,8 @@ import Text.Pandoc.Options import Text.Pandoc.XML import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Readers.TeXMath import Text.Pandoc.Readers.Odt.StyleReader +import Text.Pandoc.Writers.Math import Text.Pandoc.Pretty import Text.Printf ( printf ) import Control.Arrow ( (***), (>>>) ) @@ -58,6 +58,8 @@ plainToPara x = x -- OpenDocument writer -- +type OD m = StateT WriterState m + data WriterState = WriterState { stNotes :: [Doc] , stTableStyles :: [Doc] @@ -90,40 +92,40 @@ defaultWriterState = when :: Bool -> Doc -> Doc when p a = if p then a else empty -addTableStyle :: Doc -> State WriterState () +addTableStyle :: PandocMonad m => Doc -> OD m () addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s } -addNote :: Doc -> State WriterState () +addNote :: PandocMonad m => Doc -> OD m () addNote i = modify $ \s -> s { stNotes = i : stNotes s } -addParaStyle :: Doc -> State WriterState () +addParaStyle :: PandocMonad m => Doc -> OD m () addParaStyle i = modify $ \s -> s { stParaStyles = i : stParaStyles s } -addTextStyle :: Set.Set TextStyle -> (String, Doc) -> State WriterState () +addTextStyle :: PandocMonad m => Set.Set TextStyle -> (String, Doc) -> OD m () addTextStyle attrs i = modify $ \s -> s { stTextStyles = Map.insert attrs i (stTextStyles s) } -addTextStyleAttr :: TextStyle -> State WriterState () +addTextStyleAttr :: PandocMonad m => TextStyle -> OD m () addTextStyleAttr t = modify $ \s -> s { stTextStyleAttr = Set.insert t (stTextStyleAttr s) } -increaseIndent :: State WriterState () +increaseIndent :: PandocMonad m => OD m () increaseIndent = modify $ \s -> s { stIndentPara = 1 + stIndentPara s } -resetIndent :: State WriterState () +resetIndent :: PandocMonad m => OD m () resetIndent = modify $ \s -> s { stIndentPara = (stIndentPara s) - 1 } -inTightList :: State WriterState a -> State WriterState a +inTightList :: PandocMonad m => OD m a -> OD m a inTightList f = modify (\s -> s { stTight = True }) >> f >>= \r -> modify (\s -> s { stTight = False }) >> return r -setInDefinitionList :: Bool -> State WriterState () +setInDefinitionList :: PandocMonad m => Bool -> OD m () setInDefinitionList b = modify $ \s -> s { stInDefinition = b } -setFirstPara :: State WriterState () +setFirstPara :: PandocMonad m => OD m () setFirstPara = modify $ \s -> s { stFirstPara = True } -inParagraphTags :: Doc -> State WriterState Doc +inParagraphTags :: PandocMonad m => Doc -> OD m Doc inParagraphTags d | isEmpty d = return empty inParagraphTags d = do b <- gets stFirstPara @@ -139,7 +141,7 @@ inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)] inSpanTags :: String -> Doc -> Doc inSpanTags s = inTags False "text:span" [("text:style-name",s)] -withTextStyle :: TextStyle -> State WriterState a -> State WriterState a +withTextStyle :: PandocMonad m => TextStyle -> OD m a -> OD m a withTextStyle s f = do oldTextStyleAttr <- gets stTextStyleAttr addTextStyleAttr s @@ -147,7 +149,7 @@ withTextStyle s f = do modify $ \st -> st{ stTextStyleAttr = oldTextStyleAttr } return res -inTextStyle :: Doc -> State WriterState Doc +inTextStyle :: PandocMonad m => Doc -> OD m Doc inTextStyle d = do at <- gets stTextStyleAttr if Set.null at @@ -168,7 +170,7 @@ inTextStyle d = do return $ inTags False "text:span" [("text:style-name",styleName)] d -inHeaderTags :: Int -> Doc -> State WriterState Doc +inHeaderTags :: PandocMonad m => Int -> Doc -> OD m Doc inHeaderTags i d = return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i) , ("text:outline-level", show i)] d @@ -192,12 +194,12 @@ handleSpaces s -- | Convert Pandoc document to string in OpenDocument format. writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeOpenDocument opts (Pandoc meta blocks) = return $ +writeOpenDocument opts (Pandoc meta blocks) = do let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing - render' = render colwidth - ((body, metadata),s) = flip runState + let render' = render colwidth + ((body, metadata),s) <- flip runStateT defaultWriterState $ do m <- metaToJSON opts (fmap (render colwidth) . blocksToOpenDocument opts) @@ -210,33 +212,36 @@ writeOpenDocument opts (Pandoc meta blocks) = return $ Map.elems (stTextStyles s)) listStyle (n,l) = inTags True "text:list-style" [("style:name", "L" ++ show n)] (vcat l) - listStyles = map listStyle (stListStyles s) - automaticStyles = vcat $ reverse $ styles ++ listStyles - context = defField "body" body + let listStyles = map listStyle (stListStyles s) + let automaticStyles = vcat $ reverse $ styles ++ listStyles + let context = defField "body" body $ defField "automatic-styles" (render' automaticStyles) $ metadata - in case writerTemplate opts of - Nothing -> body - Just tpl -> renderTemplate' tpl context + return $ case writerTemplate opts of + Nothing -> body + Just tpl -> renderTemplate' tpl context -withParagraphStyle :: WriterOptions -> String -> [Block] -> State WriterState Doc +withParagraphStyle :: PandocMonad m + => WriterOptions -> String -> [Block] -> OD m Doc withParagraphStyle o s (b:bs) | Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l | otherwise = go =<< blockToOpenDocument o b where go i = (<>) i <$> withParagraphStyle o s bs withParagraphStyle _ _ [] = return empty -inPreformattedTags :: String -> State WriterState Doc +inPreformattedTags :: PandocMonad m => String -> OD m Doc inPreformattedTags s = do n <- paraStyle [("style:parent-style-name","Preformatted_20_Text")] return . inParagraphTagsWithStyle ("P" ++ show n) . handleSpaces $ s -orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc +orderedListToOpenDocument :: PandocMonad m + => WriterOptions -> Int -> [[Block]] -> OD m Doc orderedListToOpenDocument o pn bs = vcat . map (inTagsIndented "text:list-item") <$> mapM (orderedItemToOpenDocument o pn . map plainToPara) bs -orderedItemToOpenDocument :: WriterOptions -> Int -> [Block] -> State WriterState Doc +orderedItemToOpenDocument :: PandocMonad m + => WriterOptions -> Int -> [Block] -> OD m Doc orderedItemToOpenDocument o n (b:bs) | OrderedList a l <- b = newLevel a l | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show n) <$> inlinesToOpenDocument o l @@ -256,7 +261,8 @@ isTightList (b:_) | Plain {} : _ <- b = True | otherwise = False -newOrderedListStyle :: Bool -> ListAttributes -> State WriterState (Int,Int) +newOrderedListStyle :: PandocMonad m + => Bool -> ListAttributes -> OD m (Int,Int) newOrderedListStyle b a = do ln <- (+) 1 . length <$> gets stListStyles let nbs = orderedListLevelStyle a (ln, []) @@ -264,7 +270,8 @@ newOrderedListStyle b a = do modify $ \s -> s { stListStyles = nbs : stListStyles s } return (ln,pn) -bulletListToOpenDocument :: WriterOptions -> [[Block]] -> State WriterState Doc +bulletListToOpenDocument :: PandocMonad m + => WriterOptions -> [[Block]] -> OD m Doc bulletListToOpenDocument o b = do ln <- (+) 1 . length <$> gets stListStyles (pn,ns) <- if isTightList b then inTightList (bulletListStyle ln) else bulletListStyle ln @@ -272,11 +279,13 @@ bulletListToOpenDocument o b = do is <- listItemsToOpenDocument ("P" ++ show pn) o b return $ inTags True "text:list" [("text:style-name", "L" ++ show ln)] is -listItemsToOpenDocument :: String -> WriterOptions -> [[Block]] -> State WriterState Doc +listItemsToOpenDocument :: PandocMonad m + => String -> WriterOptions -> [[Block]] -> OD m Doc listItemsToOpenDocument s o is = vcat . map (inTagsIndented "text:list-item") <$> mapM (withParagraphStyle o s . map plainToPara) is -deflistItemToOpenDocument :: WriterOptions -> ([Inline],[[Block]]) -> State WriterState Doc +deflistItemToOpenDocument :: PandocMonad m + => WriterOptions -> ([Inline],[[Block]]) -> OD m Doc deflistItemToOpenDocument o (t,d) = do let ts = if isTightList d then "Definition_20_Term_20_Tight" else "Definition_20_Term" @@ -286,7 +295,8 @@ deflistItemToOpenDocument o (t,d) = do d' <- liftM vcat $ mapM (withParagraphStyle o ds . (map plainToPara)) d return $ t' $$ d' -inBlockQuote :: WriterOptions -> Int -> [Block] -> State WriterState Doc +inBlockQuote :: PandocMonad m + => WriterOptions -> Int -> [Block] -> OD m Doc inBlockQuote o i (b:bs) | BlockQuote l <- b = do increaseIndent ni <- paraStyle @@ -298,11 +308,11 @@ inBlockQuote o i (b:bs) inBlockQuote _ _ [] = resetIndent >> return empty -- | Convert a list of Pandoc blocks to OpenDocument. -blocksToOpenDocument :: WriterOptions -> [Block] -> State WriterState Doc +blocksToOpenDocument :: PandocMonad m => WriterOptions -> [Block] -> OD m Doc blocksToOpenDocument o b = vcat <$> mapM (blockToOpenDocument o) b -- | Convert a Pandoc block element to OpenDocument. -blockToOpenDocument :: WriterOptions -> Block -> State WriterState Doc +blockToOpenDocument :: PandocMonad m => WriterOptions -> Block -> OD m Doc blockToOpenDocument o bs | Plain b <- bs = if null b then return empty @@ -374,29 +384,35 @@ blockToOpenDocument o bs endsWithPageBreak [PageBreak] = True endsWithPageBreak (_ : xs) = endsWithPageBreak xs - paragraph :: [Inline] -> State WriterState Doc + paragraph :: PandocMonad m => [Inline] -> OD m Doc paragraph [] = return empty paragraph (PageBreak : rest) | endsWithPageBreak rest = paraWithBreak PageBoth rest paragraph (PageBreak : rest) = paraWithBreak PageBefore rest paragraph inlines | endsWithPageBreak inlines = paraWithBreak PageAfter inlines paragraph inlines = inParagraphTags =<< inlinesToOpenDocument o inlines - paraWithBreak :: ParaBreak -> [Inline] -> State WriterState Doc + paraWithBreak :: PandocMonad m => ParaBreak -> [Inline] -> OD m Doc paraWithBreak breakKind bs = do pn <- paraBreakStyle breakKind withParagraphStyle o ("P" ++ show pn) [Para bs] -colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc +colHeadsToOpenDocument :: PandocMonad m + => WriterOptions -> String -> [String] -> [[Block]] + -> OD m Doc colHeadsToOpenDocument o tn ns hs = inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$> mapM (tableItemToOpenDocument o tn) (zip ns hs) -tableRowToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc +tableRowToOpenDocument :: PandocMonad m + => WriterOptions -> String -> [String] -> [[Block]] + -> OD m Doc tableRowToOpenDocument o tn ns cs = inTagsIndented "table:table-row" . vcat <$> mapM (tableItemToOpenDocument o tn) (zip ns cs) -tableItemToOpenDocument :: WriterOptions -> String -> (String,[Block])-> State WriterState Doc +tableItemToOpenDocument :: PandocMonad m + => WriterOptions -> String -> (String,[Block]) + -> OD m Doc tableItemToOpenDocument o tn (n,i) = let a = [ ("table:style-name" , tn ++ ".A1" ) , ("office:value-type", "string" ) @@ -405,10 +421,10 @@ tableItemToOpenDocument o tn (n,i) = withParagraphStyle o n (map plainToPara i) -- | Convert a list of inline elements to OpenDocument. -inlinesToOpenDocument :: WriterOptions -> [Inline] -> State WriterState Doc +inlinesToOpenDocument :: PandocMonad m => WriterOptions -> [Inline] -> OD m Doc inlinesToOpenDocument o l = hcat <$> toChunks o l -toChunks :: WriterOptions -> [Inline] -> State WriterState [Doc] +toChunks :: PandocMonad m => WriterOptions -> [Inline] -> OD m [Doc] toChunks _ [] = return [] toChunks o (x : xs) | isChunkable x = do @@ -429,7 +445,7 @@ isChunkable SoftBreak = True isChunkable _ = False -- | Convert an inline element to OpenDocument. -inlineToOpenDocument :: WriterOptions -> Inline -> State WriterState Doc +inlineToOpenDocument :: PandocMonad m => WriterOptions -> Inline -> OD m Doc inlineToOpenDocument o ils = case ils of Space -> return space @@ -448,7 +464,8 @@ inlineToOpenDocument o ils SmallCaps l -> withTextStyle SmallC $ inlinesToOpenDocument o l Quoted t l -> inQuotes t <$> inlinesToOpenDocument o l Code _ s -> inlinedCode $ preformatted s - Math t s -> inlinesToOpenDocument o (texMathToInlines t s) + Math t s -> lift (texMathToInlines t s) >>= + inlinesToOpenDocument o Cite _ l -> inlinesToOpenDocument o l RawInline f s -> if f == Format "opendocument" then return $ text s @@ -489,18 +506,18 @@ inlineToOpenDocument o ils addNote nn return nn -bulletListStyle :: Int -> State WriterState (Int,(Int,[Doc])) -bulletListStyle l = - let doStyles i = inTags True "text:list-level-style-bullet" - [ ("text:level" , show (i + 1) ) - , ("text:style-name" , "Bullet_20_Symbols") - , ("style:num-suffix", "." ) - , ("text:bullet-char", [bulletList !! i] ) - ] (listLevelStyle (1 + i)) - bulletList = map chr $ cycle [8226,8227,8259] - listElStyle = map doStyles [0..9] - in do pn <- paraListStyle l - return (pn, (l, listElStyle)) +bulletListStyle :: PandocMonad m => Int -> OD m (Int,(Int,[Doc])) +bulletListStyle l = do + let doStyles i = inTags True "text:list-level-style-bullet" + [ ("text:level" , show (i + 1) ) + , ("text:style-name" , "Bullet_20_Symbols") + , ("style:num-suffix", "." ) + , ("text:bullet-char", [bulletList !! i] ) + ] (listLevelStyle (1 + i)) + bulletList = map chr $ cycle [8226,8227,8259] + listElStyle = map doStyles [0..9] + pn <- paraListStyle l + return (pn, (l, listElStyle)) orderedListLevelStyle :: ListAttributes -> (Int, [Doc]) -> (Int,[Doc]) orderedListLevelStyle (s,n, d) (l,ls) = @@ -554,7 +571,7 @@ tableStyle num wcs = columnStyles = map colStyle wcs in table $$ vcat columnStyles $$ cellStyle -paraStyle :: [(String,String)] -> State WriterState Int +paraStyle :: PandocMonad m => [(String,String)] -> OD m Int paraStyle attrs = do pn <- (+) 1 . length <$> gets stParaStyles i <- (*) 0.5 . fromIntegral <$> gets stIndentPara :: State WriterState Double @@ -578,14 +595,13 @@ paraStyle attrs = do addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) paraProps return pn -paraBreakStyle :: ParaBreak -> State WriterState Int +paraBreakStyle :: PandocMonad m => ParaBreak -> OD m Int paraBreakStyle PageBefore = paraStyle "Text_20_body" [("fo:break-before", "page")] paraBreakStyle PageAfter = paraStyle "Text_20_body" [("fo:break-after", "page")] paraBreakStyle PageBoth = paraStyle "Text_20_body" [("fo:break-before", "page"), ("fo:break-after", "page")] paraBreakStyle AutoNone = paraStyle "Text_20_body" [] - -paraListStyle :: Int -> State WriterState Int +paraListStyle :: PandocMonad m => Int -> OD m Int paraListStyle l = paraStyle [("style:parent-style-name","Text_20_body") ,("style:list-style-name", "L" ++ show l )] diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index f5d56d021..f71c97334 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -34,7 +34,7 @@ import Text.Pandoc.Definition import Text.Pandoc.Options import Text.Pandoc.Shared import Text.Pandoc.Writers.Shared -import Text.Pandoc.Readers.TeXMath +import Text.Pandoc.Writers.Math import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Walk import Data.List ( isSuffixOf, intercalate ) @@ -83,49 +83,50 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do rtfEmbedImage _ x = return x -- | Convert Pandoc to a string in rich text format, with --- images embedded as encoded binary data. -writeRTFWithEmbeddedImages :: PandocMonad m => WriterOptions -> Pandoc -> m String +-- images embedded as encoded binary data. TODO get rid of this, +-- we don't need it now that we have writeRTF in PandocMonad. +writeRTFWithEmbeddedImages :: PandocMonad m + => WriterOptions -> Pandoc -> m String writeRTFWithEmbeddedImages options doc = - writeRTF options `fmap` walkM (rtfEmbedImage options) doc + writeRTF options =<< walkM (rtfEmbedImage options) doc -- | Convert Pandoc to a string in rich text format. -writeRTF :: WriterOptions -> Pandoc -> String -writeRTF options (Pandoc meta@(Meta metamap) blocks) = +writeRTF :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeRTF options (Pandoc meta@(Meta metamap) blocks) = do let spacer = not $ all null $ docTitle meta : docDate meta : docAuthors meta - toPlain (MetaBlocks [Para ils]) = MetaInlines ils + let toPlain (MetaBlocks [Para ils]) = MetaInlines ils toPlain x = x - -- adjust title, author, date so we don't get para inside para - meta' = Meta $ M.adjust toPlain "title" + -- adjust title, author, date so we don't get para inside para + let meta' = Meta $ M.adjust toPlain "title" . M.adjust toPlain "author" . M.adjust toPlain "date" $ metamap - Just metadata = metaToJSON options - (Just . concatMap (blockToRTF 0 AlignDefault)) - (Just . inlineListToRTF) + metadata <- metaToJSON options + (fmap concat . mapM (blockToRTF 0 AlignDefault)) + (inlinesToRTF) meta' - body = concatMap (blockToRTF 0 AlignDefault) blocks - isTOCHeader (Header lev _ _) = lev <= writerTOCDepth options + body <- blocksToRTF 0 AlignDefault blocks + let isTOCHeader (Header lev _ _) = lev <= writerTOCDepth options isTOCHeader _ = False - context = defField "body" body + toc <- tableOfContents $ filter isTOCHeader blocks + let context = defField "body" body $ defField "spacer" spacer $ (if writerTableOfContents options - then defField "toc" - (tableOfContents $ filter isTOCHeader blocks) + then defField "toc" toc else id) $ metadata - in case writerTemplate options of + return $ case writerTemplate options of Just tpl -> renderTemplate' tpl context Nothing -> case reverse body of ('\n':_) -> body _ -> body ++ "\n" -- | Construct table of contents from list of header blocks. -tableOfContents :: [Block] -> String -tableOfContents headers = - let contentsTree = hierarchicalize headers - in concatMap (blockToRTF 0 AlignDefault) $ - [Header 1 nullAttr [Str "Contents"], - BulletList (map elementToListItem contentsTree)] +tableOfContents :: PandocMonad m => [Block] -> m String +tableOfContents headers = do + let contents = map elementToListItem $ hierarchicalize headers + blocksToRTF 0 AlignDefault $ + [Header 1 nullAttr [Str "Contents"], BulletList contents] elementToListItem :: Element -> [Block] elementToListItem (Blk _) = [] @@ -227,66 +228,81 @@ orderedMarkers indent (start, style, delim) = _ -> orderedListMarkers (start, LowerAlpha, Period) else orderedListMarkers (start, style, delim) +blocksToRTF :: PandocMonad m + => Int + -> Alignment + -> [Block] + -> m String +blocksToRTF indent align = fmap concat . mapM (blockToRTF indent align) + -- | Convert Pandoc block element to RTF. -blockToRTF :: Int -- ^ indent level +blockToRTF :: PandocMonad m + => Int -- ^ indent level -> Alignment -- ^ alignment -> Block -- ^ block to convert - -> String -blockToRTF _ _ Null = "" + -> m String +blockToRTF _ _ Null = return "" blockToRTF indent alignment (Div _ bs) = - concatMap (blockToRTF indent alignment) bs + blocksToRTF indent alignment bs blockToRTF indent alignment (Plain lst) = - rtfCompact indent 0 alignment $ inlineListToRTF lst + rtfCompact indent 0 alignment <$> inlinesToRTF lst blockToRTF indent alignment (Para lst) = - rtfPar indent 0 alignment $ inlineListToRTF lst + rtfPar indent 0 alignment <$> inlinesToRTF lst blockToRTF indent alignment (LineBlock lns) = blockToRTF indent alignment $ linesToPara lns blockToRTF indent alignment (BlockQuote lst) = - concatMap (blockToRTF (indent + indentIncrement) alignment) lst + blocksToRTF (indent + indentIncrement) alignment lst blockToRTF indent _ (CodeBlock _ str) = - rtfPar indent 0 AlignLeft ("\\f1 " ++ (codeStringToRTF str)) + return $ rtfPar indent 0 AlignLeft ("\\f1 " ++ (codeStringToRTF str)) blockToRTF _ _ (RawBlock f str) - | f == Format "rtf" = str - | otherwise = "" -blockToRTF indent alignment (BulletList lst) = spaceAtEnd $ - concatMap (listItemToRTF alignment indent (bulletMarker indent)) lst -blockToRTF indent alignment (OrderedList attribs lst) = spaceAtEnd $ concat $ - zipWith (listItemToRTF alignment indent) (orderedMarkers indent attribs) lst -blockToRTF indent alignment (DefinitionList lst) = spaceAtEnd $ - concatMap (definitionListItemToRTF alignment indent) lst -blockToRTF indent _ HorizontalRule = + | f == Format "rtf" = return str + | otherwise = return "" +blockToRTF indent alignment (BulletList lst) = (spaceAtEnd . concat) <$> + mapM (listItemToRTF alignment indent (bulletMarker indent)) lst +blockToRTF indent alignment (OrderedList attribs lst) = + (spaceAtEnd . concat) <$> + mapM (\(x,y) -> listItemToRTF alignment indent x y) + (zip (orderedMarkers indent attribs) lst) +blockToRTF indent alignment (DefinitionList lst) = (spaceAtEnd . concat) <$> + mapM (definitionListItemToRTF alignment indent) lst +blockToRTF indent _ HorizontalRule = return $ rtfPar indent 0 AlignCenter "\\emdash\\emdash\\emdash\\emdash\\emdash" -blockToRTF indent alignment (Header level _ lst) = rtfPar indent 0 alignment $ - "\\b \\fs" ++ (show (40 - (level * 4))) ++ " " ++ inlineListToRTF lst -blockToRTF indent alignment (Table caption aligns sizes headers rows) = - (if all null headers - then "" - else tableRowToRTF True indent aligns sizes headers) ++ - concatMap (tableRowToRTF False indent aligns sizes) rows ++ - rtfPar indent 0 alignment (inlineListToRTF caption) +blockToRTF indent alignment (Header level _ lst) = do + contents <- inlinesToRTF lst + return $ rtfPar indent 0 alignment $ + "\\b \\fs" ++ (show (40 - (level * 4))) ++ " " ++ contents +blockToRTF indent alignment (Table caption aligns sizes headers rows) = do + caption' <- inlinesToRTF caption + header' <- if all null headers + then return "" + else tableRowToRTF True indent aligns sizes headers + rows' <- concat <$> mapM (tableRowToRTF False indent aligns sizes) rows + return $ header' ++ rows' ++ rtfPar indent 0 alignment caption' -tableRowToRTF :: Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> String -tableRowToRTF header indent aligns sizes' cols = +tableRowToRTF :: PandocMonad m + => Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> m String +tableRowToRTF header indent aligns sizes' cols = do let totalTwips = 6 * 1440 -- 6 inches - sizes = if all (== 0) sizes' + let sizes = if all (== 0) sizes' then take (length cols) $ repeat (1.0 / fromIntegral (length cols)) else sizes' - columns = concat $ zipWith (tableItemToRTF indent) aligns cols - rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips)) + columns <- concat <$> mapM (\(x,y) -> tableItemToRTF indent x y) + (zip aligns cols) + let rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips)) (0 :: Integer) sizes - cellDefs = map (\edge -> (if header + let cellDefs = map (\edge -> (if header then "\\clbrdrb\\brdrs" else "") ++ "\\cellx" ++ show edge) rightEdges - start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++ + let start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++ "\\trkeep\\intbl\n{\n" - end = "}\n\\intbl\\row}\n" - in start ++ columns ++ end + let end = "}\n\\intbl\\row}\n" + return $ start ++ columns ++ end -tableItemToRTF :: Int -> Alignment -> [Block] -> String -tableItemToRTF indent alignment item = - let contents = concatMap (blockToRTF indent alignment) item - in "{" ++ substitute "\\pard" "\\pard\\intbl" contents ++ "\\cell}\n" +tableItemToRTF :: PandocMonad m => Int -> Alignment -> [Block] -> m String +tableItemToRTF indent alignment item = do + contents <- blocksToRTF indent alignment item + return $ "{" ++ substitute "\\pard" "\\pard\\intbl" contents ++ "\\cell}\n" -- | Ensure that there's the same amount of space after compact -- lists as after regular lists. @@ -297,74 +313,93 @@ spaceAtEnd str = else str -- | Convert list item (list of blocks) to RTF. -listItemToRTF :: Alignment -- ^ alignment +listItemToRTF :: PandocMonad m + => Alignment -- ^ alignment -> Int -- ^ indent level -> String -- ^ list start marker -> [Block] -- ^ list item (list of blocks) - -> [Char] -listItemToRTF alignment indent marker [] = + -> m String +listItemToRTF alignment indent marker [] = return $ rtfCompact (indent + listIncrement) (0 - listIncrement) alignment (marker ++ "\\tx" ++ (show listIncrement) ++ "\\tab ") -listItemToRTF alignment indent marker list = - let (first:rest) = map (blockToRTF (indent + listIncrement) alignment) list - listMarker = "\\fi" ++ show (0 - listIncrement) ++ " " ++ marker ++ "\\tx" ++ - show listIncrement ++ "\\tab" - insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d = +listItemToRTF alignment indent marker list = do + (first:rest) <- mapM (blockToRTF (indent + listIncrement) alignment) list + let listMarker = "\\fi" ++ show (0 - listIncrement) ++ " " ++ marker ++ + "\\tx" ++ show listIncrement ++ "\\tab" + let insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d = listMarker ++ dropWhile isDigit xs insertListMarker ('\\':'f':'i':d:xs) | isDigit d = listMarker ++ dropWhile isDigit xs insertListMarker (x:xs) = x : insertListMarker xs insertListMarker [] = [] - -- insert the list marker into the (processed) first block - in insertListMarker first ++ concat rest + -- insert the list marker into the (processed) first block + return $ insertListMarker first ++ concat rest -- | Convert definition list item (label, list of blocks) to RTF. -definitionListItemToRTF :: Alignment -- ^ alignment +definitionListItemToRTF :: PandocMonad m + => Alignment -- ^ alignment -> Int -- ^ indent level -> ([Inline],[[Block]]) -- ^ list item (list of blocks) - -> [Char] -definitionListItemToRTF alignment indent (label, defs) = - let labelText = blockToRTF indent alignment (Plain label) - itemsText = concatMap (blockToRTF (indent + listIncrement) alignment) $ - concat defs - in labelText ++ itemsText + -> m String +definitionListItemToRTF alignment indent (label, defs) = do + labelText <- blockToRTF indent alignment (Plain label) + itemsText <- blocksToRTF (indent + listIncrement) alignment (concat defs) + return $ labelText ++ itemsText -- | Convert list of inline items to RTF. -inlineListToRTF :: [Inline] -- ^ list of inlines to convert - -> String -inlineListToRTF lst = concatMap inlineToRTF lst +inlinesToRTF :: PandocMonad m + => [Inline] -- ^ list of inlines to convert + -> m String +inlinesToRTF lst = concat <$> mapM inlineToRTF lst -- | Convert inline item to RTF. -inlineToRTF :: Inline -- ^ inline to convert - -> String -inlineToRTF (Span _ lst) = inlineListToRTF lst -inlineToRTF (Emph lst) = "{\\i " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (Strong lst) = "{\\b " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (Strikeout lst) = "{\\strike " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (Superscript lst) = "{\\super " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (Subscript lst) = "{\\sub " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (SmallCaps lst) = "{\\scaps " ++ (inlineListToRTF lst) ++ "}" -inlineToRTF (Quoted SingleQuote lst) = - "\\u8216'" ++ (inlineListToRTF lst) ++ "\\u8217'" -inlineToRTF (Quoted DoubleQuote lst) = - "\\u8220\"" ++ (inlineListToRTF lst) ++ "\\u8221\"" -inlineToRTF (Code _ str) = "{\\f1 " ++ (codeStringToRTF str) ++ "}" -inlineToRTF (Str str) = stringToRTF str -inlineToRTF (Math t str) = inlineListToRTF $ texMathToInlines t str -inlineToRTF (Cite _ lst) = inlineListToRTF lst +inlineToRTF :: PandocMonad m + => Inline -- ^ inline to convert + -> m String +inlineToRTF (Span _ lst) = inlinesToRTF lst +inlineToRTF (Emph lst) = do + contents <- inlinesToRTF lst + return $ "{\\i " ++ contents ++ "}" +inlineToRTF (Strong lst) = do + contents <- inlinesToRTF lst + return $ "{\\b " ++ contents ++ "}" +inlineToRTF (Strikeout lst) = do + contents <- inlinesToRTF lst + return $ "{\\strike " ++ contents ++ "}" +inlineToRTF (Superscript lst) = do + contents <- inlinesToRTF lst + return $ "{\\super " ++ contents ++ "}" +inlineToRTF (Subscript lst) = do + contents <- inlinesToRTF lst + return $ "{\\sub " ++ contents ++ "}" +inlineToRTF (SmallCaps lst) = do + contents <- inlinesToRTF lst + return $ "{\\scaps " ++ contents ++ "}" +inlineToRTF (Quoted SingleQuote lst) = do + contents <- inlinesToRTF lst + return $ "\\u8216'" ++ contents ++ "\\u8217'" +inlineToRTF (Quoted DoubleQuote lst) = do + contents <- inlinesToRTF lst + return $ "\\u8220\"" ++ contents ++ "\\u8221\"" +inlineToRTF (Code _ str) = return $ "{\\f1 " ++ (codeStringToRTF str) ++ "}" +inlineToRTF (Str str) = return $ stringToRTF str +inlineToRTF (Math t str) = texMathToInlines t str >>= inlinesToRTF +inlineToRTF (Cite _ lst) = inlinesToRTF lst inlineToRTF (RawInline f str) - | f == Format "rtf" = str - | otherwise = "" -inlineToRTF LineBreak = "\\line " -inlineToRTF SoftBreak = " " -inlineToRTF PageBreak = "\\page " -inlineToRTF Space = " " -inlineToRTF (Link _ text (src, _)) = - "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++ - "\"}}{\\fldrslt{\\ul\n" ++ (inlineListToRTF text) ++ "\n}}}\n" + | f == Format "rtf" = return str + | otherwise = return "" +inlineToRTF (LineBreak) = return "\\line " +inlineToRTF SoftBreak = return " " +inlineToRTF PageBreak = return "\\page " +inlineToRTF Space = return " " +inlineToRTF (Link _ text (src, _)) = do + contents <- inlinesToRTF text + return $ "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++ + "\"}}{\\fldrslt{\\ul\n" ++ contents ++ "\n}}}\n" inlineToRTF (Image _ _ (source, _)) = - "{\\cf1 [image: " ++ source ++ "]\\cf0}" -inlineToRTF (Note contents) = - "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++ - (concatMap (blockToRTF 0 AlignDefault) contents) ++ "}" + return $ "{\\cf1 [image: " ++ source ++ "]\\cf0}" +inlineToRTF (Note contents) = do + body <- concat <$> mapM (blockToRTF 0 AlignDefault) contents + return $ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++ + body ++ "}" -- cgit v1.2.3 From 29b3975cbec5d393e404f96e5f68506587ee74de Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 3 Dec 2016 16:30:47 +0100 Subject: Make sure texMathToInlines issues warning. --- src/Text/Pandoc/Writers/Math.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs index 4540a2479..a7fe6d648 100644 --- a/src/Text/Pandoc/Writers/Math.hs +++ b/src/Text/Pandoc/Writers/Math.hs @@ -19,7 +19,9 @@ texMathToInlines mt inp = do res <- convertMath writePandoc mt inp case res of Right (Just ils) -> return ils - Right (Nothing) -> return [mkFallback mt inp] + Right (Nothing) -> do + warn $ "Could not render TeX math as unicode, rendering as raw TeX:\n" ++ inp + return [mkFallback mt inp] Left il -> return [il] mkFallback :: MathType -> String -> Inline -- cgit v1.2.3 From 2710fc426130738715fdf1ac6dd0c111a5ac8340 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 3 Dec 2016 17:10:50 +0100 Subject: Class: Renamed 'warn' to 'addWarning' and consolidated RTF writer. * Renaming Text.Pandoc.Class.warn to addWarning avoids conflict with Text.Pandoc.Shared.warn. * Removed writeRTFWithEmbeddedImages from Text.Pandoc.Writers.RTF. This is no longer needed; we automatically handle embedded images using the PandocM functions. [API change] --- src/Text/Pandoc.hs | 3 +-- src/Text/Pandoc/Class.hs | 12 +++++------- src/Text/Pandoc/Readers/Docx.hs | 4 ++-- src/Text/Pandoc/Readers/RST.hs | 10 +++++----- src/Text/Pandoc/Readers/TWiki.hs | 2 +- src/Text/Pandoc/Writers/Docx.hs | 2 +- src/Text/Pandoc/Writers/EPUB.hs | 4 ++-- src/Text/Pandoc/Writers/ICML.hs | 4 ++-- src/Text/Pandoc/Writers/Math.hs | 4 ++-- src/Text/Pandoc/Writers/ODT.hs | 4 ++-- src/Text/Pandoc/Writers/RTF.hs | 34 +++++++++++++++++++--------------- 11 files changed, 42 insertions(+), 41 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index 036d3cdf5..3c3a79bb7 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -322,8 +322,7 @@ writers = [ ,("dokuwiki" , StringWriter writeDokuWiki) ,("zimwiki" , StringWriter writeZimWiki) ,("textile" , StringWriter writeTextile) - ,("rtf" , StringWriter $ \o -> - writeRTFWithEmbeddedImages o) + ,("rtf" , StringWriter writeRTF) ,("org" , StringWriter writeOrg) ,("asciidoc" , StringWriter writeAsciiDoc) ,("haddock" , StringWriter writeHaddock) diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 1059f5324..3337de40a 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -36,14 +36,14 @@ module Text.Pandoc.Class ( PandocMonad(..) , PureState(..) , getPOSIXTime , getZonedTime - , warn + , addWarning + , addWarningWithPos , getWarnings , getMediaBag , setMediaBag , insertMedia , getInputFiles , getOutputFile - , addWarningWithPos , PandocIO(..) , PandocPure(..) , FileInfo(..) @@ -121,10 +121,8 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m, MonadState C -- Functions defined for all PandocMonad instances --- TODO should we rename this to avoid conflict with the like-named --- function from Shared? Perhaps "addWarning"? -warn :: PandocMonad m => String -> m () -warn msg = modify $ \st -> st{stWarnings = msg : stWarnings st} +addWarning :: PandocMonad m => String -> m () +addWarning msg = modify $ \st -> st{stWarnings = msg : stWarnings st} getWarnings :: PandocMonad m => m [String] getWarnings = gets stWarnings @@ -160,7 +158,7 @@ addWarningWithPos :: PandocMonad m -> ParserT [Char] ParserState m () addWarningWithPos mbpos msg = lift $ - warn $ + addWarning $ msg ++ maybe "" (\pos -> " " ++ show pos) mbpos -- diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 37fe5c532..16542fd1f 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -108,7 +108,7 @@ readDocx :: PandocMonad m readDocx opts bytes | Right archive <- toArchiveOrFail bytes , Right (docx, parserWarnings) <- archiveToDocxWithWarnings archive = do - mapM_ P.warn parserWarnings + mapM_ P.addWarning parserWarnings (meta, blks) <- docxToOutput opts docx return $ Pandoc meta blks readDocx _ _ = @@ -334,7 +334,7 @@ blocksToInlinesWarn cmtId blks = do notParaOrPlain (Plain _) = False notParaOrPlain _ = True when (not $ null $ filter notParaOrPlain blkList) - ((lift . lift) $ P.warn $ "Docx comment " ++ cmtId ++ " will not retain formatting") + ((lift . lift) $ P.addWarning $ "Docx comment " ++ cmtId ++ " will not retain formatting") return $ fromList $ blocksToInlines blkList parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 078d2963c..df6a8114b 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -654,20 +654,20 @@ addNewRole roleString fields = do -- warn about syntax we ignore flip mapM_ fields $ \(key, _) -> case key of - "language" -> when (baseRole /= "code") $ lift $ P.warn $ + "language" -> when (baseRole /= "code") $ lift $ P.addWarning $ "ignoring :language: field because the parent of role :" ++ role ++ ": is :" ++ baseRole ++ ": not :code:" - "format" -> when (baseRole /= "raw") $ lift $ P.warn $ + "format" -> when (baseRole /= "raw") $ lift $ P.addWarning $ "ignoring :format: field because the parent of role :" ++ role ++ ": is :" ++ baseRole ++ ": not :raw:" - _ -> lift $ P.warn $ "ignoring unknown field :" ++ key ++ + _ -> lift $ P.addWarning $ "ignoring unknown field :" ++ key ++ ": in definition of role :" ++ role ++ ": in" when (parentRole == "raw" && countKeys "format" > 1) $ - lift $ P.warn $ + lift $ P.addWarning $ "ignoring :format: fields after the first in the definition of role :" ++ role ++": in" when (parentRole == "code" && countKeys "language" > 1) $ - lift $ P.warn $ + lift $ P.addWarning $ "ignoring :language: fields after the first in the definition of role :" ++ role ++": in" diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs index b2b136f39..cc4f8f39c 100644 --- a/src/Text/Pandoc/Readers/TWiki.hs +++ b/src/Text/Pandoc/Readers/TWiki.hs @@ -58,7 +58,7 @@ readTWiki :: PandocMonad m -> m Pandoc readTWiki opts s = case readTWikiWithWarnings' opts s of Right (doc, warns) -> do - mapM_ P.warn warns + mapM_ P.addWarning warns return doc Left e -> throwError e diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 90261dede..3b1df6bd9 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1182,7 +1182,7 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do res <- (lift . lift) $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - (lift . lift) $ P.warn ("Could not find image `" ++ src ++ "', skipping...") + (lift . lift) $ P.addWarning ("Could not find image `" ++ src ++ "', skipping...") -- emit alt text inlinesToOpenXML opts alt Right (img, mt) -> do diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index e41aa96ad..b1266c4c9 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -398,7 +398,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do let matchingGlob f = do xs <- lift $ P.glob f when (null xs) $ - lift $ P.warn $ f ++ " did not match any font files." + lift $ P.addWarning $ f ++ " did not match any font files." return xs let mkFontEntry f = mkEntry (takeFileName f) `fmap` (lift $ P.readFileLazy f) fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts') @@ -864,7 +864,7 @@ modifyMediaRef opts oldsrc = do (new, mbEntry) <- case res of Left _ -> do - lift $ P.warn $ "Could not find media `" ++ oldsrc ++ "', skipping..." + lift $ P.addWarning $ "Could not find media `" ++ oldsrc ++ "', skipping..." return (oldsrc, Nothing) Right (img,mbMime) -> do let new = "media/file" ++ show (length media) ++ diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 7c42671f1..482e20f4b 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -537,13 +537,13 @@ imageICML opts style attr (src, _) = do res <- lift $ P.fetchItem (writerSourceURL opts) src imgS <- case res of Left (_) -> do - lift $ P.warn $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.addWarning $ "Could not find image `" ++ src ++ "', skipping..." return def Right (img, _) -> do case imageSize img of Right size -> return size Left msg -> do - lift $ P.warn $ "Could not determine image size in `" ++ + lift $ P.addWarning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return def let (ow, oh) = sizeInPoints imgS diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs index a7fe6d648..552db8b32 100644 --- a/src/Text/Pandoc/Writers/Math.hs +++ b/src/Text/Pandoc/Writers/Math.hs @@ -20,7 +20,7 @@ texMathToInlines mt inp = do case res of Right (Just ils) -> return ils Right (Nothing) -> do - warn $ "Could not render TeX math as unicode, rendering as raw TeX:\n" ++ inp + addWarning $ "Could not render TeX math as unicode, rendering as raw TeX:\n" ++ inp return [mkFallback mt inp] Left il -> return [il] @@ -40,7 +40,7 @@ convertMath writer mt str = do case writer dt <$> readTeX str of Right r -> return (Right r) Left e -> do - warn $ "Could not convert TeX math, rendering as raw TeX:\n" ++ + addWarning $ "Could not convert TeX math, rendering as raw TeX:\n" ++ str ++ "\n" ++ e return (Left $ mkFallback mt str) where dt = case mt of diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 02e84e26e..db9090e29 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -147,13 +147,13 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - lift $ P.warn $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.addWarning $ "Could not find image `" ++ src ++ "', skipping..." return $ Emph lab Right (img, mbMimeType) -> do (ptX, ptY) <- case imageSize img of Right s -> return $ sizeInPoints s Left msg -> do - lift $ P.warn $ "Could not determine image size in `" ++ + lift $ P.addWarning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return (100, 100) let dims = diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index f71c97334..32f70cb31 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to RTF (rich text format). -} module Text.Pandoc.Writers.RTF ( writeRTF - , writeRTFWithEmbeddedImages ) where import Text.Pandoc.Definition import Text.Pandoc.Options @@ -37,6 +36,7 @@ import Text.Pandoc.Writers.Shared import Text.Pandoc.Writers.Math import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Walk +import Text.Pandoc.Class (addWarning) import Data.List ( isSuffixOf, intercalate ) import Data.Char ( ord, chr, isDigit ) import qualified Data.ByteString as B @@ -64,7 +64,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do _ -> throwError $ PandocSomeError "Unknown file type" sizeSpec <- case imageSize imgdata of Left msg -> do - P.warn $ "Could not determine image size in `" ++ + addWarning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return "" Right sz -> return $ "\\picw" ++ show xpx ++ @@ -76,23 +76,27 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do (xpt, ypt) = desiredSizeInPoints opts attr sz let raw = "{\\pict" ++ filetype ++ sizeSpec ++ "\\bin " ++ concat bytes ++ "}" - return $ if B.null imgdata - then x - else RawInline (Format "rtf") raw - _ -> return x + if B.null imgdata + then do + addWarning $ "Image " ++ src ++ " contained no data, skipping." + return x + else return $ RawInline (Format "rtf") raw + | otherwise -> do + addWarning $ "Image " ++ src ++ " is not a jpeg or png, skipping." + return x + Right (_, Nothing) -> do + addWarning $ "Could not determine image type for " ++ src ++ ", skipping." + return x + Left e -> do + addWarning $ "Could not fetch image " ++ src ++ "\n" ++ show e + return x rtfEmbedImage _ x = return x --- | Convert Pandoc to a string in rich text format, with --- images embedded as encoded binary data. TODO get rid of this, --- we don't need it now that we have writeRTF in PandocMonad. -writeRTFWithEmbeddedImages :: PandocMonad m - => WriterOptions -> Pandoc -> m String -writeRTFWithEmbeddedImages options doc = - writeRTF options =<< walkM (rtfEmbedImage options) doc - -- | Convert Pandoc to a string in rich text format. writeRTF :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeRTF options (Pandoc meta@(Meta metamap) blocks) = do +writeRTF options doc = do + -- handle images + Pandoc meta@(Meta metamap) blocks <- walkM (rtfEmbedImage options) doc let spacer = not $ all null $ docTitle meta : docDate meta : docAuthors meta let toPlain (MetaBlocks [Para ils]) = MetaInlines ils toPlain x = x -- cgit v1.2.3 From a4bd650277ac8fd2c952f2330e4d23a200d691a5 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 3 Dec 2016 18:42:17 +0100 Subject: Class: rename addWarning[WithPos] to warning[WithPos]. There's already a function addWarning in Parsing! Maybe we can dispense with that now, but I still like 'warning' better as a name. --- src/Text/Pandoc/Class.hs | 22 ++++++++++------------ src/Text/Pandoc/Readers/Docx.hs | 4 ++-- src/Text/Pandoc/Readers/Markdown.hs | 10 +++++----- src/Text/Pandoc/Readers/RST.hs | 14 +++++++------- src/Text/Pandoc/Readers/TWiki.hs | 2 +- src/Text/Pandoc/Writers/Docx.hs | 2 +- src/Text/Pandoc/Writers/EPUB.hs | 4 ++-- src/Text/Pandoc/Writers/ICML.hs | 4 ++-- src/Text/Pandoc/Writers/Math.hs | 4 ++-- src/Text/Pandoc/Writers/ODT.hs | 4 ++-- src/Text/Pandoc/Writers/RTF.hs | 12 ++++++------ 11 files changed, 40 insertions(+), 42 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 3337de40a..7227742b2 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -36,8 +36,8 @@ module Text.Pandoc.Class ( PandocMonad(..) , PureState(..) , getPOSIXTime , getZonedTime - , addWarning - , addWarningWithPos + , warning + , warningWithPos , getWarnings , getMediaBag , setMediaBag @@ -121,8 +121,8 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m, MonadState C -- Functions defined for all PandocMonad instances -addWarning :: PandocMonad m => String -> m () -addWarning msg = modify $ \st -> st{stWarnings = msg : stWarnings st} +warning :: PandocMonad m => String -> m () +warning msg = modify $ \st -> st{stWarnings = msg : stWarnings st} getWarnings :: PandocMonad m => m [String] getWarnings = gets stWarnings @@ -152,14 +152,12 @@ getZonedTime = do tz <- getCurrentTimeZone return $ utcToZonedTime tz t -addWarningWithPos :: PandocMonad m - => Maybe SourcePos - -> String - -> ParserT [Char] ParserState m () -addWarningWithPos mbpos msg = - lift $ - addWarning $ - msg ++ maybe "" (\pos -> " " ++ show pos) mbpos +warningWithPos :: PandocMonad m + => Maybe SourcePos + -> String + -> ParserT [Char] ParserState m () +warningWithPos mbpos msg = + lift $ warning $ msg ++ maybe "" (\pos -> " " ++ show pos) mbpos -- diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 16542fd1f..490fdf878 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -108,7 +108,7 @@ readDocx :: PandocMonad m readDocx opts bytes | Right archive <- toArchiveOrFail bytes , Right (docx, parserWarnings) <- archiveToDocxWithWarnings archive = do - mapM_ P.addWarning parserWarnings + mapM_ P.warning parserWarnings (meta, blks) <- docxToOutput opts docx return $ Pandoc meta blks readDocx _ _ = @@ -334,7 +334,7 @@ blocksToInlinesWarn cmtId blks = do notParaOrPlain (Plain _) = False notParaOrPlain _ = True when (not $ null $ filter notParaOrPlain blkList) - ((lift . lift) $ P.addWarning $ "Docx comment " ++ cmtId ++ " will not retain formatting") + ((lift . lift) $ P.warning $ "Docx comment " ++ cmtId ++ " will not retain formatting") return $ fromList $ blocksToInlines blkList parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index b59e5a5f1..012edfe3b 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -280,7 +280,7 @@ yamlMetaBlock = try $ do ) nullMeta hashmap Right Yaml.Null -> return nullMeta Right _ -> do - P.addWarningWithPos (Just pos) "YAML header is not an object" + P.warningWithPos (Just pos) "YAML header is not an object" return nullMeta Left err' -> do case err' of @@ -291,13 +291,13 @@ yamlMetaBlock = try $ do yamlLine = yline , yamlColumn = ycol }}) -> - P.addWarningWithPos (Just $ setSourceLine + P.warningWithPos (Just $ setSourceLine (setSourceColumn pos (sourceColumn pos + ycol)) (sourceLine pos + 1 + yline)) $ "Could not parse YAML header: " ++ problem - _ -> P.addWarningWithPos (Just pos) + _ -> P.warningWithPos (Just pos) $ "Could not parse YAML header: " ++ show err' return nullMeta @@ -420,7 +420,7 @@ referenceKey = try $ do let oldkeys = stateKeys st let key = toKey raw case M.lookup key oldkeys of - Just _ -> P.addWarningWithPos (Just pos) $ "Duplicate link reference `" ++ raw ++ "'" + Just _ -> P.warningWithPos (Just pos) $ "Duplicate link reference `" ++ raw ++ "'" Nothing -> return () updateState $ \s -> s { stateKeys = M.insert key (target, attr') oldkeys } return $ return mempty @@ -486,7 +486,7 @@ noteBlock = try $ do let newnote = (ref, parsed) oldnotes <- stateNotes' <$> getState case lookup ref oldnotes of - Just _ -> P.addWarningWithPos (Just pos) $ "Duplicate note reference `" ++ ref ++ "'" + Just _ -> P.warningWithPos (Just pos) $ "Duplicate note reference `" ++ ref ++ "'" Nothing -> return () updateState $ \s -> s { stateNotes' = newnote : oldnotes } return mempty diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index df6a8114b..5e8aa20f5 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -626,7 +626,7 @@ directive' = do return $ B.divWith attrs children other -> do pos <- getPosition - P.addWarningWithPos (Just pos) $ "ignoring unknown directive: " ++ other + P.warningWithPos (Just pos) $ "ignoring unknown directive: " ++ other return mempty -- TODO: @@ -654,20 +654,20 @@ addNewRole roleString fields = do -- warn about syntax we ignore flip mapM_ fields $ \(key, _) -> case key of - "language" -> when (baseRole /= "code") $ lift $ P.addWarning $ + "language" -> when (baseRole /= "code") $ lift $ P.warning $ "ignoring :language: field because the parent of role :" ++ role ++ ": is :" ++ baseRole ++ ": not :code:" - "format" -> when (baseRole /= "raw") $ lift $ P.addWarning $ + "format" -> when (baseRole /= "raw") $ lift $ P.warning $ "ignoring :format: field because the parent of role :" ++ role ++ ": is :" ++ baseRole ++ ": not :raw:" - _ -> lift $ P.addWarning $ "ignoring unknown field :" ++ key ++ + _ -> lift $ P.warning $ "ignoring unknown field :" ++ key ++ ": in definition of role :" ++ role ++ ": in" when (parentRole == "raw" && countKeys "format" > 1) $ - lift $ P.addWarning $ + lift $ P.warning $ "ignoring :format: fields after the first in the definition of role :" ++ role ++": in" when (parentRole == "code" && countKeys "language" > 1) $ - lift $ P.addWarning $ + lift $ P.warning $ "ignoring :language: fields after the first in the definition of role :" ++ role ++": in" @@ -1065,7 +1065,7 @@ renderRole contents fmt role attr = case role of renderRole contents newFmt newRole newAttr Nothing -> do pos <- getPosition - P.addWarningWithPos (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in" + P.warningWithPos (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in" return $ B.str contents -- Undefined role where titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs index cc4f8f39c..b4546883b 100644 --- a/src/Text/Pandoc/Readers/TWiki.hs +++ b/src/Text/Pandoc/Readers/TWiki.hs @@ -58,7 +58,7 @@ readTWiki :: PandocMonad m -> m Pandoc readTWiki opts s = case readTWikiWithWarnings' opts s of Right (doc, warns) -> do - mapM_ P.addWarning warns + mapM_ P.warning warns return doc Left e -> throwError e diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 3b1df6bd9..0f040d19b 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1182,7 +1182,7 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do res <- (lift . lift) $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - (lift . lift) $ P.addWarning ("Could not find image `" ++ src ++ "', skipping...") + (lift . lift) $ P.warning ("Could not find image `" ++ src ++ "', skipping...") -- emit alt text inlinesToOpenXML opts alt Right (img, mt) -> do diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index b1266c4c9..1c3a44207 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -398,7 +398,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do let matchingGlob f = do xs <- lift $ P.glob f when (null xs) $ - lift $ P.addWarning $ f ++ " did not match any font files." + lift $ P.warning $ f ++ " did not match any font files." return xs let mkFontEntry f = mkEntry (takeFileName f) `fmap` (lift $ P.readFileLazy f) fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts') @@ -864,7 +864,7 @@ modifyMediaRef opts oldsrc = do (new, mbEntry) <- case res of Left _ -> do - lift $ P.addWarning $ "Could not find media `" ++ oldsrc ++ "', skipping..." + lift $ P.warning $ "Could not find media `" ++ oldsrc ++ "', skipping..." return (oldsrc, Nothing) Right (img,mbMime) -> do let new = "media/file" ++ show (length media) ++ diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 482e20f4b..6bc7436d8 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -537,13 +537,13 @@ imageICML opts style attr (src, _) = do res <- lift $ P.fetchItem (writerSourceURL opts) src imgS <- case res of Left (_) -> do - lift $ P.addWarning $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.warning $ "Could not find image `" ++ src ++ "', skipping..." return def Right (img, _) -> do case imageSize img of Right size -> return size Left msg -> do - lift $ P.addWarning $ "Could not determine image size in `" ++ + lift $ P.warning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return def let (ow, oh) = sizeInPoints imgS diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs index 552db8b32..b959ce972 100644 --- a/src/Text/Pandoc/Writers/Math.hs +++ b/src/Text/Pandoc/Writers/Math.hs @@ -20,7 +20,7 @@ texMathToInlines mt inp = do case res of Right (Just ils) -> return ils Right (Nothing) -> do - addWarning $ "Could not render TeX math as unicode, rendering as raw TeX:\n" ++ inp + warning $ "Could not render TeX math as unicode, rendering as raw TeX:\n" ++ inp return [mkFallback mt inp] Left il -> return [il] @@ -40,7 +40,7 @@ convertMath writer mt str = do case writer dt <$> readTeX str of Right r -> return (Right r) Left e -> do - addWarning $ "Could not convert TeX math, rendering as raw TeX:\n" ++ + warning $ "Could not convert TeX math, rendering as raw TeX:\n" ++ str ++ "\n" ++ e return (Left $ mkFallback mt str) where dt = case mt of diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index db9090e29..b17b18a21 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -147,13 +147,13 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src case res of Left (_ :: E.SomeException) -> do - lift $ P.addWarning $ "Could not find image `" ++ src ++ "', skipping..." + lift $ P.warning $ "Could not find image `" ++ src ++ "', skipping..." return $ Emph lab Right (img, mbMimeType) -> do (ptX, ptY) <- case imageSize img of Right s -> return $ sizeInPoints s Left msg -> do - lift $ P.addWarning $ "Could not determine image size in `" ++ + lift $ P.warning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return (100, 100) let dims = diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 32f70cb31..a3351a705 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -36,7 +36,7 @@ import Text.Pandoc.Writers.Shared import Text.Pandoc.Writers.Math import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Walk -import Text.Pandoc.Class (addWarning) +import Text.Pandoc.Class (warning) import Data.List ( isSuffixOf, intercalate ) import Data.Char ( ord, chr, isDigit ) import qualified Data.ByteString as B @@ -64,7 +64,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do _ -> throwError $ PandocSomeError "Unknown file type" sizeSpec <- case imageSize imgdata of Left msg -> do - addWarning $ "Could not determine image size in `" ++ + warning $ "Could not determine image size in `" ++ src ++ "': " ++ msg return "" Right sz -> return $ "\\picw" ++ show xpx ++ @@ -78,17 +78,17 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do concat bytes ++ "}" if B.null imgdata then do - addWarning $ "Image " ++ src ++ " contained no data, skipping." + warning $ "Image " ++ src ++ " contained no data, skipping." return x else return $ RawInline (Format "rtf") raw | otherwise -> do - addWarning $ "Image " ++ src ++ " is not a jpeg or png, skipping." + warning $ "Image " ++ src ++ " is not a jpeg or png, skipping." return x Right (_, Nothing) -> do - addWarning $ "Could not determine image type for " ++ src ++ ", skipping." + warning $ "Could not determine image type for " ++ src ++ ", skipping." return x Left e -> do - addWarning $ "Could not fetch image " ++ src ++ "\n" ++ show e + warning $ "Could not fetch image " ++ src ++ "\n" ++ show e return x rtfEmbedImage _ x = return x -- cgit v1.2.3 From bc61c6a632ea8d3e39399074c6e447a9a17b0c94 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 8 Dec 2016 22:16:35 +0100 Subject: Remove now-unnecessary lifts in Markdown writer. Other writers still TBD. --- src/Text/Pandoc/Writers/Markdown.hs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 66e0365d8..7f4d37b1f 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -200,7 +200,7 @@ pandocToMarkdown opts (Pandoc meta blocks) = do Nothing -> empty let headerBlocks = filter isHeaderBlock blocks toc <- if writerTableOfContents opts - then liftPandoc $ tableOfContents opts headerBlocks + then tableOfContents opts headerBlocks else return empty -- Strip off final 'references' header if markdown citations enabled let blocks' = if isEnabled Ext_citations opts @@ -533,7 +533,7 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do rawHeaders rawRows | isEnabled Ext_raw_html opts -> fmap (id,) $ text <$> - (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [t]) + (writeHtmlString def $ Pandoc nullMeta [t]) | otherwise -> return $ (id, text "[TABLE]") return $ nst $ tbl $$ blankline $$ caption'' $$ blankline blockToMarkdown' opts (BulletList items) = do @@ -985,7 +985,7 @@ inlineToMarkdown opts (Math InlineMath str) = return $ "\\\\(" <> text str <> "\\\\)" | otherwise -> do plain <- asks envPlain - (liftPandoc (texMathToInlines InlineMath str)) >>= + texMathToInlines InlineMath str >>= inlineListToMarkdown opts . (if plain then makeMathPlainer else id) inlineToMarkdown opts (Math DisplayMath str) = @@ -1000,8 +1000,7 @@ inlineToMarkdown opts (Math DisplayMath str) = | isEnabled Ext_tex_math_double_backslash opts -> return $ "\\\\[" <> text str <> "\\\\]" | otherwise -> (\x -> cr <> x <> cr) `fmap` - (liftPandoc (texMathToInlines DisplayMath str) >>= - inlineListToMarkdown opts) + texMathToInlines DisplayMath str >>= inlineListToMarkdown opts inlineToMarkdown opts (RawInline f str) = do plain <- asks envPlain if not plain && @@ -1063,7 +1062,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 - (text . trim) <$> (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]]) + (text . trim) <$> writeHtmlString def (Pandoc nullMeta [Plain [lnk]]) | otherwise = do plain <- asks envPlain linktext <- inlineListToMarkdown opts txt @@ -1102,7 +1101,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 - (text . trim) <$> (liftPandoc $ writeHtmlString def $ Pandoc nullMeta [Plain [img]]) + (text . trim) <$> writeHtmlString def (Pandoc nullMeta [Plain [img]]) | otherwise = do plain <- asks envPlain let txt = if null alternate || alternate == [Str source] @@ -1127,5 +1126,3 @@ makeMathPlainer = walk go go (Emph xs) = Span nullAttr xs go x = x -liftPandoc :: PandocMonad m => m a -> MD m a -liftPandoc = lift . lift -- cgit v1.2.3 From ce1664cf2ba29c8b973d7a228744b43144c0859d Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 10 Dec 2016 10:39:44 +0100 Subject: Simplified reference-docx/reference-odt to reference-doc. * Text.Pandoc.Options.WriterOptions: removed writerReferenceDocx and writerReferenceODT, replaced them with writerReferenceDoc. This can hold either an ODT or a Docx. In this way, writerReferenceDoc is like writerTemplate, which can hold templates of different formats. [API change] * Removed `--reference-docx` and `--reference-odt` options. * Added `--reference-doc` option. --- MANUAL.txt | 74 ++++++++++++++++++++--------------------- pandoc.hs | 25 ++++---------- src/Text/Pandoc/Options.hs | 6 ++-- src/Text/Pandoc/Writers/Docx.hs | 2 +- src/Text/Pandoc/Writers/ODT.hs | 2 +- tests/Tests/Writers/Docx.hs | 2 +- 6 files changed, 49 insertions(+), 62 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index c9b6c0fb1..5d53c192d 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -794,35 +794,20 @@ Options affecting specific writers : Link to a CSS style sheet. This option can be used repeatedly to include multiple files. They will be included in the order specified. -`--reference-odt=`*FILE* +`--reference-doc=`*FILE* -: Use the specified file as a style reference in producing an ODT. - For best results, the reference ODT should be a modified version - of an ODT produced using pandoc. The contents of the reference ODT - are ignored, but its stylesheets are used in the new ODT. If no - reference ODT is specified on the command line, pandoc will look - for a file `reference.odt` in the user data directory (see - `--data-dir`). If this is not found either, sensible defaults will be - used. +: Use the specified file as a style reference in producing a + docx or ODT file. - To produce a custom `reference.odt`, first get a copy of - the default `reference.odt`: `pandoc - --print-default-data-file reference.odt > - custom-reference.odt`. Then open `custom-reference.docx` in - LibreOffice, modify the styles as you wish, and save the - file. - -`--reference-docx=`*FILE* - -: Use the specified file as a style reference in producing a docx file. - For best results, the reference docx should be a modified version - of a docx file produced using pandoc. The contents of the reference docx - are ignored, but its stylesheets and document properties (including - margins, page size, header, and footer) are used in the new docx. If no - reference docx is specified on the command line, pandoc will look - for a file `reference.docx` in the user data directory (see - `--data-dir`). If this is not found either, sensible defaults will be - used. + Docx: For best results, the reference docx should be a modified + version of a docx file produced using pandoc. The contents + of the reference docx are ignored, but its stylesheets and + document properties (including margins, page size, header, + and footer) are used in the new docx. If no reference docx + is specified on the command line, pandoc will look for a + file `reference.docx` in the user data directory (see + `--data-dir`). If this is not found either, sensible + defaults will be used. To produce a custom `reference.docx`, first get a copy of the default `reference.docx`: `pandoc @@ -830,15 +815,30 @@ Options affecting specific writers custom-reference.docx`. Then open `custom-reference.docx` in Word, modify the styles as you wish, and save the file. For best results, do not make changes to this file other - than modifying the styles used by pandoc: [paragraph] Normal, - Body Text, First Paragraph, Compact, Title, Subtitle, - Author, Date, Abstract, Bibliography, Heading 1, Heading 2, - Heading 3, Heading 4, Heading 5, Heading 6, Block Text, - Footnote Text, Definition Term, Definition, Caption, Table - Caption, Image Caption, Figure, Figure With Caption, TOC - Heading; [character] Default Paragraph Font, Body Text Char, - Verbatim Char, Footnote Reference, Hyperlink; [table] Normal - Table. + than modifying the styles used by pandoc: [paragraph] + Normal, Body Text, First Paragraph, Compact, Title, + Subtitle, Author, Date, Abstract, Bibliography, Heading 1, + Heading 2, Heading 3, Heading 4, Heading 5, Heading 6, Block + Text, Footnote Text, Definition Term, Definition, Caption, + Table Caption, Image Caption, Figure, Figure With Caption, + TOC Heading; [character] Default Paragraph Font, Body Text + Char, Verbatim Char, Footnote Reference, Hyperlink; [table] + Normal Table. + + ODT: For best results, the reference ODT should be a modified + version of an ODT produced using pandoc. The contents of + the reference ODT are ignored, but its stylesheets are used + in the new ODT. If no reference ODT is specified on the + command line, pandoc will look for a file `reference.odt` in + the user data directory (see `--data-dir`). If this is not + found either, sensible defaults will be used. + + To produce a custom `reference.odt`, first get a copy of + the default `reference.odt`: `pandoc + --print-default-data-file reference.odt > + custom-reference.odt`. Then open `custom-reference.docx` in + LibreOffice, modify the styles as you wish, and save the + file. `--epub-stylesheet=`*FILE* @@ -1099,7 +1099,7 @@ directory (see `--data-dir`, above). *Exceptions:* (or the `default.beamer` template, if you use `-t beamer`, or the `default.context` template, if you use `-t context`). - `docx` has no template (however, you can use - `--reference-docx` to customize the output). + `--reference-doc` to customize the output). Templates contain *variables*, which allow for the inclusion of arbitrary information at any point in the file. Variables may be set diff --git a/pandoc.hs b/pandoc.hs index f1a9aac05..f5d5e0da6 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -185,8 +185,7 @@ data Opt = Opt , optHighlightStyle :: Style -- ^ Style to use for highlighted code , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math - , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt - , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx + , optReferenceDoc :: Maybe FilePath -- ^ Path of reference doc , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet , optEpubMetadata :: String -- ^ EPUB metadata , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed @@ -252,8 +251,7 @@ defaultOpts = Opt , optHighlightStyle = pygments , optTopLevelDivision = TopLevelDefault , optHTMLMathMethod = PlainMath - , optReferenceODT = Nothing - , optReferenceDocx = Nothing + , optReferenceDoc = Nothing , optEpubStylesheet = Nothing , optEpubMetadata = "" , optEpubFonts = [] @@ -708,19 +706,12 @@ options = "URL") "" -- "Link to CSS style sheet" - , Option "" ["reference-odt"] + , Option "" ["reference-doc"] (ReqArg (\arg opt -> - return opt { optReferenceODT = Just arg }) + return opt { optReferenceDoc = Just arg }) "FILENAME") - "" -- "Path of custom reference.odt" - - , Option "" ["reference-docx"] - (ReqArg - (\arg opt -> - return opt { optReferenceDocx = Just arg }) - "FILENAME") - "" -- "Path of custom reference.docx" + "" -- "Path of custom reference doc" , Option "" ["epub-stylesheet"] (ReqArg @@ -1190,8 +1181,7 @@ convertWithOpts opts args = do , optHighlightStyle = highlightStyle , optTopLevelDivision = topLevelDivision , optHTMLMathMethod = mathMethod' - , optReferenceODT = referenceODT - , optReferenceDocx = referenceDocx + , optReferenceDoc = referenceDoc , optEpubStylesheet = epubStylesheet , optEpubMetadata = epubMetadata , optEpubFonts = epubFonts @@ -1485,8 +1475,7 @@ convertWithOpts opts args = do writerEpubFonts = epubFonts, writerEpubChapterLevel = epubChapterLevel, writerTOCDepth = epubTOCDepth, - writerReferenceODT = referenceODT, - writerReferenceDocx = referenceDocx, + writerReferenceDoc = referenceDoc, writerMediaBag = media, writerVerbose = verbose, writerLaTeXArgs = latexEngineArgs diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 48bc5f4eb..4fee577e7 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -395,8 +395,7 @@ data WriterOptions = WriterOptions , writerEpubFonts :: [FilePath] -- ^ Paths to fonts to embed , writerEpubChapterLevel :: Int -- ^ Header level for chapters (separate files) , writerTOCDepth :: Int -- ^ Number of levels to include in TOC - , writerReferenceODT :: Maybe FilePath -- ^ Path to reference ODT if specified - , writerReferenceDocx :: Maybe FilePath -- ^ Path to reference DOCX if specified + , writerReferenceDoc :: Maybe FilePath -- ^ Path to reference document if specified , writerMediaBag :: MediaBag -- ^ Media collected by docx or epub reader , writerVerbose :: Bool -- ^ Verbose debugging output , writerLaTeXArgs :: [String] -- ^ Flags to pass to latex-engine @@ -442,8 +441,7 @@ instance Default WriterOptions where , writerEpubFonts = [] , writerEpubChapterLevel = 1 , writerTOCDepth = 3 - , writerReferenceODT = Nothing - , writerReferenceDocx = Nothing + , writerReferenceDoc = Nothing , writerMediaBag = mempty , writerVerbose = False , writerLaTeXArgs = [] diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 0f040d19b..20320907e 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -225,7 +225,7 @@ writeDocx opts doc@(Pandoc meta _) = do username <- P.lookupEnv "USERNAME" utctime <- P.getCurrentTime distArchive <- P.getDefaultReferenceDocx datadir - refArchive <- case writerReferenceDocx opts of + refArchive <- case writerReferenceDoc opts of Just f -> toArchive <$> P.readFileLazy f Nothing -> P.getDefaultReferenceDocx datadir diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index b17b18a21..a1a1c4f62 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -77,7 +77,7 @@ pandocToODT opts doc@(Pandoc meta _) = do let datadir = writerUserDataDir opts let title = docTitle meta refArchive <- - case writerReferenceODT opts of + case writerReferenceDoc opts of Just f -> liftM toArchive $ lift $ P.readFileLazy f Nothing -> lift $ P.getDefaultReferenceODT datadir -- handle formulas and pictures diff --git a/tests/Tests/Writers/Docx.hs b/tests/Tests/Writers/Docx.hs index 548e9ddcf..44095925f 100644 --- a/tests/Tests/Writers/Docx.hs +++ b/tests/Tests/Writers/Docx.hs @@ -141,7 +141,7 @@ tests = [ testGroup "inlines" ] , testGroup "customized styles" [ testCompareWithOpts - ( def{writerReferenceDocx=Just "docx/custom-style-reference.docx"} + ( def{writerReferenceDoc=Just "docx/custom-style-reference.docx"} , def) "simple customized blocks and inlines" "docx/custom-style-roundtrip-start.native" -- cgit v1.2.3 From b5d15670223ada11a357161f3b057fae6f852554 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 10 Dec 2016 23:41:37 +0100 Subject: Class: removed 'fail' from PandocMonad. Do we need this? I don't see why. There's a name clash which would better be avoided. --- src/Text/Pandoc/Class.hs | 24 ++++++++++++------------ src/Text/Pandoc/Writers/Docx.hs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 7f86e27b1..8b94d64a9 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -58,8 +58,7 @@ module Text.Pandoc.Class ( PandocMonad(..) , withWarningsToStderr ) where -import Prelude hiding (readFile, fail) -import qualified Control.Monad as M (fail) +import Prelude hiding (readFile) import System.Random (StdGen, next, mkStdGen) import qualified System.Random as IO (newStdGen) import Codec.Archive.Zip (Archive, fromArchive, emptyArchive) @@ -90,11 +89,12 @@ import System.FilePath.Glob (match, compile) import System.FilePath (()) import qualified System.FilePath.Glob as IO (glob) import qualified System.Directory as IO (getModificationTime) -import Control.Monad.State hiding (fail) +import Control.Monad as M (fail) import Control.Monad.Reader (ReaderT) +import Control.Monad.State +import Control.Monad.Except import Control.Monad.Writer (WriterT) import Control.Monad.RWS (RWST) -import Control.Monad.Except hiding (fail) import Data.Word (Word8) import Data.Default import System.IO.Error @@ -121,7 +121,7 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m) -> Maybe String -> String -> m (Either E.SomeException (B.ByteString, Maybe MimeType)) - fail :: String -> m b + -- fail :: String -> m b glob :: String -> m [FilePath] getModificationTime :: FilePath -> m UTCTime getCommonState :: m CommonState @@ -231,7 +231,7 @@ instance PandocMonad PandocIO where case eitherBS of Right bs -> return bs Left _ -> throwError $ PandocFileReadError fname - fail = M.fail + -- fail = M.fail fetchItem ms s = liftIO $ IO.fetchItem ms s fetchItem' mb ms s = liftIO $ IO.fetchItem' mb ms s glob = liftIO . IO.glob @@ -361,7 +361,7 @@ instance PandocMonad PandocPure where case infoFileContents <$> (getFileInfo (userDir fname) userDirFiles) of Just bs -> return bs Nothing -> readDataFile Nothing fname - fail = M.fail + -- fail = M.fail fetchItem _ fp = do fps <- getsPureState stFiles case infoFileContents <$> (getFileInfo fp fps) of @@ -396,7 +396,7 @@ instance PandocMonad m => PandocMonad (ParserT s st m) where newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy readDataFile mbuserdir = lift . readDataFile mbuserdir - fail = lift . fail + -- fail = lift . fail fetchItem media = lift . fetchItem media fetchItem' media sourceUrl = lift . fetchItem' media sourceUrl glob = lift . glob @@ -414,7 +414,7 @@ instance PandocMonad m => PandocMonad (ReaderT r m) where newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy readDataFile mbuserdir = lift . readDataFile mbuserdir - fail = lift . fail + -- fail = lift . fail fetchItem media = lift . fetchItem media fetchItem' media sourceUrl = lift . fetchItem' media sourceUrl glob = lift . glob @@ -432,7 +432,7 @@ instance (PandocMonad m, Monoid w) => PandocMonad (WriterT w m) where newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy readDataFile mbuserdir = lift . readDataFile mbuserdir - fail = lift . fail + -- fail = lift . fail fetchItem media = lift . fetchItem media fetchItem' media sourceUrl = lift . fetchItem' media sourceUrl glob = lift . glob @@ -450,7 +450,7 @@ instance (PandocMonad m, Monoid w) => PandocMonad (RWST r w st m) where newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy readDataFile mbuserdir = lift . readDataFile mbuserdir - fail = lift . fail + -- fail = lift . fail fetchItem media = lift . fetchItem media fetchItem' media sourceUrl = lift . fetchItem' media sourceUrl glob = lift . glob @@ -468,7 +468,7 @@ instance PandocMonad m => PandocMonad (StateT st m) where newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy readDataFile mbuserdir = lift . readDataFile mbuserdir - fail = lift . fail + -- fail = lift . fail fetchItem media = lift . fetchItem media fetchItem' media sourceUrl = lift . fetchItem' media sourceUrl glob = lift . glob diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 20320907e..662b4d3bb 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1276,7 +1276,7 @@ parseXml refArchive distArchive relpath = findEntryByPath relpath distArchive of Nothing -> fail $ relpath ++ " missing in reference docx" Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of - Nothing -> P.fail $ relpath ++ " corrupt in reference docx" + Nothing -> fail $ relpath ++ " corrupt in reference docx" Just d -> return d -- | Scales the image to fit the page -- cgit v1.2.3 From 08110c371484cb74206a150fe9c2e06eeb32e475 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 11 Dec 2016 16:21:08 +0100 Subject: Class: Removed getDefaultReferenceDocx/ODT from PandocMonad. We don't need these, since the default docx and odt can be retrieved using `readDataFile datadir "reference.docx"` (or odt). --- src/Text/Pandoc/Class.hs | 24 ++---------------------- src/Text/Pandoc/Writers/Docx.hs | 5 +++-- src/Text/Pandoc/Writers/ODT.hs | 3 ++- 3 files changed, 7 insertions(+), 25 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 402fe9dcf..7af9b8bdd 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -66,8 +66,6 @@ import Data.Unique (hashUnique) import qualified Data.Unique as IO (newUnique) import qualified Text.Pandoc.Shared as IO ( fetchItem , fetchItem' - , getDefaultReferenceDocx - , getDefaultReferenceODT , readDataFile , warn) import Text.Pandoc.Compat.Time (UTCTime) @@ -106,8 +104,6 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m) lookupEnv :: String -> m (Maybe String) getCurrentTime :: m UTCTime getCurrentTimeZone :: m TimeZone - getDefaultReferenceDocx :: Maybe FilePath -> m Archive - getDefaultReferenceODT :: Maybe FilePath -> m Archive newStdGen :: m StdGen newUniqueHash :: m Int readFileLazy :: FilePath -> m BL.ByteString @@ -215,8 +211,6 @@ instance PandocMonad PandocIO where lookupEnv = liftIO . IO.lookupEnv getCurrentTime = liftIO IO.getCurrentTime getCurrentTimeZone = liftIO IO.getCurrentTimeZone - getDefaultReferenceDocx = liftIO . IO.getDefaultReferenceDocx - getDefaultReferenceODT = liftIO . IO.getDefaultReferenceODT newStdGen = liftIO IO.newStdGen newUniqueHash = hashUnique <$> (liftIO IO.newUnique) readFileLazy s = do @@ -325,10 +319,6 @@ instance PandocMonad PandocPure where getCurrentTimeZone = getsPureState stTimeZone - getDefaultReferenceDocx _ = getsPureState stReferenceDocx - - getDefaultReferenceODT _ = getsPureState stReferenceODT - newStdGen = do g <- getsPureState stStdGen let (_, nxtGen) = next g @@ -348,9 +338,9 @@ instance PandocMonad PandocPure where Just bs -> return (BL.fromStrict bs) Nothing -> throwError $ PandocFileReadError fp readDataFile Nothing "reference.docx" = do - (B.concat . BL.toChunks . fromArchive) <$> (getDefaultReferenceDocx Nothing) + (B.concat . BL.toChunks . fromArchive) <$> getsPureState stReferenceDocx readDataFile Nothing "reference.odt" = do - (B.concat . BL.toChunks . fromArchive) <$> (getDefaultReferenceODT Nothing) + (B.concat . BL.toChunks . fromArchive) <$> getsPureState stReferenceODT readDataFile Nothing fname = do let fname' = if fname == "MANUAL.txt" then fname else "data" fname BL.toStrict <$> (readFileLazy fname') @@ -387,8 +377,6 @@ instance PandocMonad m => PandocMonad (ParserT s st m) where lookupEnv = lift . lookupEnv getCurrentTime = lift getCurrentTime getCurrentTimeZone = lift getCurrentTimeZone - getDefaultReferenceDocx = lift . getDefaultReferenceDocx - getDefaultReferenceODT = lift . getDefaultReferenceODT newStdGen = lift newStdGen newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy @@ -404,8 +392,6 @@ instance PandocMonad m => PandocMonad (ReaderT r m) where lookupEnv = lift . lookupEnv getCurrentTime = lift getCurrentTime getCurrentTimeZone = lift getCurrentTimeZone - getDefaultReferenceDocx = lift . getDefaultReferenceDocx - getDefaultReferenceODT = lift . getDefaultReferenceODT newStdGen = lift newStdGen newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy @@ -421,8 +407,6 @@ instance (PandocMonad m, Monoid w) => PandocMonad (WriterT w m) where lookupEnv = lift . lookupEnv getCurrentTime = lift getCurrentTime getCurrentTimeZone = lift getCurrentTimeZone - getDefaultReferenceDocx = lift . getDefaultReferenceDocx - getDefaultReferenceODT = lift . getDefaultReferenceODT newStdGen = lift newStdGen newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy @@ -438,8 +422,6 @@ instance (PandocMonad m, Monoid w) => PandocMonad (RWST r w st m) where lookupEnv = lift . lookupEnv getCurrentTime = lift getCurrentTime getCurrentTimeZone = lift getCurrentTimeZone - getDefaultReferenceDocx = lift . getDefaultReferenceDocx - getDefaultReferenceODT = lift . getDefaultReferenceODT newStdGen = lift newStdGen newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy @@ -455,8 +437,6 @@ instance PandocMonad m => PandocMonad (StateT st m) where lookupEnv = lift . lookupEnv getCurrentTime = lift getCurrentTime getCurrentTimeZone = lift getCurrentTimeZone - getDefaultReferenceDocx = lift . getDefaultReferenceDocx - getDefaultReferenceODT = lift . getDefaultReferenceODT newStdGen = lift newStdGen newUniqueHash = lift newUniqueHash readFileLazy = lift . readFileLazy diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 662b4d3bb..07aed0c9b 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -224,10 +224,11 @@ writeDocx opts doc@(Pandoc meta _) = do let doc' = walk fixDisplayMath $ doc username <- P.lookupEnv "USERNAME" utctime <- P.getCurrentTime - distArchive <- P.getDefaultReferenceDocx datadir + distArchive <- (toArchive . BL.fromStrict) <$> + P.readDataFile datadir "reference.docx" refArchive <- case writerReferenceDoc opts of Just f -> toArchive <$> P.readFileLazy f - Nothing -> P.getDefaultReferenceDocx datadir + Nothing -> return distArchive parsedDoc <- parseXml refArchive distArchive "word/document.xml" let wname f qn = qPrefix qn == Just "w" && f (qName qn) diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index a1a1c4f62..0e4999712 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -79,7 +79,8 @@ pandocToODT opts doc@(Pandoc meta _) = do refArchive <- case writerReferenceDoc opts of Just f -> liftM toArchive $ lift $ P.readFileLazy f - Nothing -> lift $ P.getDefaultReferenceODT datadir + Nothing -> lift $ (toArchive . B.fromStrict) <$> + P.readDataFile datadir "reference.odt" -- handle formulas and pictures -- picEntriesRef <- P.newIORef ([] :: [Entry]) doc' <- walkM (transformPicMath opts) $ walk fixDisplayMath doc -- cgit v1.2.3 From 8165014df679338d5bf228d84efc74b2c5ac39d2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 11 Dec 2016 22:09:33 +0100 Subject: Removed `--normalize` option and normalization functions from Shared. * Removed normalize, normalizeInlines, normalizeBlocks from Text.Pandoc.Shared. These shouldn't now be necessary, since normalization is handled automatically by the Builder monoid instance. * Remove `--normalize` command-line option. * Don't use normalize in tests. * A few revisions to readers so they work well without normalize. --- MANUAL.txt | 5 -- pandoc.hs | 8 +- src/Text/Pandoc/Readers/RST.hs | 2 +- src/Text/Pandoc/Readers/Txt2Tags.hs | 8 +- src/Text/Pandoc/Shared.hs | 150 ------------------------------------ src/Text/Pandoc/Writers/Docx.hs | 4 +- src/Text/Pandoc/Writers/DokuWiki.hs | 15 +++- tests/Tests/Helpers.hs | 8 +- tests/Tests/Old.hs | 12 +-- tests/Tests/Readers/Org.hs | 2 +- tests/Tests/Readers/Txt2Tags.hs | 2 +- tests/Tests/Shared.hs | 22 +----- tests/rst-reader.native | 6 -- 13 files changed, 30 insertions(+), 214 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index 9cfd6026a..9ac79da2e 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -478,11 +478,6 @@ Reader options underlying document (which is accessible from filters and may be printed in some output formats). -`--normalize` - -: Normalize the document after reading: merge adjacent - `Str` or `Emph` elements, for example, and remove repeated `Space`s. - `-p`, `--preserve-tabs` : Preserve tabs instead of converting them to spaces (the default). diff --git a/pandoc.hs b/pandoc.hs index dd58e79ab..b758aaa97 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -35,7 +35,7 @@ import Text.Pandoc.Builder (setMeta) import Text.Pandoc.PDF (makePDF) import Text.Pandoc.Walk (walk) import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile, - safeRead, headerShift, normalize, err, warn, + safeRead, headerShift, err, warn, openURL ) import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag ) import Text.Pandoc.XML ( toEntities ) @@ -731,12 +731,6 @@ options = "PROGRAM") "" -- "External JSON filter" - , Option "" ["normalize"] - (NoArg - (\opt -> return opt { optTransforms = - normalize : optTransforms opt } )) - "" -- "Normalize the Pandoc AST" - , Option "p" ["preserve-tabs"] (NoArg (\opt -> return opt { optPreserveTabs = True })) diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 75cd03d30..57b6c6f6c 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -744,7 +744,7 @@ addNewRole roleString fields = do M.insert role (baseRole, fmt, attr) customRoles } - return $ B.singleton Null + return mempty where countKeys k = length . filter (== k) . map fst $ fields inheritedRole = diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs index 4abe13827..d2459ba47 100644 --- a/src/Text/Pandoc/Readers/Txt2Tags.hs +++ b/src/Text/Pandoc/Readers/Txt2Tags.hs @@ -447,9 +447,13 @@ inlineMarkup p f c special = try $ do lastChar <- anyChar end <- many1 (char c) let parser inp = parseFromString (mconcat <$> many p) inp - let start' = special (drop 2 start) + let start' = case drop 2 start of + "" -> mempty + xs -> special xs body' <- parser (middle ++ [lastChar]) - let end' = special (drop 2 end) + let end' = case drop 2 end of + "" -> mempty + xs -> special xs return $ f (start' <> body' <> end') Nothing -> do -- Either bad or case such as ***** guard (l >= 5) diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 3df016996..6f52a8290 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -55,9 +55,6 @@ module Text.Pandoc.Shared ( orderedListMarkers, normalizeSpaces, extractSpaces, - normalize, - normalizeInlines, - normalizeBlocks, removeFormatting, stringify, capitalize, @@ -398,153 +395,6 @@ extractSpaces f is = _ -> mempty in (left <> f (B.trimInlines . B.Many $ contents) <> right) --- | Normalize @Pandoc@ document, consolidating doubled 'Space's, --- combining adjacent 'Str's and 'Emph's, remove 'Null's and --- empty elements, etc. -normalize :: Pandoc -> Pandoc -normalize (Pandoc (Meta meta) blocks) = - Pandoc (Meta $ M.map go meta) (normalizeBlocks blocks) - where go (MetaInlines xs) = MetaInlines $ normalizeInlines xs - go (MetaBlocks xs) = MetaBlocks $ normalizeBlocks xs - go (MetaList ms) = MetaList $ map go ms - go (MetaMap m) = MetaMap $ M.map go m - go x = x - -normalizeBlocks :: [Block] -> [Block] -normalizeBlocks (Null : xs) = normalizeBlocks xs -normalizeBlocks (Div attr bs : xs) = - Div attr (normalizeBlocks bs) : normalizeBlocks xs -normalizeBlocks (BlockQuote bs : xs) = - case normalizeBlocks bs of - [] -> normalizeBlocks xs - bs' -> BlockQuote bs' : normalizeBlocks xs -normalizeBlocks (BulletList [] : xs) = normalizeBlocks xs -normalizeBlocks (BulletList items : xs) = - BulletList (map normalizeBlocks items) : normalizeBlocks xs -normalizeBlocks (OrderedList _ [] : xs) = normalizeBlocks xs -normalizeBlocks (OrderedList attr items : xs) = - OrderedList attr (map normalizeBlocks items) : normalizeBlocks xs -normalizeBlocks (DefinitionList [] : xs) = normalizeBlocks xs -normalizeBlocks (DefinitionList items : xs) = - DefinitionList (map go items) : normalizeBlocks xs - where go (ils, bs) = (normalizeInlines ils, map normalizeBlocks bs) -normalizeBlocks (RawBlock _ "" : xs) = normalizeBlocks xs -normalizeBlocks (RawBlock f x : xs) = - case normalizeBlocks xs of - (RawBlock f' x' : rest) | f' == f -> - RawBlock f (x ++ ('\n':x')) : rest - rest -> RawBlock f x : rest -normalizeBlocks (Para ils : xs) = - case normalizeInlines ils of - [] -> normalizeBlocks xs - ils' -> Para ils' : normalizeBlocks xs -normalizeBlocks (Plain ils : xs) = - case normalizeInlines ils of - [] -> normalizeBlocks xs - ils' -> Plain ils' : normalizeBlocks xs -normalizeBlocks (Header lev attr ils : xs) = - Header lev attr (normalizeInlines ils) : normalizeBlocks xs -normalizeBlocks (Table capt aligns widths hdrs rows : xs) = - Table (normalizeInlines capt) aligns widths - (map normalizeBlocks hdrs) (map (map normalizeBlocks) rows) - : normalizeBlocks xs -normalizeBlocks (x:xs) = x : normalizeBlocks xs -normalizeBlocks [] = [] - -normalizeInlines :: [Inline] -> [Inline] -normalizeInlines (Str x : ys) = - case concat (x : map fromStr strs) of - "" -> rest - n -> Str n : rest - where - (strs, rest) = span isStr $ normalizeInlines ys - isStr (Str _) = True - isStr _ = False - fromStr (Str z) = z - fromStr _ = error "normalizeInlines - fromStr - not a Str" -normalizeInlines (Space : SoftBreak : ys) = - SoftBreak : normalizeInlines ys -normalizeInlines (Space : ys) = - if null rest - then [] - else Space : rest - where isSp Space = True - isSp _ = False - rest = dropWhile isSp $ normalizeInlines ys -normalizeInlines (Emph xs : zs) = - case normalizeInlines zs of - (Emph ys : rest) -> normalizeInlines $ - Emph (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> Emph xs' : rest -normalizeInlines (Strong xs : zs) = - case normalizeInlines zs of - (Strong ys : rest) -> normalizeInlines $ - Strong (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> Strong xs' : rest -normalizeInlines (Subscript xs : zs) = - case normalizeInlines zs of - (Subscript ys : rest) -> normalizeInlines $ - Subscript (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> Subscript xs' : rest -normalizeInlines (Superscript xs : zs) = - case normalizeInlines zs of - (Superscript ys : rest) -> normalizeInlines $ - Superscript (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> Superscript xs' : rest -normalizeInlines (SmallCaps xs : zs) = - case normalizeInlines zs of - (SmallCaps ys : rest) -> normalizeInlines $ - SmallCaps (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> SmallCaps xs' : rest -normalizeInlines (Strikeout xs : zs) = - case normalizeInlines zs of - (Strikeout ys : rest) -> normalizeInlines $ - Strikeout (normalizeInlines $ xs ++ ys) : rest - rest -> case normalizeInlines xs of - [] -> rest - xs' -> Strikeout xs' : rest -normalizeInlines (RawInline _ [] : ys) = normalizeInlines ys -normalizeInlines (RawInline f xs : zs) = - case normalizeInlines zs of - (RawInline f' ys : rest) | f == f' -> normalizeInlines $ - RawInline f (xs ++ ys) : rest - rest -> RawInline f xs : rest -normalizeInlines (Code _ "" : ys) = normalizeInlines ys -normalizeInlines (Code attr xs : zs) = - case normalizeInlines zs of - (Code attr' ys : rest) | attr == attr' -> normalizeInlines $ - Code attr (xs ++ ys) : rest - rest -> Code attr xs : rest --- allow empty spans, they may carry identifiers etc. --- normalizeInlines (Span _ [] : ys) = normalizeInlines ys -normalizeInlines (Span attr xs : zs) = - case normalizeInlines zs of - (Span attr' ys : rest) | attr == attr' -> normalizeInlines $ - Span attr (normalizeInlines $ xs ++ ys) : rest - rest -> Span attr (normalizeInlines xs) : rest -normalizeInlines (Note bs : ys) = Note (normalizeBlocks bs) : - normalizeInlines ys -normalizeInlines (Quoted qt ils : ys) = - Quoted qt (normalizeInlines ils) : normalizeInlines ys -normalizeInlines (Link attr ils t : ys) = - Link attr (normalizeInlines ils) t : normalizeInlines ys -normalizeInlines (Image attr ils t : ys) = - Image attr (normalizeInlines ils) t : normalizeInlines ys -normalizeInlines (Cite cs ils : ys) = - Cite cs (normalizeInlines ils) : normalizeInlines ys -normalizeInlines (x : xs) = x : normalizeInlines xs -normalizeInlines [] = [] - -- | Extract inlines, removing formatting. removeFormatting :: Walkable Inline a => a -> [Inline] removeFormatting = query go . walk deNote diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 07aed0c9b..163b2f3af 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -141,7 +141,7 @@ defaultWriterState = WriterState{ , stDelId = 1 , stStyleMaps = defaultStyleMaps , stFirstPara = False - , stTocTitle = normalizeInlines [Str "Table of Contents"] + , stTocTitle = [Str "Table of Contents"] , stDynamicParaProps = [] , stDynamicTextProps = [] } @@ -207,7 +207,7 @@ isValidChar (ord -> c) | otherwise = False metaValueToInlines :: MetaValue -> [Inline] -metaValueToInlines (MetaString s) = normalizeInlines [Str s] +metaValueToInlines (MetaString s) = [Str s] metaValueToInlines (MetaInlines ils) = ils metaValueToInlines (MetaBlocks bs) = query return bs metaValueToInlines (MetaBool b) = [Str $ show b] diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs index c7a09fe50..42cddcef8 100644 --- a/src/Text/Pandoc/Writers/DokuWiki.hs +++ b/src/Text/Pandoc/Writers/DokuWiki.hs @@ -45,7 +45,7 @@ import Text.Pandoc.Options ( WriterOptions( , writerTemplate , writerWrapText), WrapOption(..) ) import Text.Pandoc.Shared ( escapeURI, linesToPara, removeFormatting - , camelCaseToHyphenated, trimr, normalize, substitute ) + , camelCaseToHyphenated, trimr, substitute ) import Text.Pandoc.Writers.Shared ( defField, metaToJSON ) import Text.Pandoc.ImageSize import Text.Pandoc.Templates ( renderTemplate' ) @@ -80,7 +80,7 @@ type DokuWiki = ReaderT WriterEnvironment (State WriterState) -- | Convert Pandoc to DokuWiki. writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String writeDokuWiki opts document = return $ - runDokuWiki (pandocToDokuWiki opts $ normalize document) + runDokuWiki (pandocToDokuWiki opts document) runDokuWiki :: DokuWiki a -> a runDokuWiki = flip evalState def . flip runReaderT def @@ -394,9 +394,16 @@ blockListToDokuWiki :: WriterOptions -- ^ Options -> DokuWiki String blockListToDokuWiki opts blocks = do backSlash <- stBackSlashLB <$> ask + let blocks' = consolidateRawBlocks blocks if backSlash - then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks - else vcat <$> mapM (blockToDokuWiki opts) blocks + then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks' + else vcat <$> mapM (blockToDokuWiki opts) blocks' + +consolidateRawBlocks :: [Block] -> [Block] +consolidateRawBlocks [] = [] +consolidateRawBlocks (RawBlock f1 b1 : RawBlock f2 b2 : xs) + | f1 == f2 = consolidateRawBlocks (RawBlock f1 (b1 ++ "\n" ++ b2) : xs) +consolidateRawBlocks (x:xs) = x : consolidateRawBlocks xs -- | Convert list of Pandoc inline elements to DokuWiki. inlineListToDokuWiki :: WriterOptions -> [Inline] -> DokuWiki String diff --git a/tests/Tests/Helpers.hs b/tests/Tests/Helpers.hs index 28a11266b..84c2394bc 100644 --- a/tests/Tests/Helpers.hs +++ b/tests/Tests/Helpers.hs @@ -17,7 +17,7 @@ import Test.Framework import Test.Framework.Providers.HUnit import Test.Framework.Providers.QuickCheck2 import Test.HUnit (assertBool) -import Text.Pandoc.Shared (normalize, trimr) +import Text.Pandoc.Shared (trimr) import Text.Pandoc.Options import Text.Pandoc.Writers.Native (writeNative) import qualified Test.QuickCheck.Property as QP @@ -81,10 +81,10 @@ class ToPandoc a where toPandoc :: a -> Pandoc instance ToPandoc Pandoc where - toPandoc = normalize + toPandoc = id instance ToPandoc Blocks where - toPandoc = normalize . doc + toPandoc = doc instance ToPandoc Inlines where - toPandoc = normalize . doc . plain + toPandoc = doc . plain diff --git a/tests/Tests/Old.hs b/tests/Tests/Old.hs index cc35c8aa0..c52a368e2 100644 --- a/tests/Tests/Old.hs +++ b/tests/Tests/Old.hs @@ -11,15 +11,10 @@ import System.FilePath ( (), (<.>), takeDirectory, splitDirectories, import System.Directory import System.Exit import Data.Algorithm.Diff -import Text.Pandoc.Shared ( normalize ) -import Text.Pandoc.Options -import Text.Pandoc.Writers.Native ( writeNative ) -import Text.Pandoc.Readers.Native ( readNative ) import Prelude hiding ( readFile ) import qualified Data.ByteString.Lazy as B import Text.Pandoc.UTF8 (toStringLazy) import Text.Printf -import Tests.Helpers (purely) readFileUTF8 :: FilePath -> IO String readFileUTF8 f = B.readFile f >>= return . toStringLazy @@ -193,12 +188,9 @@ lhsWriterTests format lhsReaderTest :: String -> Test lhsReaderTest format = - testWithNormalize normalizer "lhs" ["-r", format, "-w", "native"] + test "lhs" ["-r", format, "-w", "native"] ("lhs-test" <.> format) norm - where normalizer = purely $ \nat -> do - d <- readNative def nat - writeNative def $ normalize d - norm = if format == "markdown+lhs" + where norm = if format == "markdown+lhs" then "lhs-test-markdown.native" else "lhs-test.native" diff --git a/tests/Tests/Readers/Org.hs b/tests/Tests/Readers/Org.hs index b1db75b83..96a783045 100644 --- a/tests/Tests/Readers/Org.hs +++ b/tests/Tests/Readers/Org.hs @@ -1525,7 +1525,7 @@ tests = , "" , "#+RESULTS:" , ": 65" ] =?> - rawBlock "html" "" + (mempty :: Blocks) , "Source block with toggling header arguments" =: unlines [ "#+BEGIN_SRC sh :noeval" diff --git a/tests/Tests/Readers/Txt2Tags.hs b/tests/Tests/Readers/Txt2Tags.hs index 77430601b..46831d86f 100644 --- a/tests/Tests/Readers/Txt2Tags.hs +++ b/tests/Tests/Readers/Txt2Tags.hs @@ -88,7 +88,7 @@ tests = para "1970-01-01" , "Macros: Mod Time" =: "%%mtime" =?> - para "" + para (str "") , "Macros: Infile" =: "%%infile" =?> para "in" diff --git a/tests/Tests/Shared.hs b/tests/Tests/Shared.hs index 55f520433..4ff1dc837 100644 --- a/tests/Tests/Shared.hs +++ b/tests/Tests/Shared.hs @@ -1,9 +1,7 @@ module Tests.Shared (tests) where -import Text.Pandoc.Definition import Text.Pandoc.Shared import Test.Framework -import Tests.Helpers import Text.Pandoc.Arbitrary() import Test.Framework.Providers.HUnit import Test.HUnit ( assertBool, (@?=) ) @@ -11,13 +9,7 @@ import Text.Pandoc.Builder import System.FilePath.Posix (joinPath) tests :: [Test] -tests = [ testGroup "normalize" - [ property "p_normalize_blocks_rt" p_normalize_blocks_rt - , property "p_normalize_inlines_rt" p_normalize_inlines_rt - , property "p_normalize_no_trailing_spaces" - p_normalize_no_trailing_spaces - ] - , testGroup "compactify'DL" +tests = [ testGroup "compactify'DL" [ testCase "compactify'DL with empty def" $ assertBool "compactify'DL" (let x = [(str "word", [para (str "def"), mempty])] @@ -26,18 +18,6 @@ tests = [ testGroup "normalize" , testGroup "collapseFilePath" testCollapse ] -p_normalize_blocks_rt :: [Block] -> Bool -p_normalize_blocks_rt bs = - normalizeBlocks bs == normalizeBlocks (normalizeBlocks bs) - -p_normalize_inlines_rt :: [Inline] -> Bool -p_normalize_inlines_rt ils = - normalizeInlines ils == normalizeInlines (normalizeInlines ils) - -p_normalize_no_trailing_spaces :: [Inline] -> Bool -p_normalize_no_trailing_spaces ils = null ils' || last ils' /= Space - where ils' = normalizeInlines $ ils ++ [Space] - testCollapse :: [Test] testCollapse = map (testCase "collapse") [ (collapseFilePath (joinPath [ ""]) @?= (joinPath [ ""])) diff --git a/tests/rst-reader.native b/tests/rst-reader.native index 768a05c24..bc4641a3f 100644 --- a/tests/rst-reader.native +++ b/tests/rst-reader.native @@ -327,15 +327,9 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."] ,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."] ,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."] -,Null ,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "inline HTML",Str "."] -,Null ,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["haskell","sourceCode"],[]) "fmap id [1,2..10]",Str "."] -,Null -,Null ,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["py","python","indirect","sourceCode"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."] -,Null -,Null ,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["c","different-indirect","sourceCode"],[]) "int x = 15;",Str "."] ,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"] ,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]] -- cgit v1.2.3 From 6aff97e4e16b3829151a5e84b63a0aee26ea8511 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 12 Dec 2016 13:51:20 +0100 Subject: Text.Pandoc.Shared: Removed fetchItem, fetchItem'. Made changes where these are used, so that the version of fetchItem from PandocMonad can be used instead. --- src/Text/Pandoc/PDF.hs | 9 +++--- src/Text/Pandoc/SelfContained.hs | 6 ++-- src/Text/Pandoc/Shared.hs | 69 ++-------------------------------------- src/Text/Pandoc/Writers/Docx.hs | 9 +++--- src/Text/Pandoc/Writers/EPUB.hs | 33 +++++++++---------- src/Text/Pandoc/Writers/FB2.hs | 18 ++++++++--- src/Text/Pandoc/Writers/ICML.hs | 8 +++-- src/Text/Pandoc/Writers/ODT.hs | 7 ++-- src/Text/Pandoc/Writers/RTF.hs | 7 ++-- 9 files changed, 58 insertions(+), 108 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 348f6a2fe..68151f569 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -49,8 +49,7 @@ import Data.Maybe (fromMaybe) import qualified Text.Pandoc.UTF8 as UTF8 import Text.Pandoc.Definition import Text.Pandoc.Walk (walkM) -import Text.Pandoc.Shared (fetchItem', warn, withTempDir, inDirectory, - stringify) +import Text.Pandoc.Shared (warn, withTempDir, inDirectory, stringify) import Text.Pandoc.Writers.Shared (getField, metaToJSON) import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..)) import Text.Pandoc.MIME (extensionFromMimeType, getMimeType) @@ -61,7 +60,7 @@ import qualified Codec.Picture as JP #ifdef _WINDOWS import Data.List (intercalate) #endif -import Text.Pandoc.Class (PandocIO, runIOorExplode) +import Text.Pandoc.Class (PandocIO, runIOorExplode, fetchItem, setMediaBag, runIO) #ifdef _WINDOWS changePathSeparators :: FilePath -> FilePath @@ -123,7 +122,9 @@ handleImage' opts tmpdir (Image attr ils (src,tit)) = do if exists then return $ Image attr ils (src,tit) else do - res <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + res <- runIO $ do + setMediaBag $ writerMediaBag opts + fetchItem (writerSourceURL opts) src case res of Right (contents, Just mime) -> do let ext = fromMaybe (takeExtension src) $ diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs index 6bcdc8728..176de99be 100644 --- a/src/Text/Pandoc/SelfContained.hs +++ b/src/Text/Pandoc/SelfContained.hs @@ -41,7 +41,7 @@ import Data.Char (toLower, isAscii, isAlphaNum) import Codec.Compression.GZip as Gzip import qualified Data.ByteString.Lazy as L import Control.Monad.Trans (MonadIO(..)) -import Text.Pandoc.Shared (renderTags', err, fetchItem', warn, trim) +import Text.Pandoc.Shared (renderTags', err, warn, trim) import Text.Pandoc.MediaBag (MediaBag) import Text.Pandoc.MIME (MimeType) import Text.Pandoc.UTF8 (toString) @@ -51,6 +51,7 @@ import Control.Applicative ((<|>)) import Text.Parsec (runParserT, ParsecT) import qualified Text.Parsec as P import Control.Monad.Trans (lift) +import Text.Pandoc.Class (fetchItem, runIO, setMediaBag) isOk :: Char -> Bool isOk c = isAscii c && isAlphaNum c @@ -144,7 +145,8 @@ getDataURI :: MediaBag -> Maybe String -> MimeType -> String getDataURI _ _ _ src@('d':'a':'t':'a':':':_) = return src -- already data: uri getDataURI media sourceURL mimetype src = do let ext = map toLower $ takeExtension src - fetchResult <- fetchItem' media sourceURL src + fetchResult <- runIO $ do setMediaBag media + fetchItem sourceURL src (raw, respMime) <- case fetchResult of Left msg -> err 67 $ "Could not fetch " ++ src ++ "\n" ++ show msg diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 0ff30dcce..fabda42ed 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -79,8 +79,6 @@ module Text.Pandoc.Shared ( getDefaultReferenceODT, readDataFile, readDataFileUTF8, - fetchItem, - fetchItem', openURL, collapseFilePath, filteredFilesFromArchive, @@ -100,7 +98,6 @@ module Text.Pandoc.Shared ( import Text.Pandoc.Definition import Text.Pandoc.Walk -import Text.Pandoc.MediaBag (MediaBag, lookupMedia) import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..)) import qualified Text.Pandoc.Builder as B import qualified Text.Pandoc.UTF8 as UTF8 @@ -111,15 +108,13 @@ import Data.List ( find, stripPrefix, intercalate ) import Data.Maybe (mapMaybe) import Data.Version ( showVersion ) import qualified Data.Map as M -import Network.URI ( escapeURIString, nonStrictRelativeTo, - unEscapeString, parseURIReference, isAllowedInURI, - parseURI, URI(..) ) +import Network.URI ( escapeURIString, unEscapeString ) import qualified Data.Set as Set import System.Directory import System.FilePath (splitDirectories, isPathSeparator) import qualified System.FilePath.Posix as Posix -import Text.Pandoc.MIME (MimeType, getMimeType) -import System.FilePath ( (), takeExtension, dropExtension) +import Text.Pandoc.MIME (MimeType) +import System.FilePath ( () ) import Data.Generics (Typeable, Data) import qualified Control.Monad.State as S import Control.Monad.Trans (MonadIO (..)) @@ -752,64 +747,6 @@ readDataFileUTF8 :: Maybe FilePath -> FilePath -> IO String readDataFileUTF8 userDir fname = UTF8.toString `fmap` readDataFile userDir fname --- | Specialized version of parseURIReference that disallows --- single-letter schemes. Reason: these are usually windows absolute --- paths. -parseURIReference' :: String -> Maybe URI -parseURIReference' s = - case parseURIReference s of - Just u - | length (uriScheme u) > 2 -> Just u - | null (uriScheme u) -> Just u -- protocol-relative - _ -> Nothing - --- | Fetch an image or other item from the local filesystem or the net. --- Returns raw content and maybe mime type. -fetchItem :: Maybe String -> String - -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType)) -fetchItem sourceURL s = - case (sourceURL >>= parseURIReference' . ensureEscaped, ensureEscaped s) of - (Just u, s') -> -- try fetching from relative path at source - case parseURIReference' s' of - Just u' -> openURL $ show $ u' `nonStrictRelativeTo` u - Nothing -> openURL s' -- will throw error - (Nothing, s'@('/':'/':_)) -> -- protocol-relative URI - case parseURIReference' s' of - Just u' -> openURL $ show $ u' `nonStrictRelativeTo` httpcolon - Nothing -> openURL s' -- will throw error - (Nothing, s') -> - case parseURI s' of -- requires absolute URI - -- We don't want to treat C:/ as a scheme: - Just u' | length (uriScheme u') > 2 -> openURL (show u') - Just u' | uriScheme u' == "file:" -> - E.try $ readLocalFile $ dropWhile (=='/') (uriPath u') - _ -> E.try $ readLocalFile fp -- get from local file system - where readLocalFile f = do - cont <- BS.readFile f - return (cont, mime) - httpcolon = URI{ uriScheme = "http:", - uriAuthority = Nothing, - uriPath = "", - uriQuery = "", - uriFragment = "" } - dropFragmentAndQuery = takeWhile (\c -> c /= '?' && c /= '#') - fp = unEscapeString $ dropFragmentAndQuery s - mime = case takeExtension fp of - ".gz" -> getMimeType $ dropExtension fp - ".svgz" -> getMimeType $ dropExtension fp ++ ".svg" - x -> getMimeType x - ensureEscaped = escapeURIString isAllowedInURI . map convertSlash - convertSlash '\\' = '/' - convertSlash x = x - --- | Like 'fetchItem', but also looks for items in a 'MediaBag'. -fetchItem' :: MediaBag -> Maybe String -> String - -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType)) -fetchItem' media sourceURL s = do - case lookupMedia s media of - Nothing -> fetchItem sourceURL s - Just (mime, bs) -> return $ Right (BS.concat $ toChunks bs, Just mime) - -- | Read from a URL and return raw data and maybe mime type. openURL :: String -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType)) openURL u diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 163b2f3af..25e224a7a 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -48,6 +48,7 @@ import Text.Pandoc.Options import Text.Pandoc.Writers.Math import Text.Pandoc.Highlighting ( highlight ) import Text.Pandoc.Walk +import Text.Pandoc.Error (PandocError) import Text.XML.Light as XML import Text.TeXMath import Text.Pandoc.Readers.Docx.StyleMap @@ -55,9 +56,9 @@ import Text.Pandoc.Readers.Docx.Util (elemName) import Control.Monad.Reader import Control.Monad.State import Skylighting +import Control.Monad.Except (runExceptT) import System.Random (randomR) import Text.Printf (printf) -import qualified Control.Exception as E import Data.Monoid ((<>)) import qualified Data.Text as T import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef, @@ -1180,10 +1181,10 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do case M.lookup src imgs of Just (_,_,_,elt,_) -> return [elt] Nothing -> do - res <- (lift . lift) $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + res <- runExceptT $ lift (P.fetchItem (writerSourceURL opts) src) case res of - Left (_ :: E.SomeException) -> do - (lift . lift) $ P.warning ("Could not find image `" ++ src ++ "', skipping...") + Left (_ :: PandocError) -> do + P.warning ("Could not find image `" ++ src ++ "', skipping...") -- emit alt text inlinesToOpenXML opts alt Right (img, mt) -> do diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 1c3a44207..d6c3ff533 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -64,7 +64,7 @@ import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) -import Control.Monad.Except (throwError) +import Control.Monad.Except (throwError, catchError) import Text.Pandoc.Error import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P @@ -858,23 +858,20 @@ modifyMediaRef opts oldsrc = do media <- gets stMediaPaths case lookup oldsrc media of Just (n,_) -> return n - Nothing -> do - res <- lift $ P.fetchItem' (writerMediaBag opts) - (writerSourceURL opts) oldsrc - (new, mbEntry) <- - case res of - Left _ -> do - lift $ P.warning $ "Could not find media `" ++ oldsrc ++ "', skipping..." - return (oldsrc, Nothing) - Right (img,mbMime) -> do - let new = "media/file" ++ show (length media) ++ - fromMaybe (takeExtension (takeWhile (/='?') oldsrc)) - (('.':) <$> (mbMime >>= extensionFromMimeType)) - epochtime <- floor `fmap` lift P.getPOSIXTime - let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img - return (new, Just entry) - modify $ \st -> st{ stMediaPaths = (oldsrc, (new, mbEntry)):media} - return new + Nothing -> catchError + (do (img, mbMime) <- P.fetchItem (writerSourceURL opts) oldsrc + let new = "media/file" ++ show (length media) ++ + fromMaybe (takeExtension (takeWhile (/='?') oldsrc)) + (('.':) <$> (mbMime >>= extensionFromMimeType)) + epochtime <- floor `fmap` lift P.getPOSIXTime + let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img + modify $ \st -> st{ stMediaPaths = + (oldsrc, (new, Just entry)):media} + return new) + (\e -> do + P.warning $ "Could not find media `" ++ oldsrc ++ + "', skipping...\n" ++ show e + return oldsrc) transformBlock :: PandocMonad m => WriterOptions diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 20af67b62..7baac4f9e 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -39,7 +39,7 @@ import Text.XML.Light import qualified Text.XML.Light as X import qualified Text.XML.Light.Cursor as XC import qualified Data.ByteString.Char8 as B8 -import Control.Monad.Except (throwError) +import Control.Monad.Except (throwError, catchError) import Text.Pandoc.Definition @@ -241,10 +241,18 @@ fetchImage href link = do else return Nothing (True, Just _) -> return Nothing -- not base64-encoded _ -> do - response <- P.fetchItem Nothing link - case response of - Right (bs, Just mime) -> return $ Just (mime, B8.unpack $ encode bs) - _ -> return $ Nothing + catchError (do (bs, mbmime) <- P.fetchItem Nothing link + case mbmime of + Nothing -> do + P.warning ("Could not determine mime type for " + ++ link) + return Nothing + Just mime -> return $ Just (mime, + B8.unpack $ encode bs)) + (\e -> + do P.warning ("Could not fetch " ++ link ++ + ":\n" ++ show e) + return Nothing) case mbimg of Just (imgtype, imgdata) -> do return . Right $ el "binary" diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 6bc7436d8..b68b9067a 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE OverloadedStrings, FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings, FlexibleContexts, ScopedTypeVariables #-} {- | Module : Text.Pandoc.Writers.ICML @@ -15,6 +15,7 @@ into InDesign with File -> Place. -} module Text.Pandoc.Writers.ICML (writeICML) where import Text.Pandoc.Definition +import Text.Pandoc.Error (PandocError) import Text.Pandoc.XML import Text.Pandoc.Writers.Math (texMathToInlines) import Text.Pandoc.Writers.Shared @@ -26,6 +27,7 @@ import Text.Pandoc.ImageSize import Data.List (isPrefixOf, isInfixOf, stripPrefix, intersperse) import Data.Text as Text (breakOnAll, pack) import Control.Monad.State +import Control.Monad.Except (runExceptT) import Network.URI (isURI) import qualified Data.Set as Set import Text.Pandoc.Class (PandocMonad) @@ -534,9 +536,9 @@ styleToStrAttr style = -- | Assemble an ICML Image. imageICML :: PandocMonad m => WriterOptions -> Style -> Attr -> Target -> WS m Doc imageICML opts style attr (src, _) = do - res <- lift $ P.fetchItem (writerSourceURL opts) src + res <- runExceptT $ lift $ P.fetchItem (writerSourceURL opts) src imgS <- case res of - Left (_) -> do + Left (_ :: PandocError) -> do lift $ P.warning $ "Could not find image `" ++ src ++ "', skipping..." return def Right (img, _) -> do diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 0e4999712..5672719f9 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -45,9 +45,10 @@ import Text.Pandoc.Walk import Text.Pandoc.Writers.Shared ( fixDisplayMath ) import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) import Control.Monad.State +import Control.Monad.Except (runExceptT) +import Text.Pandoc.Error (PandocError) import Text.Pandoc.XML import Text.Pandoc.Pretty -import qualified Control.Exception as E import System.FilePath ( takeExtension, takeDirectory, (<.>)) import Text.Pandoc.Class ( PandocMonad ) import qualified Text.Pandoc.Class as P @@ -145,9 +146,9 @@ pandocToODT opts doc@(Pandoc meta _) = do -- | transform both Image and Math elements transformPicMath :: PandocMonad m => WriterOptions ->Inline -> O m Inline transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do - res <- lift $ P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + res <- runExceptT $ lift $ P.fetchItem (writerSourceURL opts) src case res of - Left (_ :: E.SomeException) -> do + Left (_ :: PandocError) -> do lift $ P.warning $ "Could not find image `" ++ src ++ "', skipping..." return $ Emph lab Right (img, mbMimeType) -> do diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index a3351a705..bd3461a03 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ScopedTypeVariables #-} {- Copyright (C) 2006-2015 John MacFarlane @@ -43,7 +44,7 @@ import qualified Data.ByteString as B import qualified Data.Map as M import Text.Printf ( printf ) import Text.Pandoc.ImageSize -import Control.Monad.Except (throwError) +import Control.Monad.Except (throwError, runExceptT, lift) import Text.Pandoc.Error import Text.Pandoc.Class (PandocMonad) import qualified Text.Pandoc.Class as P @@ -53,7 +54,7 @@ import qualified Text.Pandoc.Class as P -- If file not found or filetype not jpeg or png, leave the inline unchanged. rtfEmbedImage :: PandocMonad m => WriterOptions -> Inline -> m Inline rtfEmbedImage opts x@(Image attr _ (src,_)) = do - result <- P.fetchItem' (writerMediaBag opts) (writerSourceURL opts) src + result <- runExceptT $ lift $ P.fetchItem (writerSourceURL opts) src case result of Right (imgdata, Just mime) | mime == "image/jpeg" || mime == "image/png" -> do @@ -87,7 +88,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do Right (_, Nothing) -> do warning $ "Could not determine image type for " ++ src ++ ", skipping." return x - Left e -> do + Left ( e :: PandocError ) -> do warning $ "Could not fetch image " ++ src ++ "\n" ++ show e return x rtfEmbedImage _ x = return x -- cgit v1.2.3 From 93e4cd9f8ca30253d3bf31bbf6e13a762c4c78a0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 24 Dec 2016 15:57:23 -0700 Subject: Fixed something small that broke in rebase. --- src/Text/Pandoc/Writers/Markdown.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 7f4d37b1f..6a5a1130e 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -1000,7 +1000,7 @@ inlineToMarkdown opts (Math DisplayMath str) = | isEnabled Ext_tex_math_double_backslash opts -> return $ "\\\\[" <> text str <> "\\\\]" | otherwise -> (\x -> cr <> x <> cr) `fmap` - texMathToInlines DisplayMath str >>= inlineListToMarkdown opts + (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts) inlineToMarkdown opts (RawInline f str) = do plain <- asks envPlain if not plain && -- cgit v1.2.3 From 412ed3f1321a49d3c3b2119ebd28705376bbd551 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jan 2017 11:56:26 +0100 Subject: Make the `smart` extension affect the Markdown writer. Thus, to "unsmartify" something that has been parsed as smart by pandoc, you can use `-t markdown+smart`, and straight quotes will be produced instead of curly quotes, etc. Example: % pandoc -f latex -t markdown+smart ``hi''---ok ^D "hi"---ok --- MANUAL.txt | 23 ++++++++++++----------- src/Text/Pandoc/Writers/Markdown.hs | 35 +++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index 236deeed4..ec3499513 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -3383,17 +3383,18 @@ example, `markdown+hard_line_breaks` is Markdown with hard line breaks. #### Extension: `smart` #### -Produce typographically correct output, converting straight -quotes to curly quotes, `---` to em-dashes, `--` to en-dashes, -and `...` to ellipses. Nonbreaking spaces are inserted after -certain abbreviations, such as "Mr." (Note: This option is -selected automatically when the output format is `latex` or -`context`, unless `--no-tex-ligatures` is used. It has no -effect for `latex` input.) - -Note: if your LaTeX template or any included header file call -for the [`csquotes`] package, pandoc will detect this -automatically and use `\enquote{...}` for quoted text. +Interpret straight quotes as curly quotes, `---` as em-dashes, +`--` as en-dashes, and `...` as ellipses. Nonbreaking spaces are +inserted after certain abbreviations, such as "Mr." + +Notes: + + * This extension option is selected automatically when the + output format is `latex` or `context`, unless + `--no-tex-ligatures` is used. It has no effect for `latex` input. + * If your LaTeX template or any included header file call + for the [`csquotes`] package, pandoc will detect this + automatically and use `\enquote{...}` for quoted text. #### Extension: `old_dashes` #### diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 6a5a1130e..9ef968fc6 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -280,7 +280,10 @@ escapeString opts = escapeStringUsing markdownEscapes (if isEnabled Ext_tex_math_dollars opts then ('$':) else id) $ - "\\`*_[]#" + "\\`*_[]#" ++ + if isEnabled Ext_smart opts + then "\"'" + else "" -- | Construct table of contents from list of header blocks. tableOfContents :: PandocMonad m => WriterOptions -> [Block] -> m Doc @@ -949,10 +952,14 @@ inlineToMarkdown opts (SmallCaps lst) = do else inlineListToMarkdown opts $ capitalize lst inlineToMarkdown opts (Quoted SingleQuote lst) = do contents <- inlineListToMarkdown opts lst - return $ "‘" <> contents <> "’" + return $ if isEnabled Ext_smart opts + then "'" <> contents <> "'" + else "‘" <> contents <> "’" inlineToMarkdown opts (Quoted DoubleQuote lst) = do contents <- inlineListToMarkdown opts lst - return $ "“" <> contents <> "”" + return $ if isEnabled Ext_smart opts + then "\"" <> contents <> "\"" + else "“" <> contents <> "”" inlineToMarkdown opts (Code attr str) = do let tickGroups = filter (\s -> '`' `elem` s) $ group str let longest = if null tickGroups @@ -969,9 +976,13 @@ inlineToMarkdown opts (Code attr str) = do else return $ text (marker ++ spacer ++ str ++ spacer ++ marker) <> attrs inlineToMarkdown opts (Str str) = do isPlain <- asks envPlain - if isPlain - then return $ text str - else return $ text $ escapeString opts str + let str' = (if isEnabled Ext_smart opts + then unsmartify opts + else id) $ + if isPlain + then str + else escapeString opts str + return $ text str' inlineToMarkdown opts (Math InlineMath str) = case writerHTMLMathMethod opts of WebTeX url -> @@ -1126,3 +1137,15 @@ makeMathPlainer = walk go go (Emph xs) = Span nullAttr xs go x = x +unsmartify :: WriterOptions -> String -> String +unsmartify opts ('\8217':xs) = '\'' : unsmartify opts xs +unsmartify opts ('\8230':xs) = "..." ++ unsmartify opts xs +unsmartify opts ('\8211':xs) + | isEnabled Ext_old_dashes opts = '-' : unsmartify opts xs + | otherwise = "--" ++ unsmartify opts xs +unsmartify opts ('\8212':xs) + | isEnabled Ext_old_dashes opts = "--" ++ unsmartify opts xs + | otherwise = "---" ++ unsmartify opts xs +unsmartify opts (x:xs) = x : unsmartify opts xs +unsmartify _ [] = [] + -- cgit v1.2.3 From 0bcc81c0b149f1ae3eda7ce72f28199e48744a76 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jan 2017 21:00:22 +0100 Subject: Removed writerTeXLigatures. Make `smart` extension work in LaTeX/ConTeXt writers instead. Instead of `-t latex --no-tex-ligatures`, do `-t latex-smart`. --- MANUAL.txt | 30 ++++++++++++------------------ pandoc.hs | 9 --------- src/Text/Pandoc/Options.hs | 2 -- src/Text/Pandoc/Writers/ConTeXt.hs | 2 +- src/Text/Pandoc/Writers/LaTeX.hs | 6 +++--- 5 files changed, 16 insertions(+), 33 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index 2b55b8239..171f55955 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -697,20 +697,6 @@ Options affecting specific writers be numbered "1.5", specify `--number-offset=1,4`. Offsets are 0 by default. Implies `--number-sections`. -`--no-tex-ligatures` - -: Do not use the TeX ligatures for quotation marks, apostrophes, - and dashes (`` `...' ``, ` ``..'' `, `--`, `---`) when - writing or reading LaTeX or ConTeXt. In reading LaTeX, - parse the characters `` ` ``, `'`, and `-` literally, rather - than parsing ligatures for quotation marks and dashes. In - writing LaTeX or ConTeXt, print unicode quotation mark and - dash characters literally, rather than converting them to - the standard ASCII TeX ligatures. Note: If you use literal - curly quotes, dashes, and ellipses in your source, then you - may want to use disable the `smart` extension in your - source format. - `--listings` : Use the [`listings`] package for LaTeX code blocks @@ -3185,15 +3171,23 @@ Typography Interpret straight quotes as curly quotes, `---` as em-dashes, `--` as en-dashes, and `...` as ellipses. Nonbreaking spaces are -inserted after certain abbreviations, such as "Mr." +inserted after certain abbreviations, such as "Mr." This +option currently affects the input formats `markdown`, +`commonmark`, `latex`, `mediawiki`, `org`, `rst`, and `twiki`, +and the output formats `markdown`, `latex`, and `context`. Note: If you are *writing* Markdown, then the `smart` extension has the reverse effect: what would have been curly quotes comes out straight. -If your LaTeX template or any included header file call -for the [`csquotes`] package, pandoc will detect this -automatically and use `\enquote{...}` for quoted text. +In LaTeX, `smart` means to use the standard TeX ligatures +for quotation marks (` `` ` and ` '' ` for double quotes, +`` ` `` and `` ' `` for single quotes) and dashes (`--` for +en-dash and `---` for em-dash). If `smart` is disabled, +then in reading LaTeX pandoc will parse these characters +literally. In writing LaTeX, enabling `smart` tells pandoc +to use the ligatures when possible; if `smart` is disabled +pandoc will use unicode quotation mark and dash characters. Citations --------- diff --git a/pandoc.hs b/pandoc.hs index 0baf555de..fe9cdba00 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -146,7 +146,6 @@ convertWithOpts opts args = do , optSlideLevel = slideLevel , optSetextHeaders = setextHeaders , optAscii = ascii - , optTeXLigatures = texLigatures , optDefaultImageExtension = defaultImageExtension , optExtractMedia = mbExtractMedia , optTrace = trace @@ -330,7 +329,6 @@ convertWithOpts opts args = do writerHighlight = highlight, writerHighlightStyle = highlightStyle, writerSetextHeaders = setextHeaders, - writerTeXLigatures = texLigatures, writerEpubMetadata = epubMetadata, writerEpubStylesheet = epubStylesheet, writerEpubFonts = epubFonts, @@ -570,7 +568,6 @@ data Opt = Opt , optSlideLevel :: Maybe Int -- ^ Header level that creates slides , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2 , optAscii :: Bool -- ^ Use ascii characters only in html - , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes , optDefaultImageExtension :: String -- ^ Default image extension , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media , optTrace :: Bool -- ^ Print debug information @@ -634,7 +631,6 @@ defaultOpts = Opt , optSlideLevel = Nothing , optSetextHeaders = True , optAscii = False - , optTeXLigatures = True , optDefaultImageExtension = "" , optExtractMedia = Nothing , optTrace = False @@ -955,11 +951,6 @@ options = "NUMBERS") "" -- "Starting number for sections, subsections, etc." - , Option "" ["no-tex-ligatures"] - (NoArg - (\opt -> return opt { optTeXLigatures = False })) - "" -- "Don't use tex ligatures for quotes, dashes" - , Option "" ["listings"] (NoArg (\opt -> return opt { optListings = True })) diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 5e4c51abf..4fe92dbbf 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -178,7 +178,6 @@ data WriterOptions = WriterOptions , writerHighlight :: Bool -- ^ Highlight source code , writerHighlightStyle :: Style -- ^ Style to use for highlighting , writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown - , writerTeXLigatures :: Bool -- ^ Use tex ligatures quotes, dashes in latex , writerEpubVersion :: Maybe EPUBVersion -- ^ Nothing or EPUB version , writerEpubMetadata :: String -- ^ Metadata to include in EPUB , writerEpubStylesheet :: Maybe String -- ^ EPUB stylesheet specified at command line @@ -224,7 +223,6 @@ instance Default WriterOptions where , writerHighlight = False , writerHighlightStyle = pygments , writerSetextHeaders = True - , writerTeXLigatures = True , writerEpubVersion = Nothing , writerEpubMetadata = "" , writerEpubStylesheet = Nothing diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index c8a4abfd5..b997c306a 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -111,7 +111,7 @@ toContextDir _ = "" -- | escape things as needed for ConTeXt escapeCharForConTeXt :: WriterOptions -> Char -> String escapeCharForConTeXt opts ch = - let ligatures = writerTeXLigatures opts in + let ligatures = isEnabled Ext_smart opts in case ch of '{' -> "\\{" '}' -> "\\}" diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index dbb8e4326..d9a31751e 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -272,7 +272,7 @@ stringToLaTeX _ [] = return "" stringToLaTeX ctx (x:xs) = do opts <- gets stOptions rest <- stringToLaTeX ctx xs - let ligatures = writerTeXLigatures opts && ctx == TextString + let ligatures = isEnabled Ext_smart opts && ctx == TextString let isUrl = ctx == URLString when (x == '€') $ modify $ \st -> st{ stUsesEuro = True } @@ -938,11 +938,11 @@ inlineToLaTeX (Quoted qt lst) = do let inner = s1 <> contents <> s2 return $ case qt of DoubleQuote -> - if writerTeXLigatures opts + if isEnabled Ext_smart opts then text "``" <> inner <> text "''" else char '\x201C' <> inner <> char '\x201D' SingleQuote -> - if writerTeXLigatures opts + if isEnabled Ext_smart opts then char '`' <> inner <> char '\'' else char '\x2018' <> inner <> char '\x2019' inlineToLaTeX (Str str) = liftM text $ stringToLaTeX TextString str -- cgit v1.2.3 From 4007d6a89749ff6576e65bb08631ff14a6d0ee20 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jan 2017 22:34:14 +0100 Subject: Removed writerIgnoreNotes. Instead, just temporarily remove notes when generating TOC lists in HTML and Markdown (as we already did in LaTeX). Also export deNote from Text.Pandoc.Shared. API change in Shared and Options.WriterOptions. --- pandoc.hs | 1 - src/Text/Pandoc/Options.hs | 2 -- src/Text/Pandoc/Shared.hs | 1 + src/Text/Pandoc/Writers/HTML.hs | 10 ++++------ src/Text/Pandoc/Writers/LaTeX.hs | 4 ---- src/Text/Pandoc/Writers/Markdown.hs | 10 +++++----- 6 files changed, 10 insertions(+), 18 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.hs b/pandoc.hs index ee97e54a0..e1c2c9097 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -306,7 +306,6 @@ convertWithOpts opts args = do writerHTMLMathMethod = mathMethod, writerIncremental = incremental, writerCiteMethod = citeMethod, - writerIgnoreNotes = False, writerNumberSections = numberSections, writerNumberOffset = numberFrom, writerSectionDivs = sectionDivs, diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index d81f4da88..cd10abeff 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -151,7 +151,6 @@ data WriterOptions = WriterOptions , writerSlideVariant :: HTMLSlideVariant -- ^ Are we writing S5, Slidy or Slideous? , writerIncremental :: Bool -- ^ True if lists should be incremental , writerHTMLMathMethod :: HTMLMathMethod -- ^ How to print math in HTML - , writerIgnoreNotes :: Bool -- ^ Ignore footnotes (used in making toc) , writerNumberSections :: Bool -- ^ Number sections in LaTeX , writerNumberOffset :: [Int] -- ^ Starting number for section, subsection, ... , writerSectionDivs :: Bool -- ^ Put sections in div tags in HTML @@ -197,7 +196,6 @@ instance Default WriterOptions where , writerSlideVariant = NoSlides , writerIncremental = False , writerHTMLMathMethod = PlainMath - , writerIgnoreNotes = False , writerNumberSections = False , writerNumberOffset = [0,0,0,0,0,0] , writerSectionDivs = False diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 18b4d3eac..f2a80fccf 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -56,6 +56,7 @@ module Text.Pandoc.Shared ( normalizeSpaces, extractSpaces, removeFormatting, + deNote, stringify, capitalize, compactify, diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 40658eaa8..a63047866 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -30,6 +30,7 @@ Conversion of 'Pandoc' documents to HTML. -} module Text.Pandoc.Writers.HTML ( writeHtml , writeHtmlString ) where import Text.Pandoc.Definition +import Text.Pandoc.Walk import Data.Monoid ((<>)) import Text.Pandoc.Shared import Text.Pandoc.Writers.Shared @@ -228,8 +229,7 @@ defList opts items = toList H.dl opts (items ++ [nl opts]) tableOfContents :: PandocMonad m => WriterOptions -> [Element] -> StateT WriterState m (Maybe Html) tableOfContents _ [] = return Nothing tableOfContents opts sects = do - let opts' = opts { writerIgnoreNotes = True } - contents <- mapM (elementToListItem opts') sects + contents <- mapM (elementToListItem opts) sects let tocList = catMaybes contents return $ if null tocList then Nothing @@ -253,7 +253,7 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs) then (H.span ! A.class_ "toc-section-number" $ toHtml $ showSecNum num') >> preEscapedString " " else mempty - txt <- liftM (sectnum >>) $ inlineListToHtml opts headerText + txt <- liftM (sectnum >>) $ inlineListToHtml opts $ walk deNote headerText subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes let subList = if null subHeads then mempty @@ -852,9 +852,7 @@ inlineToHtml opts inline = imgAttrsToHtml opts attr return $ foldl (!) H5.embed attributes -- note: null title included, as in Markdown.pl - (Note contents) - | writerIgnoreNotes opts -> return mempty - | otherwise -> do + (Note contents) -> do notes <- gets stNotes let number = (length notes) + 1 let ref = show number diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index d9a31751e..655ea7dac 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -1318,10 +1318,6 @@ commonFromBcp47 x = fromIso $ head x fromIso "vi" = "vietnamese" fromIso _ = "" -deNote :: Inline -> Inline -deNote (Note _) = RawInline (Format "latex") "" -deNote x = x - pDocumentOptions :: P.Parsec String () [String] pDocumentOptions = do P.char '[' diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 9ef968fc6..8ae550fe1 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -288,9 +288,8 @@ escapeString opts = escapeStringUsing markdownEscapes -- | Construct table of contents from list of header blocks. tableOfContents :: PandocMonad m => WriterOptions -> [Block] -> m Doc tableOfContents opts headers = - let opts' = opts { writerIgnoreNotes = True } - contents = BulletList $ map (elementToListItem opts) $ hierarchicalize headers - in evalMD (blockToMarkdown opts' contents) def def + let contents = BulletList $ map (elementToListItem opts) $ hierarchicalize headers + in evalMD (blockToMarkdown opts contents) def def -- | Converts an Element to a list item for a table of contents, elementToListItem :: WriterOptions -> Element -> [Block] @@ -299,8 +298,9 @@ elementToListItem opts (Sec lev _nums (ident,_,_) headerText subsecs) [ BulletList (map (elementToListItem opts) subsecs) | not (null subsecs) && lev < writerTOCDepth opts ] where headerLink = if null ident - then headerText - else [Link nullAttr headerText ('#':ident, "")] + then walk deNote headerText + else [Link nullAttr (walk deNote headerText) + ('#':ident, "")] elementToListItem _ (Blk _) = [] attrsToMarkdown :: Attr -> Doc -- cgit v1.2.3 From 73f57daf69d4f1dbeb4b2574eb4e85280293ed67 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 16 Jan 2017 21:10:34 +0100 Subject: Fixed shadowing warnings. --- src/Text/Pandoc/Writers/OpenDocument.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 1a758193a..71e599e09 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -35,7 +35,7 @@ import Text.Pandoc.Options import Text.Pandoc.XML import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Readers.Odt.StyleReader +import Text.Pandoc.Readers.Odt.StyleReader hiding (listStyle) import Text.Pandoc.Writers.Math import Text.Pandoc.Pretty import Text.Printf ( printf ) @@ -392,9 +392,9 @@ blockToOpenDocument o bs paragraph inlines = inParagraphTags =<< inlinesToOpenDocument o inlines paraWithBreak :: PandocMonad m => ParaBreak -> [Inline] -> OD m Doc - paraWithBreak breakKind bs = do + paraWithBreak breakKind bs' = do pn <- paraBreakStyle breakKind - withParagraphStyle o ("P" ++ show pn) [Para bs] + withParagraphStyle o ("P" ++ show pn) [Para bs'] colHeadsToOpenDocument :: PandocMonad m => WriterOptions -> String -> [String] -> [[Block]] -- cgit v1.2.3 From 01483f91bd152ad806a8110d75353edfc9551ec8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 22 Jan 2017 10:37:19 +0100 Subject: Revert "Added page breaks into Pandoc." This reverts commit f02a12aff638fa2339192231b8f601bffdfe3e14. --- pandoc.cabal | 6 +++--- src/Text/Pandoc/Readers/Odt/ContentReader.hs | 19 ++++--------------- src/Text/Pandoc/Readers/Odt/StyleReader.hs | 27 ++++++--------------------- src/Text/Pandoc/Writers/AsciiDoc.hs | 1 - src/Text/Pandoc/Writers/CommonMark.hs | 1 - src/Text/Pandoc/Writers/ConTeXt.hs | 1 - src/Text/Pandoc/Writers/Custom.hs | 2 -- src/Text/Pandoc/Writers/Docbook.hs | 1 - src/Text/Pandoc/Writers/Docx.hs | 1 - src/Text/Pandoc/Writers/DokuWiki.hs | 2 -- src/Text/Pandoc/Writers/FB2.hs | 2 -- src/Text/Pandoc/Writers/HTML.hs | 1 - src/Text/Pandoc/Writers/Haddock.hs | 1 - src/Text/Pandoc/Writers/ICML.hs | 1 - src/Text/Pandoc/Writers/LaTeX.hs | 1 - src/Text/Pandoc/Writers/Man.hs | 1 - src/Text/Pandoc/Writers/Markdown.hs | 1 - src/Text/Pandoc/Writers/MediaWiki.hs | 2 -- src/Text/Pandoc/Writers/OpenDocument.hs | 27 +++------------------------ src/Text/Pandoc/Writers/Org.hs | 1 - src/Text/Pandoc/Writers/RST.hs | 1 - src/Text/Pandoc/Writers/RTF.hs | 1 - src/Text/Pandoc/Writers/TEI.hs | 1 - src/Text/Pandoc/Writers/Texinfo.hs | 2 -- src/Text/Pandoc/Writers/Textile.hs | 2 -- src/Text/Pandoc/Writers/ZimWiki.hs | 2 -- stack.yaml | 5 +---- 27 files changed, 17 insertions(+), 96 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.cabal b/pandoc.cabal index b62fe551d..7cb292b05 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -270,7 +270,7 @@ Library xml >= 1.3.12 && < 1.4, random >= 1 && < 1.2, extensible-exceptions >= 0.1 && < 0.2, - pandoc-types >= 1.18 && < 1.19, + pandoc-types >= 1.17 && < 1.18, aeson >= 0.7 && < 1.2, tagsoup >= 0.13.7 && < 0.15, base64-bytestring >= 0.1 && < 1.1, @@ -426,7 +426,7 @@ Library Executable pandoc Build-Depends: pandoc, - pandoc-types >= 1.18 && < 1.19, + pandoc-types >= 1.17 && < 1.18, base >= 4.2 && <5, directory >= 1.2 && < 1.4, filepath >= 1.1 && < 1.5, @@ -504,7 +504,7 @@ Test-Suite test-pandoc Build-Depends: base >= 4.2 && < 5, syb >= 0.1 && < 0.7, pandoc, - pandoc-types >= 1.18 && < 1.19, + pandoc-types >= 1.17 && < 1.18, bytestring >= 0.9 && < 0.11, text >= 0.11 && < 1.3, directory >= 1 && < 1.4, diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs index 0df86e2a5..2672b01ef 100644 --- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs +++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs @@ -381,9 +381,9 @@ getParaModifier :: Style -> ParaModifier getParaModifier Style{..} | Just props <- paraProperties styleProperties , isBlockQuote (indentation props) (margin_left props) - = pageBreakMaybe (paraProperties styleProperties) blockQuote + = blockQuote | otherwise - = pageBreakMaybe (paraProperties styleProperties) id + = id where isBlockQuote mIndent mMargin | LengthValueMM indent <- mIndent @@ -408,19 +408,7 @@ getParaModifier Style{..} | Just props <- paraProperties styleProperties | otherwise = False - pageBreakMaybe :: Maybe ParaProperties -> ParaModifier -> ParaModifier - pageBreakMaybe (Just props) modifier = insertPageBreak (page_break props) modifier - pageBreakMaybe Nothing modifier = modifier - - insertPageBreak :: ParaBreak -> ParaModifier -> ParaModifier - insertPageBreak PageAfter modifier = - \x -> (fromList (toList (modifier x) ++ [Para (toList pageBreak)])) - insertPageBreak PageBefore modifier = - \x -> (fromList (Para (toList pageBreak) : toList (modifier x))) - insertPageBreak PageBoth modifier = - \x -> (fromList ((Para (toList pageBreak) : toList (modifier x)) ++ [Para (toList pageBreak)])) - insertPageBreak _ modifier = - modifier + -- constructPara :: OdtReaderSafe Blocks Blocks -> OdtReaderSafe Blocks Blocks constructPara reader = proc blocks -> do @@ -906,6 +894,7 @@ read_reference_ref = matchingElement NsText "reference-ref" $ maybeInAnchorRef <<< matchChildContent [] read_plain_text + ---------------------- -- Entry point ---------------------- diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs index cd31f50a8..26ba6df82 100644 --- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs +++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs @@ -43,7 +43,6 @@ module Text.Pandoc.Readers.Odt.StyleReader , TextProperties (..) , ParaProperties (..) , VerticalTextPosition (..) -, ParaBreak (..) , ListItemNumberFormat (..) , ListLevel , ListStyle (..) @@ -274,7 +273,6 @@ instance Default TextProperties where data ParaProperties = PropP { paraNumbering :: ParaNumbering , indentation :: LengthOrPercent , margin_left :: LengthOrPercent - , page_break :: ParaBreak } deriving ( Eq, Show ) @@ -282,7 +280,6 @@ instance Default ParaProperties where def = PropP { paraNumbering = NumberingNone , indentation = def , margin_left = def - , page_break = AutoNone } ---- @@ -317,9 +314,6 @@ instance Lookupable UnderlineMode where data ParaNumbering = NumberingNone | NumberingKeep | NumberingRestart Int deriving ( Eq, Show ) -data ParaBreak = AutoNone | PageBefore | PageAfter | PageBoth - deriving ( Eq, Show ) - data LengthOrPercent = LengthValueMM Int | PercentValue Int deriving ( Eq, Show ) @@ -539,20 +533,16 @@ readLineMode modeAttr styleAttr = proc x -> do readParaProperties :: StyleReader _x ParaProperties readParaProperties = executeIn NsStyle "paragraph-properties" $ liftAsSuccess - ( liftA4 PropP + ( liftA3 PropP ( liftA2 readNumbering - ( isSet' NsText "number-lines" ) - ( readAttr' NsText "line-number" ) + ( isSet' NsText "number-lines" ) + ( readAttr' NsText "line-number" ) ) ( liftA2 readIndentation - ( isSetWithDefault NsStyle "auto-text-indent" False ) - ( getAttr NsXSL_FO "text-indent" ) - ) - ( getAttr NsXSL_FO "margin-left" ) - ( liftA2 readPageBreak - ( findAttrWithDefault NsXSL_FO "break-before" "auto" ) - ( findAttrWithDefault NsXSL_FO "break-after" "auto" ) + ( isSetWithDefault NsStyle "auto-text-indent" False ) + ( getAttr NsXSL_FO "text-indent" ) ) + ( getAttr NsXSL_FO "margin-left" ) ) where readNumbering (Just True) (Just n) = NumberingRestart n readNumbering (Just True) _ = NumberingKeep @@ -561,11 +551,6 @@ readParaProperties = readIndentation False indent = indent readIndentation True _ = def - readPageBreak "page" "page" = PageBoth - readPageBreak "page" _ = PageBefore - readPageBreak _ "page" = PageAfter - readPageBreak _ _ = AutoNone - ---- -- List styles ---- diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs index eed6183b4..356b29504 100644 --- a/src/Text/Pandoc/Writers/AsciiDoc.hs +++ b/src/Text/Pandoc/Writers/AsciiDoc.hs @@ -413,7 +413,6 @@ inlineToAsciiDoc _ (RawInline f s) | f == "asciidoc" = return $ text s | otherwise = return empty inlineToAsciiDoc _ LineBreak = return $ " +" <> cr -inlineToAsciiDoc _ PageBreak = return empty inlineToAsciiDoc _ Space = return space inlineToAsciiDoc opts SoftBreak = case writerWrapText opts of diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index c1963a9a8..c58e83f19 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -149,7 +149,6 @@ inlineToNodes :: Inline -> [Node] -> [Node] inlineToNodes (Str s) = (node (TEXT (T.pack s)) [] :) inlineToNodes Space = (node (TEXT (T.pack " ")) [] :) inlineToNodes LineBreak = (node LINEBREAK [] :) -inlineToNodes PageBreak = id inlineToNodes SoftBreak = (node SOFTBREAK [] :) inlineToNodes (Emph xs) = (node EMPH (inlinesToNodes xs) :) inlineToNodes (Strong xs) = (node STRONG (inlinesToNodes xs) :) diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index b997c306a..ea8b90db3 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -347,7 +347,6 @@ inlineToConTeXt SoftBreak = do WrapAuto -> space WrapNone -> space WrapPreserve -> cr -inlineToConTeXt PageBreak = return empty inlineToConTeXt Space = return space -- Handle HTML-like internal document references to sections inlineToConTeXt (Link _ txt (('#' : ref), _)) = do diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index 371dd21c3..cf641dcd6 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -310,8 +310,6 @@ inlineToCustom lua (RawInline format str) = inlineToCustom lua (LineBreak) = callfunc lua "LineBreak" -inlineToCustom lua (PageBreak) = callfunc lua "PageBreak" - inlineToCustom lua (Link attr txt (src,tit)) = callfunc lua "Link" txt src tit (attrToMap attr) diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index 0ec7445be..32695e128 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -373,7 +373,6 @@ inlineToDocbook _ (RawInline f x) inlineToDocbook _ LineBreak = return $ text "\n" -- currently ignore, would require the option to add custom -- styles to the document -inlineToDocbook _ PageBreak = return empty inlineToDocbook _ Space = return space -- because we use \n for LineBreak, we can't do soft breaks: inlineToDocbook _ SoftBreak = return space diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 25e224a7a..b7fd3e2a3 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -1106,7 +1106,6 @@ inlineToOpenXML' opts (Strikeout lst) = withTextProp (mknode "w:strike" [] ()) $ inlinesToOpenXML opts lst inlineToOpenXML' _ LineBreak = return [br] -inlineToOpenXML' _ PageBreak = return [pageBreak] inlineToOpenXML' _ (RawInline f str) | f == Format "openxml" = return [ x | Elem x <- parseXML str ] | otherwise = return [] diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs index 42cddcef8..79a371d4d 100644 --- a/src/Text/Pandoc/Writers/DokuWiki.hs +++ b/src/Text/Pandoc/Writers/DokuWiki.hs @@ -475,8 +475,6 @@ inlineToDokuWiki _ (RawInline f str) inlineToDokuWiki _ LineBreak = return "\\\\\n" -inlineToDokuWiki _ PageBreak = return mempty - inlineToDokuWiki opts SoftBreak = case writerWrapText opts of WrapNone -> return " " diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 7baac4f9e..600d34499 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -437,7 +437,6 @@ toXml (Code _ s) = return [el "code" s] toXml Space = return [txt " "] toXml SoftBreak = return [txt " "] toXml LineBreak = return [el "empty-line" ()] -toXml PageBreak = return [] toXml (Math _ formula) = insertMath InlineImage formula toXml (RawInline _ _) = return [] -- raw TeX and raw HTML are suppressed toXml (Link _ text (url,ttl)) = do @@ -569,7 +568,6 @@ plain (Code _ s) = s plain Space = " " plain SoftBreak = " " plain LineBreak = "\n" -plain PageBreak = "\n" plain (Math _ s) = s plain (RawInline _ s) = s plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"]) diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index a63047866..e144d0d63 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -713,7 +713,6 @@ inlineToHtml opts inline = WrapPreserve -> preEscapedString "\n" (LineBreak) -> return $ (if writerHtml5 opts then H5.br else H.br) <> strToHtml "\n" - (PageBreak) -> return mempty (Span (id',classes,kvs) ils) -> inlineListToHtml opts ils >>= return . addAttrs opts attr' . H.span diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 115d5d8d8..1c160ea1c 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -339,7 +339,6 @@ inlineToHaddock _ (RawInline f str) | otherwise = return empty -- no line break in haddock (see above on CodeBlock) inlineToHaddock _ LineBreak = return cr -inlineToHaddock _ PageBreak = return empty inlineToHaddock opts SoftBreak = case writerWrapText opts of WrapAuto -> return space diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index b68b9067a..41bca11b2 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -435,7 +435,6 @@ inlineToICML opts style SoftBreak = WrapNone -> charStyle style space WrapPreserve -> charStyle style cr inlineToICML _ style LineBreak = charStyle style $ text lineSeparator -inlineToICML _ _ PageBreak = return empty inlineToICML opts style (Math mt str) = lift (texMathToInlines mt str) >>= (fmap cat . mapM (inlineToICML opts style)) diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 655ea7dac..031cd584e 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -961,7 +961,6 @@ inlineToLaTeX SoftBreak = do WrapAuto -> return space WrapNone -> return space WrapPreserve -> return cr -inlineToLaTeX PageBreak = return $ "\\clearpage{}" inlineToLaTeX Space = return space inlineToLaTeX (Link _ txt ('#':ident, _)) = do contents <- inlineListToLaTeX txt diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index a9a30fd45..36ed5fab0 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -351,7 +351,6 @@ inlineToMan _ (RawInline f str) | otherwise = return empty inlineToMan _ LineBreak = return $ cr <> text ".PD 0" $$ text ".P" $$ text ".PD" <> cr -inlineToMan _ PageBreak = return empty inlineToMan _ SoftBreak = return space inlineToMan _ Space = return space inlineToMan opts (Link _ txt (src, _)) = do diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 8ae550fe1..8de09864a 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -1038,7 +1038,6 @@ inlineToMarkdown opts SoftBreak = do WrapNone -> space' WrapAuto -> space' WrapPreserve -> cr -inlineToMarkdown _ PageBreak = return empty inlineToMarkdown opts (Cite [] lst) = inlineListToMarkdown opts lst inlineToMarkdown opts (Cite (c:cs) lst) | not (isEnabled Ext_citations opts) = inlineListToMarkdown opts lst diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs index 774139c43..dc6206e6c 100644 --- a/src/Text/Pandoc/Writers/MediaWiki.hs +++ b/src/Text/Pandoc/Writers/MediaWiki.hs @@ -405,8 +405,6 @@ inlineToMediaWiki (RawInline f str) inlineToMediaWiki LineBreak = return "
\n" -inlineToMediaWiki PageBreak = return mempty - inlineToMediaWiki SoftBreak = do wrapText <- gets (writerWrapText . stOptions) case wrapText of diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 71e599e09..f50b240a4 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -35,7 +35,6 @@ import Text.Pandoc.Options import Text.Pandoc.XML import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Readers.Odt.StyleReader hiding (listStyle) import Text.Pandoc.Writers.Math import Text.Pandoc.Pretty import Text.Printf ( printf ) @@ -319,7 +318,9 @@ blockToOpenDocument o bs else inParagraphTags =<< inlinesToOpenDocument o b | Para [Image attr c (s,'f':'i':'g':':':t)] <- bs = figure attr c s t - | Para b <- bs = paragraph b + | Para b <- bs = if null b + then return empty + else inParagraphTags =<< inlinesToOpenDocument o b | LineBlock b <- bs = blockToOpenDocument o $ linesToPara b | Div _ xs <- bs = blocksToOpenDocument o xs | Header i _ b <- bs = setFirstPara >> @@ -380,22 +381,6 @@ blockToOpenDocument o bs captionDoc <- withParagraphStyle o "FigureCaption" [Para caption] return $ imageDoc $$ captionDoc - endsWithPageBreak [] = False - endsWithPageBreak [PageBreak] = True - endsWithPageBreak (_ : xs) = endsWithPageBreak xs - - paragraph :: PandocMonad m => [Inline] -> OD m Doc - paragraph [] = return empty - paragraph (PageBreak : rest) | endsWithPageBreak rest = paraWithBreak PageBoth rest - paragraph (PageBreak : rest) = paraWithBreak PageBefore rest - paragraph inlines | endsWithPageBreak inlines = paraWithBreak PageAfter inlines - paragraph inlines = inParagraphTags =<< inlinesToOpenDocument o inlines - - paraWithBreak :: PandocMonad m => ParaBreak -> [Inline] -> OD m Doc - paraWithBreak breakKind bs' = do - pn <- paraBreakStyle breakKind - withParagraphStyle o ("P" ++ show pn) [Para bs'] - colHeadsToOpenDocument :: PandocMonad m => WriterOptions -> String -> [String] -> [[Block]] -> OD m Doc @@ -595,12 +580,6 @@ paraStyle attrs = do addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) paraProps return pn -paraBreakStyle :: PandocMonad m => ParaBreak -> OD m Int -paraBreakStyle PageBefore = paraStyle "Text_20_body" [("fo:break-before", "page")] -paraBreakStyle PageAfter = paraStyle "Text_20_body" [("fo:break-after", "page")] -paraBreakStyle PageBoth = paraStyle "Text_20_body" [("fo:break-before", "page"), ("fo:break-after", "page")] -paraBreakStyle AutoNone = paraStyle "Text_20_body" [] - paraListStyle :: PandocMonad m => Int -> OD m Int paraListStyle l = paraStyle [("style:parent-style-name","Text_20_body") diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs index febb2e98f..09c924397 100644 --- a/src/Text/Pandoc/Writers/Org.hs +++ b/src/Text/Pandoc/Writers/Org.hs @@ -351,7 +351,6 @@ inlineToOrg (RawInline f@(Format f') str) = then text str else "@@" <> text f' <> ":" <> text str <> "@@" inlineToOrg LineBreak = return (text "\\\\" <> cr) -inlineToOrg PageBreak = return empty inlineToOrg Space = return space inlineToOrg SoftBreak = do wrapText <- gets (writerWrapText . stOptions) diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 438407cce..ee3ecd9cd 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -462,7 +462,6 @@ inlineToRST SoftBreak = do WrapPreserve -> return cr WrapAuto -> return space WrapNone -> return space -inlineToRST PageBreak = return $ ".. pagebreak::" -- autolink inlineToRST (Link _ [Str str] (src, _)) | isURI src && diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index bd3461a03..77f01e4a1 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -396,7 +396,6 @@ inlineToRTF (RawInline f str) | otherwise = return "" inlineToRTF (LineBreak) = return "\\line " inlineToRTF SoftBreak = return " " -inlineToRTF PageBreak = return "\\page " inlineToRTF Space = return " " inlineToRTF (Link _ text (src, _)) = do contents <- inlinesToRTF text diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs index 0a22ae085..c589c0c36 100644 --- a/src/Text/Pandoc/Writers/TEI.hs +++ b/src/Text/Pandoc/Writers/TEI.hs @@ -285,7 +285,6 @@ inlineToTEI _ (Math t str) = inlineToTEI _ (RawInline f x) | f == "tei" = text x | otherwise = empty inlineToTEI _ LineBreak = selfClosingTag "lb" [] -inlineToTEI _ PageBreak = selfClosingTag "pb" [] inlineToTEI _ Space = space -- because we use \n for LineBreak, we can't do soft breaks: inlineToTEI _ SoftBreak = space diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 783a01063..a66ffe88b 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -458,8 +458,6 @@ inlineToTexinfo SoftBreak = do WrapPreserve -> return cr inlineToTexinfo Space = return space -inlineToTexinfo PageBreak = return $ text "@page" - inlineToTexinfo (Link _ txt (src@('#':_), _)) = do contents <- escapeCommas $ inlineListToTexinfo txt return $ text "@ref" <> diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs index 9691b7705..45f1780cf 100644 --- a/src/Text/Pandoc/Writers/Textile.hs +++ b/src/Text/Pandoc/Writers/Textile.hs @@ -438,8 +438,6 @@ inlineToTextile opts (RawInline f str) inlineToTextile _ LineBreak = return "\n" -inlineToTextile _ PageBreak = return mempty - inlineToTextile _ SoftBreak = return " " inlineToTextile _ Space = return " " diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs index f15b290e4..42b168418 100644 --- a/src/Text/Pandoc/Writers/ZimWiki.hs +++ b/src/Text/Pandoc/Writers/ZimWiki.hs @@ -320,8 +320,6 @@ inlineToZimWiki opts (RawInline f str) inlineToZimWiki _ LineBreak = return "\n" -- was \\\\ -inlineToZimWiki _ PageBreak = return mempty - inlineToZimWiki opts SoftBreak = case writerWrapText opts of WrapNone -> return " " diff --git a/stack.yaml b/stack.yaml index 3d4d4797d..66cab58a5 100644 --- a/stack.yaml +++ b/stack.yaml @@ -7,10 +7,6 @@ flags: network-uri: true packages: - '.' -- location: - git: https://github.com/jgm/pandoc-types.git - commit: 973394685aad945ccd92a86bf76e5c644e72e127 - extra-dep: true - location: git: https://github.com/jgm/texmath.git commit: 31273683a376e97848028e4619f28ab8c03c88af @@ -19,4 +15,5 @@ extra-deps: - doctemplates-0.1.0.2 - pandoc-types-1.17.0.4 - skylighting-0.1.1.1 +- texmath-0.9 resolver: lts-7.14 -- cgit v1.2.3 From d1efc839f129d23fe8a6523e33a01b0b463ee409 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 22 Jan 2017 11:36:30 +0100 Subject: Removed writerHighlight; made writerHighlightStyle a Maybe. API change. For no highlighting, set writerHighlightStyle to Nothing. --- pandoc.hs | 12 ++++-------- src/Text/Pandoc/Options.hs | 7 +++---- src/Text/Pandoc/Writers/Docx.hs | 29 ++++++++--------------------- src/Text/Pandoc/Writers/HTML.hs | 19 ++++++++++++------- src/Text/Pandoc/Writers/LaTeX.hs | 19 ++++++++++++------- tests/Tests/Writers/HTML.hs | 2 +- tests/Tests/Writers/LaTeX.hs | 2 +- tests/Tests/Writers/RST.hs | 2 +- 8 files changed, 42 insertions(+), 50 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.hs b/pandoc.hs index e1c2c9097..d13686cee 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -114,7 +114,6 @@ convertWithOpts opts args = do , optSelfContained = selfContained , optHtml5 = html5 , optHtmlQTags = htmlQTags - , optHighlight = highlight , optHighlightStyle = highlightStyle , optTopLevelDivision = topLevelDivision , optHTMLMathMethod = mathMethod' @@ -324,7 +323,6 @@ convertWithOpts opts args = do writerListings = listings, writerBeamer = False, writerSlideLevel = slideLevel, - writerHighlight = highlight, writerHighlightStyle = highlightStyle, writerSetextHeaders = setextHeaders, writerEpubMetadata = epubMetadata, @@ -532,8 +530,7 @@ data Opt = Opt , optSelfContained :: Bool -- ^ Make HTML accessible offline , optHtml5 :: Bool -- ^ Produce HTML5 in HTML , optHtmlQTags :: Bool -- ^ Use tags in HTML - , optHighlight :: Bool -- ^ Highlight source code - , optHighlightStyle :: Style -- ^ Style to use for highlighted code + , optHighlightStyle :: Maybe Style -- ^ Style to use for highlighted code , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math , optReferenceDoc :: Maybe FilePath -- ^ Path of reference doc @@ -595,8 +592,7 @@ defaultOpts = Opt , optSelfContained = False , optHtml5 = False , optHtmlQTags = False - , optHighlight = True - , optHighlightStyle = pygments + , optHighlightStyle = Just pygments , optTopLevelDivision = TopLevelDefault , optHTMLMathMethod = PlainMath , optReferenceDoc = Nothing @@ -836,14 +832,14 @@ options = , Option "" ["no-highlight"] (NoArg - (\opt -> return opt { optHighlight = False })) + (\opt -> return opt { optHighlightStyle = Nothing })) "" -- "Don't highlight source code" , Option "" ["highlight-style"] (ReqArg (\arg opt -> do case lookup (map toLower arg) highlightingStyles of - Just s -> return opt{ optHighlightStyle = s } + Just s -> return opt{ optHighlightStyle = Just s } Nothing -> err 39 $ "Unknown style: " ++ arg) "STYLE") "" -- "Style for highlighted code" diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 3a787a733..e7dec6492 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -171,8 +171,8 @@ data WriterOptions = WriterOptions , writerSlideLevel :: Maybe Int -- ^ Force header level of slides , writerTopLevelDivision :: TopLevelDivision -- ^ Type of top-level divisions , writerListings :: Bool -- ^ Use listings package for code - , writerHighlight :: Bool -- ^ Highlight source code - , writerHighlightStyle :: Style -- ^ Style to use for highlighting + , writerHighlightStyle :: Maybe Style -- ^ Style to use for highlighting + -- (Nothing = no highlighting) , writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown , writerEpubVersion :: Maybe EPUBVersion -- ^ Nothing or EPUB version , writerEpubMetadata :: String -- ^ Metadata to include in EPUB @@ -214,8 +214,7 @@ instance Default WriterOptions where , writerSlideLevel = Nothing , writerTopLevelDivision = TopLevelDefault , writerListings = False - , writerHighlight = False - , writerHighlightStyle = pygments + , writerHighlightStyle = Just pygments , writerSetextHeaders = True , writerEpubVersion = Nothing , writerEpubMetadata = "" diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index b7fd3e2a3..6a53485c4 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -52,7 +52,6 @@ import Text.Pandoc.Error (PandocError) import Text.XML.Light as XML import Text.TeXMath import Text.Pandoc.Readers.Docx.StyleMap -import Text.Pandoc.Readers.Docx.Util (elemName) import Control.Monad.Reader import Control.Monad.State import Skylighting @@ -450,18 +449,11 @@ writeDocx opts doc@(Pandoc meta _) = do let newstyles = map newParaPropToOpenXml newDynamicParaProps ++ map newTextPropToOpenXml newDynamicTextProps ++ - (styleToOpenXml styleMaps $ writerHighlightStyle opts) - let styledoc' = styledoc{ elContent = modifyContent (elContent styledoc) } - where - modifyContent - | writerHighlight opts = (++ map Elem newstyles) - | otherwise = filter notTokStyle - notTokStyle (Elem el) = notStyle el || notTokId el - notTokStyle _ = True - notStyle = (/= elemName' "style") . elName - notTokId = maybe True (`notElem` tokStys) . findAttr (elemName' "styleId") - tokStys = "SourceCode" : map show (enumFromTo KeywordTok NormalTok) - elemName' = elemName (sNameSpaces styleMaps) "w" + (case writerHighlightStyle opts of + Nothing -> [] + Just sty -> (styleToOpenXml styleMaps sty)) + let styledoc' = styledoc{ elContent = elContent styledoc ++ + map Elem newstyles } let styleEntry = toEntry stylepath epochtime $ renderXml styledoc' -- construct word/numbering.xml @@ -1130,11 +1122,9 @@ inlineToOpenXML' opts (Code attrs str) = do [ rCustomStyle (show toktype) ] , mknode "w:t" [("xml:space","preserve")] (T.unpack tok) ] withTextProp (rCustomStyle "VerbatimChar") - $ if writerHighlight opts - then case highlight formatOpenXML attrs str of - Nothing -> unhighlighted - Just h -> return h - else unhighlighted + $ case writerHighlightStyle opts >> highlight formatOpenXML attrs str of + Just h -> return h + Nothing -> unhighlighted inlineToOpenXML' opts (Note bs) = do notes <- gets stFootnotes notenum <- (lift . lift) getUniqueId @@ -1249,9 +1239,6 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do br :: Element br = breakElement "textWrapping" -pageBreak :: Element -pageBreak = breakElement "page" - breakElement :: String -> Element breakElement kind = mknode "w:r" [] [mknode "w:br" [("w:type",kind)] () ] diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index e144d0d63..c6d7b7f6a 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -179,8 +179,10 @@ pandocToHtml opts (Pandoc meta blocks) = do | otherwise -> mempty Nothing -> mempty let context = (if stHighlighting st - then defField "highlighting-css" - (styleToCss $ writerHighlightStyle opts) + then case writerHighlightStyle opts of + Just sty -> defField "highlighting-css" + (styleToCss sty) + Nothing -> id else id) $ (if stMath st then defField "math" (renderHtml math) @@ -509,8 +511,9 @@ blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do adjCode = if tolhs then unlines . map ("> " ++) . lines $ rawCode else rawCode - hlCode = if writerHighlight opts -- check highlighting options - then highlight formatHtmlBlock (id',classes',keyvals) adjCode + hlCode = if isJust (writerHighlightStyle opts) + then highlight formatHtmlBlock + (id',classes',keyvals) adjCode else Nothing case hlCode of Nothing -> return $ addAttrs opts (id',classes,keyvals) @@ -702,7 +705,8 @@ annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, -- | Convert Pandoc inline element to HTML. -inlineToHtml :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Html +inlineToHtml :: PandocMonad m + => WriterOptions -> Inline -> StateT WriterState m Html inlineToHtml opts inline = case inline of (Str str) -> return $ strToHtml str @@ -739,8 +743,9 @@ inlineToHtml opts inline = modify $ \st -> st{ stHighlighting = True } return $ addAttrs opts (id',[],keyvals) h where (id',_,keyvals) = attr - hlCode = if writerHighlight opts - then highlight formatHtmlInline attr str + hlCode = if isJust (writerHighlightStyle opts) + then highlight formatHtmlInline + attr str else Nothing (Strikeout lst) -> inlineListToHtml opts lst >>= return . H.del diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 031cd584e..953e4250f 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -188,8 +188,11 @@ pandocToLaTeX options (Pandoc meta blocks) = do defField "listings" (writerListings options || stLHS st) $ defField "beamer" (writerBeamer options) $ (if stHighlighting st - then defField "highlighting-macros" (styleToLaTeX - $ writerHighlightStyle options ) + then case writerHighlightStyle options of + Just sty -> + defField "highlighting-macros" + (styleToLaTeX sty) + Nothing -> id else id) $ (case writerCiteMethod options of Natbib -> defField "biblio-title" biblioTitle . @@ -512,10 +515,11 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do return (flush $ linkAnchor $$ text (T.unpack h)) case () of _ | isEnabled Ext_literate_haskell opts && "haskell" `elem` classes && - "literate" `elem` classes -> lhsCodeBlock - | writerListings opts -> listingsCodeBlock - | writerHighlight opts && not (null classes) -> highlightedCodeBlock - | otherwise -> rawCodeBlock + "literate" `elem` classes -> lhsCodeBlock + | writerListings opts -> listingsCodeBlock + | not (null classes) && isJust (writerHighlightStyle opts) + -> highlightedCodeBlock + | otherwise -> rawCodeBlock blockToLaTeX (RawBlock f x) | f == Format "latex" || f == Format "tex" = return $ text x @@ -904,7 +908,8 @@ inlineToLaTeX (Code (_,classes,_) str) = do inHeading <- gets stInHeading case () of _ | writerListings opts && not inHeading -> listingsCode - | writerHighlight opts && not (null classes) -> highlightCode + | isJust (writerHighlightStyle opts) && not (null classes) + -> highlightCode | otherwise -> rawCode where listingsCode = do inNote <- gets stInNote diff --git a/tests/Tests/Writers/HTML.hs b/tests/Tests/Writers/HTML.hs index 0ce9aecb3..d99698c21 100644 --- a/tests/Tests/Writers/HTML.hs +++ b/tests/Tests/Writers/HTML.hs @@ -31,7 +31,7 @@ tests :: [Test] tests = [ testGroup "inline code" [ "basic" =: code "@&" =?> "@&" , "haskell" =: codeWith ("",["haskell"],[]) ">>=" - =?> ">>=" + =?> ">>=" , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>=" =?> ">>=" ] diff --git a/tests/Tests/Writers/LaTeX.hs b/tests/Tests/Writers/LaTeX.hs index 9eee1f58b..00c590370 100644 --- a/tests/Tests/Writers/LaTeX.hs +++ b/tests/Tests/Writers/LaTeX.hs @@ -8,7 +8,7 @@ import Text.Pandoc.Arbitrary () import Text.Pandoc.Builder latex :: (ToPandoc a) => a -> String -latex = latexWithOpts def{ writerHighlight = True } +latex = latexWithOpts def latexListing :: (ToPandoc a) => a -> String latexListing = latexWithOpts def{ writerListings = True } diff --git a/tests/Tests/Writers/RST.hs b/tests/Tests/Writers/RST.hs index 68a890ca8..dd55580c9 100644 --- a/tests/Tests/Writers/RST.hs +++ b/tests/Tests/Writers/RST.hs @@ -10,7 +10,7 @@ import Text.Pandoc.Arbitrary() infix 4 =: (=:) :: (ToString a, ToPandoc a) => String -> (a, String) -> Test -(=:) = test (purely (writeRST def{ writerHighlight = True }) . toPandoc) +(=:) = test (purely (writeRST def . toPandoc)) tests :: [Test] tests = [ testGroup "rubrics" -- cgit v1.2.3 From 65b8570e0e0b2c7e570e051859c9e0db0b7442f6 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 24 Jan 2017 15:28:02 +0100 Subject: Cleanups for rebase. --- src/Text/Pandoc/Readers/Org/Blocks.hs | 2 +- src/Text/Pandoc/Writers/OpenDocument.hs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index 5176e0f6c..8ffc0bb19 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -682,7 +682,7 @@ exampleCode = B.codeBlockWith ("", ["example"], []) specialLine :: PandocMonad m => OrgParser m (F Blocks) specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine -rawExportLine :: PnadocMonad m => OrgParser m Blocks +rawExportLine :: PandocMonad m => OrgParser m Blocks rawExportLine = try $ do metaLineStart key <- metaKey diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index f50b240a4..59470c2f9 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -206,7 +206,7 @@ writeOpenDocument opts (Pandoc meta blocks) = do meta b <- render' `fmap` blocksToOpenDocument opts blocks return (b, m) - styles = stTableStyles s ++ stParaStyles s ++ + let styles = stTableStyles s ++ stParaStyles s ++ map snd (reverse $ sortBy (comparing fst) $ Map.elems (stTextStyles s)) listStyle (n,l) = inTags True "text:list-style" @@ -559,7 +559,7 @@ tableStyle num wcs = paraStyle :: PandocMonad m => [(String,String)] -> OD m Int paraStyle attrs = do pn <- (+) 1 . length <$> gets stParaStyles - i <- (*) 0.5 . fromIntegral <$> gets stIndentPara :: State WriterState Double + i <- (*) (0.5 :: Double) . fromIntegral <$> gets stIndentPara b <- gets stInDefinition t <- gets stTight let styleAttr = [ ("style:name" , "P" ++ show pn) -- cgit v1.2.3 From fce0a60f0a85d6c3a9e7633074ecd781af08c75b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 25 Jan 2017 21:51:26 +0100 Subject: Provide explicit separate functions for HTML 4 and 5. * Text.Pandoc.Writers.HTML: removed writeHtml, writeHtmlString, added writeHtml4, writeHtml4String, writeHtml5, writeHtml5String. * Removed writerHtml5 from WriterOptions. * Renamed default.html template to default.html4. * "html" now aliases to "html5"; to get the old HTML4 behavior, you must now specify "-t html4". --- pandoc.cabal | 8 +- pandoc.hs | 10 +- src/Text/Pandoc.hs | 27 +- src/Text/Pandoc/Options.hs | 2 - src/Text/Pandoc/Templates.hs | 1 + src/Text/Pandoc/Writers/CommonMark.hs | 4 +- src/Text/Pandoc/Writers/EPUB.hs | 11 +- src/Text/Pandoc/Writers/HTML.hs | 117 +++++--- src/Text/Pandoc/Writers/Markdown.hs | 8 +- src/Text/Pandoc/Writers/OPML.hs | 4 +- tests/Tests/Old.hs | 7 +- tests/Tests/Writers/HTML.hs | 2 +- tests/lhs-test.html | 13 +- tests/lhs-test.html+lhs | 13 +- tests/tables.html | 204 ------------- tests/tables.html4 | 204 +++++++++++++ tests/tables.html5 | 204 +++++++++++++ tests/writer.html | 546 --------------------------------- tests/writer.html4 | 546 +++++++++++++++++++++++++++++++++ tests/writer.html5 | 548 ++++++++++++++++++++++++++++++++++ 20 files changed, 1633 insertions(+), 846 deletions(-) delete mode 100644 tests/tables.html create mode 100644 tests/tables.html4 create mode 100644 tests/tables.html5 delete mode 100644 tests/writer.html create mode 100644 tests/writer.html4 create mode 100644 tests/writer.html5 (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.cabal b/pandoc.cabal index 7cb292b05..97e70c830 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -36,7 +36,7 @@ Description: Pandoc is a Haskell library for converting from one markup only adding a reader or writer. Data-Files: -- templates - data/templates/default.html + data/templates/default.html4 data/templates/default.html5 data/templates/default.docbook data/templates/default.docbook5 @@ -150,7 +150,8 @@ Extra-Source-Files: tests/tables.dokuwiki tests/tables.zimwiki tests/tables.icml - tests/tables.html + tests/tables.html4 + tests/tables.html5 tests/tables.latex tests/tables.man tests/tables.plain @@ -172,7 +173,8 @@ Extra-Source-Files: tests/writer.context tests/writer.docbook tests/writer.docbook5 - tests/writer.html + tests/writer.html4 + tests/writer.html5 tests/writer.man tests/writer.markdown tests/writer.plain diff --git a/pandoc.hs b/pandoc.hs index c6faa9edf..9ee6e376b 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -111,7 +111,6 @@ convertWithOpts opts args = do , optSectionDivs = sectionDivs , optIncremental = incremental , optSelfContained = selfContained - , optHtml5 = html5 , optHtmlQTags = htmlQTags , optHighlightStyle = highlightStyle , optTopLevelDivision = topLevelDivision @@ -188,13 +187,11 @@ convertWithOpts opts args = do (if any isURI sources then "html" else "markdown") sources - "html4" -> "html" x -> x let writerName' = case map toLower writerName of [] -> defaultWriterName outputFile "epub2" -> "epub" - "html4" -> "html" x -> x let format = takeWhile (`notElem` ['+','-']) $ takeFileName writerName' -- in case path to lua script @@ -203,7 +200,7 @@ convertWithOpts opts args = do let laTeXOutput = format `elem` ["latex", "beamer"] let conTeXtOutput = format == "context" - let html5Output = format == "html5" + let html5Output = format == "html5" || format == "html" -- disabling the custom writer for now writer <- if ".lua" `isSuffixOf` format @@ -313,7 +310,6 @@ convertWithOpts opts args = do writerIdentifierPrefix = idPrefix, writerSourceURL = sourceURL, writerUserDataDir = datadir, - writerHtml5 = html5, writerHtmlQTags = htmlQTags, writerTopLevelDivision = topLevelDivision, writerListings = listings, @@ -413,7 +409,7 @@ convertWithOpts opts args = do err 43 "Error producing PDF" | otherwise -> do let htmlFormat = format `elem` - ["html","html5","s5","slidy","slideous","dzslides","revealjs"] + ["html","html4","html5","s5","slidy","slideous","dzslides","revealjs"] selfcontain = if selfContained && htmlFormat then makeSelfContained writerOptions media else return @@ -523,7 +519,6 @@ data Opt = Opt , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5 , optSelfContained :: Bool -- ^ Make HTML accessible offline - , optHtml5 :: Bool -- ^ Produce HTML5 in HTML , optHtmlQTags :: Bool -- ^ Use tags in HTML , optHighlightStyle :: Maybe Style -- ^ Style to use for highlighted code , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions @@ -583,7 +578,6 @@ defaultOpts = Opt , optSectionDivs = False , optIncremental = False , optSelfContained = False - , optHtml5 = False , optHtmlQTags = False , optHighlightStyle = Just pygments , optTopLevelDivision = TopLevelDefault diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index f9e032f4f..aa4cab840 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -99,8 +99,10 @@ module Text.Pandoc , writeLaTeX , writeConTeXt , writeTexinfo - , writeHtml - , writeHtmlString + , writeHtml4 + , writeHtml4String + , writeHtml5 + , writeHtml5String , writeICML , writeDocbook , writeOPML @@ -281,23 +283,21 @@ writers = [ ,("epub3" , ByteStringWriter $ \o -> writeEPUB o{ writerEpubVersion = Just EPUB3 }) ,("fb2" , StringWriter writeFB2) - ,("html" , StringWriter writeHtmlString) - ,("html5" , StringWriter $ \o -> - writeHtmlString o{ writerHtml5 = True }) + ,("html" , StringWriter writeHtml5String) + ,("html4" , StringWriter writeHtml4String) + ,("html5" , StringWriter writeHtml5String) ,("icml" , StringWriter writeICML) ,("s5" , StringWriter $ \o -> - writeHtmlString o{ writerSlideVariant = S5Slides - , writerTableOfContents = False }) + writeHtml4String o{ writerSlideVariant = S5Slides + , writerTableOfContents = False }) ,("slidy" , StringWriter $ \o -> - writeHtmlString o{ writerSlideVariant = SlidySlides }) + writeHtml4String o{ writerSlideVariant = SlidySlides }) ,("slideous" , StringWriter $ \o -> - writeHtmlString o{ writerSlideVariant = SlideousSlides }) + writeHtml4String o{ writerSlideVariant = SlideousSlides }) ,("dzslides" , StringWriter $ \o -> - writeHtmlString o{ writerSlideVariant = DZSlides - , writerHtml5 = True }) + writeHtml5String o{ writerSlideVariant = DZSlides }) ,("revealjs" , StringWriter $ \o -> - writeHtmlString o{ writerSlideVariant = RevealJsSlides - , writerHtml5 = True }) + writeHtml5String o{ writerSlideVariant = RevealJsSlides }) ,("docbook" , StringWriter writeDocbook) ,("docbook5" , StringWriter $ \o -> writeDocbook o{ writerDocbook5 = True }) @@ -342,6 +342,7 @@ getDefaultExtensions "html" = extensionsFromList [Ext_auto_identifiers, Ext_native_divs, Ext_native_spans] +getDefaultExtensions "html4" = getDefaultExtensions "html" getDefaultExtensions "html5" = getDefaultExtensions "html" getDefaultExtensions "epub" = extensionsFromList [Ext_raw_html, diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index cd525a3c1..6cb2d883a 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -168,7 +168,6 @@ data WriterOptions = WriterOptions , writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory , writerCiteMethod :: CiteMethod -- ^ How to print cites , writerDocbook5 :: Bool -- ^ Produce DocBook5 - , writerHtml5 :: Bool -- ^ Produce HTML5 , writerHtmlQTags :: Bool -- ^ Use @@ tags for quotes in HTML , writerBeamer :: Bool -- ^ Produce beamer LaTeX slide show , writerSlideLevel :: Maybe Int -- ^ Force header level of slides @@ -210,7 +209,6 @@ instance Default WriterOptions where , writerUserDataDir = Nothing , writerCiteMethod = Citeproc , writerDocbook5 = False - , writerHtml5 = False , writerHtmlQTags = False , writerBeamer = False , writerSlideLevel = Nothing diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs index d15d27438..03dc917e6 100644 --- a/src/Text/Pandoc/Templates.hs +++ b/src/Text/Pandoc/Templates.hs @@ -60,6 +60,7 @@ getDefaultTemplate user writer = do "docx" -> return $ Right "" "fb2" -> return $ Right "" "odt" -> getDefaultTemplate user "opendocument" + "html" -> getDefaultTemplate user "html5" "markdown_strict" -> getDefaultTemplate user "markdown" "multimarkdown" -> getDefaultTemplate user "markdown" "markdown_github" -> getDefaultTemplate user "markdown" diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index c58e83f19..b83f6785d 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -31,7 +31,7 @@ CommonMark: -} module Text.Pandoc.Writers.CommonMark (writeCommonMark) where -import Text.Pandoc.Writers.HTML (writeHtmlString) +import Text.Pandoc.Writers.HTML (writeHtml5String) import Text.Pandoc.Definition import Text.Pandoc.Shared (isTightList, linesToPara) import Text.Pandoc.Templates (renderTemplate') @@ -138,7 +138,7 @@ blockToNodes (DefinitionList items) ns = blockToNodes (BulletList items') ns dlToBullet (term, xs) = Para term : concat xs blockToNodes t@(Table _ _ _ _ _) ns = do - s <- writeHtmlString def $! Pandoc nullMeta [t] + s <- writeHtml5String def $! Pandoc nullMeta [t] return (node (HTML_BLOCK (T.pack $! s)) [] : ns) blockToNodes Null ns = return ns diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index d6c3ff533..bd95c170e 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -59,7 +59,7 @@ import Control.Monad (mplus, when, zipWithM) import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs , strContent, lookupAttr, Node(..), QName(..), parseXML , onlyElems, node, ppElement) -import Text.Pandoc.Writers.HTML ( writeHtml ) +import Text.Pandoc.Writers.HTML ( writeHtml4, writeHtml5 ) import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) import Text.Blaze.Html.Renderer.Utf8 (renderHtml) @@ -361,13 +361,15 @@ pandocToEPUB opts doc@(Pandoc meta _) = do : writerVariables opts let opts' = opts{ writerEmailObfuscation = NoObfuscation , writerSectionDivs = True - , writerHtml5 = epub3 , writerVariables = vars , writerHTMLMathMethod = if epub3 then MathML Nothing else writerHTMLMathMethod opts , writerWrapText = WrapAuto } + let writeHtml = if epub3 + then writeHtml5 + else writeHtml4 metadata <- getEPUBMetadata opts' meta -- cover page @@ -376,7 +378,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do Nothing -> return ([],[]) Just img -> do let coverImage = "media/" ++ takeFileName img - cpContent <- renderHtml <$> (lift $ writeHtml + cpContent <- renderHtml <$> (lift $ writeHtml opts'{ writerVariables = ("coverpage","true"):vars } (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"])) imgContent <- lift $ P.readFileLazy img @@ -484,8 +486,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do Chapter mbnum $ walk fixInternalReferences bs) chapters' - let chapToEntry :: PandocMonad m => Int -> Chapter -> m Entry - chapToEntry num (Chapter mbnum bs) = + let chapToEntry num (Chapter mbnum bs) = (mkEntry (showChapter num) . renderHtml) <$> (writeHtml opts'{ writerNumberOffset = fromMaybe [] mbnum } diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index c6d7b7f6a..ee1f260b6 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -28,7 +28,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to HTML. -} -module Text.Pandoc.Writers.HTML ( writeHtml , writeHtmlString ) where +module Text.Pandoc.Writers.HTML ( + writeHtml4, writeHtml4String, + writeHtml5, writeHtml5String ) where import Text.Pandoc.Definition import Text.Pandoc.Walk import Data.Monoid ((<>)) @@ -80,12 +82,13 @@ data WriterState = WriterState , stHighlighting :: Bool -- ^ Syntax highlighting is used , stSecNum :: [Int] -- ^ Number of current section , stElement :: Bool -- ^ Processing an Element + , stHtml5 :: Bool -- ^ Use HTML5 } defaultWriterState :: WriterState defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False, stHighlighting = False, stSecNum = [], - stElement = False} + stElement = False, stHtml5 = False} -- Helpers to render HTML with the appropriate function. @@ -102,19 +105,35 @@ nl opts = if writerWrapText opts == WrapNone then mempty else preEscapedString "\n" --- | Convert Pandoc document to Html string. -writeHtmlString :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeHtmlString opts d = do - (body, context) <- evalStateT (pandocToHtml opts d) defaultWriterState +-- | Convert Pandoc document to Html 5 string. +writeHtml5String :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeHtml5String = writeHtmlString' True + +-- | Convert Pandoc document to Html 5 structure. +writeHtml5 :: PandocMonad m => WriterOptions -> Pandoc -> m Html +writeHtml5 = writeHtml' True + +-- | Convert Pandoc document to Html 4 string. +writeHtml4String :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeHtml4String = writeHtmlString' False + +-- | Convert Pandoc document to Html 4 structure. +writeHtml4 :: PandocMonad m => WriterOptions -> Pandoc -> m Html +writeHtml4 = writeHtml' False + +writeHtmlString' :: PandocMonad m => Bool -> WriterOptions -> Pandoc -> m String +writeHtmlString' html5 opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) + defaultWriterState{ stHtml5 = html5 } return $ case writerTemplate opts of Nothing -> renderHtml body Just tpl -> renderTemplate' tpl $ defField "body" (renderHtml body) context --- | Convert Pandoc document to Html structure. -writeHtml :: PandocMonad m => WriterOptions -> Pandoc -> m Html -writeHtml opts d = do - (body, context) <- evalStateT (pandocToHtml opts d) defaultWriterState +writeHtml' :: PandocMonad m => Bool -> WriterOptions -> Pandoc -> m Html +writeHtml' html5 opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) + defaultWriterState{ stHtml5 = html5 } return $ case writerTemplate opts of Nothing -> body Just tpl -> renderTemplate' tpl $ @@ -144,8 +163,8 @@ pandocToHtml opts (Pandoc meta blocks) = do blocks' <- liftM (mconcat . intersperse (nl opts)) $ mapM (elementToHtml slideLevel opts) sects st <- get - let notes = reverse (stNotes st) - let thebody = blocks' >> footnoteSection opts notes + notes <- footnoteSection opts (reverse (stNotes st)) + let thebody = blocks' >> notes let math = case writerHTMLMathMethod opts of LaTeXMathML (Just url) -> H.script ! A.src (toValue url) @@ -172,7 +191,7 @@ pandocToHtml opts (Pandoc meta blocks) = do (H.link ! A.rel "stylesheet" ! A.href (toValue css)) <> (H.script ! A.type_ "text/javascript" $ toHtml renderKaTeX) _ -> case lookup "mathml-script" (writerVariables opts) of - Just s | not (writerHtml5 opts) -> + Just s | not (stHtml5 st) -> H.script ! A.type_ "text/javascript" $ preEscapedString ("/**/\n") @@ -199,7 +218,7 @@ pandocToHtml opts (Pandoc meta blocks) = do defField "slideous-url" ("slideous" :: String) $ defField "revealjs-url" ("reveal.js" :: String) $ defField "s5-url" ("s5/default" :: String) $ - defField "html5" (writerHtml5 opts) $ + defField "html5" (stHtml5 st) $ metadata return (thebody, context) @@ -277,6 +296,7 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen let slide = writerSlideVariant opts /= NoSlides && level <= slideLevel let num' = zipWith (+) num (writerNumberOffset opts ++ repeat 0) modify $ \st -> st{stSecNum = num'} -- update section number + html5 <- gets stHtml5 let titleSlide = slide && level < slideLevel header' <- if title' == [Str "\0"] -- marker for hrule then return mempty @@ -307,10 +327,10 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen let inNl x = mconcat $ nl opts : intersperse (nl opts) x ++ [nl opts] let classes' = ["titleslide" | titleSlide] ++ ["slide" | slide] ++ ["section" | (slide || writerSectionDivs opts) && - not (writerHtml5 opts) ] ++ + not html5 ] ++ ["level" ++ show level | slide || writerSectionDivs opts ] ++ classes - let secttag = if writerHtml5 opts + let secttag = if html5 then H5.section else H.div let attr = (id',classes',keyvals) @@ -327,19 +347,22 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen -- | Convert list of Note blocks to a footnote
. -- Assumes notes are sorted. -footnoteSection :: WriterOptions -> [Html] -> Html -footnoteSection opts notes = - if null notes - then mempty - else nl opts >> (container - $ nl opts >> hrtag >> nl opts >> - H.ol (mconcat notes >> nl opts) >> nl opts) - where container x = if writerHtml5 opts - then H5.section ! A.class_ "footnotes" $ x - else if writerSlideVariant opts /= NoSlides - then H.div ! A.class_ "footnotes slide" $ x - else H.div ! A.class_ "footnotes" $ x - hrtag = if writerHtml5 opts then H5.hr else H.hr +footnoteSection :: PandocMonad m + => WriterOptions -> [Html] -> StateT WriterState m Html +footnoteSection opts notes = do + html5 <- gets stHtml5 + let hrtag = if html5 then H5.hr else H.hr + let container x = if html5 + then H5.section ! A.class_ "footnotes" $ x + else if writerSlideVariant opts /= NoSlides + then H.div ! A.class_ "footnotes slide" $ x + else H.div ! A.class_ "footnotes" $ x + return $ + if null notes + then mempty + else nl opts >> (container + $ nl opts >> hrtag >> nl opts >> + H.ol (mconcat notes >> nl opts) >> nl opts) -- | Parse a mailto link; return Just (name, domain) or Nothing. parseMailto :: String -> Maybe (String, String) @@ -448,13 +471,14 @@ blockToHtml opts (Plain lst) = inlineListToHtml opts lst -- title beginning with fig: indicates that the image is a figure blockToHtml opts (Para [Image attr txt (s,'f':'i':'g':':':tit)]) = do img <- inlineToHtml opts (Image attr txt (s,tit)) - let tocapt = if writerHtml5 opts + html5 <- gets stHtml5 + let tocapt = if html5 then H5.figcaption else H.p ! A.class_ "caption" capt <- if null txt then return mempty else tocapt `fmap` inlineListToHtml opts txt - return $ if writerHtml5 opts + return $ if html5 then H5.figure $ mconcat [nl opts, img, capt, nl opts] else H.div ! A.class_ "figure" $ mconcat @@ -475,12 +499,13 @@ blockToHtml opts (LineBlock lns) = htmlLines <- mconcat . intersperse lf <$> mapM (inlineListToHtml opts) lns return $ H.div ! A.style "white-space: pre-line;" $ htmlLines blockToHtml opts (Div attr@(ident, classes, kvs) bs) = do + html5 <- gets stHtml5 let speakerNotes = "notes" `elem` classes -- we don't want incremental output inside speaker notes, see #1394 let opts' = if speakerNotes then opts{ writerIncremental = False } else opts contents <- blockListToHtml opts' bs let contents' = nl opts >> contents >> nl opts - let (divtag, classes') = if writerHtml5 opts && "section" `elem` classes + let (divtag, classes') = if html5 && "section" `elem` classes then (H5.section, filter (/= "section") classes) else (H.div, classes) return $ @@ -498,7 +523,9 @@ blockToHtml opts (RawBlock f str) allowsMathEnvironments (writerHTMLMathMethod opts) && isMathEnvironment str = blockToHtml opts $ Plain [Math DisplayMath str] | otherwise = return mempty -blockToHtml opts (HorizontalRule) = return $ if writerHtml5 opts then H5.hr else H.hr +blockToHtml _ (HorizontalRule) = do + html5 <- gets stHtml5 + return $ if html5 then H5.hr else H.hr blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do let tolhs = isEnabled Ext_literate_haskell opts && any (\c -> map toLower c == "haskell") classes && @@ -564,6 +591,7 @@ blockToHtml opts (BulletList lst) = do return $ unordList opts contents blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do contents <- mapM (blockListToHtml opts) lst + html5 <- gets stHtml5 let numstyle' = case numstyle of Example -> "decimal" _ -> camelCaseToHyphenated $ show numstyle @@ -574,7 +602,7 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do then [A.class_ "example"] else []) ++ (if numstyle /= DefaultStyle - then if writerHtml5 opts + then if html5 then [A.type_ $ case numstyle of Decimal -> "1" @@ -603,6 +631,7 @@ blockToHtml opts (Table capt aligns widths headers rows') = do else do cs <- inlineListToHtml opts capt return $ H.caption cs >> nl opts + html5 <- gets stHtml5 let percent w = show (truncate (100*w) :: Integer) ++ "%" let coltags = if all (== 0.0) widths then mempty @@ -610,7 +639,7 @@ blockToHtml opts (Table capt aligns widths headers rows') = do H.colgroup $ do nl opts mapM_ (\w -> do - if writerHtml5 opts + if html5 then H.col ! A.style (toValue $ "width: " ++ percent w) else H.col ! A.width (toValue $ percent w) @@ -666,8 +695,9 @@ tableItemToHtml :: PandocMonad m -> StateT WriterState m Html tableItemToHtml opts tag' align' item = do contents <- blockListToHtml opts item + html5 <- gets stHtml5 let alignStr = alignmentToString align' - let attribs = if writerHtml5 opts + let attribs = if html5 then A.style (toValue $ "text-align: " ++ alignStr ++ ";") else A.align (toValue alignStr) let tag'' = if null alignStr @@ -707,7 +737,8 @@ annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, -- | Convert Pandoc inline element to HTML. inlineToHtml :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Html -inlineToHtml opts inline = +inlineToHtml opts inline = do + html5 <- gets stHtml5 case inline of (Str str) -> return $ strToHtml str (Space) -> return $ strToHtml " " @@ -715,7 +746,7 @@ inlineToHtml opts inline = WrapNone -> preEscapedString " " WrapAuto -> preEscapedString " " WrapPreserve -> preEscapedString "\n" - (LineBreak) -> return $ (if writerHtml5 opts then H5.br else H.br) + (LineBreak) -> return $ (if html5 then H5.br else H.br) <> strToHtml "\n" (Span (id',classes,kvs) ils) -> inlineListToHtml opts ils >>= @@ -784,12 +815,12 @@ inlineToHtml opts inline = InlineMath -> H.span ! A.class_ mathClass $ m DisplayMath -> H.div ! A.class_ mathClass $ m WebTeX url -> do - let imtag = if writerHtml5 opts then H5.img else H.img + let imtag = if html5 then H5.img else H.img let m = imtag ! A.style "vertical-align:middle" ! A.src (toValue $ url ++ urlEncode str) ! A.alt (toValue str) ! A.title (toValue str) - let brtag = if writerHtml5 opts then H5.br else H.br + let brtag = if html5 then H5.br else H.br return $ case t of InlineMath -> m DisplayMath -> brtag >> m >> brtag @@ -817,7 +848,7 @@ inlineToHtml opts inline = PlainMath -> do x <- lift (texMathToInlines t str) >>= inlineListToHtml opts let m = H.span ! A.class_ mathClass $ x - let brtag = if writerHtml5 opts then H5.br else H.br + let brtag = if html5 then H5.br else H.br return $ case t of InlineMath -> m DisplayMath -> brtag >> m >> brtag @@ -847,7 +878,7 @@ inlineToHtml opts inline = [A.title $ toValue tit | not (null tit)] ++ [A.alt $ toValue alternate' | not (null txt)] ++ imgAttrsToHtml opts attr - let tag = if writerHtml5 opts then H5.img else H.img + let tag = if html5 then H5.img else H.img return $ foldl (!) tag attributes -- note: null title included, as in Markdown.pl (Image attr _ (s,tit)) -> do @@ -880,7 +911,7 @@ inlineToHtml opts inline = (Cite cits il)-> do contents <- inlineListToHtml opts il let citationIds = unwords $ map citationId cits let result = H.span ! A.class_ "citation" $ contents - return $ if writerHtml5 opts + return $ if html5 then result ! customAttribute "data-cites" (toValue citationIds) else result diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 8de09864a..e965528cc 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -47,7 +47,7 @@ import Text.Pandoc.Pretty import Control.Monad.Reader import Control.Monad.State import Control.Monad.Except (throwError) -import Text.Pandoc.Writers.HTML (writeHtmlString) +import Text.Pandoc.Writers.HTML (writeHtml5String) import Text.Pandoc.Writers.Math (texMathToInlines) import Text.HTML.TagSoup (parseTags, isTagText, Tag(..)) import Network.URI (isURI) @@ -536,7 +536,7 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do rawHeaders rawRows | isEnabled Ext_raw_html opts -> fmap (id,) $ text <$> - (writeHtmlString def $ Pandoc nullMeta [t]) + (writeHtml5String def $ Pandoc nullMeta [t]) | otherwise -> return $ (id, text "[TABLE]") return $ nst $ tbl $$ blankline $$ caption'' $$ blankline blockToMarkdown' opts (BulletList items) = do @@ -1072,7 +1072,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 - (text . trim) <$> writeHtmlString def (Pandoc nullMeta [Plain [lnk]]) + (text . trim) <$> writeHtml5String def (Pandoc nullMeta [Plain [lnk]]) | otherwise = do plain <- asks envPlain linktext <- inlineListToMarkdown opts txt @@ -1111,7 +1111,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 - (text . trim) <$> writeHtmlString def (Pandoc nullMeta [Plain [img]]) + (text . trim) <$> writeHtml5String def (Pandoc nullMeta [Plain [img]]) | otherwise = do plain <- asks envPlain let txt = if null alternate || alternate == [Str source] diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index 38c96589a..bc0cfc300 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -35,7 +35,7 @@ import Text.Pandoc.Writers.Shared import Text.Pandoc.Shared import Text.Pandoc.Options import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Writers.HTML (writeHtmlString) +import Text.Pandoc.Writers.HTML (writeHtml5String) import Text.Pandoc.Writers.Markdown (writeMarkdown) import Text.Pandoc.Pretty import Text.Pandoc.Compat.Time @@ -65,7 +65,7 @@ writeOPML opts (Pandoc meta blocks) = do writeHtmlInlines :: PandocMonad m => [Inline] -> m String writeHtmlInlines ils = - trim <$> (writeHtmlString def $ Pandoc nullMeta [Plain ils]) + trim <$> (writeHtml5String def $ Pandoc nullMeta [Plain ils]) -- date format: RFC 822: Thu, 14 Jul 2005 23:41:05 GMT showDateTimeRFC822 :: UTCTime -> String diff --git a/tests/Tests/Old.hs b/tests/Tests/Old.hs index 21e00b033..a46ac2260 100644 --- a/tests/Tests/Old.hs +++ b/tests/Tests/Old.hs @@ -81,16 +81,17 @@ tests = [ testGroup "markdown" ] ] , testGroup "html" - [ testGroup "writer" (writerTests "html" ++ lhsWriterTests "html") + [ testGroup "writer" (writerTests "html4" ++ writerTests "html5" ++ + lhsWriterTests "html") , test "reader" ["-r", "html", "-w", "native", "-s"] "html-reader.html" "html-reader.native" ] , testGroup "s5" [ s5WriterTest "basic" ["-s"] "s5" , s5WriterTest "fancy" ["-s","-m","-i"] "s5" - , s5WriterTest "fragment" [] "html" + , s5WriterTest "fragment" [] "html4" , s5WriterTest "inserts" ["-s", "-H", "insert", - "-B", "insert", "-A", "insert", "-c", "main.css"] "html" + "-B", "insert", "-A", "insert", "-c", "main.css"] "html4" ] , testGroup "textile" [ testGroup "writer" $ writerTests "textile" diff --git a/tests/Tests/Writers/HTML.hs b/tests/Tests/Writers/HTML.hs index d99698c21..45de2b042 100644 --- a/tests/Tests/Writers/HTML.hs +++ b/tests/Tests/Writers/HTML.hs @@ -8,7 +8,7 @@ import Tests.Helpers import Text.Pandoc.Arbitrary() html :: (ToPandoc a) => a -> String -html = purely (writeHtmlString def{ writerWrapText = WrapNone }) . toPandoc +html = purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc {- "my test" =: X =?> Y diff --git a/tests/lhs-test.html b/tests/lhs-test.html index e4a5b3868..2c3b6b0f8 100644 --- a/tests/lhs-test.html +++ b/tests/lhs-test.html @@ -1,9 +1,9 @@ - - + + - - - + + + +

lhs test

diff --git a/tests/lhs-test.html+lhs b/tests/lhs-test.html+lhs index 41e9ca283..443b0642f 100644 --- a/tests/lhs-test.html+lhs +++ b/tests/lhs-test.html+lhs @@ -1,9 +1,9 @@ - - + + - - - + + + +

lhs test

diff --git a/tests/tables.html b/tests/tables.html deleted file mode 100644 index 5bb7a7de2..000000000 --- a/tests/tables.html +++ /dev/null @@ -1,204 +0,0 @@ -

Simple table with caption:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
-

Simple table without caption:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RightLeftCenterDefault
12121212
123123123123
1111
-

Simple table indented two spaces:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
-

Multiline table with caption:

- - ------ - - - - - - - - - - - - - - - - - - - - - - -
Here’s the caption. It may span multiple lines.
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
-

Multiline table without caption:

- ------ - - - - - - - - - - - - - - - - - - - - - - -
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
-

Table without column headers:

- - - - - - - - - - - - - - - - - - - - - -
12121212
123123123123
1111
-

Multiline table without column headers:

- ------ - - - - - - - - - - - - - - -
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
diff --git a/tests/tables.html4 b/tests/tables.html4 new file mode 100644 index 000000000..5bb7a7de2 --- /dev/null +++ b/tests/tables.html4 @@ -0,0 +1,204 @@ +

Simple table with caption:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
+

Simple table without caption:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RightLeftCenterDefault
12121212
123123123123
1111
+

Simple table indented two spaces:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
+

Multiline table with caption:

+ + ++++++ + + + + + + + + + + + + + + + + + + + + + + +
Here’s the caption. It may span multiple lines.
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
+

Multiline table without caption:

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + +
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
+

Table without column headers:

+ + + + + + + + + + + + + + + + + + + + + +
12121212
123123123123
1111
+

Multiline table without column headers:

+ ++++++ + + + + + + + + + + + + + + +
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
diff --git a/tests/tables.html5 b/tests/tables.html5 new file mode 100644 index 000000000..17a82110f --- /dev/null +++ b/tests/tables.html5 @@ -0,0 +1,204 @@ +

Simple table with caption:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
+

Simple table without caption:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RightLeftCenterDefault
12121212
123123123123
1111
+

Simple table indented two spaces:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
+

Multiline table with caption:

+ + ++++++ + + + + + + + + + + + + + + + + + + + + + + +
Here’s the caption. It may span multiple lines.
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
+

Multiline table without caption:

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + +
Centered HeaderLeft AlignedRight AlignedDefault aligned
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
+

Table without column headers:

+ + + + + + + + + + + + + + + + + + + + + +
12121212
123123123123
1111
+

Multiline table without column headers:

+ ++++++ + + + + + + + + + + + + + + +
Firstrow12.0Example of a row that spans multiple lines.
Secondrow5.0Here’s another one. Note the blank line between rows.
diff --git a/tests/writer.html b/tests/writer.html deleted file mode 100644 index 3b63f4e16..000000000 --- a/tests/writer.html +++ /dev/null @@ -1,546 +0,0 @@ - - - - - - - - - - Pandoc Test Suite - - - - -

This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.

-
-

Headers

- -

Level 3 with emphasis

-

Level 4

-
Level 5
-

Level 1

-

Level 2 with emphasis

-

Level 3

-

with no blank line

-

Level 2

-

with no blank line

-
-

Paragraphs

-

Here’s a regular paragraph.

-

In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.

-

Here’s one with a bullet. * criminey.

-

There should be a hard line break
-here.

-
-

Block Quotes

-

E-mail style:

-
-

This is a block quote. It is pretty short.

-
-
-

Code in a block quote:

-
sub status {
-    print "working";
-}
-

A list:

-
    -
  1. item one
  2. -
  3. item two
  4. -
-

Nested block quotes:

-
-

nested

-
-
-

nested

-
-
-

This should not be a block quote: 2 > 1.

-

And a following paragraph.

-
-

Code Blocks

-

Code:

-
---- (should be four hyphens)
-
-sub status {
-    print "working";
-}
-
-this code block is indented by one tab
-

And:

-
    this code block is indented by two tabs
-
-These should not be escaped:  \$ \\ \> \[ \{
-
-

Lists

-

Unordered

-

Asterisks tight:

-
    -
  • asterisk 1
  • -
  • asterisk 2
  • -
  • asterisk 3
  • -
-

Asterisks loose:

-
    -
  • asterisk 1

  • -
  • asterisk 2

  • -
  • asterisk 3

  • -
-

Pluses tight:

-
    -
  • Plus 1
  • -
  • Plus 2
  • -
  • Plus 3
  • -
-

Pluses loose:

-
    -
  • Plus 1

  • -
  • Plus 2

  • -
  • Plus 3

  • -
-

Minuses tight:

-
    -
  • Minus 1
  • -
  • Minus 2
  • -
  • Minus 3
  • -
-

Minuses loose:

-
    -
  • Minus 1

  • -
  • Minus 2

  • -
  • Minus 3

  • -
-

Ordered

-

Tight:

-
    -
  1. First
  2. -
  3. Second
  4. -
  5. Third
  6. -
-

and:

-
    -
  1. One
  2. -
  3. Two
  4. -
  5. Three
  6. -
-

Loose using tabs:

-
    -
  1. First

  2. -
  3. Second

  4. -
  5. Third

  6. -
-

and using spaces:

-
    -
  1. One

  2. -
  3. Two

  4. -
  5. Three

  6. -
-

Multiple paragraphs:

-
    -
  1. Item 1, graf one.

    -

    Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.

  2. -
  3. Item 2.

  4. -
  5. Item 3.

  6. -
-

Nested

-
    -
  • Tab -
      -
    • Tab -
        -
      • Tab
      • -
    • -
  • -
-

Here’s another:

-
    -
  1. First
  2. -
  3. Second: -
      -
    • Fee
    • -
    • Fie
    • -
    • Foe
    • -
  4. -
  5. Third
  6. -
-

Same thing but with paragraphs:

-
    -
  1. First

  2. -
  3. Second:

    -
      -
    • Fee
    • -
    • Fie
    • -
    • Foe
    • -
  4. -
  5. Third

  6. -
-

Tabs and spaces

-
    -
  • this is a list item indented with tabs

  • -
  • this is a list item indented with spaces

    -
      -
    • this is an example list item indented with tabs

    • -
    • this is an example list item indented with spaces

    • -
  • -
-

Fancy list markers

-
    -
  1. begins with 2
  2. -
  3. and now 3

    -

    with a continuation

    -
      -
    1. sublist with roman numerals, starting with 4
    2. -
    3. more items -
        -
      1. a subsublist
      2. -
      3. a subsublist
      4. -
    4. -
  4. -
-

Nesting:

-
    -
  1. Upper Alpha -
      -
    1. Upper Roman. -
        -
      1. Decimal start with 6 -
          -
        1. Lower alpha with paren
        2. -
      2. -
    2. -
  2. -
-

Autonumbering:

-
    -
  1. Autonumber.
  2. -
  3. More. -
      -
    1. Nested.
    2. -
  4. -
-

Should not be a list item:

-

M.A. 2007

-

B. Williams

-
-

Definition Lists

-

Tight using spaces:

-
-
apple
-
red fruit -
-
orange
-
orange fruit -
-
banana
-
yellow fruit -
-
-

Tight using tabs:

-
-
apple
-
red fruit -
-
orange
-
orange fruit -
-
banana
-
yellow fruit -
-
-

Loose:

-
-
apple
-

red fruit

-
-
orange
-

orange fruit

-
-
banana
-

yellow fruit

-
-
-

Multiple blocks with italics:

-
-
apple
-

red fruit

-

contains seeds, crisp, pleasant to taste

-
-
orange
-

orange fruit

-
{ orange code block }
-
-

orange block quote

-
-
-
-

Multiple definitions, tight:

-
-
apple
-
red fruit -
-
computer -
-
orange
-
orange fruit -
-
bank -
-
-

Multiple definitions, loose:

-
-
apple
-

red fruit

-
-

computer

-
-
orange
-

orange fruit

-
-

bank

-
-
-

Blank line after term, indented marker, alternate markers:

-
-
apple
-

red fruit

-
-

computer

-
-
orange
-

orange fruit

-
    -
  1. sublist
  2. -
  3. sublist
  4. -
-
-
-

HTML Blocks

-

Simple block on one line:

-
-foo -
-

And nested without indentation:

-
-
-
-

foo

-
-
-
-bar -
-
-

Interpreted markdown in a table:

- - - - - -
-This is emphasized - -And this is strong -
- -

Here’s a simple block:

-
-

foo

-
-

This should be a code block, though:

-
<div>
-    foo
-</div>
-

As should this:

-
<div>foo</div>
-

Now, nested:

-
-
-
-foo -
-
-
-

This should just be an HTML comment:

- -

Multiline:

- - -

Code block:

-
<!-- Comment -->
-

Just plain comment, with trailing spaces on the line:

- -

Code:

-
<hr />
-

Hr’s:

-
-
-
-
-
-
-
-
-
-
-

Inline Markup

-

This is emphasized, and so is this.

-

This is strong, and so is this.

-

An emphasized link.

-

This is strong and em.

-

So is this word.

-

This is strong and em.

-

So is this word.

-

This is code: >, $, \, \$, <html>.

-

This is strikeout.

-

Superscripts: abcd ahello ahello there.

-

Subscripts: H2O, H23O, Hmany of themO.

-

These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.

-
-

Smart quotes, ellipses, dashes

-

“Hello,” said the spider. “‘Shelob’ is my name.”

-

‘A’, ‘B’, and ‘C’ are letters.

-

‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’

-

‘He said, “I want to go.”’ Were you alive in the 70’s?

-

Here is some quoted ‘code’ and a “quoted link”.

-

Some dashes: one—two — three—four — five.

-

Dashes between numbers: 5–7, 255–66, 1987–1999.

-

Ellipses…and…and….

-
-

LaTeX

-
    -
  • -
  • 2 + 2 = 4
  • -
  • x ∈ y
  • -
  • α ∧ ω
  • -
  • 223
  • -
  • p-Tree
  • -
  • Here’s some display math:
    $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
  • -
  • Here’s one that has a line break in it: α + ω × x2.
  • -
-

These shouldn’t be math:

-
    -
  • To get the famous equation, write $e = mc^2$.
  • -
  • $22,000 is a lot of money. So is $34,000. (It worked if “lot” is emphasized.)
  • -
  • Shoes ($20) and socks ($5).
  • -
  • Escaped $: $73 this should be emphasized 23$.
  • -
-

Here’s a LaTeX table:

- -
-

Special Characters

-

Here is some unicode:

-
    -
  • I hat: Î
  • -
  • o umlaut: ö
  • -
  • section: §
  • -
  • set membership: ∈
  • -
  • copyright: ©
  • -
-

AT&T has an ampersand in their name.

-

AT&T is another way to write it.

-

This & that.

-

4 < 5.

-

6 > 5.

-

Backslash: \

-

Backtick: `

-

Asterisk: *

-

Underscore: _

-

Left brace: {

-

Right brace: }

-

Left bracket: [

-

Right bracket: ]

-

Left paren: (

-

Right paren: )

-

Greater-than: >

-

Hash: #

-

Period: .

-

Bang: !

-

Plus: +

-

Minus: -

-
-

Links

-

Explicit

-

Just a URL.

-

URL and title.

-

URL and title.

-

URL and title.

-

URL and title

-

URL and title

-

with_underscore

-

Email link

-

Empty.

-

Reference

-

Foo bar.

-

Foo bar.

-

Foo bar.

-

With embedded [brackets].

-

b by itself should be a link.

-

Indented once.

-

Indented twice.

-

Indented thrice.

-

This should [not][] be a link.

-
[not]: /url
-

Foo bar.

-

Foo biz.

-

With ampersands

-

Here’s a link with an ampersand in the URL.

-

Here’s a link with an amersand in the link text: AT&T.

-

Here’s an inline link.

-

Here’s an inline link in pointy braces.

- -

With an ampersand: http://example.com/?foo=1&bar=2

- -

An e-mail address: nobody@nowhere.net

-
-

Blockquoted: http://example.com/

-
-

Auto-links should not occur here: <http://example.com/>

-
or here: <http://example.com/>
-
-

Images

-

From “Voyage dans la Lune” by Georges Melies (1902):

-
-lalune -

lalune

-
-

Here is a movie movie icon.

-
-

Footnotes

-

Here is a footnote reference,1 and another.2 This should not be a footnote reference, because it contains a space.[^my note] Here is an inline note.3

-
-

Notes can go in quotes.4

-
-
    -
  1. And in list items.5
  2. -
-

This paragraph should not be part of the note, as it is not indented.

-
-
-
    -
  1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.

  2. -
  3. Here’s the long note. This one contains multiple blocks.

    -

    Subsequent blocks are indented to show that they belong to the footnote (as with list items).

    -
      { <code> }
    -

    If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.

  4. -
  5. This is easier to type. Inline notes may contain links and ] verbatim characters, as well as [bracketed text].

  6. -
  7. In quote.

  8. -
  9. In list.

  10. -
-
- - diff --git a/tests/writer.html4 b/tests/writer.html4 new file mode 100644 index 000000000..3b63f4e16 --- /dev/null +++ b/tests/writer.html4 @@ -0,0 +1,546 @@ + + + + + + + + + + Pandoc Test Suite + + + + +

This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.

+
+

Headers

+ +

Level 3 with emphasis

+

Level 4

+
Level 5
+

Level 1

+

Level 2 with emphasis

+

Level 3

+

with no blank line

+

Level 2

+

with no blank line

+
+

Paragraphs

+

Here’s a regular paragraph.

+

In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.

+

Here’s one with a bullet. * criminey.

+

There should be a hard line break
+here.

+
+

Block Quotes

+

E-mail style:

+
+

This is a block quote. It is pretty short.

+
+
+

Code in a block quote:

+
sub status {
+    print "working";
+}
+

A list:

+
    +
  1. item one
  2. +
  3. item two
  4. +
+

Nested block quotes:

+
+

nested

+
+
+

nested

+
+
+

This should not be a block quote: 2 > 1.

+

And a following paragraph.

+
+

Code Blocks

+

Code:

+
---- (should be four hyphens)
+
+sub status {
+    print "working";
+}
+
+this code block is indented by one tab
+

And:

+
    this code block is indented by two tabs
+
+These should not be escaped:  \$ \\ \> \[ \{
+
+

Lists

+

Unordered

+

Asterisks tight:

+
    +
  • asterisk 1
  • +
  • asterisk 2
  • +
  • asterisk 3
  • +
+

Asterisks loose:

+
    +
  • asterisk 1

  • +
  • asterisk 2

  • +
  • asterisk 3

  • +
+

Pluses tight:

+
    +
  • Plus 1
  • +
  • Plus 2
  • +
  • Plus 3
  • +
+

Pluses loose:

+
    +
  • Plus 1

  • +
  • Plus 2

  • +
  • Plus 3

  • +
+

Minuses tight:

+
    +
  • Minus 1
  • +
  • Minus 2
  • +
  • Minus 3
  • +
+

Minuses loose:

+
    +
  • Minus 1

  • +
  • Minus 2

  • +
  • Minus 3

  • +
+

Ordered

+

Tight:

+
    +
  1. First
  2. +
  3. Second
  4. +
  5. Third
  6. +
+

and:

+
    +
  1. One
  2. +
  3. Two
  4. +
  5. Three
  6. +
+

Loose using tabs:

+
    +
  1. First

  2. +
  3. Second

  4. +
  5. Third

  6. +
+

and using spaces:

+
    +
  1. One

  2. +
  3. Two

  4. +
  5. Three

  6. +
+

Multiple paragraphs:

+
    +
  1. Item 1, graf one.

    +

    Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.

  2. +
  3. Item 2.

  4. +
  5. Item 3.

  6. +
+

Nested

+
    +
  • Tab +
      +
    • Tab +
        +
      • Tab
      • +
    • +
  • +
+

Here’s another:

+
    +
  1. First
  2. +
  3. Second: +
      +
    • Fee
    • +
    • Fie
    • +
    • Foe
    • +
  4. +
  5. Third
  6. +
+

Same thing but with paragraphs:

+
    +
  1. First

  2. +
  3. Second:

    +
      +
    • Fee
    • +
    • Fie
    • +
    • Foe
    • +
  4. +
  5. Third

  6. +
+

Tabs and spaces

+
    +
  • this is a list item indented with tabs

  • +
  • this is a list item indented with spaces

    +
      +
    • this is an example list item indented with tabs

    • +
    • this is an example list item indented with spaces

    • +
  • +
+

Fancy list markers

+
    +
  1. begins with 2
  2. +
  3. and now 3

    +

    with a continuation

    +
      +
    1. sublist with roman numerals, starting with 4
    2. +
    3. more items +
        +
      1. a subsublist
      2. +
      3. a subsublist
      4. +
    4. +
  4. +
+

Nesting:

+
    +
  1. Upper Alpha +
      +
    1. Upper Roman. +
        +
      1. Decimal start with 6 +
          +
        1. Lower alpha with paren
        2. +
      2. +
    2. +
  2. +
+

Autonumbering:

+
    +
  1. Autonumber.
  2. +
  3. More. +
      +
    1. Nested.
    2. +
  4. +
+

Should not be a list item:

+

M.A. 2007

+

B. Williams

+
+

Definition Lists

+

Tight using spaces:

+
+
apple
+
red fruit +
+
orange
+
orange fruit +
+
banana
+
yellow fruit +
+
+

Tight using tabs:

+
+
apple
+
red fruit +
+
orange
+
orange fruit +
+
banana
+
yellow fruit +
+
+

Loose:

+
+
apple
+

red fruit

+
+
orange
+

orange fruit

+
+
banana
+

yellow fruit

+
+
+

Multiple blocks with italics:

+
+
apple
+

red fruit

+

contains seeds, crisp, pleasant to taste

+
+
orange
+

orange fruit

+
{ orange code block }
+
+

orange block quote

+
+
+
+

Multiple definitions, tight:

+
+
apple
+
red fruit +
+
computer +
+
orange
+
orange fruit +
+
bank +
+
+

Multiple definitions, loose:

+
+
apple
+

red fruit

+
+

computer

+
+
orange
+

orange fruit

+
+

bank

+
+
+

Blank line after term, indented marker, alternate markers:

+
+
apple
+

red fruit

+
+

computer

+
+
orange
+

orange fruit

+
    +
  1. sublist
  2. +
  3. sublist
  4. +
+
+
+

HTML Blocks

+

Simple block on one line:

+
+foo +
+

And nested without indentation:

+
+
+
+

foo

+
+
+
+bar +
+
+

Interpreted markdown in a table:

+ + + + + +
+This is emphasized + +And this is strong +
+ +

Here’s a simple block:

+
+

foo

+
+

This should be a code block, though:

+
<div>
+    foo
+</div>
+

As should this:

+
<div>foo</div>
+

Now, nested:

+
+
+
+foo +
+
+
+

This should just be an HTML comment:

+ +

Multiline:

+ + +

Code block:

+
<!-- Comment -->
+

Just plain comment, with trailing spaces on the line:

+ +

Code:

+
<hr />
+

Hr’s:

+
+
+
+
+
+
+
+
+
+
+

Inline Markup

+

This is emphasized, and so is this.

+

This is strong, and so is this.

+

An emphasized link.

+

This is strong and em.

+

So is this word.

+

This is strong and em.

+

So is this word.

+

This is code: >, $, \, \$, <html>.

+

This is strikeout.

+

Superscripts: abcd ahello ahello there.

+

Subscripts: H2O, H23O, Hmany of themO.

+

These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.

+
+

Smart quotes, ellipses, dashes

+

“Hello,” said the spider. “‘Shelob’ is my name.”

+

‘A’, ‘B’, and ‘C’ are letters.

+

‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’

+

‘He said, “I want to go.”’ Were you alive in the 70’s?

+

Here is some quoted ‘code’ and a “quoted link”.

+

Some dashes: one—two — three—four — five.

+

Dashes between numbers: 5–7, 255–66, 1987–1999.

+

Ellipses…and…and….

+
+

LaTeX

+
    +
  • +
  • 2 + 2 = 4
  • +
  • x ∈ y
  • +
  • α ∧ ω
  • +
  • 223
  • +
  • p-Tree
  • +
  • Here’s some display math:
    $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
  • +
  • Here’s one that has a line break in it: α + ω × x2.
  • +
+

These shouldn’t be math:

+
    +
  • To get the famous equation, write $e = mc^2$.
  • +
  • $22,000 is a lot of money. So is $34,000. (It worked if “lot” is emphasized.)
  • +
  • Shoes ($20) and socks ($5).
  • +
  • Escaped $: $73 this should be emphasized 23$.
  • +
+

Here’s a LaTeX table:

+ +
+

Special Characters

+

Here is some unicode:

+
    +
  • I hat: Î
  • +
  • o umlaut: ö
  • +
  • section: §
  • +
  • set membership: ∈
  • +
  • copyright: ©
  • +
+

AT&T has an ampersand in their name.

+

AT&T is another way to write it.

+

This & that.

+

4 < 5.

+

6 > 5.

+

Backslash: \

+

Backtick: `

+

Asterisk: *

+

Underscore: _

+

Left brace: {

+

Right brace: }

+

Left bracket: [

+

Right bracket: ]

+

Left paren: (

+

Right paren: )

+

Greater-than: >

+

Hash: #

+

Period: .

+

Bang: !

+

Plus: +

+

Minus: -

+
+

Links

+

Explicit

+

Just a URL.

+

URL and title.

+

URL and title.

+

URL and title.

+

URL and title

+

URL and title

+

with_underscore

+

Email link

+

Empty.

+

Reference

+

Foo bar.

+

Foo bar.

+

Foo bar.

+

With embedded [brackets].

+

b by itself should be a link.

+

Indented once.

+

Indented twice.

+

Indented thrice.

+

This should [not][] be a link.

+
[not]: /url
+

Foo bar.

+

Foo biz.

+

With ampersands

+

Here’s a link with an ampersand in the URL.

+

Here’s a link with an amersand in the link text: AT&T.

+

Here’s an inline link.

+

Here’s an inline link in pointy braces.

+ +

With an ampersand: http://example.com/?foo=1&bar=2

+ +

An e-mail address: nobody@nowhere.net

+
+

Blockquoted: http://example.com/

+
+

Auto-links should not occur here: <http://example.com/>

+
or here: <http://example.com/>
+
+

Images

+

From “Voyage dans la Lune” by Georges Melies (1902):

+
+lalune +

lalune

+
+

Here is a movie movie icon.

+
+

Footnotes

+

Here is a footnote reference,1 and another.2 This should not be a footnote reference, because it contains a space.[^my note] Here is an inline note.3

+
+

Notes can go in quotes.4

+
+
    +
  1. And in list items.5
  2. +
+

This paragraph should not be part of the note, as it is not indented.

+
+
+
    +
  1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.

  2. +
  3. Here’s the long note. This one contains multiple blocks.

    +

    Subsequent blocks are indented to show that they belong to the footnote (as with list items).

    +
      { <code> }
    +

    If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.

  4. +
  5. This is easier to type. Inline notes may contain links and ] verbatim characters, as well as [bracketed text].

  6. +
  7. In quote.

  8. +
  9. In list.

  10. +
+
+ + diff --git a/tests/writer.html5 b/tests/writer.html5 new file mode 100644 index 000000000..8e0dff764 --- /dev/null +++ b/tests/writer.html5 @@ -0,0 +1,548 @@ + + + + + + + + + + Pandoc Test Suite + + + + +
+

Pandoc Test Suite

+

John MacFarlane

+

Anonymous

+

July 17, 2006

+
+

This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.

+
+

Headers

+ +

Level 3 with emphasis

+

Level 4

+
Level 5
+

Level 1

+

Level 2 with emphasis

+

Level 3

+

with no blank line

+

Level 2

+

with no blank line

+
+

Paragraphs

+

Here’s a regular paragraph.

+

In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.

+

Here’s one with a bullet. * criminey.

+

There should be a hard line break
+here.

+
+

Block Quotes

+

E-mail style:

+
+

This is a block quote. It is pretty short.

+
+
+

Code in a block quote:

+
sub status {
+    print "working";
+}
+

A list:

+
    +
  1. item one
  2. +
  3. item two
  4. +
+

Nested block quotes:

+
+

nested

+
+
+

nested

+
+
+

This should not be a block quote: 2 > 1.

+

And a following paragraph.

+
+

Code Blocks

+

Code:

+
---- (should be four hyphens)
+
+sub status {
+    print "working";
+}
+
+this code block is indented by one tab
+

And:

+
    this code block is indented by two tabs
+
+These should not be escaped:  \$ \\ \> \[ \{
+
+

Lists

+

Unordered

+

Asterisks tight:

+
    +
  • asterisk 1
  • +
  • asterisk 2
  • +
  • asterisk 3
  • +
+

Asterisks loose:

+
    +
  • asterisk 1

  • +
  • asterisk 2

  • +
  • asterisk 3

  • +
+

Pluses tight:

+
    +
  • Plus 1
  • +
  • Plus 2
  • +
  • Plus 3
  • +
+

Pluses loose:

+
    +
  • Plus 1

  • +
  • Plus 2

  • +
  • Plus 3

  • +
+

Minuses tight:

+
    +
  • Minus 1
  • +
  • Minus 2
  • +
  • Minus 3
  • +
+

Minuses loose:

+
    +
  • Minus 1

  • +
  • Minus 2

  • +
  • Minus 3

  • +
+

Ordered

+

Tight:

+
    +
  1. First
  2. +
  3. Second
  4. +
  5. Third
  6. +
+

and:

+
    +
  1. One
  2. +
  3. Two
  4. +
  5. Three
  6. +
+

Loose using tabs:

+
    +
  1. First

  2. +
  3. Second

  4. +
  5. Third

  6. +
+

and using spaces:

+
    +
  1. One

  2. +
  3. Two

  4. +
  5. Three

  6. +
+

Multiple paragraphs:

+
    +
  1. Item 1, graf one.

    +

    Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.

  2. +
  3. Item 2.

  4. +
  5. Item 3.

  6. +
+

Nested

+
    +
  • Tab +
      +
    • Tab +
        +
      • Tab
      • +
    • +
  • +
+

Here’s another:

+
    +
  1. First
  2. +
  3. Second: +
      +
    • Fee
    • +
    • Fie
    • +
    • Foe
    • +
  4. +
  5. Third
  6. +
+

Same thing but with paragraphs:

+
    +
  1. First

  2. +
  3. Second:

    +
      +
    • Fee
    • +
    • Fie
    • +
    • Foe
    • +
  4. +
  5. Third

  6. +
+

Tabs and spaces

+
    +
  • this is a list item indented with tabs

  • +
  • this is a list item indented with spaces

    +
      +
    • this is an example list item indented with tabs

    • +
    • this is an example list item indented with spaces

    • +
  • +
+

Fancy list markers

+
    +
  1. begins with 2
  2. +
  3. and now 3

    +

    with a continuation

    +
      +
    1. sublist with roman numerals, starting with 4
    2. +
    3. more items +
        +
      1. a subsublist
      2. +
      3. a subsublist
      4. +
    4. +
  4. +
+

Nesting:

+
    +
  1. Upper Alpha +
      +
    1. Upper Roman. +
        +
      1. Decimal start with 6 +
          +
        1. Lower alpha with paren
        2. +
      2. +
    2. +
  2. +
+

Autonumbering:

+
    +
  1. Autonumber.
  2. +
  3. More. +
      +
    1. Nested.
    2. +
  4. +
+

Should not be a list item:

+

M.A. 2007

+

B. Williams

+
+

Definition Lists

+

Tight using spaces:

+
+
apple
+
red fruit +
+
orange
+
orange fruit +
+
banana
+
yellow fruit +
+
+

Tight using tabs:

+
+
apple
+
red fruit +
+
orange
+
orange fruit +
+
banana
+
yellow fruit +
+
+

Loose:

+
+
apple
+

red fruit

+
+
orange
+

orange fruit

+
+
banana
+

yellow fruit

+
+
+

Multiple blocks with italics:

+
+
apple
+

red fruit

+

contains seeds, crisp, pleasant to taste

+
+
orange
+

orange fruit

+
{ orange code block }
+
+

orange block quote

+
+
+
+

Multiple definitions, tight:

+
+
apple
+
red fruit +
+
computer +
+
orange
+
orange fruit +
+
bank +
+
+

Multiple definitions, loose:

+
+
apple
+

red fruit

+
+

computer

+
+
orange
+

orange fruit

+
+

bank

+
+
+

Blank line after term, indented marker, alternate markers:

+
+
apple
+

red fruit

+
+

computer

+
+
orange
+

orange fruit

+
    +
  1. sublist
  2. +
  3. sublist
  4. +
+
+
+

HTML Blocks

+

Simple block on one line:

+
+foo +
+

And nested without indentation:

+
+
+
+

foo

+
+
+
+bar +
+
+

Interpreted markdown in a table:

+ + + + + +
+This is emphasized + +And this is strong +
+ +

Here’s a simple block:

+
+

foo

+
+

This should be a code block, though:

+
<div>
+    foo
+</div>
+

As should this:

+
<div>foo</div>
+

Now, nested:

+
+
+
+foo +
+
+
+

This should just be an HTML comment:

+ +

Multiline:

+ + +

Code block:

+
<!-- Comment -->
+

Just plain comment, with trailing spaces on the line:

+ +

Code:

+
<hr />
+

Hr’s:

+
+
+
+
+
+
+
+
+
+
+

Inline Markup

+

This is emphasized, and so is this.

+

This is strong, and so is this.

+

An emphasized link.

+

This is strong and em.

+

So is this word.

+

This is strong and em.

+

So is this word.

+

This is code: >, $, \, \$, <html>.

+

This is strikeout.

+

Superscripts: abcd ahello ahello there.

+

Subscripts: H2O, H23O, Hmany of themO.

+

These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.

+
+

Smart quotes, ellipses, dashes

+

“Hello,” said the spider. “‘Shelob’ is my name.”

+

‘A’, ‘B’, and ‘C’ are letters.

+

‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’

+

‘He said, “I want to go.”’ Were you alive in the 70’s?

+

Here is some quoted ‘code’ and a “quoted link”.

+

Some dashes: one—two — three—four — five.

+

Dashes between numbers: 5–7, 255–66, 1987–1999.

+

Ellipses…and…and….

+
+

LaTeX

+
    +
  • +
  • 2 + 2 = 4
  • +
  • x ∈ y
  • +
  • α ∧ ω
  • +
  • 223
  • +
  • p-Tree
  • +
  • Here’s some display math:
    $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
  • +
  • Here’s one that has a line break in it: α + ω × x2.
  • +
+

These shouldn’t be math:

+
    +
  • To get the famous equation, write $e = mc^2$.
  • +
  • $22,000 is a lot of money. So is $34,000. (It worked if “lot” is emphasized.)
  • +
  • Shoes ($20) and socks ($5).
  • +
  • Escaped $: $73 this should be emphasized 23$.
  • +
+

Here’s a LaTeX table:

+ +
+

Special Characters

+

Here is some unicode:

+
    +
  • I hat: Î
  • +
  • o umlaut: ö
  • +
  • section: §
  • +
  • set membership: ∈
  • +
  • copyright: ©
  • +
+

AT&T has an ampersand in their name.

+

AT&T is another way to write it.

+

This & that.

+

4 < 5.

+

6 > 5.

+

Backslash: \

+

Backtick: `

+

Asterisk: *

+

Underscore: _

+

Left brace: {

+

Right brace: }

+

Left bracket: [

+

Right bracket: ]

+

Left paren: (

+

Right paren: )

+

Greater-than: >

+

Hash: #

+

Period: .

+

Bang: !

+

Plus: +

+

Minus: -

+
+

Links

+

Explicit

+

Just a URL.

+

URL and title.

+

URL and title.

+

URL and title.

+

URL and title

+

URL and title

+

with_underscore

+

Email link

+

Empty.

+

Reference

+

Foo bar.

+

Foo bar.

+

Foo bar.

+

With embedded [brackets].

+

b by itself should be a link.

+

Indented once.

+

Indented twice.

+

Indented thrice.

+

This should [not][] be a link.

+
[not]: /url
+

Foo bar.

+

Foo biz.

+

With ampersands

+

Here’s a link with an ampersand in the URL.

+

Here’s a link with an amersand in the link text: AT&T.

+

Here’s an inline link.

+

Here’s an inline link in pointy braces.

+ +

With an ampersand: http://example.com/?foo=1&bar=2

+ +

An e-mail address: nobody@nowhere.net

+
+

Blockquoted: http://example.com/

+
+

Auto-links should not occur here: <http://example.com/>

+
or here: <http://example.com/>
+
+

Images

+

From “Voyage dans la Lune” by Georges Melies (1902):

+
+lalune
lalune
+
+

Here is a movie movie icon.

+
+

Footnotes

+

Here is a footnote reference,1 and another.2 This should not be a footnote reference, because it contains a space.[^my note] Here is an inline note.3

+
+

Notes can go in quotes.4

+
+
    +
  1. And in list items.5
  2. +
+

This paragraph should not be part of the note, as it is not indented.

+
+
+
    +
  1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.

  2. +
  3. Here’s the long note. This one contains multiple blocks.

    +

    Subsequent blocks are indented to show that they belong to the footnote (as with list items).

    +
      { <code> }
    +

    If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.

  4. +
  5. This is easier to type. Inline notes may contain links and ] verbatim characters, as well as [bracketed text].

  6. +
  7. In quote.

  8. +
  9. In list.

  10. +
+
+ + -- cgit v1.2.3 From 190943e1fd75b7fa30689387e4416dd81b584f5e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 26 Jan 2017 20:39:32 +0100 Subject: EPUB writer: split writeEPUB into writeEPUB2, writeEPUB3. Also include explicit epub2 output format in CLI tool. --- MANUAL.txt | 23 ++++++++++++----------- data/templates | 2 +- pandoc.cabal | 2 +- src/Text/Pandoc.hs | 12 +++++++----- src/Text/Pandoc/Templates.hs | 1 + src/Text/Pandoc/Writers/EPUB.hs | 31 ++++++++++++++++++++++++------- 6 files changed, 46 insertions(+), 25 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index 3b8ac2b85..91f4bacc0 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -101,7 +101,7 @@ If no *input-file* is specified, input is read from *stdin*. Otherwise, the *input-files* are concatenated (with a blank line between each) and used as input. Output goes to *stdout* by default (though output to *stdout* is disabled for the `odt`, `docx`, -`epub`, and `epub3` output formats). For output to a file, use the +`epub2`, and `epub3` output formats). For output to a file, use the `-o` option: pandoc -o output.html input.txt @@ -273,7 +273,7 @@ General options (original unextended Markdown), `markdown_phpextra` (PHP Markdown Extra), `markdown_github` (GitHub-Flavored Markdown), `markdown_mmd` (MultiMarkdown), `commonmark` (CommonMark Markdown), `rst` - (reStructuredText), `html` (XHTML), `html5` (HTML5), `latex` + (reStructuredText), `html4` (XHTML4), `html` or `html5` (HTML5), `latex` (LaTeX), `beamer` (LaTeX beamer slide show), `context` (ConTeXt), `man` (groff man), `mediawiki` (MediaWiki markup), `dokuwiki` (DokuWiki markup), `zimwiki` (ZimWiki markup), @@ -281,7 +281,7 @@ General options `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` (DocBook 4), `docbook5` (DocBook 5), `opendocument` (OpenDocument), `odt` (OpenOffice text document), `docx` (Word docx), `haddock` - (Haddock markup), `rtf` (rich text format), `epub` (EPUB v2 + (Haddock markup), `rtf` (rich text format), `epub` or `epub2` (EPUB v2 book), `epub3` (EPUB v3), `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml` (InDesign ICML), `tei` (TEI Simple), `slidy` (Slidy HTML and JavaScript slide show), @@ -293,7 +293,7 @@ General options `epub`, and `epub3` output will not be directed to *stdout*; an output filename must be specified using the `-o/--output` option. If `+lhs` is appended to `markdown`, `rst`, `latex`, - `beamer`, `html`, or `html5`, the output will be rendered as + `beamer`, `html4`, or `html5`, the output will be rendered as literate Haskell source: see [Literate Haskell support], below. Markdown syntax extensions can be individually enabled or disabled by appending `+EXTENSION` or @@ -626,7 +626,7 @@ Options affecting specific writers images, and videos. The resulting file should be "self-contained," in the sense that it needs no external files and no net access to be displayed properly by a browser. This option works only with HTML output - formats, including `html`, `html5`, `html+lhs`, `html5+lhs`, `s5`, + formats, including `html4`, `html5`, `html+lhs`, `html5+lhs`, `s5`, `slidy`, `slideous`, `dzslides`, and `revealjs`. Scripts, images, and stylesheets at absolute URLs will be downloaded; those at relative URLs will be sought relative to the working directory (if the first source @@ -947,10 +947,11 @@ Math rendering in HTML `--mathml`[`=`*URL*] -: Convert TeX math to [MathML] (in `docbook`, `docbook5`, `html` and `html5`). - In standalone `html` output, a small JavaScript (or a link to such a - script if a *URL* is supplied) will be inserted that allows the MathML to - be viewed on some browsers. +: Convert TeX math to [MathML] (in `docbook`, `docbook5`, + `html4` and `html5`). In standalone HTML output, a small + JavaScript (or a link to such a script if a *URL* is + supplied) will be inserted that allows the MathML to be + viewed on some browsers. `--jsmath`[`=`*URL*] @@ -1647,7 +1648,7 @@ Note, however, that this method of providing links to sections works only in HTML, LaTeX, and ConTeXt formats. If the `--section-divs` option is specified, then each section will -be wrapped in a `div` (or a `section`, if `--html5` was specified), +be wrapped in a `div` (or a `section`, if `html5` was specified), and the identifier will be attached to the enclosing `
` (or `
`) tag rather than the header itself. This allows entire sections to be manipulated using JavaScript or treated differently in @@ -3891,7 +3892,7 @@ Literate Haskell support If you append `+lhs` (or `+literate_haskell`) to an appropriate input or output format (`markdown`, `markdown_strict`, `rst`, or `latex` for input or output; -`beamer`, `html` or `html5` for output only), pandoc will treat the document as +`beamer`, `html4` or `html5` for output only), pandoc will treat the document as literate Haskell source. This means that - In Markdown input, "bird track" sections will be parsed as Haskell diff --git a/data/templates b/data/templates index 67d601119..335360e40 160000 --- a/data/templates +++ b/data/templates @@ -1 +1 @@ -Subproject commit 67d601119928f95c525dfb2c518ec61661f1e770 +Subproject commit 335360e40c5cd395b33954906144c834783b41fd diff --git a/pandoc.cabal b/pandoc.cabal index 97e70c830..341ab5a12 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -66,7 +66,7 @@ Data-Files: data/templates/default.haddock data/templates/default.textile data/templates/default.org - data/templates/default.epub + data/templates/default.epub2 data/templates/default.epub3 -- source files for reference.docx data/docx/[Content_Types].xml diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index aa4cab840..449cab120 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -115,7 +115,8 @@ module Text.Pandoc , writeRTF , writeODT , writeDocx - , writeEPUB + , writeEPUB2 + , writeEPUB3 , writeFB2 , writeOrg , writeAsciiDoc @@ -278,10 +279,9 @@ writers = [ ,("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 }) + ,("epub" , ByteStringWriter writeEPUB2) + ,("epub2" , ByteStringWriter writeEPUB2) + ,("epub3" , ByteStringWriter writeEPUB3) ,("fb2" , StringWriter writeFB2) ,("html" , StringWriter writeHtml5String) ,("html4" , StringWriter writeHtml4String) @@ -349,6 +349,8 @@ getDefaultExtensions "epub" = extensionsFromList Ext_native_divs, Ext_native_spans, Ext_epub_html_exts] +getDefaultExtensions "epub2" = getDefaultExtensions "epub" +getDefaultExtensions "epub3" = getDefaultExtensions "epub" getDefaultExtensions "latex" = extensionsFromList [Ext_smart, Ext_auto_identifiers] diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs index 03dc917e6..38d956f1f 100644 --- a/src/Text/Pandoc/Templates.hs +++ b/src/Text/Pandoc/Templates.hs @@ -61,6 +61,7 @@ getDefaultTemplate user writer = do "fb2" -> return $ Right "" "odt" -> getDefaultTemplate user "opendocument" "html" -> getDefaultTemplate user "html5" + "epub" -> getDefaultTemplate user "epub2" "markdown_strict" -> getDefaultTemplate user "markdown" "multimarkdown" -> getDefaultTemplate user "markdown" "markdown_github" -> getDefaultTemplate user "markdown" diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index bd95c170e..c2fc4422e 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to EPUB. -} -module Text.Pandoc.Writers.EPUB ( writeEPUB ) where +module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe ( fromMaybe, catMaybes ) @@ -75,8 +75,9 @@ import qualified Text.Pandoc.Class as P -- in filenames, chapter0003.xhtml. data Chapter = Chapter (Maybe [Int]) [Block] -data EPUBState = EPUBState { stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))] - } +data EPUBState = EPUBState { + stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))] + } type E m = StateT EPUBState m @@ -336,16 +337,32 @@ metadataFromMeta opts meta = EPUBMetadata{ Just "rtl" -> Just RTL _ -> Nothing +-- | Produce an EPUB2 file from a Pandoc document. +writeEPUB2 :: PandocMonad m + => WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> m B.ByteString +writeEPUB2 = writeEPUB EPUB2 + +-- | Produce an EPUB3 file from a Pandoc document. +writeEPUB3 :: PandocMonad m + => WriterOptions -- ^ Writer options + -> Pandoc -- ^ Document to convert + -> m B.ByteString +writeEPUB3 = writeEPUB EPUB3 + -- | Produce an EPUB file from a Pandoc document. writeEPUB :: PandocMonad m - => WriterOptions -- ^ Writer options + => EPUBVersion + -> WriterOptions -- ^ Writer options -> Pandoc -- ^ Document to convert -> m B.ByteString -writeEPUB opts doc = +writeEPUB epubVersion opts doc = let initState = EPUBState { stMediaPaths = [] } in - evalStateT (pandocToEPUB opts doc) initState + evalStateT (pandocToEPUB opts{ writerEpubVersion = Just epubVersion } doc) + initState pandocToEPUB :: PandocMonad m => WriterOptions @@ -353,7 +370,7 @@ pandocToEPUB :: PandocMonad m -> E m B.ByteString pandocToEPUB opts doc@(Pandoc meta _) = do let version = fromMaybe EPUB2 (writerEpubVersion opts) - let epub3 = version == EPUB3 + let epub3 = writerEpubVersion opts == Just EPUB3 epochtime <- floor <$> lift P.getPOSIXTime let mkEntry path content = toEntry path epochtime content let vars = ("epub3", if epub3 then "true" else "false") -- cgit v1.2.3 From b6c1d491f5379f1924657f525540766dbbc1ae0f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 26 Jan 2017 22:40:57 +0100 Subject: Split writeDocbook into writeDocbook4, writeDocbook5. Removed writerDocbookVersion in WriterOptions. Renamed default.docbook template to default.docbook4. Allow docbook4 as an output format. But alias docbook = docbook4. --- MANUAL.txt | 10 +- data/templates | 2 +- pandoc.cabal | 6 +- src/Text/Pandoc.hs | 9 +- src/Text/Pandoc/Options.hs | 2 - src/Text/Pandoc/Templates.hs | 15 +- src/Text/Pandoc/Writers/Docbook.hs | 62 +- tests/Tests/Old.hs | 2 +- tests/Tests/Writers/Docbook.hs | 2 +- tests/tables.docbook | 432 ----------- tests/tables.docbook4 | 432 +++++++++++ tests/writer.docbook | 1422 ------------------------------------ tests/writer.docbook4 | 1422 ++++++++++++++++++++++++++++++++++++ 13 files changed, 1918 insertions(+), 1900 deletions(-) delete mode 100644 tests/tables.docbook create mode 100644 tests/tables.docbook4 delete mode 100644 tests/writer.docbook create mode 100644 tests/writer.docbook4 (limited to 'src/Text/Pandoc/Writers') diff --git a/MANUAL.txt b/MANUAL.txt index 91f4bacc0..5d14773a5 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -278,9 +278,9 @@ General options `man` (groff man), `mediawiki` (MediaWiki markup), `dokuwiki` (DokuWiki markup), `zimwiki` (ZimWiki markup), `textile` (Textile), `org` (Emacs Org mode), - `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` (DocBook 4), - `docbook5` (DocBook 5), `opendocument` (OpenDocument), `odt` - (OpenOffice text document), `docx` (Word docx), `haddock` + `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` or `docbook4` + (DocBook 4), `docbook5` (DocBook 5), `opendocument` (OpenDocument), + `odt` (OpenOffice text document), `docx` (Word docx), `haddock` (Haddock markup), `rtf` (rich text format), `epub` or `epub2` (EPUB v2 book), `epub3` (EPUB v3), `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml` (InDesign ICML), `tei` (TEI @@ -569,7 +569,7 @@ General writer options : Include an automatically generated table of contents (or, in the case of `latex`, `context`, `docx`, and `rst`, an instruction to create one) in the output document. This option has no effect on `man`, - `docbook`, `docbook5`, `slidy`, `slideous`, `s5`, or `odt` output. + `docbook4`, `docbook5`, `slidy`, `slideous`, `s5`, or `odt` output. `--toc-depth=`*NUMBER* @@ -947,7 +947,7 @@ Math rendering in HTML `--mathml`[`=`*URL*] -: Convert TeX math to [MathML] (in `docbook`, `docbook5`, +: Convert TeX math to [MathML] (in `docbook4`, `docbook5`, `html4` and `html5`). In standalone HTML output, a small JavaScript (or a link to such a script if a *URL* is supplied) will be inserted that allows the MathML to be diff --git a/data/templates b/data/templates index 335360e40..c4ba8bab6 160000 --- a/data/templates +++ b/data/templates @@ -1 +1 @@ -Subproject commit 335360e40c5cd395b33954906144c834783b41fd +Subproject commit c4ba8bab6248f8999e520547f1c45f10de85db9d diff --git a/pandoc.cabal b/pandoc.cabal index 341ab5a12..194332619 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -38,7 +38,7 @@ Data-Files: -- templates data/templates/default.html4 data/templates/default.html5 - data/templates/default.docbook + data/templates/default.docbook4 data/templates/default.docbook5 data/templates/default.tei data/templates/default.beamer @@ -145,7 +145,7 @@ Extra-Source-Files: tests/s5-fragment.html tests/s5-inserts.html tests/tables.context - tests/tables.docbook + tests/tables.docbook4 tests/tables.docbook5 tests/tables.dokuwiki tests/tables.zimwiki @@ -171,7 +171,7 @@ Extra-Source-Files: tests/testsuite.txt tests/writer.latex tests/writer.context - tests/writer.docbook + tests/writer.docbook4 tests/writer.docbook5 tests/writer.html4 tests/writer.html5 diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index 449cab120..ea625ffa1 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -104,7 +104,8 @@ module Text.Pandoc , writeHtml5 , writeHtml5String , writeICML - , writeDocbook + , writeDocbook4 + , writeDocbook5 , writeOPML , writeOpenDocument , writeMan @@ -298,9 +299,9 @@ writers = [ writeHtml5String o{ writerSlideVariant = DZSlides }) ,("revealjs" , StringWriter $ \o -> writeHtml5String o{ writerSlideVariant = RevealJsSlides }) - ,("docbook" , StringWriter writeDocbook) - ,("docbook5" , StringWriter $ \o -> - writeDocbook o{ writerDocbook5 = True }) + ,("docbook" , StringWriter writeDocbook5) + ,("docbook4" , StringWriter writeDocbook4) + ,("docbook5" , StringWriter writeDocbook5) ,("opml" , StringWriter writeOPML) ,("opendocument" , StringWriter writeOpenDocument) ,("latex" , StringWriter writeLaTeX) diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 6cb2d883a..39fee298d 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -167,7 +167,6 @@ data WriterOptions = WriterOptions , writerSourceURL :: Maybe String -- ^ Absolute URL + directory of 1st source file , writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory , writerCiteMethod :: CiteMethod -- ^ How to print cites - , writerDocbook5 :: Bool -- ^ Produce DocBook5 , writerHtmlQTags :: Bool -- ^ Use @@ tags for quotes in HTML , writerBeamer :: Bool -- ^ Produce beamer LaTeX slide show , writerSlideLevel :: Maybe Int -- ^ Force header level of slides @@ -208,7 +207,6 @@ instance Default WriterOptions where , writerSourceURL = Nothing , writerUserDataDir = Nothing , writerCiteMethod = Citeproc - , writerDocbook5 = False , writerHtmlQTags = False , writerBeamer = False , writerSlideLevel = Nothing diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs index 38d956f1f..ddb073409 100644 --- a/src/Text/Pandoc/Templates.hs +++ b/src/Text/Pandoc/Templates.hs @@ -55,13 +55,14 @@ getDefaultTemplate :: (Maybe FilePath) -- ^ User data directory to search first getDefaultTemplate user writer = do let format = takeWhile (`notElem` ("+-" :: String)) writer -- strip off extensions case format of - "native" -> return $ Right "" - "json" -> return $ Right "" - "docx" -> return $ Right "" - "fb2" -> return $ Right "" - "odt" -> getDefaultTemplate user "opendocument" - "html" -> getDefaultTemplate user "html5" - "epub" -> getDefaultTemplate user "epub2" + "native" -> return $ Right "" + "json" -> return $ Right "" + "docx" -> return $ Right "" + "fb2" -> return $ Right "" + "odt" -> getDefaultTemplate user "opendocument" + "html" -> getDefaultTemplate user "html5" + "docbook" -> getDefaultTemplate user "docbook5" + "epub" -> getDefaultTemplate user "epub2" "markdown_strict" -> getDefaultTemplate user "markdown" "multimarkdown" -> getDefaultTemplate user "markdown" "markdown_github" -> getDefaultTemplate user "markdown" diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index 32695e128..53618d173 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to Docbook XML. -} -module Text.Pandoc.Writers.Docbook ( writeDocbook) where +module Text.Pandoc.Writers.Docbook ( writeDocbook4, writeDocbook5 ) where import Text.Pandoc.Definition import Text.Pandoc.XML import Text.Pandoc.Shared @@ -48,9 +48,15 @@ import Text.TeXMath import qualified Text.XML.Light as Xml import Data.Generics (everywhere, mkT) import Text.Pandoc.Class (PandocMonad) +import Control.Monad.Reader + +data DocBookVersion = DocBook4 | DocBook5 + deriving (Eq, Show) + +type DB = ReaderT DocBookVersion -- | Convert list of authors to a docbook section -authorToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> m B.Inlines +authorToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> DB m B.Inlines authorToDocbook opts name' = do name <- render Nothing <$> inlinesToDocbook opts name' let colwidth = if writerWrapText opts == WrapAuto @@ -73,8 +79,16 @@ authorToDocbook opts name' = do in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$ inTagsSimple "surname" (text $ escapeStringForXML lastname) +writeDocbook4 :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeDocbook4 opts d = + runReaderT (writeDocbook opts d) DocBook4 + +writeDocbook5 :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeDocbook5 opts d = + runReaderT (writeDocbook opts d) DocBook5 + -- | Convert Pandoc document to string in Docbook format. -writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> DB m String writeDocbook opts (Pandoc meta blocks) = do let elements = hierarchicalize blocks let colwidth = if writerWrapText opts == WrapAuto @@ -100,7 +114,7 @@ writeDocbook opts (Pandoc meta blocks) = do hierarchicalize)) (fmap (render colwidth) . inlinesToDocbook opts') meta' - main <- (render' . vcat) <$> mapM (elementToDocbook opts' startLvl) elements + main <- (render' . vcat) <$> (mapM (elementToDocbook opts' startLvl) elements) let context = defField "body" main $ defField "mathml" (case writerHTMLMathMethod opts of MathML _ -> True @@ -111,9 +125,10 @@ writeDocbook opts (Pandoc meta blocks) = do Just tpl -> renderTemplate' tpl context -- | Convert an Element to Docbook. -elementToDocbook :: PandocMonad m => WriterOptions -> Int -> Element -> m Doc +elementToDocbook :: PandocMonad m => WriterOptions -> Int -> Element -> DB m Doc elementToDocbook opts _ (Blk block) = blockToDocbook opts block elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = do + version <- ask -- Docbook doesn't allow sections with no content, so insert some if needed let elements' = if null elements then [Blk (Para [])] @@ -121,15 +136,15 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = do tag = case lvl of -1 -> "part" 0 -> "chapter" - n | n >= 1 && n <= 5 -> if writerDocbook5 opts + n | n >= 1 && n <= 5 -> if version == DocBook5 then "section" else "sect" ++ show n _ -> "simplesect" - idName = if writerDocbook5 opts + idName = if version == DocBook5 then "xml:id" else "id" idAttr = [(idName, writerIdentifierPrefix opts ++ id') | not (null id')] - nsAttr = if writerDocbook5 opts && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")] + nsAttr = if version == DocBook5 && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")] else [] attribs = nsAttr ++ idAttr contents <- mapM (elementToDocbook opts (lvl + 1)) elements' @@ -138,7 +153,7 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = do inTagsSimple "title" title' $$ vcat contents -- | Convert a list of Pandoc blocks to Docbook. -blocksToDocbook :: PandocMonad m => WriterOptions -> [Block] -> m Doc +blocksToDocbook :: PandocMonad m => WriterOptions -> [Block] -> DB m Doc blocksToDocbook opts = fmap vcat . mapM (blockToDocbook opts) -- | Auxiliary function to convert Plain block to Para. @@ -149,13 +164,13 @@ plainToPara x = x -- | Convert a list of pairs of terms and definitions into a list of -- Docbook varlistentrys. deflistItemsToDocbook :: PandocMonad m - => WriterOptions -> [([Inline],[[Block]])] -> m Doc + => WriterOptions -> [([Inline],[[Block]])] -> DB m Doc deflistItemsToDocbook opts items = vcat <$> mapM (\(term, defs) -> deflistItemToDocbook opts term defs) items -- | Convert a term and a list of blocks into a Docbook varlistentry. deflistItemToDocbook :: PandocMonad m - => WriterOptions -> [Inline] -> [[Block]] -> m Doc + => WriterOptions -> [Inline] -> [[Block]] -> DB m Doc deflistItemToDocbook opts term defs = do term' <- inlinesToDocbook opts term def' <- blocksToDocbook opts $ concatMap (map plainToPara) defs @@ -164,11 +179,11 @@ deflistItemToDocbook opts term defs = do inTagsIndented "listitem" def' -- | Convert a list of lists of blocks to a list of Docbook list items. -listItemsToDocbook :: PandocMonad m => WriterOptions -> [[Block]] -> m Doc +listItemsToDocbook :: PandocMonad m => WriterOptions -> [[Block]] -> DB m Doc listItemsToDocbook opts items = vcat <$> mapM (listItemToDocbook opts) items -- | Convert a list of blocks into a Docbook list item. -listItemToDocbook :: PandocMonad m => WriterOptions -> [Block] -> m Doc +listItemToDocbook :: PandocMonad m => WriterOptions -> [Block] -> DB m Doc listItemToDocbook opts item = inTagsIndented "listitem" <$> blocksToDocbook opts (map plainToPara item) @@ -182,7 +197,7 @@ imageToDocbook _ attr src = selfClosingTag "imagedata" $ Nothing -> [] -- | Convert a Pandoc block element to Docbook. -blockToDocbook :: PandocMonad m => WriterOptions -> Block -> m Doc +blockToDocbook :: PandocMonad m => WriterOptions -> Block -> DB m Doc blockToDocbook _ Null = return empty -- Add ids to paragraphs in divs with ids - this is needed for -- pandoc-citeproc to get link anchors in bibliographies: @@ -260,9 +275,11 @@ blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = do blockToDocbook opts (DefinitionList lst) = do let attribs = [("spacing", "compact") | isTightList $ concatMap snd lst] inTags True "variablelist" attribs <$> deflistItemsToDocbook opts lst -blockToDocbook opts (RawBlock f str) +blockToDocbook _ (RawBlock f str) | f == "docbook" = return $ text str -- raw XML block - | f == "html" = if writerDocbook5 opts + | f == "html" = do + version <- ask + if version == DocBook5 then return empty -- No html in Docbook5 else return $ text str -- allow html for backwards compatibility | otherwise = return empty @@ -306,23 +323,23 @@ alignmentToString alignment = case alignment of tableRowToDocbook :: PandocMonad m => WriterOptions -> [[Block]] - -> m Doc + -> DB m Doc tableRowToDocbook opts cols = (inTagsIndented "row" . vcat) <$> mapM (tableItemToDocbook opts) cols tableItemToDocbook :: PandocMonad m => WriterOptions -> [Block] - -> m Doc + -> DB m Doc tableItemToDocbook opts item = (inTags True "entry" [] . vcat) <$> mapM (blockToDocbook opts) item -- | Convert a list of inline elements to Docbook. -inlinesToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> m Doc +inlinesToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> DB m Doc inlinesToDocbook opts lst = hcat <$> mapM (inlineToDocbook opts) lst -- | Convert an inline element to Docbook. -inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> m Doc +inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> DB m Doc inlineToDocbook _ (Str str) = return $ text $ escapeStringForXML str inlineToDocbook opts (Emph lst) = inTagsSimple "emphasis" <$> inlinesToDocbook opts lst @@ -385,10 +402,11 @@ inlineToDocbook opts (Link attr txt (src, _)) _ -> do contents <- inlinesToDocbook opts txt return $ contents <+> char '(' <> emailLink <> char ')' - | otherwise = + | otherwise = do + version <- ask (if isPrefixOf "#" src then inTags False "link" $ ("linkend", drop 1 src) : idAndRole attr - else if writerDocbook5 opts + else if version == DocBook5 then inTags False "link" $ ("xlink:href", src) : idAndRole attr else inTags False "ulink" $ ("url", src) : idAndRole attr ) <$> inlinesToDocbook opts txt diff --git a/tests/Tests/Old.hs b/tests/Tests/Old.hs index a46ac2260..f22636747 100644 --- a/tests/Tests/Old.hs +++ b/tests/Tests/Old.hs @@ -99,7 +99,7 @@ tests = [ testGroup "markdown" "textile-reader.textile" "textile-reader.native" ] , testGroup "docbook" - [ testGroup "writer" $ writerTests "docbook" + [ testGroup "writer" $ writerTests "docbook4" , test "reader" ["-r", "docbook", "-w", "native", "-s"] "docbook-reader.docbook" "docbook-reader.native" , test "reader" ["-r", "docbook", "-w", "native", "-s"] diff --git a/tests/Tests/Writers/Docbook.hs b/tests/Tests/Writers/Docbook.hs index adf6e9050..f34f2495c 100644 --- a/tests/Tests/Writers/Docbook.hs +++ b/tests/Tests/Writers/Docbook.hs @@ -11,7 +11,7 @@ docbook :: (ToPandoc a) => a -> String docbook = docbookWithOpts def{ writerWrapText = WrapNone } docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String -docbookWithOpts opts = purely (writeDocbook opts) . toPandoc +docbookWithOpts opts = purely (writeDocbook4 opts) . toPandoc {- "my test" =: X =?> Y diff --git a/tests/tables.docbook b/tests/tables.docbook deleted file mode 100644 index f86b1c390..000000000 --- a/tests/tables.docbook +++ /dev/null @@ -1,432 +0,0 @@ - - Simple table with caption: - - - - Demonstration of simple table syntax. - - - - - - - - - - Right - - - Left - - - Center - - - Default - - - - - - - 12 - - - 12 - - - 12 - - - 12 - - - - - 123 - - - 123 - - - 123 - - - 123 - - - - - 1 - - - 1 - - - 1 - - - 1 - - - - -
- - Simple table without caption: - - - - - - - - - - - Right - - - Left - - - Center - - - Default - - - - - - - 12 - - - 12 - - - 12 - - - 12 - - - - - 123 - - - 123 - - - 123 - - - 123 - - - - - 1 - - - 1 - - - 1 - - - 1 - - - - - - - Simple table indented two spaces: - - - - Demonstration of simple table syntax. - - - - - - - - - - Right - - - Left - - - Center - - - Default - - - - - - - 12 - - - 12 - - - 12 - - - 12 - - - - - 123 - - - 123 - - - 123 - - - 123 - - - - - 1 - - - 1 - - - 1 - - - 1 - - - - -
- - Multiline table with caption: - - - - Here’s the caption. It may span multiple lines. - - - - - - - - - - Centered Header - - - Left Aligned - - - Right Aligned - - - Default aligned - - - - - - - First - - - row - - - 12.0 - - - Example of a row that spans multiple lines. - - - - - Second - - - row - - - 5.0 - - - Here’s another one. Note the blank line between rows. - - - - -
- - Multiline table without caption: - - - - - - - - - - - Centered Header - - - Left Aligned - - - Right Aligned - - - Default aligned - - - - - - - First - - - row - - - 12.0 - - - Example of a row that spans multiple lines. - - - - - Second - - - row - - - 5.0 - - - Here’s another one. Note the blank line between rows. - - - - - - - Table without column headers: - - - - - - - - - - - 12 - - - 12 - - - 12 - - - 12 - - - - - 123 - - - 123 - - - 123 - - - 123 - - - - - 1 - - - 1 - - - 1 - - - 1 - - - - - - - Multiline table without column headers: - - - - - - - - - - - First - - - row - - - 12.0 - - - Example of a row that spans multiple lines. - - - - - Second - - - row - - - 5.0 - - - Here’s another one. Note the blank line between rows. - - - - - diff --git a/tests/tables.docbook4 b/tests/tables.docbook4 new file mode 100644 index 000000000..f86b1c390 --- /dev/null +++ b/tests/tables.docbook4 @@ -0,0 +1,432 @@ + + Simple table with caption: + + + + Demonstration of simple table syntax. + + + + + + + + + + Right + + + Left + + + Center + + + Default + + + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 123 + + + 123 + + + 123 + + + 123 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + + +
+ + Simple table without caption: + + + + + + + + + + + Right + + + Left + + + Center + + + Default + + + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 123 + + + 123 + + + 123 + + + 123 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + + Simple table indented two spaces: + + + + Demonstration of simple table syntax. + + + + + + + + + + Right + + + Left + + + Center + + + Default + + + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 123 + + + 123 + + + 123 + + + 123 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + + +
+ + Multiline table with caption: + + + + Here’s the caption. It may span multiple lines. + + + + + + + + + + Centered Header + + + Left Aligned + + + Right Aligned + + + Default aligned + + + + + + + First + + + row + + + 12.0 + + + Example of a row that spans multiple lines. + + + + + Second + + + row + + + 5.0 + + + Here’s another one. Note the blank line between rows. + + + + +
+ + Multiline table without caption: + + + + + + + + + + + Centered Header + + + Left Aligned + + + Right Aligned + + + Default aligned + + + + + + + First + + + row + + + 12.0 + + + Example of a row that spans multiple lines. + + + + + Second + + + row + + + 5.0 + + + Here’s another one. Note the blank line between rows. + + + + + + + Table without column headers: + + + + + + + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 123 + + + 123 + + + 123 + + + 123 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + + Multiline table without column headers: + + + + + + + + + + + First + + + row + + + 12.0 + + + Example of a row that spans multiple lines. + + + + + Second + + + row + + + 5.0 + + + Here’s another one. Note the blank line between rows. + + + + + diff --git a/tests/writer.docbook b/tests/writer.docbook deleted file mode 100644 index eee19cdd9..000000000 --- a/tests/writer.docbook +++ /dev/null @@ -1,1422 +0,0 @@ - - -
- - Pandoc Test Suite - - - John - MacFarlane - - - - Anonymous - - - July 17, 2006 - - - This is a set of tests for pandoc. Most of them are adapted from John - Gruber’s markdown test suite. - - - Headers - - Level 2 with an <ulink url="/url">embedded link</ulink> - - Level 3 with <emphasis>emphasis</emphasis> - - Level 4 - - Level 5 - - - - - - - - - Level 1 - - Level 2 with <emphasis>emphasis</emphasis> - - Level 3 - - with no blank line - - - - - Level 2 - - with no blank line - - - - - Paragraphs - - Here’s a regular paragraph. - - - In Markdown 1.0.0 and earlier. Version 8. This line turns into a list - item. Because a hard-wrapped line in the middle of a paragraph looked like - a list item. - - - Here’s one with a bullet. * criminey. - -There should be a hard line break -here. - - - Block Quotes - - E-mail style: - -
- - This is a block quote. It is pretty short. - -
-
- - Code in a block quote: - - -sub status { - print "working"; -} - - - A list: - - - - - item one - - - - - item two - - - - - Nested block quotes: - -
- - nested - -
-
- - nested - -
-
- - This should not be a block quote: 2 > 1. - - - And a following paragraph. - -
- - Code Blocks - - Code: - - ----- (should be four hyphens) - -sub status { - print "working"; -} - -this code block is indented by one tab - - - And: - - - this code block is indented by two tabs - -These should not be escaped: \$ \\ \> \[ \{ - - - - Lists - - Unordered - - Asterisks tight: - - - - - asterisk 1 - - - - - asterisk 2 - - - - - asterisk 3 - - - - - Asterisks loose: - - - - - asterisk 1 - - - - - asterisk 2 - - - - - asterisk 3 - - - - - Pluses tight: - - - - - Plus 1 - - - - - Plus 2 - - - - - Plus 3 - - - - - Pluses loose: - - - - - Plus 1 - - - - - Plus 2 - - - - - Plus 3 - - - - - Minuses tight: - - - - - Minus 1 - - - - - Minus 2 - - - - - Minus 3 - - - - - Minuses loose: - - - - - Minus 1 - - - - - Minus 2 - - - - - Minus 3 - - - - - - Ordered - - Tight: - - - - - First - - - - - Second - - - - - Third - - - - - and: - - - - - One - - - - - Two - - - - - Three - - - - - Loose using tabs: - - - - - First - - - - - Second - - - - - Third - - - - - and using spaces: - - - - - One - - - - - Two - - - - - Three - - - - - Multiple paragraphs: - - - - - Item 1, graf one. - - - Item 1. graf two. The quick brown fox jumped over the lazy dog’s - back. - - - - - Item 2. - - - - - Item 3. - - - - - - Nested - - - - Tab - - - - - Tab - - - - - Tab - - - - - - - - - Here’s another: - - - - - First - - - - - Second: - - - - - Fee - - - - - Fie - - - - - Foe - - - - - - - Third - - - - - Same thing but with paragraphs: - - - - - First - - - - - Second: - - - - - Fee - - - - - Fie - - - - - Foe - - - - - - - Third - - - - - - Tabs and spaces - - - - this is a list item indented with tabs - - - - - this is a list item indented with spaces - - - - - this is an example list item indented with tabs - - - - - this is an example list item indented with spaces - - - - - - - - Fancy list markers - - - - begins with 2 - - - - - and now 3 - - - with a continuation - - - - - sublist with roman numerals, starting with 4 - - - - - more items - - - - - a subsublist - - - - - a subsublist - - - - - - - - - Nesting: - - - - - Upper Alpha - - - - - Upper Roman. - - - - - Decimal start with 6 - - - - - Lower alpha with paren - - - - - - - - - - - Autonumbering: - - - - - Autonumber. - - - - - More. - - - - - Nested. - - - - - - - Should not be a list item: - - - M.A. 2007 - - - B. Williams - - - - - Definition Lists - - Tight using spaces: - - - - - apple - - - - red fruit - - - - - - orange - - - - orange fruit - - - - - - banana - - - - yellow fruit - - - - - - Tight using tabs: - - - - - apple - - - - red fruit - - - - - - orange - - - - orange fruit - - - - - - banana - - - - yellow fruit - - - - - - Loose: - - - - - apple - - - - red fruit - - - - - - orange - - - - orange fruit - - - - - - banana - - - - yellow fruit - - - - - - Multiple blocks with italics: - - - - - apple - - - - red fruit - - - contains seeds, crisp, pleasant to taste - - - - - - orange - - - - orange fruit - - -{ orange code block } - -
- - orange block quote - -
-
-
-
- - Multiple definitions, tight: - - - - - apple - - - - red fruit - - - computer - - - - - - orange - - - - orange fruit - - - bank - - - - - - Multiple definitions, loose: - - - - - apple - - - - red fruit - - - computer - - - - - - orange - - - - orange fruit - - - bank - - - - - - Blank line after term, indented marker, alternate markers: - - - - - apple - - - - red fruit - - - computer - - - - - - orange - - - - orange fruit - - - - - sublist - - - - - sublist - - - - - - -
- - HTML Blocks - - Simple block on one line: - - - foo - - - And nested without indentation: - - - foo - - - bar - - - Interpreted markdown in a table: - - - - - - -
- This is emphasized - - And this is strong -
- - - Here’s a simple block: - - - foo - - - This should be a code block, though: - - -<div> - foo -</div> - - - As should this: - - -<div>foo</div> - - - Now, nested: - - - foo - - - This should just be an HTML comment: - - - - Multiline: - - - - - Code block: - - -<!-- Comment --> - - - Just plain comment, with trailing spaces on the line: - - - - Code: - - -<hr /> - - - Hr’s: - -
-
-
-
-
-
-
-
-
-
- - Inline Markup - - This is emphasized, and so is - this. - - - This is strong, and so - is this. - - - An emphasized link. - - - This is strong and - em. - - - So is this word. - - - This is strong and - em. - - - So is this word. - - - This is code: >, $, - \, \$, - <html>. - - - This is - strikeout. - - - Superscripts: abcd - ahello - ahello there. - - - Subscripts: H2O, H23O, - Hmany of themO. - - - These should not be superscripts or subscripts, because of the unescaped - spaces: a^b c^d, a~b c~d. - - - - Smart quotes, ellipses, dashes - - Hello, said the spider. Shelob is my - name. - - - A, B, and C are letters. - - - Oak, elm, and beech are names - of trees. So is pine. - - - He said, I want to go. Were you alive in the - 70’s? - - - Here is some quoted code and a - quoted - link. - - - Some dashes: one—two — three—four — five. - - - Dashes between numbers: 5–7, 255–66, 1987–1999. - - - Ellipses…and…and…. - - - - LaTeX - - - - - - - - 2 + 2 = 4 - - - - - x ∈ y - - - - - α ∧ ω - - - - - 223 - - - - - p-Tree - - - - - Here’s some display math: - $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$ - - - - - Here’s one that has a line break in it: - α + ω × x2. - - - - - These shouldn’t be math: - - - - - To get the famous equation, write $e = mc^2$. - - - - - $22,000 is a lot of money. So is $34,000. (It - worked if lot is emphasized.) - - - - - Shoes ($20) and socks ($5). - - - - - Escaped $: $73 this should be - emphasized 23$. - - - - - Here’s a LaTeX table: - - - - Special Characters - - Here is some unicode: - - - - - I hat: Î - - - - - o umlaut: ö - - - - - section: § - - - - - set membership: ∈ - - - - - copyright: © - - - - - AT&T has an ampersand in their name. - - - AT&T is another way to write it. - - - This & that. - - - 4 < 5. - - - 6 > 5. - - - Backslash: \ - - - Backtick: ` - - - Asterisk: * - - - Underscore: _ - - - Left brace: { - - - Right brace: } - - - Left bracket: [ - - - Right bracket: ] - - - Left paren: ( - - - Right paren: ) - - - Greater-than: > - - - Hash: # - - - Period: . - - - Bang: ! - - - Plus: + - - - Minus: - - - - - Links - - Explicit - - Just a URL. - - - URL and title. - - - URL and title. - - - URL and title. - - - URL and title - - - URL and title - - - with_underscore - - - Email link (nobody@nowhere.net) - - - Empty. - - - - Reference - - Foo bar. - - - Foo bar. - - - Foo bar. - - - With embedded [brackets]. - - - b by itself should be a link. - - - Indented once. - - - Indented twice. - - - Indented thrice. - - - This should [not][] be a link. - - -[not]: /url - - - Foo bar. - - - Foo biz. - - - - With ampersands - - Here’s a link with an - ampersand in the URL. - - - Here’s a link with an amersand in the link text: - AT&T. - - - Here’s an inline link. - - - Here’s an inline link in pointy - braces. - - - - Autolinks - - With an ampersand: - http://example.com/?foo=1&bar=2 - - - - - In a list? - - - - - http://example.com/ - - - - - It should. - - - - - An e-mail address: nobody@nowhere.net - -
- - Blockquoted: - http://example.com/ - -
- - Auto-links should not occur here: - <http://example.com/> - - -or here: <http://example.com/> - -
-
- - Images - - From Voyage dans la Lune by Georges Melies (1902): - -
- lalune - - - - - lalune - -
- - Here is a movie - - - - icon. - -
- - Footnotes - - Here is a footnote reference, - - Here is the footnote. It can go anywhere after the footnote reference. - It need not be placed at the end of the document. - - and another. - - Here’s the long note. This one contains multiple blocks. - - - Subsequent blocks are indented to show that they belong to the - footnote (as with list items). - - - { <code> } - - - If you want, you can indent every line, but you can also be lazy and - just indent the first line of each block. - - This should not be a footnote reference, - because it contains a space.[^my note] Here is an inline note. - - This is easier to type. Inline notes may contain - links and ] - verbatim characters, as well as [bracketed text]. - - - -
- - Notes can go in quotes. - - In quote. - - - -
- - - - And in list items. - - In list. - - - - - - - This paragraph should not be part of the note, as it is not indented. - -
-
diff --git a/tests/writer.docbook4 b/tests/writer.docbook4 new file mode 100644 index 000000000..eee19cdd9 --- /dev/null +++ b/tests/writer.docbook4 @@ -0,0 +1,1422 @@ + + +
+ + Pandoc Test Suite + + + John + MacFarlane + + + + Anonymous + + + July 17, 2006 + + + This is a set of tests for pandoc. Most of them are adapted from John + Gruber’s markdown test suite. + + + Headers + + Level 2 with an <ulink url="/url">embedded link</ulink> + + Level 3 with <emphasis>emphasis</emphasis> + + Level 4 + + Level 5 + + + + + + + + + Level 1 + + Level 2 with <emphasis>emphasis</emphasis> + + Level 3 + + with no blank line + + + + + Level 2 + + with no blank line + + + + + Paragraphs + + Here’s a regular paragraph. + + + In Markdown 1.0.0 and earlier. Version 8. This line turns into a list + item. Because a hard-wrapped line in the middle of a paragraph looked like + a list item. + + + Here’s one with a bullet. * criminey. + +There should be a hard line break +here. + + + Block Quotes + + E-mail style: + +
+ + This is a block quote. It is pretty short. + +
+
+ + Code in a block quote: + + +sub status { + print "working"; +} + + + A list: + + + + + item one + + + + + item two + + + + + Nested block quotes: + +
+ + nested + +
+
+ + nested + +
+
+ + This should not be a block quote: 2 > 1. + + + And a following paragraph. + +
+ + Code Blocks + + Code: + + +---- (should be four hyphens) + +sub status { + print "working"; +} + +this code block is indented by one tab + + + And: + + + this code block is indented by two tabs + +These should not be escaped: \$ \\ \> \[ \{ + + + + Lists + + Unordered + + Asterisks tight: + + + + + asterisk 1 + + + + + asterisk 2 + + + + + asterisk 3 + + + + + Asterisks loose: + + + + + asterisk 1 + + + + + asterisk 2 + + + + + asterisk 3 + + + + + Pluses tight: + + + + + Plus 1 + + + + + Plus 2 + + + + + Plus 3 + + + + + Pluses loose: + + + + + Plus 1 + + + + + Plus 2 + + + + + Plus 3 + + + + + Minuses tight: + + + + + Minus 1 + + + + + Minus 2 + + + + + Minus 3 + + + + + Minuses loose: + + + + + Minus 1 + + + + + Minus 2 + + + + + Minus 3 + + + + + + Ordered + + Tight: + + + + + First + + + + + Second + + + + + Third + + + + + and: + + + + + One + + + + + Two + + + + + Three + + + + + Loose using tabs: + + + + + First + + + + + Second + + + + + Third + + + + + and using spaces: + + + + + One + + + + + Two + + + + + Three + + + + + Multiple paragraphs: + + + + + Item 1, graf one. + + + Item 1. graf two. The quick brown fox jumped over the lazy dog’s + back. + + + + + Item 2. + + + + + Item 3. + + + + + + Nested + + + + Tab + + + + + Tab + + + + + Tab + + + + + + + + + Here’s another: + + + + + First + + + + + Second: + + + + + Fee + + + + + Fie + + + + + Foe + + + + + + + Third + + + + + Same thing but with paragraphs: + + + + + First + + + + + Second: + + + + + Fee + + + + + Fie + + + + + Foe + + + + + + + Third + + + + + + Tabs and spaces + + + + this is a list item indented with tabs + + + + + this is a list item indented with spaces + + + + + this is an example list item indented with tabs + + + + + this is an example list item indented with spaces + + + + + + + + Fancy list markers + + + + begins with 2 + + + + + and now 3 + + + with a continuation + + + + + sublist with roman numerals, starting with 4 + + + + + more items + + + + + a subsublist + + + + + a subsublist + + + + + + + + + Nesting: + + + + + Upper Alpha + + + + + Upper Roman. + + + + + Decimal start with 6 + + + + + Lower alpha with paren + + + + + + + + + + + Autonumbering: + + + + + Autonumber. + + + + + More. + + + + + Nested. + + + + + + + Should not be a list item: + + + M.A. 2007 + + + B. Williams + + + + + Definition Lists + + Tight using spaces: + + + + + apple + + + + red fruit + + + + + + orange + + + + orange fruit + + + + + + banana + + + + yellow fruit + + + + + + Tight using tabs: + + + + + apple + + + + red fruit + + + + + + orange + + + + orange fruit + + + + + + banana + + + + yellow fruit + + + + + + Loose: + + + + + apple + + + + red fruit + + + + + + orange + + + + orange fruit + + + + + + banana + + + + yellow fruit + + + + + + Multiple blocks with italics: + + + + + apple + + + + red fruit + + + contains seeds, crisp, pleasant to taste + + + + + + orange + + + + orange fruit + + +{ orange code block } + +
+ + orange block quote + +
+
+
+
+ + Multiple definitions, tight: + + + + + apple + + + + red fruit + + + computer + + + + + + orange + + + + orange fruit + + + bank + + + + + + Multiple definitions, loose: + + + + + apple + + + + red fruit + + + computer + + + + + + orange + + + + orange fruit + + + bank + + + + + + Blank line after term, indented marker, alternate markers: + + + + + apple + + + + red fruit + + + computer + + + + + + orange + + + + orange fruit + + + + + sublist + + + + + sublist + + + + + + +
+ + HTML Blocks + + Simple block on one line: + + + foo + + + And nested without indentation: + + + foo + + + bar + + + Interpreted markdown in a table: + + + + + + +
+ This is emphasized + + And this is strong +
+ + + Here’s a simple block: + + + foo + + + This should be a code block, though: + + +<div> + foo +</div> + + + As should this: + + +<div>foo</div> + + + Now, nested: + + + foo + + + This should just be an HTML comment: + + + + Multiline: + + + + + Code block: + + +<!-- Comment --> + + + Just plain comment, with trailing spaces on the line: + + + + Code: + + +<hr /> + + + Hr’s: + +
+
+
+
+
+
+
+
+
+
+ + Inline Markup + + This is emphasized, and so is + this. + + + This is strong, and so + is this. + + + An emphasized link. + + + This is strong and + em. + + + So is this word. + + + This is strong and + em. + + + So is this word. + + + This is code: >, $, + \, \$, + <html>. + + + This is + strikeout. + + + Superscripts: abcd + ahello + ahello there. + + + Subscripts: H2O, H23O, + Hmany of themO. + + + These should not be superscripts or subscripts, because of the unescaped + spaces: a^b c^d, a~b c~d. + + + + Smart quotes, ellipses, dashes + + Hello, said the spider. Shelob is my + name. + + + A, B, and C are letters. + + + Oak, elm, and beech are names + of trees. So is pine. + + + He said, I want to go. Were you alive in the + 70’s? + + + Here is some quoted code and a + quoted + link. + + + Some dashes: one—two — three—four — five. + + + Dashes between numbers: 5–7, 255–66, 1987–1999. + + + Ellipses…and…and…. + + + + LaTeX + + + + + + + + 2 + 2 = 4 + + + + + x ∈ y + + + + + α ∧ ω + + + + + 223 + + + + + p-Tree + + + + + Here’s some display math: + $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$ + + + + + Here’s one that has a line break in it: + α + ω × x2. + + + + + These shouldn’t be math: + + + + + To get the famous equation, write $e = mc^2$. + + + + + $22,000 is a lot of money. So is $34,000. (It + worked if lot is emphasized.) + + + + + Shoes ($20) and socks ($5). + + + + + Escaped $: $73 this should be + emphasized 23$. + + + + + Here’s a LaTeX table: + + + + Special Characters + + Here is some unicode: + + + + + I hat: Î + + + + + o umlaut: ö + + + + + section: § + + + + + set membership: ∈ + + + + + copyright: © + + + + + AT&T has an ampersand in their name. + + + AT&T is another way to write it. + + + This & that. + + + 4 < 5. + + + 6 > 5. + + + Backslash: \ + + + Backtick: ` + + + Asterisk: * + + + Underscore: _ + + + Left brace: { + + + Right brace: } + + + Left bracket: [ + + + Right bracket: ] + + + Left paren: ( + + + Right paren: ) + + + Greater-than: > + + + Hash: # + + + Period: . + + + Bang: ! + + + Plus: + + + + Minus: - + + + + Links + + Explicit + + Just a URL. + + + URL and title. + + + URL and title. + + + URL and title. + + + URL and title + + + URL and title + + + with_underscore + + + Email link (nobody@nowhere.net) + + + Empty. + + + + Reference + + Foo bar. + + + Foo bar. + + + Foo bar. + + + With embedded [brackets]. + + + b by itself should be a link. + + + Indented once. + + + Indented twice. + + + Indented thrice. + + + This should [not][] be a link. + + +[not]: /url + + + Foo bar. + + + Foo biz. + + + + With ampersands + + Here’s a link with an + ampersand in the URL. + + + Here’s a link with an amersand in the link text: + AT&T. + + + Here’s an inline link. + + + Here’s an inline link in pointy + braces. + + + + Autolinks + + With an ampersand: + http://example.com/?foo=1&bar=2 + + + + + In a list? + + + + + http://example.com/ + + + + + It should. + + + + + An e-mail address: nobody@nowhere.net + +
+ + Blockquoted: + http://example.com/ + +
+ + Auto-links should not occur here: + <http://example.com/> + + +or here: <http://example.com/> + +
+
+ + Images + + From Voyage dans la Lune by Georges Melies (1902): + +
+ lalune + + + + + lalune + +
+ + Here is a movie + + + + icon. + +
+ + Footnotes + + Here is a footnote reference, + + Here is the footnote. It can go anywhere after the footnote reference. + It need not be placed at the end of the document. + + and another. + + Here’s the long note. This one contains multiple blocks. + + + Subsequent blocks are indented to show that they belong to the + footnote (as with list items). + + + { <code> } + + + If you want, you can indent every line, but you can also be lazy and + just indent the first line of each block. + + This should not be a footnote reference, + because it contains a space.[^my note] Here is an inline note. + + This is easier to type. Inline notes may contain + links and ] + verbatim characters, as well as [bracketed text]. + + + +
+ + Notes can go in quotes. + + In quote. + + + +
+ + + + And in list items. + + In list. + + + + + + + This paragraph should not be part of the note, as it is not indented. + +
+
-- cgit v1.2.3 From f5dd1238198450c4917707214f19e2f0da8c3cb4 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 27 Jan 2017 10:27:34 +0100 Subject: HTML writer: export writeHtmlStringForEPUB. Options: Remove writerEPUBVersion. --- src/Text/Pandoc/Options.hs | 2 -- src/Text/Pandoc/Writers/EPUB.hs | 36 ++++++++++++++++-------------------- src/Text/Pandoc/Writers/HTML.hs | 32 ++++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 28 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 39fee298d..755ab9add 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -175,7 +175,6 @@ data WriterOptions = WriterOptions , writerHighlightStyle :: Maybe Style -- ^ Style to use for highlighting -- (Nothing = no highlighting) , writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown - , writerEpubVersion :: Maybe EPUBVersion -- ^ Nothing or EPUB version , writerEpubMetadata :: String -- ^ Metadata to include in EPUB , writerEpubStylesheet :: Maybe String -- ^ EPUB stylesheet specified at command line , writerEpubFonts :: [FilePath] -- ^ Paths to fonts to embed @@ -214,7 +213,6 @@ instance Default WriterOptions where , writerListings = False , writerHighlightStyle = Just pygments , writerSetextHeaders = True - , writerEpubVersion = Nothing , writerEpubMetadata = "" , writerEpubStylesheet = Nothing , writerEpubFonts = [] diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index c2fc4422e..ae77c10a2 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -59,10 +59,9 @@ import Control.Monad (mplus, when, zipWithM) import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs , strContent, lookupAttr, Node(..), QName(..), parseXML , onlyElems, node, ppElement) -import Text.Pandoc.Writers.HTML ( writeHtml4, writeHtml5 ) +import Text.Pandoc.Writers.HTML ( writeHtmlStringForEPUB ) import Data.Char ( toLower, isDigit, isAlphaNum ) import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType) -import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags) import Control.Monad.Except (throwError, catchError) import Text.Pandoc.Error @@ -361,16 +360,18 @@ writeEPUB epubVersion opts doc = let initState = EPUBState { stMediaPaths = [] } in - evalStateT (pandocToEPUB opts{ writerEpubVersion = Just epubVersion } doc) + evalStateT (pandocToEPUB epubVersion opts doc) initState pandocToEPUB :: PandocMonad m - => WriterOptions + => EPUBVersion + -> WriterOptions -> Pandoc -> E m B.ByteString -pandocToEPUB opts doc@(Pandoc meta _) = do - let version = fromMaybe EPUB2 (writerEpubVersion opts) - let epub3 = writerEpubVersion opts == Just EPUB3 +pandocToEPUB version opts doc@(Pandoc meta _) = do + let epub3 = version == EPUB3 + let writeHtml o = fmap UTF8.fromStringLazy . + writeHtmlStringForEPUB version o epochtime <- floor <$> lift P.getPOSIXTime let mkEntry path content = toEntry path epochtime content let vars = ("epub3", if epub3 then "true" else "false") @@ -384,9 +385,6 @@ pandocToEPUB opts doc@(Pandoc meta _) = do then MathML Nothing else writerHTMLMathMethod opts , writerWrapText = WrapAuto } - let writeHtml = if epub3 - then writeHtml5 - else writeHtml4 metadata <- getEPUBMetadata opts' meta -- cover page @@ -395,17 +393,17 @@ pandocToEPUB opts doc@(Pandoc meta _) = do Nothing -> return ([],[]) Just img -> do let coverImage = "media/" ++ takeFileName img - cpContent <- renderHtml <$> (lift $ writeHtml + cpContent <- lift $ writeHtml opts'{ writerVariables = ("coverpage","true"):vars } - (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"])) + (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"]) imgContent <- lift $ P.readFileLazy img return ( [mkEntry "cover.xhtml" cpContent] , [mkEntry coverImage imgContent] ) -- title page - tpContent <- renderHtml <$> (lift $ writeHtml opts'{ + tpContent <- lift $ writeHtml opts'{ writerVariables = ("titlepage","true"):vars } - (Pandoc meta [])) + (Pandoc meta []) let tpEntry = mkEntry "title_page.xhtml" tpContent -- handle pictures @@ -504,9 +502,8 @@ pandocToEPUB opts doc@(Pandoc meta _) = do chapters' let chapToEntry num (Chapter mbnum bs) = - (mkEntry (showChapter num) . renderHtml) <$> - (writeHtml opts'{ writerNumberOffset = - fromMaybe [] mbnum } + mkEntry (showChapter num) <$> + (writeHtml opts'{ writerNumberOffset = fromMaybe [] mbnum } $ case bs of (Header _ _ xs : _) -> -- remove notes or we get doubled footnotes @@ -702,11 +699,10 @@ pandocToEPUB opts doc@(Pandoc meta _) = do ] ] else [] - navData <- renderHtml <$> (lift $ writeHtml - opts'{ writerVariables = ("navpage","true"):vars } + navData <- 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 diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index ee1f260b6..518848139 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -29,8 +29,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' documents to HTML. -} module Text.Pandoc.Writers.HTML ( - writeHtml4, writeHtml4String, - writeHtml5, writeHtml5String ) where + writeHtml4, + writeHtml4String, + writeHtml5, + writeHtml5String, + writeHtmlStringForEPUB + ) where import Text.Pandoc.Definition import Text.Pandoc.Walk import Data.Monoid ((<>)) @@ -83,12 +87,14 @@ data WriterState = WriterState , stSecNum :: [Int] -- ^ Number of current section , stElement :: Bool -- ^ Processing an Element , stHtml5 :: Bool -- ^ Use HTML5 + , stEPUBVersion :: Maybe EPUBVersion -- ^ EPUB version if for epub } defaultWriterState :: WriterState defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False, stHighlighting = False, stSecNum = [], - stElement = False, stHtml5 = False} + stElement = False, stHtml5 = False, + stEPUBVersion = Nothing} -- Helpers to render HTML with the appropriate function. @@ -121,6 +127,18 @@ writeHtml4String = writeHtmlString' False writeHtml4 :: PandocMonad m => WriterOptions -> Pandoc -> m Html writeHtml4 = writeHtml' False +-- | Convert Pandoc document to Html appropriate for an epub version. +writeHtmlStringForEPUB :: PandocMonad m + => EPUBVersion -> WriterOptions -> Pandoc -> m String +writeHtmlStringForEPUB version opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) + defaultWriterState{ stHtml5 = version == EPUB3, + stEPUBVersion = Just version } + return $ case writerTemplate opts of + Nothing -> renderHtml body + Just tpl -> renderTemplate' tpl $ + defField "body" (renderHtml body) context + writeHtmlString' :: PandocMonad m => Bool -> WriterOptions -> Pandoc -> m String writeHtmlString' html5 opts d = do (body, context) <- evalStateT (pandocToHtml opts d) @@ -892,6 +910,7 @@ inlineToHtml opts inline = do let number = (length notes) + 1 let ref = show number htmlContents <- blockListToNote opts ref contents + epubVersion <- gets stEPUBVersion -- push contents onto front of notes modify $ \st -> st {stNotes = (htmlContents:notes)} let revealSlash = ['/' | writerSlideVariant opts @@ -901,11 +920,11 @@ inlineToHtml opts inline = do writerIdentifierPrefix opts ++ "fn" ++ ref) ! A.class_ "footnoteRef" ! prefixedId opts ("fnref" ++ ref) - $ (if isJust (writerEpubVersion opts) + $ (if isJust epubVersion then id else H.sup) $ toHtml ref - return $ case writerEpubVersion opts of + return $ case epubVersion of Just EPUB3 -> link ! customAttribute "epub:type" "noteref" _ -> link (Cite cits il)-> do contents <- inlineListToHtml opts il @@ -933,7 +952,8 @@ blockListToNote opts ref blocks = Plain backlink] in do contents <- blockListToHtml opts blocks' let noteItem = H.li ! (prefixedId opts ("fn" ++ ref)) $ contents - let noteItem' = case writerEpubVersion opts of + epubVersion <- gets stEPUBVersion + let noteItem' = case epubVersion of Just EPUB3 -> noteItem ! customAttribute "epub:type" "footnote" _ -> noteItem return $ nl opts >> noteItem' -- cgit v1.2.3 From 91cdcc796df3db290d1930b159eb3ee2f74d4c03 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 27 Jan 2017 22:39:36 +0100 Subject: HTML: export separate functions for slide formats. writeS5, writeSlideous, writeRevealJs, writeDZSlides, writeSlidy. Removed writerSlideVariant from WriterOptions. --- src/Text/Pandoc.hs | 21 +++-- src/Text/Pandoc/Options.hs | 2 - src/Text/Pandoc/Writers/HTML.hs | 164 +++++++++++++++++++++++++++------------- 3 files changed, 121 insertions(+), 66 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index ea625ffa1..4d0dde96c 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -103,6 +103,11 @@ module Text.Pandoc , writeHtml4String , writeHtml5 , writeHtml5String + , writeRevealJs + , writeS5 + , writeSlidy + , writeSlideous + , writeDZSlides , writeICML , writeDocbook4 , writeDocbook5 @@ -288,17 +293,11 @@ writers = [ ,("html4" , StringWriter writeHtml4String) ,("html5" , StringWriter writeHtml5String) ,("icml" , StringWriter writeICML) - ,("s5" , StringWriter $ \o -> - writeHtml4String o{ writerSlideVariant = S5Slides - , writerTableOfContents = False }) - ,("slidy" , StringWriter $ \o -> - writeHtml4String o{ writerSlideVariant = SlidySlides }) - ,("slideous" , StringWriter $ \o -> - writeHtml4String o{ writerSlideVariant = SlideousSlides }) - ,("dzslides" , StringWriter $ \o -> - writeHtml5String o{ writerSlideVariant = DZSlides }) - ,("revealjs" , StringWriter $ \o -> - writeHtml5String o{ writerSlideVariant = RevealJsSlides }) + ,("s5" , StringWriter writeS5) + ,("slidy" , StringWriter writeSlidy) + ,("slideous" , StringWriter writeSlideous) + ,("dzslides" , StringWriter writeDZSlides) + ,("revealjs" , StringWriter writeRevealJs) ,("docbook" , StringWriter writeDocbook5) ,("docbook4" , StringWriter writeDocbook4) ,("docbook5" , StringWriter writeDocbook5) diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index 755ab9add..ddd81ec51 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -150,7 +150,6 @@ data WriterOptions = WriterOptions , writerVariables :: [(String, String)] -- ^ Variables to set in template , writerTabStop :: Int -- ^ Tabstop for conversion btw spaces and tabs , writerTableOfContents :: Bool -- ^ Include table of contents - , writerSlideVariant :: HTMLSlideVariant -- ^ Are we writing S5, Slidy or Slideous? , writerIncremental :: Bool -- ^ True if lists should be incremental , writerHTMLMathMethod :: HTMLMathMethod -- ^ How to print math in HTML , writerNumberSections :: Bool -- ^ Number sections in LaTeX @@ -190,7 +189,6 @@ instance Default WriterOptions where , writerVariables = [] , writerTabStop = 4 , writerTableOfContents = False - , writerSlideVariant = NoSlides , writerIncremental = False , writerHTMLMathMethod = PlainMath , writerNumberSections = False diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 518848139..9037bfbec 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -33,7 +33,12 @@ module Text.Pandoc.Writers.HTML ( writeHtml4String, writeHtml5, writeHtml5String, - writeHtmlStringForEPUB + writeHtmlStringForEPUB, + writeS5, + writeSlidy, + writeSlideous, + writeDZSlides, + writeRevealJs ) where import Text.Pandoc.Definition import Text.Pandoc.Walk @@ -88,13 +93,15 @@ data WriterState = WriterState , stElement :: Bool -- ^ Processing an Element , stHtml5 :: Bool -- ^ Use HTML5 , stEPUBVersion :: Maybe EPUBVersion -- ^ EPUB version if for epub + , stSlideVariant :: HTMLSlideVariant } defaultWriterState :: WriterState defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False, stHighlighting = False, stSecNum = [], stElement = False, stHtml5 = False, - stEPUBVersion = Nothing} + stEPUBVersion = Nothing, + stSlideVariant = NoSlides} -- Helpers to render HTML with the appropriate function. @@ -113,45 +120,79 @@ nl opts = if writerWrapText opts == WrapNone -- | Convert Pandoc document to Html 5 string. writeHtml5String :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeHtml5String = writeHtmlString' True +writeHtml5String = writeHtmlString' + defaultWriterState{ stHtml5 = True } -- | Convert Pandoc document to Html 5 structure. writeHtml5 :: PandocMonad m => WriterOptions -> Pandoc -> m Html -writeHtml5 = writeHtml' True +writeHtml5 = writeHtml' defaultWriterState{ stHtml5 = True } -- | Convert Pandoc document to Html 4 string. writeHtml4String :: PandocMonad m => WriterOptions -> Pandoc -> m String -writeHtml4String = writeHtmlString' False +writeHtml4String = writeHtmlString' + defaultWriterState{ stHtml5 = False } -- | Convert Pandoc document to Html 4 structure. writeHtml4 :: PandocMonad m => WriterOptions -> Pandoc -> m Html -writeHtml4 = writeHtml' False +writeHtml4 = writeHtml' defaultWriterState{ stHtml5 = False } -- | Convert Pandoc document to Html appropriate for an epub version. writeHtmlStringForEPUB :: PandocMonad m => EPUBVersion -> WriterOptions -> Pandoc -> m String -writeHtmlStringForEPUB version opts d = do - (body, context) <- evalStateT (pandocToHtml opts d) +writeHtmlStringForEPUB version = writeHtmlString' defaultWriterState{ stHtml5 = version == EPUB3, stEPUBVersion = Just version } - return $ case writerTemplate opts of - Nothing -> renderHtml body - Just tpl -> renderTemplate' tpl $ - defField "body" (renderHtml body) context -writeHtmlString' :: PandocMonad m => Bool -> WriterOptions -> Pandoc -> m String -writeHtmlString' html5 opts d = do - (body, context) <- evalStateT (pandocToHtml opts d) - defaultWriterState{ stHtml5 = html5 } +-- | Convert Pandoc document to Reveal JS HTML slide show. +writeRevealJs :: PandocMonad m + => WriterOptions -> Pandoc -> m String +writeRevealJs = writeHtmlSlideShow' RevealJsSlides + +-- | Convert Pandoc document to S5 HTML slide show. +writeS5 :: PandocMonad m + => WriterOptions -> Pandoc -> m String +writeS5 = writeHtmlSlideShow' S5Slides + +-- | Convert Pandoc document to Slidy HTML slide show. +writeSlidy :: PandocMonad m + => WriterOptions -> Pandoc -> m String +writeSlidy = writeHtmlSlideShow' SlidySlides + +-- | Convert Pandoc document to Slideous HTML slide show. +writeSlideous :: PandocMonad m + => WriterOptions -> Pandoc -> m String +writeSlideous = writeHtmlSlideShow' SlideousSlides + +-- | Convert Pandoc document to DZSlides HTML slide show. +writeDZSlides :: PandocMonad m + => WriterOptions -> Pandoc -> m String +writeDZSlides = writeHtmlSlideShow' DZSlides + +writeHtmlSlideShow' :: PandocMonad m + => HTMLSlideVariant -> WriterOptions -> Pandoc -> m String +writeHtmlSlideShow' variant = writeHtmlString' + defaultWriterState{ stSlideVariant = variant + , stHtml5 = case variant of + RevealJsSlides -> True + S5Slides -> False + SlidySlides -> False + DZSlides -> True + SlideousSlides -> False + NoSlides -> False + } + +writeHtmlString' :: PandocMonad m + => WriterState -> WriterOptions -> Pandoc -> m String +writeHtmlString' st opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) st return $ case writerTemplate opts of Nothing -> renderHtml body Just tpl -> renderTemplate' tpl $ defField "body" (renderHtml body) context -writeHtml' :: PandocMonad m => Bool -> WriterOptions -> Pandoc -> m Html -writeHtml' html5 opts d = do - (body, context) <- evalStateT (pandocToHtml opts d) - defaultWriterState{ stHtml5 = html5 } +writeHtml' :: PandocMonad m => WriterState -> WriterOptions -> Pandoc -> m Html +writeHtml' st opts d = do + (body, context) <- evalStateT (pandocToHtml opts d) st return $ case writerTemplate opts of Nothing -> body Just tpl -> renderTemplate' tpl $ @@ -171,11 +212,12 @@ pandocToHtml opts (Pandoc meta blocks) = do let authsMeta = map stringifyHTML $ docAuthors meta let dateMeta = stringifyHTML $ docDate meta let slideLevel = fromMaybe (getSlideLevel blocks) $ writerSlideLevel opts + slideVariant <- gets stSlideVariant let sects = hierarchicalize $ - if writerSlideVariant opts == NoSlides + if slideVariant == NoSlides then blocks else prepSlides slideLevel blocks - toc <- if writerTableOfContents opts + toc <- if writerTableOfContents opts && slideVariant /= S5Slides then tableOfContents opts sects else return Nothing blocks' <- liftM (mconcat . intersperse (nl opts)) $ @@ -195,7 +237,7 @@ pandocToHtml opts (Pandoc meta blocks) = do MathJax url -> H.script ! A.src (toValue url) ! A.type_ "text/javascript" - $ case writerSlideVariant opts of + $ case slideVariant of SlideousSlides -> preEscapedString "MathJax.Hub.Queue([\"Typeset\",MathJax.Hub]);" @@ -247,21 +289,30 @@ prefixedId opts s = "" -> mempty _ -> A.id $ toValue $ writerIdentifierPrefix opts ++ s -toList :: (Html -> Html) -> WriterOptions -> ([Html] -> Html) +toList :: PandocMonad m + => (Html -> Html) + -> WriterOptions + -> [Html] + -> StateT WriterState m Html toList listop opts items = do - if (writerIncremental opts) - then if (writerSlideVariant opts /= RevealJsSlides) - then (listop $ mconcat items) ! A.class_ "incremental" - else listop $ mconcat $ map (! A.class_ "fragment") items - else listop $ mconcat items + slideVariant <- gets stSlideVariant + return $ + if (writerIncremental opts) + then if (slideVariant /= RevealJsSlides) + then (listop $ mconcat items) ! A.class_ "incremental" + else listop $ mconcat $ map (! A.class_ "fragment") items + else listop $ mconcat items -unordList :: WriterOptions -> [Html] -> Html +unordList :: PandocMonad m + => WriterOptions -> [Html] -> StateT WriterState m Html unordList opts = toList H.ul opts . toListItems opts -ordList :: WriterOptions -> [Html] -> Html +ordList :: PandocMonad m + => WriterOptions -> [Html] -> StateT WriterState m Html ordList opts = toList H.ol opts . toListItems opts -defList :: WriterOptions -> [Html] -> Html +defList :: PandocMonad m + => WriterOptions -> [Html] -> StateT WriterState m Html defList opts items = toList H.dl opts (items ++ [nl opts]) -- | Construct table of contents from list of elements. @@ -270,9 +321,9 @@ tableOfContents _ [] = return Nothing tableOfContents opts sects = do contents <- mapM (elementToListItem opts) sects let tocList = catMaybes contents - return $ if null tocList - then Nothing - else Just $ unordList opts tocList + if null tocList + then return Nothing + else Just <$> unordList opts tocList -- | Convert section number to string showSecNum :: [Int] -> String @@ -294,11 +345,12 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs) else mempty txt <- liftM (sectnum >>) $ inlineListToHtml opts $ walk deNote headerText subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes - let subList = if null subHeads - then mempty - else unordList opts subHeads + subList <- if null subHeads + then return mempty + else unordList opts subHeads -- in reveal.js, we need #/apples, not #apples: - let revealSlash = ['/' | writerSlideVariant opts == RevealJsSlides] + slideVariant <- gets stSlideVariant + let revealSlash = ['/' | slideVariant== RevealJsSlides] return $ Just $ if null id' then (H.a $ toHtml txt) >> subList @@ -311,7 +363,8 @@ elementToListItem _ _ = return Nothing elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element -> StateT WriterState m Html elementToHtml _slideLevel opts (Blk block) = blockToHtml opts block elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elements) = do - let slide = writerSlideVariant opts /= NoSlides && level <= slideLevel + slideVariant <- gets stSlideVariant + let slide = slideVariant /= NoSlides && level <= slideLevel let num' = zipWith (+) num (writerNumberOffset opts ++ repeat 0) modify $ \st -> st{stSecNum = num'} -- update section number html5 <- gets stHtml5 @@ -329,7 +382,7 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen isSec (Blk _) = False let isPause (Blk x) = x == Para [Str ".",Space,Str ".",Space,Str "."] isPause _ = False - let fragmentClass = case writerSlideVariant opts of + let fragmentClass = case slideVariant of RevealJsSlides -> "fragment" _ -> "incremental" let inDiv xs = Blk (RawBlock (Format "html") ("
WriterOptions -> [Html] -> StateT WriterState m Html footnoteSection opts notes = do html5 <- gets stHtml5 + slideVariant <- gets stSlideVariant let hrtag = if html5 then H5.hr else H.hr let container x = if html5 then H5.section ! A.class_ "footnotes" $ x - else if writerSlideVariant opts /= NoSlides + else if slideVariant /= NoSlides then H.div ! A.class_ "footnotes slide" $ x else H.div ! A.class_ "footnotes" $ x return $ @@ -526,9 +580,10 @@ blockToHtml opts (Div attr@(ident, classes, kvs) bs) = do let (divtag, classes') = if html5 && "section" `elem` classes then (H5.section, filter (/= "section") classes) else (H.div, classes) + slideVariant <- gets stSlideVariant return $ if speakerNotes - then case writerSlideVariant opts of + then case slideVariant of RevealJsSlides -> addAttrs opts' attr $ H5.aside $ contents' DZSlides -> (addAttrs opts' attr $ H5.div $ contents') ! (H5.customAttribute "role" "note") @@ -565,11 +620,12 @@ blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do $ H.pre $ H.code $ toHtml adjCode Just h -> modify (\st -> st{ stHighlighting = True }) >> return (addAttrs opts (id',[],keyvals) h) -blockToHtml opts (BlockQuote blocks) = +blockToHtml opts (BlockQuote blocks) = do -- in S5, treat list in blockquote specially -- if default is incremental, make it nonincremental; -- otherwise incremental - if writerSlideVariant opts /= NoSlides + slideVariant <- gets stSlideVariant + if slideVariant /= NoSlides then let inc = not (writerIncremental opts) in case blocks of [BulletList lst] -> blockToHtml (opts {writerIncremental = inc}) @@ -606,7 +662,7 @@ blockToHtml opts (Header level attr@(_,classes,_) lst) = do _ -> H.p contents' blockToHtml opts (BulletList lst) = do contents <- mapM (blockListToHtml opts) lst - return $ unordList opts contents + unordList opts contents blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do contents <- mapM (blockListToHtml opts) lst html5 <- gets stHtml5 @@ -632,7 +688,8 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do else [A.style $ toValue $ "list-style-type: " ++ numstyle'] else []) - return $ foldl (!) (ordList opts contents) attribs + l <- ordList opts contents + return $ foldl (!) l attribs blockToHtml opts (DefinitionList lst) = do contents <- mapM (\(term, defs) -> do term' <- if null term @@ -642,7 +699,7 @@ blockToHtml opts (DefinitionList lst) = do blockListToHtml opts) defs return $ mconcat $ nl opts : term' : nl opts : intersperse (nl opts) defs') lst - return $ defList opts contents + defList opts contents blockToHtml opts (Table capt aligns widths headers rows') = do captionDoc <- if null capt then return mempty @@ -878,9 +935,10 @@ inlineToHtml opts inline = do lift $ obfuscateLink opts attr linkText s (Link attr txt (s,tit)) -> do linkText <- inlineListToHtml opts txt + slideVariant <- gets stSlideVariant let s' = case s of - '#':xs | writerSlideVariant opts == - RevealJsSlides -> '#':'/':xs + '#':xs | slideVariant == RevealJsSlides + -> '#':'/':xs _ -> s let link = H.a ! A.href (toValue s') $ linkText let link' = if txt == [Str (unEscapeString s)] @@ -913,8 +971,8 @@ inlineToHtml opts inline = do epubVersion <- gets stEPUBVersion -- push contents onto front of notes modify $ \st -> st {stNotes = (htmlContents:notes)} - let revealSlash = ['/' | writerSlideVariant opts - == RevealJsSlides] + slideVariant <- gets stSlideVariant + let revealSlash = ['/' | slideVariant == RevealJsSlides] let link = H.a ! A.href (toValue $ "#" ++ revealSlash ++ writerIdentifierPrefix opts ++ "fn" ++ ref) -- cgit v1.2.3 From d2e0592e0174d4890ef0971bd4d47bbb45a98c3a Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 28 Jan 2017 09:52:45 +0100 Subject: LaTeX writer: export writeBeamer. Removed writerBeamer from WriterOptions. --- pandoc.hs | 1 - src/Text/Pandoc.hs | 4 +-- src/Text/Pandoc/Options.hs | 2 -- src/Text/Pandoc/Writers/LaTeX.hs | 75 ++++++++++++++++++++++++++-------------- tests/Tests/Writers/LaTeX.hs | 6 ++-- 5 files changed, 56 insertions(+), 32 deletions(-) (limited to 'src/Text/Pandoc/Writers') diff --git a/pandoc.hs b/pandoc.hs index 9ee6e376b..a5163dae5 100644 --- a/pandoc.hs +++ b/pandoc.hs @@ -313,7 +313,6 @@ convertWithOpts opts args = do writerHtmlQTags = htmlQTags, writerTopLevelDivision = topLevelDivision, writerListings = listings, - writerBeamer = False, writerSlideLevel = slideLevel, writerHighlightStyle = highlightStyle, writerSetextHeaders = setextHeaders, diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index 4d0dde96c..a1c3f8486 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -97,6 +97,7 @@ module Text.Pandoc , writePlain , writeRST , writeLaTeX + , writeBeamer , writeConTeXt , writeTexinfo , writeHtml4 @@ -304,8 +305,7 @@ writers = [ ,("opml" , StringWriter writeOPML) ,("opendocument" , StringWriter writeOpenDocument) ,("latex" , StringWriter writeLaTeX) - ,("beamer" , StringWriter $ \o -> - writeLaTeX o{ writerBeamer = True }) + ,("beamer" , StringWriter writeBeamer) ,("context" , StringWriter writeConTeXt) ,("texinfo" , StringWriter writeTexinfo) ,("man" , StringWriter writeMan) diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index ddd81ec51..02ae9f771 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -167,7 +167,6 @@ data WriterOptions = WriterOptions , writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory , writerCiteMethod :: CiteMethod -- ^ How to print cites , writerHtmlQTags :: Bool -- ^ Use @@ tags for quotes in HTML - , writerBeamer :: Bool -- ^ Produce beamer LaTeX slide show , writerSlideLevel :: Maybe Int -- ^ Force header level of slides , writerTopLevelDivision :: TopLevelDivision -- ^ Type of top-level divisions , writerListings :: Bool -- ^ Use listings package for code @@ -205,7 +204,6 @@ instance Default WriterOptions where , writerUserDataDir = Nothing , writerCiteMethod = Citeproc , writerHtmlQTags = False - , writerBeamer = False , writerSlideLevel = Nothing , writerTopLevelDivision = TopLevelDefault , writerListings = False diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 953e4250f..67318a549 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -29,7 +29,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of 'Pandoc' format into LaTeX. -} -module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where +module Text.Pandoc.Writers.LaTeX ( + writeLaTeX + , writeBeamer + ) where import Text.Pandoc.Definition import Text.Pandoc.Walk import Text.Pandoc.Shared @@ -76,26 +79,46 @@ data WriterState = , stIncremental :: Bool -- true if beamer lists should be displayed bit by bit , stInternalLinks :: [String] -- list of internal link targets , stUsesEuro :: Bool -- true if euro symbol used + , stBeamer :: Bool -- produce beamer } +startingState :: WriterOptions -> WriterState +startingState options = WriterState { + stInNote = False + , stInQuote = False + , stInMinipage = False + , stInHeading = False + , stNotes = [] + , stOLLevel = 1 + , stOptions = options + , stVerbInNote = False + , stTable = False + , stStrikeout = False + , stUrl = False + , stGraphics = False + , stLHS = False + , stBook = (case writerTopLevelDivision options of + TopLevelPart -> True + TopLevelChapter -> True + _ -> False) + , stCsquotes = False + , stHighlighting = False + , stIncremental = writerIncremental options + , stInternalLinks = [] + , stUsesEuro = False + , stBeamer = False } + -- | Convert Pandoc to LaTeX. writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m String writeLaTeX options document = return $ evalState (pandocToLaTeX options document) $ - WriterState { stInNote = False, stInQuote = False, - stInMinipage = False, stInHeading = False, - stNotes = [], stOLLevel = 1, - stOptions = options, stVerbInNote = False, - stTable = False, stStrikeout = False, - stUrl = False, stGraphics = False, - stLHS = False, - stBook = (case writerTopLevelDivision options of - TopLevelPart -> True - TopLevelChapter -> True - _ -> False), - stCsquotes = False, stHighlighting = False, - stIncremental = writerIncremental options, - stInternalLinks = [], stUsesEuro = False } + startingState options + +-- | Convert Pandoc to LaTeX Beamer. +writeBeamer :: PandocMonad m => WriterOptions -> Pandoc -> m String +writeBeamer options document = return $ + evalState (pandocToLaTeX options document) $ + (startingState options){ stBeamer = True } pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String pandocToLaTeX options (Pandoc meta blocks) = do @@ -144,7 +167,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do else case last blocks' of Header 1 _ il -> (init blocks', il) _ -> (blocks', []) - blocks''' <- if writerBeamer options + beamer <- gets stBeamer + blocks''' <- if beamer then toSlides blocks'' else return blocks'' body <- mapM (elementToLaTeX options) $ hierarchicalize blocks''' @@ -171,7 +195,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do defField "body" main $ defField "title-meta" titleMeta $ defField "author-meta" (intercalate "; " authorsMeta) $ - defField "documentclass" (if writerBeamer options + defField "documentclass" (if beamer then ("beamer" :: String) else if stBook st then "book" @@ -186,7 +210,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do defField "book-class" (stBook st) $ defField "euro" (stUsesEuro st) $ defField "listings" (writerListings options || stLHS st) $ - defField "beamer" (writerBeamer options) $ + defField "beamer" beamer $ (if stHighlighting st then case writerHighlightStyle options of Just sty -> @@ -388,7 +412,7 @@ blockToLaTeX :: Block -- ^ Block to convert -> State WriterState Doc blockToLaTeX Null = return empty blockToLaTeX (Div (identifier,classes,kvs) bs) = do - beamer <- writerBeamer `fmap` gets stOptions + beamer <- gets stBeamer ref <- toLabel identifier let linkAnchor = if null identifier then empty @@ -439,7 +463,7 @@ blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = d else figure $$ footnotes -- . . . indicates pause in beamer slides blockToLaTeX (Para [Str ".",Space,Str ".",Space,Str "."]) = do - beamer <- writerBeamer `fmap` gets stOptions + beamer <- gets stBeamer if beamer then blockToLaTeX (RawBlock "latex" "\\pause") else inlineListToLaTeX [Str ".",Space,Str ".",Space,Str "."] @@ -448,7 +472,7 @@ blockToLaTeX (Para lst) = blockToLaTeX (LineBlock lns) = do blockToLaTeX $ linesToPara lns blockToLaTeX (BlockQuote lst) = do - beamer <- writerBeamer `fmap` gets stOptions + beamer <- gets stBeamer case lst of [b] | beamer && isListBlock b -> do oldIncremental <- gets stIncremental @@ -527,7 +551,7 @@ blockToLaTeX (RawBlock f x) blockToLaTeX (BulletList []) = return empty -- otherwise latex error blockToLaTeX (BulletList lst) = do incremental <- gets stIncremental - beamer <- writerBeamer `fmap` gets stOptions + beamer <- gets stBeamer let inc = if beamer && incremental then "[<+->]" else "" items <- mapM listItemToLaTeX lst let spacing = if isTightList lst @@ -772,7 +796,8 @@ sectionHeader unnumbered ident level lst = do let topLevelDivision = if book && writerTopLevelDivision opts == TopLevelDefault then TopLevelChapter else writerTopLevelDivision opts - let level' = if writerBeamer opts && + beamer <- gets stBeamer + let level' = if beamer && topLevelDivision `elem` [TopLevelPart, TopLevelChapter] -- beamer has parts but no chapters then if level == 1 then -1 else level - 1 @@ -1022,9 +1047,9 @@ inlineToLaTeX (Note contents) = do (CodeBlock _ _ : _) -> cr _ -> empty let noteContents = nest 2 contents' <> optnl - opts <- gets stOptions + beamer <- gets stBeamer -- in beamer slides, display footnote from current overlay forward - let beamerMark = if writerBeamer opts + let beamerMark = if beamer then text "<.->" else empty modify $ \st -> st{ stNotes = noteContents : stNotes st } diff --git a/tests/Tests/Writers/LaTeX.hs b/tests/Tests/Writers/LaTeX.hs index 00c590370..f54aef4dc 100644 --- a/tests/Tests/Writers/LaTeX.hs +++ b/tests/Tests/Writers/LaTeX.hs @@ -16,6 +16,9 @@ latexListing = latexWithOpts def{ writerListings = True } latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String latexWithOpts opts = purely (writeLaTeX opts) . toPandoc +beamerWithOpts :: (ToPandoc a) => WriterOptions -> a -> String +beamerWithOpts opts = purely (writeBeamer opts) . toPandoc + {- "my test" =: X =?> Y @@ -95,8 +98,7 @@ tests = [ testGroup "code blocks" beamerTopLevelDiv :: (ToPandoc a) => TopLevelDivision -> a -> String beamerTopLevelDiv division = - latexWithOpts def { writerTopLevelDivision = division - , writerBeamer = True } + beamerWithOpts def { writerTopLevelDivision = division } in [ test (latexTopLevelDiv TopLevelSection) "sections as top-level" $ headers =?> -- cgit v1.2.3