@@ -54,6 +54,8 @@ import Text.Pandoc.Walk
54import Text.Highlighting.Kate.Types ()
54import Text.Highlighting.Kate.Types ()
55import Text.XML.Light as XML
55import Text.XML.Light as XML
56import Text.TeXMath
56import Text.TeXMath
57+import Text.Pandoc.Readers.Docx.StyleMap
58+import Text.Pandoc.Readers.Docx.Util (elemName)
57import Control.Monad.State
59import Control.Monad.State
58import Text.Highlighting.Kate
60import Text.Highlighting.Kate
59import Data.Unique (hashUnique, newUnique)
61import Data.Unique (hashUnique, newUnique)
@@ -64,7 +66,6 @@ import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef,
64 extensionFromMimeType)
66 extensionFromMimeType)
65import Control.Applicative ((<$>), (<|>), (<*>))
67import Control.Applicative ((<$>), (<|>), (<*>))
66import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
68import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
67−import Data.Char (toLower)
69data ListMarker = NoMarker
70data ListMarker = NoMarker
70 | BulletMarker
71 | BulletMarker
@@ -90,9 +91,6 @@ listMarkerToId (NumberMarker sty delim n) =
90 OneParen -> '2'
91 OneParen -> '2'
91 TwoParens -> '3'
92 TwoParens -> '3'
93−newtype ParaStyleMap = ParaStyleMap (M.Map String String) deriving Show
94−newtype CharStyleMap = CharStyleMap (M.Map String String) deriving Show
96data WriterState = WriterState{
94data WriterState = WriterState{
97 stTextProperties :: [Element]
95 stTextProperties :: [Element]
98 , stParaProperties :: [Element]
96 , stParaProperties :: [Element]
@@ -109,8 +107,7 @@ data WriterState = WriterState{
109 , stChangesAuthor :: String
107 , stChangesAuthor :: String
110 , stChangesDate :: String
108 , stChangesDate :: String
111 , stPrintWidth :: Integer
109 , stPrintWidth :: Integer
112− , stParaStyles :: ParaStyleMap
110+ , stStyleMaps :: StyleMaps
113− , stCharStyles :: CharStyleMap
114 , stFirstPara :: Bool
111 , stFirstPara :: Bool
@@ -131,8 +128,7 @@ defaultWriterState = WriterState{
131 , stChangesAuthor = "unknown"
128 , stChangesAuthor = "unknown"
132 , stChangesDate = "1969-12-31T19:00:00Z"
129 , stChangesDate = "1969-12-31T19:00:00Z"
133 , stPrintWidth = 1
130 , stPrintWidth = 1
134− , stParaStyles = ParaStyleMap M.empty
131+ , stStyleMaps = defaultStyleMaps
135− , stCharStyles = CharStyleMap M.empty
136 , stFirstPara = False
132 , stFirstPara = False
@@ -220,28 +216,14 @@ writeDocx opts doc@(Pandoc meta _) = do
220 styledoc <- parseXml refArchive distArchive stylepath
216 styledoc <- parseXml refArchive distArchive stylepath
222 -- parse styledoc for heading styles
218 -- parse styledoc for heading styles
223− let styleNamespaces = map ((,) <$> qName . attrKey <*> attrVal) .
219+ let styleMaps = getStyleMaps styledoc
224− filter ((==Just "xmlns") . qPrefix . attrKey) .
225− elAttribs $ styledoc
226− mywURI = lookup "w" styleNamespaces
227− myName name = QName name mywURI (Just "w")
228− getAttrStyleId = findAttr (myName "styleId")
229− getAttrType = findAttr (myName "type")
230− isParaStyle = (Just "paragraph" ==) . getAttrType
231− isCharStyle = (Just "character" ==) . getAttrType
232− getNameVal = findChild (myName "name") >=> findAttr (myName "val") >=> return . map toLower
233− genStyleItem f e | f e = liftM2 (,) <$> getNameVal <*> getAttrStyleId $ e
234− | otherwise = Nothing
235− genStyleMap f = M.fromList $ mapMaybe (genStyleItem f) $ findChildren (myName "style") styledoc
236− paraStyles = ParaStyleMap $ genStyleMap isParaStyle
237− charStyles = CharStyleMap $ genStyleMap isCharStyle
239 ((contents, footnotes), st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc')
221 ((contents, footnotes), st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc')
240 defaultWriterState{ stChangesAuthor = fromMaybe "unknown" username
222 defaultWriterState{ stChangesAuthor = fromMaybe "unknown" username
241 , stChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime
223 , stChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime
242 , stPrintWidth = (maybe 420 (\x -> quot x 20) pgContentWidth)
224 , stPrintWidth = (maybe 420 (\x -> quot x 20) pgContentWidth)
243− , stParaStyles = paraStyles
225+ , stStyleMaps = styleMaps
244− , stCharStyles = charStyles}
226+ }
245 let epochtime = floor $ utcTimeToPOSIXSeconds utctime
227 let epochtime = floor $ utcTimeToPOSIXSeconds utctime
246 let imgs = M.elems $ stImages st
228 let imgs = M.elems $ stImages st
@@ -394,7 +376,7 @@ writeDocx opts doc@(Pandoc meta _) = do
396 -- styles
378 -- styles
397− let newstyles = styleToOpenXml charStyles paraStyles $ writerHighlightStyle opts
379+ let newstyles = styleToOpenXml styleMaps $ writerHighlightStyle opts
398 let styledoc' = styledoc{ elContent = modifyContent (elContent styledoc) }
380 let styledoc' = styledoc{ elContent = modifyContent (elContent styledoc) }
400 modifyContent
382 modifyContent
@@ -402,9 +384,10 @@ writeDocx opts doc@(Pandoc meta _) = do
402 | otherwise = filter notTokStyle
384 | otherwise = filter notTokStyle
403 notTokStyle (Elem el) = notStyle el || notTokId el
385 notTokStyle (Elem el) = notStyle el || notTokId el
404 notTokStyle _ = True
386 notTokStyle _ = True
405− notStyle = (/= myName "style") . elName
387+ notStyle = (/= elemName' "style") . elName
406− notTokId = maybe True (`notElem` tokStys) . getAttrStyleId
388+ notTokId = maybe True (`notElem` tokStys) . findAttr (elemName' "styleId")
407 tokStys = "SourceCode" : map show (enumFromTo KeywordTok NormalTok)
389 tokStys = "SourceCode" : map show (enumFromTo KeywordTok NormalTok)
390+ elemName' = elemName (sNameSpaces styleMaps) "w"
408 let styleEntry = toEntry stylepath epochtime $ renderXml styledoc'
391 let styleEntry = toEntry stylepath epochtime $ renderXml styledoc'
410 -- construct word/numbering.xml
393 -- construct word/numbering.xml
@@ -481,12 +464,11 @@ writeDocx opts doc@(Pandoc meta _) = do
481 miscRelEntries ++ otherMediaEntries
464 miscRelEntries ++ otherMediaEntries
482 return $ fromArchive archive
465 return $ fromArchive archive
484−styleToOpenXml :: CharStyleMap -> ParaStyleMap -> Style -> [Element]
467+styleToOpenXml :: StyleMaps -> Style -> [Element]
485−styleToOpenXml (CharStyleMap csm) (ParaStyleMap psm) style =
468+styleToOpenXml sm style =
486 maybeToList parStyle ++ mapMaybe toStyle alltoktypes
469 maybeToList parStyle ++ mapMaybe toStyle alltoktypes
487 where alltoktypes = enumFromTo KeywordTok NormalTok
470 where alltoktypes = enumFromTo KeywordTok NormalTok
488− styleExists m styleName = M.member (map toLower styleName) m
489− toStyle toktype | styleExists csm $ show toktype = Nothing
471+ toStyle toktype | hasStyleName (show toktype) (sCharStyleMap sm) = Nothing
490 | otherwise = Just $
472 | otherwise = Just $
491 mknode "w:style" [("w:type","character"),
473 mknode "w:style" [("w:type","character"),
492 ("w:customStyle","1"),("w:styleId",show toktype)]
474 ("w:customStyle","1"),("w:styleId",show toktype)]
@@ -509,7 +491,7 @@ styleToOpenXml (CharStyleMap csm) (ParaStyleMap psm) style =
509 tokBg toktype = maybe "auto" (drop 1 . fromColor)
491 tokBg toktype = maybe "auto" (drop 1 . fromColor)
510 $ (tokenBackground =<< lookup toktype tokStyles)
492 $ (tokenBackground =<< lookup toktype tokStyles)
511 `mplus` backgroundColor style
493 `mplus` backgroundColor style
512− parStyle | styleExists psm "Source Code" = Nothing
494+ parStyle | hasStyleName "Source Code" (sParaStyleMap sm) = Nothing
513 | otherwise = Just $
495 | otherwise = Just $
514 mknode "w:style" [("w:type","paragraph"),
496 mknode "w:style" [("w:type","paragraph"),
515 ("w:customStyle","1"),("w:styleId","SourceCode")]
497 ("w:customStyle","1"),("w:styleId","SourceCode")]
@@ -638,30 +620,27 @@ writeOpenXML opts (Pandoc meta blocks) = do
638blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element]
620blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element]
639blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
621blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
641−getStyleId :: String -> M.Map String String -> String
642−getStyleId s = M.findWithDefault (filter (/=' ') s) (map toLower s)
644−pStyle :: String -> ParaStyleMap -> Element
623+pStyle :: String -> StyleMaps -> Element
645−pStyle sty (ParaStyleMap m) = mknode "w:pStyle" [("w:val",sty')] ()
624+pStyle sty m = mknode "w:pStyle" [("w:val",sty')] ()
647− sty' = getStyleId sty m
626+ sty' = getStyleId sty $ sParaStyleMap m
649pCustomStyle :: String -> Element
628pCustomStyle :: String -> Element
650pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
629pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
652pStyleM :: String -> WS XML.Element
631pStyleM :: String -> WS XML.Element
653−pStyleM = flip fmap (gets stParaStyles) . pStyle
632+pStyleM = (`fmap` gets stStyleMaps) . pStyle
655−rStyle :: String -> CharStyleMap -> Element
634+rStyle :: String -> StyleMaps -> Element
656−rStyle sty (CharStyleMap m) = mknode "w:rStyle" [("w:val",sty')] ()
635+rStyle sty m = mknode "w:rStyle" [("w:val",sty')] ()
658− sty' = getStyleId sty m
637+ sty' = getStyleId sty $ sCharStyleMap m
660rCustomStyle :: String -> Element
639rCustomStyle :: String -> Element
661rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
640rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
663rStyleM :: String -> WS XML.Element
642rStyleM :: String -> WS XML.Element
664−rStyleM = flip fmap (gets stCharStyles) . rStyle
643+rStyleM = (`fmap` gets stStyleMaps) . rStyle
666getUniqueId :: MonadIO m => m String
645getUniqueId :: MonadIO m => m String
667-- the + 20 is to ensure that there are no clashes with the rIds
646-- the + 20 is to ensure that there are no clashes with the rIds
@@ -710,10 +689,10 @@ blockToOpenXML opts (Para lst) = do
710 paraProps <- getParaProps $ case lst of
689 paraProps <- getParaProps $ case lst of
711 [Math DisplayMath _] -> True
690 [Math DisplayMath _] -> True
712 _ -> False
691 _ -> False
713− pSM <- gets stParaStyles
692+ sm <- gets stStyleMaps
714 let paraProps' = case paraProps of
693 let paraProps' = case paraProps of
715 [] | isFirstPara -> [mknode "w:pPr" [] [pCustomStyle "FirstParagraph"]]
694 [] | isFirstPara -> [mknode "w:pPr" [] [pCustomStyle "FirstParagraph"]]
716− [] -> [mknode "w:pPr" [] [pStyle "Body Text" pSM]]
695+ [] -> [mknode "w:pPr" [] [pStyle "Body Text" sm]]
718 modify $ \s -> s { stFirstPara = False }
697 modify $ \s -> s { stFirstPara = False }
719 contents <- inlinesToOpenXML opts lst
698 contents <- inlinesToOpenXML opts lst