@@ -82,6 +82,7 @@ import qualified Data.ByteString.Lazy as B
82import Data.Default (Default)
82import Data.Default (Default)
83import Data.List (delete, intersect)
83import Data.List (delete, intersect)
84import qualified Data.Map as M
84import qualified Data.Map as M
85+import Data.Maybe (isJust)
85import Data.Sequence (ViewL (..), viewl)
86import Data.Sequence (ViewL (..), viewl)
86import qualified Data.Sequence as Seq
87import qualified Data.Sequence as Seq
87import qualified Data.Set as Set
88import qualified Data.Set as Set
@@ -119,6 +120,7 @@ readDocx _ _ =
120data DState = DState { docxAnchorMap :: M.Map String String
121data DState = DState { docxAnchorMap :: M.Map String String
121 , docxAnchorSet :: Set.Set String
122 , docxAnchorSet :: Set.Set String
123+ , docxImmedPrevAnchor :: Maybe String
122 , docxMediaBag :: MediaBag
124 , docxMediaBag :: MediaBag
123 , docxDropCap :: Inlines
125 , docxDropCap :: Inlines
124 , docxWarnings :: [String]
126 , docxWarnings :: [String]
@@ -130,6 +132,7 @@ data DState = DState { docxAnchorMap :: M.Map String String
130instance Default DState where
132instance Default DState where
131 def = DState { docxAnchorMap = M.empty
133 def = DState { docxAnchorMap = M.empty
132 , docxAnchorSet = mempty
134 , docxAnchorSet = mempty
135+ , docxImmedPrevAnchor = Nothing
133 , docxMediaBag = mempty
136 , docxMediaBag = mempty
134 , docxDropCap = mempty
137 , docxDropCap = mempty
135 , docxWarnings = []
138 , docxWarnings = []
@@ -341,9 +344,26 @@ blocksToInlinesWarn cmtId blks = do
341 "Docx comment " ++ cmtId ++ " will not retain formatting"
344 "Docx comment " ++ cmtId ++ " will not retain formatting"
342 return $ blocksToInlines' blkList
345 return $ blocksToInlines' blkList
347+-- The majority of work in this function is done in the primted
348+-- subfunction `partPartToInlines'`. We make this wrapper so that we
349+-- don't have to modify `docxImmedPrevAnchor` state after every function.
344parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
350parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
351+parPartToInlines parPart =
353+ (BookMark _ anchor) | not $ anchor `elem` dummyAnchors -> do
354+ inHdrBool <- asks docxInHeaderBlock
355+ ils <- parPartToInlines' parPart
356+ immedPrevAnchor <- gets docxImmedPrevAnchor
357+ unless (isJust immedPrevAnchor || inHdrBool)
358+ (modify $ \s -> s{ docxImmedPrevAnchor = Just anchor})
361+ ils <- parPartToInlines' parPart
362+ modify $ \s -> s{ docxImmedPrevAnchor = Nothing}
364+parPartToInlines' :: PandocMonad m => ParPart -> DocxContext m Inlines
345−parPartToInlines (PlainRun r) = runToInlines r
365+parPartToInlines' (PlainRun r) = runToInlines r
346−parPartToInlines (Insertion _ author date runs) = do
366+parPartToInlines' (Insertion _ author date runs) = do
347 opts <- asks docxOptions
367 opts <- asks docxOptions
348 case readerTrackChanges opts of
368 case readerTrackChanges opts of
349 AcceptChanges -> smushInlines <$> mapM runToInlines runs
369 AcceptChanges -> smushInlines <$> mapM runToInlines runs
@@ -352,7 +372,7 @@ parPartToInlines (Insertion _ author date runs) = do
352 ils <- smushInlines <$> mapM runToInlines runs
372 ils <- smushInlines <$> mapM runToInlines runs
353 let attr = ("", ["insertion"], [("author", author), ("date", date)])
373 let attr = ("", ["insertion"], [("author", author), ("date", date)])
354 return $ spanWith attr ils
374 return $ spanWith attr ils
355−parPartToInlines (Deletion _ author date runs) = do
375+parPartToInlines' (Deletion _ author date runs) = do
356 opts <- asks docxOptions
376 opts <- asks docxOptions
357 case readerTrackChanges opts of
377 case readerTrackChanges opts of
358 AcceptChanges -> return mempty
378 AcceptChanges -> return mempty
@@ -361,7 +381,7 @@ parPartToInlines (Deletion _ author date runs) = do
361 ils <- smushInlines <$> mapM runToInlines runs
381 ils <- smushInlines <$> mapM runToInlines runs
362 let attr = ("", ["deletion"], [("author", author), ("date", date)])
382 let attr = ("", ["deletion"], [("author", author), ("date", date)])
363 return $ spanWith attr ils
383 return $ spanWith attr ils
364−parPartToInlines (CommentStart cmtId author date bodyParts) = do
384+parPartToInlines' (CommentStart cmtId author date bodyParts) = do
365 opts <- asks docxOptions
385 opts <- asks docxOptions
366 case readerTrackChanges opts of
386 case readerTrackChanges opts of
367 AllChanges -> do
387 AllChanges -> do
@@ -370,16 +390,16 @@ parPartToInlines (CommentStart cmtId author date bodyParts) = do
370 let attr = ("", ["comment-start"], [("id", cmtId), ("author", author), ("date", date)])
390 let attr = ("", ["comment-start"], [("id", cmtId), ("author", author), ("date", date)])
371 return $ spanWith attr ils
391 return $ spanWith attr ils
372 _ -> return mempty
392 _ -> return mempty
373−parPartToInlines (CommentEnd cmtId) = do
393+parPartToInlines' (CommentEnd cmtId) = do
374 opts <- asks docxOptions
394 opts <- asks docxOptions
375 case readerTrackChanges opts of
395 case readerTrackChanges opts of
376 AllChanges -> do
396 AllChanges -> do
377 let attr = ("", ["comment-end"], [("id", cmtId)])
397 let attr = ("", ["comment-end"], [("id", cmtId)])
378 return $ spanWith attr mempty
398 return $ spanWith attr mempty
379 _ -> return mempty
399 _ -> return mempty
380−parPartToInlines (BookMark _ anchor) | anchor `elem` dummyAnchors =
400+parPartToInlines' (BookMark _ anchor) | anchor `elem` dummyAnchors =
381 return mempty
401 return mempty
382−parPartToInlines (BookMark _ anchor) =
402+parPartToInlines' (BookMark _ anchor) =
383 -- We record these, so we can make sure not to overwrite
403 -- We record these, so we can make sure not to overwrite
384 -- user-defined anchor links with header auto ids.
404 -- user-defined anchor links with header auto ids.
@@ -395,27 +415,34 @@ parPartToInlines (BookMark _ anchor) =
395 -- of rewriting user-defined anchor links. However, since these
415 -- of rewriting user-defined anchor links. However, since these
396 -- are not defined in pandoc, it seems like a necessary evil to
416 -- are not defined in pandoc, it seems like a necessary evil to
397 -- avoid an extra pass.
417 -- avoid an extra pass.
418+ immedPrevAnchor <- gets docxImmedPrevAnchor
419+ case immedPrevAnchor of
420+ Just prevAnchor -> do
422+ (modify $ \s -> s { docxAnchorMap = M.insert anchor prevAnchor anchorMap})
398− let newAnchor =
425+ let newAnchor =
399− if not inHdrBool && anchor `elem` M.elems anchorMap
426+ if not inHdrBool && anchor `elem` M.elems anchorMap
400− then uniqueIdent [Str anchor] (Set.fromList $ M.elems anchorMap)
427+ then uniqueIdent [Str anchor] (Set.fromList $ M.elems anchorMap)
401− else anchor
428+ else anchor
402− unless inHdrBool
429+ unless inHdrBool
403− (modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
430+ (modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
404− return $ spanWith (newAnchor, ["anchor"], []) mempty
431+ return $ spanWith (newAnchor, ["anchor"], []) mempty
405−parPartToInlines (Drawing fp title alt bs ext) = do
432+parPartToInlines' (Drawing fp title alt bs ext) = do
406 (lift . lift) $ P.insertMedia fp Nothing bs
433 (lift . lift) $ P.insertMedia fp Nothing bs
407 return $ imageWith (extentToAttr ext) fp title $ text alt
434 return $ imageWith (extentToAttr ext) fp title $ text alt
408−parPartToInlines Chart =
435+parPartToInlines' Chart =
409 return $ spanWith ("", ["chart"], []) $ text "[CHART]"
436 return $ spanWith ("", ["chart"], []) $ text "[CHART]"
410−parPartToInlines (InternalHyperLink anchor runs) = do
437+parPartToInlines' (InternalHyperLink anchor runs) = do
411 ils <- smushInlines <$> mapM runToInlines runs
438 ils <- smushInlines <$> mapM runToInlines runs
412 return $ link ('#' : anchor) "" ils
439 return $ link ('#' : anchor) "" ils
413−parPartToInlines (ExternalHyperLink target runs) = do
440+parPartToInlines' (ExternalHyperLink target runs) = do
414 ils <- smushInlines <$> mapM runToInlines runs
441 ils <- smushInlines <$> mapM runToInlines runs
415 return $ link target "" ils
442 return $ link target "" ils
416−parPartToInlines (PlainOMath exps) =
443+parPartToInlines' (PlainOMath exps) =
417 return $ math $ writeTeX exps
444 return $ math $ writeTeX exps
418−parPartToInlines (SmartTag runs) = do
445+parPartToInlines' (SmartTag runs) = do
419 smushInlines <$> mapM runToInlines runs
446 smushInlines <$> mapM runToInlines runs
421isAnchorSpan :: Inline -> Bool
448isAnchorSpan :: Inline -> Bool