@@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29Conversion of 'Pandoc' documents to docx.
29Conversion of 'Pandoc' documents to docx.
31−module Text.Pandoc.Writers.Docx ( writeDocx, writeDocxPure ) where
31+module Text.Pandoc.Writers.Docx ( writeDocx ) where
32import Data.List ( intercalate, isPrefixOf, isSuffixOf )
32import Data.List ( intercalate, isPrefixOf, isSuffixOf )
33import qualified Data.ByteString as B
33import qualified Data.ByteString as B
34import qualified Data.ByteString.Lazy as BL
34import qualified Data.ByteString.Lazy as BL
@@ -65,8 +65,8 @@ import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef,
65import Control.Applicative ((<|>))
65import Control.Applicative ((<|>))
66import Data.Maybe (fromMaybe, mapMaybe, maybeToList, isNothing)
66import Data.Maybe (fromMaybe, mapMaybe, maybeToList, isNothing)
67import Data.Char (ord, isSpace, toLower)
67import Data.Char (ord, isSpace, toLower)
68−import Text.Pandoc.Free (PandocAction, runIO)
68+import Text.Pandoc.Class (PandocMonad)
69−import qualified Text.Pandoc.Free as P
69+import qualified Text.Pandoc.Class as P
71data ListMarker = NoMarker
71data ListMarker = NoMarker
72 | BulletMarker
72 | BulletMarker
@@ -146,7 +146,7 @@ defaultWriterState = WriterState{
146 , stDynamicTextProps = []
146 , stDynamicTextProps = []
149−type WS = ReaderT WriterEnv (StateT WriterState (PandocAction))
149+type WS m = ReaderT WriterEnv (StateT WriterState m)
151mknode :: Node t => String -> [(String,String)] -> t -> Element
151mknode :: Node t => String -> [(String,String)] -> t -> Element
152mknode s attrs =
152mknode s attrs =
@@ -215,17 +215,11 @@ metaValueToInlines _ = []
218+writeDocx :: (PandocMonad m)
218−writeDocx :: WriterOptions -- ^ Writer options
219+ => WriterOptions -- ^ Writer options
219 -> Pandoc -- ^ Document to convert
220 -> Pandoc -- ^ Document to convert
220− -> IO BL.ByteString
221+ -> m BL.ByteString
221−writeDocx opts doc = runIO $ writeDocxPure opts doc
222+writeDocx opts doc@(Pandoc meta _) = do
224−-- | Produce an Docx file from a Pandoc document.
225−writeDocxPure :: WriterOptions -- ^ Writer options
226− -> Pandoc -- ^ Document to convert
227− -> PandocAction BL.ByteString
228−writeDocxPure opts doc@(Pandoc meta _) = do
229 let datadir = writerUserDataDir opts
223 let datadir = writerUserDataDir opts
230 let doc' = walk fixDisplayMath $ doc
224 let doc' = walk fixDisplayMath $ doc
231 username <- P.lookupEnv "USERNAME"
225 username <- P.lookupEnv "USERNAME"
@@ -611,7 +605,7 @@ styleToOpenXml sm style =
611 $ backgroundColor style )
605 $ backgroundColor style )
614−copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> PandocAction Entry
608+copyChildren :: (PandocMonad m) => Archive -> Archive -> String -> Integer -> [String] -> m Entry
615copyChildren refArchive distArchive path timestamp elNames = do
609copyChildren refArchive distArchive path timestamp elNames = do
616 ref <- parseXml refArchive distArchive path
610 ref <- parseXml refArchive distArchive path
617 dist <- parseXml distArchive distArchive path
611 dist <- parseXml distArchive distArchive path
@@ -630,7 +624,7 @@ copyChildren refArchive distArchive path timestamp elNames = do
630baseListId :: Int
624baseListId :: Int
631baseListId = 1000
625baseListId = 1000
633−mkNumbering :: [ListMarker] -> PandocAction [Element]
627+mkNumbering :: (PandocMonad m) => [ListMarker] -> m [Element]
634mkNumbering lists = do
628mkNumbering lists = do
635 elts <- mapM mkAbstractNum (ordNub lists)
629 elts <- mapM mkAbstractNum (ordNub lists)
636 return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)]
630 return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)]
@@ -646,7 +640,7 @@ mkNum marker numid =
646 map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))]
640 map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))]
647 $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6]
641 $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6]
649−mkAbstractNum :: ListMarker -> PandocAction Element
643+mkAbstractNum :: (PandocMonad m) => ListMarker -> m Element
650mkAbstractNum marker = do
644mkAbstractNum marker = do
651 gen <- P.newStdGen
645 gen <- P.newStdGen
652 let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen
646 let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen
@@ -701,11 +695,11 @@ mkLvl marker lvl =
701 patternFor TwoParens s = "(" ++ s ++ ")"
695 patternFor TwoParens s = "(" ++ s ++ ")"
702 patternFor _ s = s ++ "."
696 patternFor _ s = s ++ "."
704−getNumId :: WS Int
698+getNumId :: (PandocMonad m) => WS m Int
705getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists
699getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists
708−makeTOC :: WriterOptions -> WS [Element]
702+makeTOC :: (PandocMonad m) => WriterOptions -> WS m [Element]
709makeTOC opts | writerTableOfContents opts = do
703makeTOC opts | writerTableOfContents opts = do
710 let depth = "1-"++(show (writerTOCDepth opts))
704 let depth = "1-"++(show (writerTOCDepth opts))
711 let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u"
705 let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u"
@@ -735,7 +729,7 @@ makeTOC _ = return []
736-- | Convert Pandoc document to two lists of
730-- | Convert Pandoc document to two lists of
737-- OpenXML elements (the main document and footnotes).
731-- OpenXML elements (the main document and footnotes).
738−writeOpenXML :: WriterOptions -> Pandoc -> WS ([Element], [Element])
732+writeOpenXML :: (PandocMonad m) => WriterOptions -> Pandoc -> WS m ([Element], [Element])
739writeOpenXML opts (Pandoc meta blocks) = do
733writeOpenXML opts (Pandoc meta blocks) = do
740 let tit = docTitle meta ++ case lookupMeta "subtitle" meta of
734 let tit = docTitle meta ++ case lookupMeta "subtitle" meta of
741 Just (MetaBlocks [Plain xs]) -> LineBreak : xs
735 Just (MetaBlocks [Plain xs]) -> LineBreak : xs
@@ -770,13 +764,13 @@ writeOpenXML opts (Pandoc meta blocks) = do
770 return (meta' ++ doc', notes')
764 return (meta' ++ doc', notes')
772-- | Convert a list of Pandoc blocks to OpenXML.
766-- | Convert a list of Pandoc blocks to OpenXML.
773−blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element]
767+blocksToOpenXML :: (PandocMonad m) => WriterOptions -> [Block] -> WS m [Element]
774blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
768blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
776pCustomStyle :: String -> Element
770pCustomStyle :: String -> Element
777pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
771pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
779−pStyleM :: String -> WS XML.Element
773+pStyleM :: (PandocMonad m) => String -> WS m XML.Element
780pStyleM styleName = do
774pStyleM styleName = do
781 styleMaps <- gets stStyleMaps
775 styleMaps <- gets stStyleMaps
782 let sty' = getStyleId styleName $ sParaStyleMap styleMaps
776 let sty' = getStyleId styleName $ sParaStyleMap styleMaps
@@ -785,13 +779,13 @@ pStyleM styleName = do
785rCustomStyle :: String -> Element
779rCustomStyle :: String -> Element
786rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
780rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
788−rStyleM :: String -> WS XML.Element
782+rStyleM :: (PandocMonad m) => String -> WS m XML.Element
789rStyleM styleName = do
783rStyleM styleName = do
790 styleMaps <- gets stStyleMaps
784 styleMaps <- gets stStyleMaps
791 let sty' = getStyleId styleName $ sCharStyleMap styleMaps
785 let sty' = getStyleId styleName $ sCharStyleMap styleMaps
792 return $ mknode "w:rStyle" [("w:val",sty')] ()
786 return $ mknode "w:rStyle" [("w:val",sty')] ()
794−getUniqueId :: PandocAction String
788+getUniqueId :: (PandocMonad m) => m String
795-- the + 20 is to ensure that there are no clashes with the rIds
789-- the + 20 is to ensure that there are no clashes with the rIds
796-- already in word/document.xml.rel
790-- already in word/document.xml.rel
797getUniqueId = (show . (+ 20)) <$> P.newUniqueHash
791getUniqueId = (show . (+ 20)) <$> P.newUniqueHash
@@ -801,10 +795,10 @@ dynamicStyleKey :: String
801dynamicStyleKey = "custom-style"
795dynamicStyleKey = "custom-style"
803-- | Convert a Pandoc block element to OpenXML.
797-- | Convert a Pandoc block element to OpenXML.
804−blockToOpenXML :: WriterOptions -> Block -> WS [Element]
798+blockToOpenXML :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element]
805blockToOpenXML opts blk = withDirection $ blockToOpenXML' opts blk
799blockToOpenXML opts blk = withDirection $ blockToOpenXML' opts blk
807−blockToOpenXML' :: WriterOptions -> Block -> WS [Element]
801+blockToOpenXML' :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element]
808blockToOpenXML' _ Null = return []
802blockToOpenXML' _ Null = return []
809blockToOpenXML' opts (Div (ident,classes,kvs) bs)
803blockToOpenXML' opts (Div (ident,classes,kvs) bs)
810 | Just sty <- lookup dynamicStyleKey kvs = do
804 | Just sty <- lookup dynamicStyleKey kvs = do
@@ -955,7 +949,7 @@ blockToOpenXML' opts (DefinitionList items) = do
955 setFirstPara
949 setFirstPara
958−definitionListItemToOpenXML :: WriterOptions -> ([Inline],[[Block]]) -> WS [Element]
952+definitionListItemToOpenXML :: (PandocMonad m) => WriterOptions -> ([Inline],[[Block]]) -> WS m [Element]
959definitionListItemToOpenXML opts (term,defs) = do
953definitionListItemToOpenXML opts (term,defs) = do
960 term' <- withParaProp (pCustomStyle "DefinitionTerm")
954 term' <- withParaProp (pCustomStyle "DefinitionTerm")
961 $ blockToOpenXML opts (Para term)
955 $ blockToOpenXML opts (Para term)
@@ -963,12 +957,12 @@ definitionListItemToOpenXML opts (term,defs) = do
963 $ concat `fmap` mapM (blocksToOpenXML opts) defs
957 $ concat `fmap` mapM (blocksToOpenXML opts) defs
964 return $ term' ++ defs'
958 return $ term' ++ defs'
966−addList :: ListMarker -> WS ()
960+addList :: (PandocMonad m) => ListMarker -> WS m ()
967addList marker = do
961addList marker = do
968 lists <- gets stLists
962 lists <- gets stLists
969 modify $ \st -> st{ stLists = lists ++ [marker] }
963 modify $ \st -> st{ stLists = lists ++ [marker] }
971−listItemToOpenXML :: WriterOptions -> Int -> [Block] -> WS [Element]
965+listItemToOpenXML :: (PandocMonad m) => WriterOptions -> Int -> [Block] -> WS m [Element]
972listItemToOpenXML _ _ [] = return []
966listItemToOpenXML _ _ [] = return []
973listItemToOpenXML opts numid (first:rest) = do
967listItemToOpenXML opts numid (first:rest) = do
974 first' <- withNumId numid $ blockToOpenXML opts first
968 first' <- withNumId numid $ blockToOpenXML opts first
@@ -984,30 +978,30 @@ alignmentToString alignment = case alignment of
984 AlignDefault -> "left"
978 AlignDefault -> "left"
986-- | Convert a list of inline elements to OpenXML.
980-- | Convert a list of inline elements to OpenXML.
987−inlinesToOpenXML :: WriterOptions -> [Inline] -> WS [Element]
981+inlinesToOpenXML :: (PandocMonad m) => WriterOptions -> [Inline] -> WS m [Element]
988inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst
982inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst
990−withNumId :: Int -> WS a -> WS a
984+withNumId :: (PandocMonad m) => Int -> WS m a -> WS m a
991withNumId numid = local $ \env -> env{ envListNumId = numid }
985withNumId numid = local $ \env -> env{ envListNumId = numid }
993−asList :: WS a -> WS a
987+asList :: (PandocMonad m) => WS m a -> WS m a
994asList = local $ \env -> env{ envListLevel = envListLevel env + 1 }
988asList = local $ \env -> env{ envListLevel = envListLevel env + 1 }
996−getTextProps :: WS [Element]
990+getTextProps :: (PandocMonad m) => WS m [Element]
997getTextProps = do
991getTextProps = do
998 props <- asks envTextProperties
992 props <- asks envTextProperties
999 return $ if null props
993 return $ if null props
1001 else [mknode "w:rPr" [] props]
995 else [mknode "w:rPr" [] props]
1003−withTextProp :: Element -> WS a -> WS a
997+withTextProp :: PandocMonad m => Element -> WS m a -> WS m a
1004withTextProp d p =
998withTextProp d p =
1005 local (\env -> env {envTextProperties = d : envTextProperties env}) p
999 local (\env -> env {envTextProperties = d : envTextProperties env}) p
1007−withTextPropM :: WS Element -> WS a -> WS a
1001+withTextPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
1008withTextPropM = (. flip withTextProp) . (>>=)
1002withTextPropM = (. flip withTextProp) . (>>=)
1010−getParaProps :: Bool -> WS [Element]
1004+getParaProps :: PandocMonad m => Bool -> WS m [Element]
1011getParaProps displayMathPara = do
1005getParaProps displayMathPara = do
1012 props <- asks envParaProperties
1006 props <- asks envParaProperties
1013 listLevel <- asks envListLevel
1007 listLevel <- asks envListLevel
@@ -1022,14 +1016,14 @@ getParaProps displayMathPara = do
1022 [] -> []
1016 [] -> []
1023 ps -> [mknode "w:pPr" [] ps]
1017 ps -> [mknode "w:pPr" [] ps]
1025−withParaProp :: Element -> WS a -> WS a
1019+withParaProp :: PandocMonad m => Element -> WS m a -> WS m a
1026withParaProp d p =
1020withParaProp d p =
1027 local (\env -> env {envParaProperties = d : envParaProperties env}) p
1021 local (\env -> env {envParaProperties = d : envParaProperties env}) p
1029−withParaPropM :: WS Element -> WS a -> WS a
1023+withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
1030withParaPropM = (. flip withParaProp) . (>>=)
1024withParaPropM = (. flip withParaProp) . (>>=)
1032−formattedString :: String -> WS [Element]
1026+formattedString :: PandocMonad m => String -> WS m [Element]
1033formattedString str = do
1027formattedString str = do
1034 props <- getTextProps
1028 props <- getTextProps
1035 inDel <- asks envInDel
1029 inDel <- asks envInDel
@@ -1038,14 +1032,14 @@ formattedString str = do
1038 [ mknode (if inDel then "w:delText" else "w:t")
1032 [ mknode (if inDel then "w:delText" else "w:t")
1039 [("xml:space","preserve")] (stripInvalidChars str) ] ]
1033 [("xml:space","preserve")] (stripInvalidChars str) ] ]
1041−setFirstPara :: WS ()
1035+setFirstPara :: PandocMonad m => WS m ()
1042setFirstPara = modify $ \s -> s { stFirstPara = True }
1036setFirstPara = modify $ \s -> s { stFirstPara = True }
1044-- | Convert an inline element to OpenXML.
1038-- | Convert an inline element to OpenXML.
1045−inlineToOpenXML :: WriterOptions -> Inline -> WS [Element]
1039+inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
1046inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
1040inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
1048−inlineToOpenXML' :: WriterOptions -> Inline -> WS [Element]
1042+inlineToOpenXML' :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
1049inlineToOpenXML' _ (Str str) = formattedString str
1043inlineToOpenXML' _ (Str str) = formattedString str
1050inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
1044inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
1051inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
1045inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
@@ -1281,7 +1275,7 @@ defaultFootnotes = [ mknode "w:footnote"
1281 [ mknode "w:r" [] $
1275 [ mknode "w:r" [] $
1282 [ mknode "w:continuationSeparator" [] ()]]]]
1276 [ mknode "w:continuationSeparator" [] ()]]]]
1284−parseXml :: Archive -> Archive -> String -> PandocAction Element
1278+parseXml :: (PandocMonad m) => Archive -> Archive -> String -> m Element
1285parseXml refArchive distArchive relpath =
1279parseXml refArchive distArchive relpath =
1286 case findEntryByPath relpath refArchive `mplus`
1280 case findEntryByPath relpath refArchive `mplus`
1287 findEntryByPath relpath distArchive of
1281 findEntryByPath relpath distArchive of
@@ -1299,7 +1293,7 @@ fitToPage (x, y) pageWidth
1299 (pageWidth, floor $ ((fromIntegral pageWidth) / x) * y)
1293 (pageWidth, floor $ ((fromIntegral pageWidth) / x) * y)
1300 | otherwise = (floor x, floor y)
1294 | otherwise = (floor x, floor y)
1302−withDirection :: WS a -> WS a
1296+withDirection :: PandocMonad m => WS m a -> WS m a
1303withDirection x = do
1297withDirection x = do
1304 isRTL <- asks envRTL
1298 isRTL <- asks envRTL
1305 paraProps <- asks envParaProperties
1299 paraProps <- asks envParaProperties