git.iko.soy/typeable/pandoc
on master help sign in
Docx writer: Fix bookmarks to headers with long titles.
d333c28John MacFarlane
Makefile+1−1
@@ -2,7 +2,7 @@ version?=$(shell grep '^[Vv]ersion:' pandoc.cabal | awk '{print $$2;}')
2pandoc=$(shell find dist -name pandoc -type f -exec ls -t {} \; | head -1)
2pandoc=$(shell find dist -name pandoc -type f -exec ls -t {} \; | head -1)
3SOURCEFILES?=$(shell find pandoc.hs src test -name '*.hs')
3SOURCEFILES?=$(shell find pandoc.hs src test -name '*.hs')
4BRANCH?=master
4BRANCH?=master
5−RESOLVER=lts-12
5+RESOLVER?=lts-12
6GHCOPTS=-fdiagnostics-color=always -Wall -fno-warn-unused-do-bind -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -Wincomplete-uni-patterns -Werror=missing-home-modules -Widentities -Wcpp-undef -fhide-source-paths -j +RTS -A32M -RTS
6GHCOPTS=-fdiagnostics-color=always -Wall -fno-warn-unused-do-bind -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -Wincomplete-uni-patterns -Werror=missing-home-modules -Widentities -Wcpp-undef -fhide-source-paths -j +RTS -A32M -RTS
7# Later:
7# Later:
8# -Wpartial-fields (currently used in Powerpoint writer)
8# -Wpartial-fields (currently used in Powerpoint writer)
src/Text/Pandoc/Writers/Docx.hs+18−4
@@ -41,19 +41,21 @@ import Control.Monad.Reader
41import Control.Monad.State.Strict
41import Control.Monad.State.Strict
42import qualified Data.ByteString as B
42import qualified Data.ByteString as B
43import qualified Data.ByteString.Lazy as BL
43import qualified Data.ByteString.Lazy as BL
44−import Data.Char (isSpace, ord, toLower)
44+import Data.Char (isSpace, ord, toLower, isLetter)
45import Data.List (intercalate, isPrefixOf, isSuffixOf)
45import Data.List (intercalate, isPrefixOf, isSuffixOf)
46import qualified Data.Map as M
46import qualified Data.Map as M
47import Data.Maybe (fromMaybe, isNothing, mapMaybe, maybeToList)
47import Data.Maybe (fromMaybe, isNothing, mapMaybe, maybeToList)
48import qualified Data.Set as Set
48import qualified Data.Set as Set
49import qualified Data.Text as T
49import qualified Data.Text as T
50import Data.Time.Clock.POSIX
50import Data.Time.Clock.POSIX
51+import Data.Digest.Pure.SHA (sha1, showDigest)
51import Skylighting
52import Skylighting
52import System.Random (randomR, StdGen, mkStdGen)
53import System.Random (randomR, StdGen, mkStdGen)
53import Text.Pandoc.BCP47 (getLang, renderLang)
54import Text.Pandoc.BCP47 (getLang, renderLang)
54import Text.Pandoc.Class (PandocMonad, report, toLang)
55import Text.Pandoc.Class (PandocMonad, report, toLang)
55import qualified Text.Pandoc.Class as P
56import qualified Text.Pandoc.Class as P
56import Data.Time
57import Data.Time
58+import Text.Pandoc.UTF8 (fromStringLazy)
57import Text.Pandoc.Definition
59import Text.Pandoc.Definition
58import Text.Pandoc.Generic
60import Text.Pandoc.Generic
59import Text.Pandoc.Highlighting (highlight)
61import Text.Pandoc.Highlighting (highlight)
@@ -1268,7 +1270,8 @@ inlineToOpenXML' opts (Note bs) = do
1268-- internal link:
1270-- internal link:
1269inlineToOpenXML' opts (Link _ txt ('#':xs,_)) = do
1271inlineToOpenXML' opts (Link _ txt ('#':xs,_)) = do
1270 contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
1272 contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
1273+ return
1271− return [ mknode "w:hyperlink" [("w:anchor",xs)] contents ]
1274+ [ mknode "w:hyperlink" [("w:anchor", toBookmarkName xs)] contents ]
1272-- external link:
1275-- external link:
1273inlineToOpenXML' opts (Link _ txt (src,_)) = do
1276inlineToOpenXML' opts (Link _ txt (src,_)) = do
1274 contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
1277 contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
@@ -1427,7 +1430,18 @@ wrapBookmark :: (PandocMonad m) => String -> [Element] -> WS m [Element]
1427wrapBookmark [] contents = return contents
1430wrapBookmark [] contents = return contents
1428wrapBookmark ident contents = do
1431wrapBookmark ident contents = do
1429 id' <- getUniqueId
1432 id' <- getUniqueId
1430− let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id')
1433+ let bookmarkStart = mknode "w:bookmarkStart"
1434+ [("w:id", id')
1431− ,("w:name",ident)] ()
1435+ ,("w:name", toBookmarkName ident)] ()
1432 bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
1436 bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
1433 return $ bookmarkStart : contents ++ [bookmarkEnd]
1437 return $ bookmarkStart : contents ++ [bookmarkEnd]
1438+
1439+-- Word imposes a 40 character limit on bookmark names and requires
1440+-- that they begin with a letter. So we just use a hash of the
1441+-- identifer when otherwise we'd have an illegal bookmark name.
1442+toBookmarkName :: String -> String
1443+toBookmarkName s =
1444+ case s of
1445+ (c:_) | isLetter c
1446+ , length s <= 40 -> s
1447+ _ -> 'X' : drop 1 (showDigest (sha1 (fromStringLazy s)))
test/docx/golden/nested_anchors_in_header.docx

Binary file not shown.