git.iko.soy/typeable/pandoc
on master help sign in
Docx Reader: Introduce link rewriting.
dce360eJesse Rosenthal
src/Text/Pandoc/Readers/Docx.hs+30−7
@@ -104,7 +104,7 @@ readDocx opts bytes =
104 Nothing -> error $ "couldn't parse docx file"
104 Nothing -> error $ "couldn't parse docx file"
105
105
106
106
107−data DState = DState { docxHeaderAnchors :: M.Map String String }
107+data DState = DState { docxAnchorMap :: M.Map String String }
108
108
109data DEnv = DEnv { docxOptions :: ReaderOptions
109data DEnv = DEnv { docxOptions :: ReaderOptions
110 , docxDocument :: Docx}
110 , docxDocument :: Docx}
@@ -276,7 +276,22 @@ parPartToInlines (Deletion _ author date runs) = do
276 ("", ["deletion"], [("author", author), ("date", date)])
276 ("", ["deletion"], [("author", author), ("date", date)])
277 ils]
277 ils]
278parPartToInlines (BookMark _ anchor) | anchor `elem` dummyAnchors = return []
278parPartToInlines (BookMark _ anchor) | anchor `elem` dummyAnchors = return []
279−parPartToInlines (BookMark _ anchor) = return [Span (anchor, ["anchor"], []) []]
279+parPartToInlines (BookMark _ anchor) =
280+ -- We record these, so we can make sure not to overwrite
281+ -- user-defined anchor links with header auto ids.
282+ do
283+ -- Get the anchor map.
284+ anchorMap <- gets docxAnchorMap
285+ -- Check to see if the id is already in there. Rewrite if
286+ -- necessary. This will have the possible effect of rewriting
287+ -- user-defined anchor links. However, since these are not defined
288+ -- in pandoc, it seems like a necessary evil to avoid an extra
289+ -- pass.
290+ let newAnchor = case anchor `elem` (M.elems anchorMap) of
291+ True -> uniqueIdent [Str anchor] (M.elems anchorMap)
292+ False -> anchor
293+ put DState{ docxAnchorMap = M.insert anchor newAnchor anchorMap}
294+ return [Span (anchor, ["anchor"], []) []]
280parPartToInlines (Drawing relid) = do
295parPartToInlines (Drawing relid) = do
281 (Docx _ _ _ rels _) <- asks docxDocument
296 (Docx _ _ _ rels _) <- asks docxDocument
282 return $ case lookupRelationship relid rels of
297 return $ case lookupRelationship relid rels of
@@ -311,9 +326,9 @@ makeHeaderAnchor (Header n (_, classes, kvs) ils)
311 , (Span (ident, _, _) _) <- x
326 , (Span (ident, _, _) _) <- x
312 , notElem ident dummyAnchors =
327 , notElem ident dummyAnchors =
313 do
328 do
314− hdrIDMap <- gets docxHeaderAnchors
329+ hdrIDMap <- gets docxAnchorMap
315 let newIdent = uniqueIdent ils (M.elems hdrIDMap)
330 let newIdent = uniqueIdent ils (M.elems hdrIDMap)
316− put DState{docxHeaderAnchors = M.insert ident newIdent hdrIDMap}
331+ put DState{docxAnchorMap = M.insert ident newIdent hdrIDMap}
317 return $ Header n (newIdent, classes, kvs) (ils \\ (x:xs))
332 return $ Header n (newIdent, classes, kvs) (ils \\ (x:xs))
318makeHeaderAnchor blk = return blk
333makeHeaderAnchor blk = return blk
319
334
@@ -411,6 +426,14 @@ bodyPartToBlocks (Tbl cap _ look (r:rs)) = do
411
426
412 return [Table caption alignments widths hdrCells cells]
427 return [Table caption alignments widths hdrCells cells]
413
428
429+-- replace targets with generated anchors.
430+rewriteLink :: Inline -> DocxContext Inline
431+rewriteLink l@(Link ils ('#':target, title)) = do
432+ anchorMap <- gets docxAnchorMap
433+ return $ case M.lookup target anchorMap of
434+ Just newTarget -> (Link ils ('#':newTarget, title))
435+ Nothing -> l
436+rewriteLink il = return il
414
437
415makeImagesSelfContained :: Inline -> DocxContext Inline
438makeImagesSelfContained :: Inline -> DocxContext Inline
416makeImagesSelfContained i@(Image alt (uri, title)) = do
439makeImagesSelfContained i@(Image alt (uri, title)) = do
@@ -429,14 +452,15 @@ makeImagesSelfContained inline = return inline
429
452
430bodyToBlocks :: Body -> DocxContext [Block]
453bodyToBlocks :: Body -> DocxContext [Block]
431bodyToBlocks (Body bps) = do
454bodyToBlocks (Body bps) = do
432− blks <- concatMapM bodyPartToBlocks bps
455+ blks <- concatMapM bodyPartToBlocks bps >>=
456+ walkM rewriteLink
433 return $
457 return $
434 blocksToDefinitions $
458 blocksToDefinitions $
435 blocksToBullets $ blks
459 blocksToBullets $ blks
436
460
437docxToBlocks :: ReaderOptions -> Docx -> [Block]
461docxToBlocks :: ReaderOptions -> Docx -> [Block]
438docxToBlocks opts d@(Docx (Document _ body) _ _ _ _) =
462docxToBlocks opts d@(Docx (Document _ body) _ _ _ _) =
439− let dState = DState { docxHeaderAnchors = M.empty }
463+ let dState = DState { docxAnchorMap = M.empty }
440 dEnv = DEnv { docxOptions = opts
464 dEnv = DEnv { docxOptions = opts
441 , docxDocument = d}
465 , docxDocument = d}
442 in
466 in
@@ -447,7 +471,6 @@ ilToCode (Str s) = s
447ilToCode Space = " "
471ilToCode Space = " "
448ilToCode _ = ""
472ilToCode _ = ""
449
473
450−
451isHeaderClass :: String -> Maybe Int
474isHeaderClass :: String -> Maybe Int
452isHeaderClass s | "Heading" `isPrefixOf` s =
475isHeaderClass s | "Heading" `isPrefixOf` s =
453 case reads (drop (length "Heading") s) :: [(Int, String)] of
476 case reads (drop (length "Heading") s) :: [(Int, String)] of