From d596b0db8321cdb9c018ac8037d301291d0cc63c Mon Sep 17 00:00:00 2001
From: John MacFarlane <fiddlosopher@gmail.com>
Date: Mon, 18 Mar 2013 19:31:48 -0700
Subject: Docx writer: Fixed rendering of display math in lists.

In 1.11 and 1.11.1, display math in lists rendered as a new list
item.  Now it always appears centered, just as outside of lists,
and in proper display math style, no matter how far indented the
containing list item is.

Closes #784.
---
 src/Text/Pandoc/Writers/Docx.hs | 40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

(limited to 'src')

diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 7a782efb6..0549772af 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -105,12 +105,13 @@ writeDocx :: WriterOptions  -- ^ Writer options
           -> IO BL.ByteString
 writeDocx opts doc@(Pandoc (Meta tit auths date) _) = do
   let datadir = writerUserDataDir opts
+  let doc' = bottomUp (concatMap fixDisplayMath) doc
   refArchive <- liftM (toArchive . toLazy) $
        case writerReferenceDocx opts of
              Just f  -> B.readFile f
              Nothing -> readDataFile datadir "reference.docx"
 
-  ((contents, footnotes), st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc)
+  ((contents, footnotes), st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc')
                        defaultWriterState
   epochtime <- floor `fmap` getPOSIXTime
   let imgs = M.elems $ stImages st
@@ -420,19 +421,17 @@ blockToOpenXML opts (Header lev (ident,_,_) lst) = do
 blockToOpenXML opts (Plain lst) = blockToOpenXML opts (Para lst)
 -- title beginning with fig: indicates that the image is a figure
 blockToOpenXML opts (Para [Image alt (src,'f':'i':'g':':':tit)]) = do
-  paraProps <- getParaProps
+  paraProps <- getParaProps False
   contents <- inlinesToOpenXML opts [Image alt (src,tit)]
   captionNode <- withParaProp (pStyle "ImageCaption")
                  $ blockToOpenXML opts (Para alt)
   return $ mknode "w:p" [] (paraProps ++ contents) : captionNode
-blockToOpenXML opts (Para lst)
-  | any isDisplayMath lst && not (all isDisplayMath lst) = do
-    -- chop into several paragraphs so each displaymath is its own
-    let lsts = groupBy (\x y -> (isDisplayMath x && isDisplayMath y) ||
-                         not (isDisplayMath x || isDisplayMath y)) lst
-    blocksToOpenXML opts (map Para lsts)
-  | otherwise = do
-    paraProps <- getParaProps
+-- fixDisplayMath sometimes produces a Para [] as artifact
+blockToOpenXML _ (Para []) = return []
+blockToOpenXML opts (Para lst) = do
+    paraProps <- getParaProps $ case lst of
+                                     [Math DisplayMath _] -> True
+                                     _                    -> False
     contents <- inlinesToOpenXML opts lst
     return [mknode "w:p" [] (paraProps ++ contents)]
 blockToOpenXML _ (RawBlock format str)
@@ -571,12 +570,12 @@ withTextProp d p = do
   popTextProp
   return res
 
-getParaProps :: WS [Element]
-getParaProps = do
+getParaProps :: Bool -> WS [Element]
+getParaProps displayMathPara = do
   props <- gets stParaProperties
   listLevel <- gets stListLevel
   numid <- gets stListNumId
-  let listPr = if listLevel >= 0
+  let listPr = if listLevel >= 0 && not displayMathPara
                   then [ mknode "w:numPr" []
                          [ mknode "w:numId" [("w:val",show numid)] ()
                          , mknode "w:ilvl" [("w:val",show listLevel)] () ]
@@ -775,3 +774,18 @@ parseXml refArchive relpath =
 isDisplayMath :: Inline -> Bool
 isDisplayMath (Math DisplayMath _) = True
 isDisplayMath _                    = False
+
+stripLeadingTrailingSpace :: [Inline] -> [Inline]
+stripLeadingTrailingSpace = go . reverse . go . reverse
+  where go (Space:xs) = xs
+        go xs         = xs
+
+fixDisplayMath :: Block -> [Block]
+fixDisplayMath (Plain lst) = fixDisplayMath (Para lst)
+fixDisplayMath (Para lst)
+  | any isDisplayMath lst && not (all isDisplayMath lst) =
+    -- chop into several paragraphs so each displaymath is its own
+    map (Para . stripLeadingTrailingSpace) $
+       groupBy (\x y -> (isDisplayMath x && isDisplayMath y) ||
+                         not (isDisplayMath x || isDisplayMath y)) lst
+fixDisplayMath x = [x]
-- 
cgit v1.2.3