@@ -24,12 +24,13 @@ import Control.Monad.State.Strict (StateT, evalState, evalStateT, get,
2424 gets, lift, modify)
2525import qualified Data.ByteString.Lazy as B
2626import qualified Data.ByteString.Lazy.Char8 as B8
27−import Data.Char (isAlphaNum, isAscii, isDigit, toLower)
27+import Data.Char (isAlphaNum, isAscii, isDigit)
2828import Data.List (isInfixOf, isPrefixOf)
2929import qualified Data.Map as M
3030import Data.Maybe (fromMaybe, isNothing, mapMaybe, isJust)
3131import qualified Data.Set as Set
32−import qualified Data.Text as TS
32+import qualified Data.Text as T
33+import Data.Text (Text)
3334import qualified Data.Text.Lazy as TL
3435import Network.HTTP (urlEncode)
3536import System.FilePath (takeExtension, takeFileName, makeRelative)
@@ -48,16 +49,13 @@ import Text.Pandoc.Options (EPUBVersion (..), HTMLMathMethod (..),
4849 ObfuscationMethod (NoObfuscation), WrapOption (..),
4950 WriterOptions (..))
5051import Text.Pandoc.Shared (makeSections, normalizeDate, renderTags',
51− safeRead, stringify, trim, uniqueIdent, tshow)
52+ stringify, uniqueIdent, tshow)
5253import qualified Text.Pandoc.UTF8 as UTF8
5354import Text.Pandoc.UUID (getRandomUUID)
5455import Text.Pandoc.Walk (query, walk, walkM)
5556import Text.Pandoc.Writers.HTML (writeHtmlStringForEPUB)
5657import Text.Printf (printf)
57−import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..),
58− add_attrs, lookupAttr, node, onlyElems,
59− ppElement, showElement, strContent, unode, unqual)
60−import Text.Pandoc.XMLParser (parseXMLContents)
58+import Text.Pandoc.XML.Light
6159import Text.Pandoc.XML (escapeStringForXML)
6260import Text.DocTemplates (FromContext(lookupContext), Context(..),
6361 ToContext(toVal), Val(..))
@@ -69,7 +67,7 @@ newtype Chapter = Chapter [Block]
6967data EPUBState = EPUBState {
7068 stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))]
7169 , stMediaNextId :: Int
72− , stEpubSubdir :: String
70+ , stEpubSubdir :: FilePath
7371 }
7472
7573type E m = StateT EPUBState m
@@ -78,62 +76,63 @@ data EPUBMetadata = EPUBMetadata{
7876 epubIdentifier :: [Identifier]
7977 , epubTitle :: [Title]
8078 , epubDate :: [Date]
81− , epubLanguage :: String
79+ , epubLanguage :: Text
8280 , epubCreator :: [Creator]
8381 , epubContributor :: [Creator]
84− , epubSubject :: [String]
85− , epubDescription :: Maybe String
86− , epubType :: Maybe String
87− , epubFormat :: Maybe String
88− , epubPublisher :: Maybe String
89− , epubSource :: Maybe String
90− , epubRelation :: Maybe String
91− , epubCoverage :: Maybe String
92− , epubRights :: Maybe String
93− , epubBelongsToCollection :: Maybe String
94− , epubGroupPosition :: Maybe String
95− , epubCoverImage :: Maybe String
82+ , epubSubject :: [Text]
83+ , epubDescription :: Maybe Text
84+ , epubType :: Maybe Text
85+ , epubFormat :: Maybe Text
86+ , epubPublisher :: Maybe Text
87+ , epubSource :: Maybe Text
88+ , epubRelation :: Maybe Text
89+ , epubCoverage :: Maybe Text
90+ , epubRights :: Maybe Text
91+ , epubBelongsToCollection :: Maybe Text
92+ , epubGroupPosition :: Maybe Text
93+ , epubCoverImage :: Maybe FilePath
9694 , epubStylesheets :: [FilePath]
9795 , epubPageDirection :: Maybe ProgressionDirection
98− , epubIbooksFields :: [(String, String)]
99− , epubCalibreFields :: [(String, String)]
96+ , epubIbooksFields :: [(Text, Text)]
97+ , epubCalibreFields :: [(Text, Text)]
10098 } deriving Show
10199
102100data Date = Date{
103− dateText :: String
104− , dateEvent :: Maybe String
101+ dateText :: Text
102+ , dateEvent :: Maybe Text
105103 } deriving Show
106104
107105data Creator = Creator{
108− creatorText :: String
109− , creatorRole :: Maybe String
110− , creatorFileAs :: Maybe String
106+ creatorText :: Text
107+ , creatorRole :: Maybe Text
108+ , creatorFileAs :: Maybe Text
111109 } deriving Show
112110
113111data Identifier = Identifier{
114− identifierText :: String
115− , identifierScheme :: Maybe String
112+ identifierText :: Text
113+ , identifierScheme :: Maybe Text
116114 } deriving Show
117115
118116data Title = Title{
119− titleText :: String
120− , titleFileAs :: Maybe String
121− , titleType :: Maybe String
117+ titleText :: Text
118+ , titleFileAs :: Maybe Text
119+ , titleType :: Maybe Text
122120 } deriving Show
123121
124122data ProgressionDirection = LTR | RTL deriving Show
125123
126−dcName :: String -> QName
124+dcName :: Text -> QName
127125dcName n = QName n Nothing (Just "dc")
128126
129−dcNode :: Node t => String -> t -> Element
127+dcNode :: Node t => Text -> t -> Element
130128dcNode = node . dcName
131129
132−opfName :: String -> QName
130+opfName :: Text -> QName
133131opfName n = QName n Nothing (Just "opf")
134132
135−toId :: FilePath -> String
136−toId = map (\x -> if isAlphaNum x || x == '-' || x == '_'
133+toId :: FilePath -> Text
134+toId = T.pack .
135+ map (\x -> if isAlphaNum x || x == '-' || x == '_'
137136 then x
138137 else '_') . takeFileName
139138
@@ -141,8 +140,8 @@ removeNote :: Inline -> Inline
141140removeNote (Note _) = Str ""
142141removeNote x = x
143142
144−toVal' :: String -> Val TS.Text
145−toVal' = toVal . TS.pack
143+toVal' :: Text -> Val T.Text
144+toVal' = toVal
146145
147146mkEntry :: PandocMonad m => FilePath -> B.ByteString -> E m Entry
148147mkEntry path content = do
@@ -172,21 +171,21 @@ getEPUBMetadata opts meta = do
172171 if null (epubIdentifier m)
173172 then do
174173 randomId <- getRandomUUID
175− return $ m{ epubIdentifier = [Identifier (show randomId) Nothing] }
174+ return $ m{ epubIdentifier = [Identifier (tshow randomId) Nothing] }
176175 else return m
177176 let addLanguage m =
178− if null (epubLanguage m)
177+ if T.null (epubLanguage m)
179178 then case lookupContext "lang" (writerVariables opts) of
180− Just x -> return m{ epubLanguage = TS.unpack x }
179+ Just x -> return m{ epubLanguage = x }
181180 Nothing -> do
182181 mLang <- lift $ P.lookupEnv "LANG"
183182 let localeLang =
184183 case mLang of
185184 Just lang ->
186− TS.map (\c -> if c == '_' then '-' else c) $
187− TS.takeWhile (/='.') lang
185+ T.map (\c -> if c == '_' then '-' else c) $
186+ T.takeWhile (/='.') lang
188187 Nothing -> "en-US"
189− return m{ epubLanguage = TS.unpack localeLang }
188+ return m{ epubLanguage = localeLang }
190189 else return m
191190 let fixDate m =
192191 if null (epubDate m)
@@ -201,7 +200,7 @@ getEPUBMetadata opts meta = do
201200 then return m
202201 else do
203202 let authors' = map stringify $ docAuthors meta
204− let toAuthor name = Creator{ creatorText = TS.unpack name
203+ let toAuthor name = Creator{ creatorText = name
205204 , creatorRole = Just "aut"
206205 , creatorFileAs = Nothing }
207206 return $ m{ epubCreator = map toAuthor authors' ++ epubCreator m }
@@ -249,31 +248,31 @@ addMetadataFromXML e@(Element (QName name _ (Just "dc")) attrs _ _) md
249248 where getAttr n = lookupAttr (opfName n) attrs
250249addMetadataFromXML e@(Element (QName "meta" _ _) attrs _ _) md =
251250 case getAttr "property" of
252− Just s | "ibooks:" `isPrefixOf` s ->
253− md{ epubIbooksFields = (drop 7 s, strContent e) :
251+ Just s | "ibooks:" `T.isPrefixOf` s ->
252+ md{ epubIbooksFields = (T.drop 7 s, strContent e) :
254253 epubIbooksFields md }
255254 _ -> case getAttr "name" of
256− Just s | "calibre:" `isPrefixOf` s ->
255+ Just s | "calibre:" `T.isPrefixOf` s ->
257256 md{ epubCalibreFields =
258− (drop 8 s, fromMaybe "" $ getAttr "content") :
257+ (T.drop 8 s, fromMaybe "" $ getAttr "content") :
259258 epubCalibreFields md }
260259 _ -> md
261260 where getAttr n = lookupAttr (unqual n) attrs
262261addMetadataFromXML _ md = md
263262
264−metaValueToString :: MetaValue -> String
265−metaValueToString (MetaString s) = TS.unpack s
266−metaValueToString (MetaInlines ils) = TS.unpack $ stringify ils
267−metaValueToString (MetaBlocks bs) = TS.unpack $ stringify bs
263+metaValueToString :: MetaValue -> Text
264+metaValueToString (MetaString s) = s
265+metaValueToString (MetaInlines ils) = stringify ils
266+metaValueToString (MetaBlocks bs) = stringify bs
268267metaValueToString (MetaBool True) = "true"
269268metaValueToString (MetaBool False) = "false"
270269metaValueToString _ = ""
271270
272271metaValueToPaths :: MetaValue -> [FilePath]
273−metaValueToPaths (MetaList xs) = map metaValueToString xs
274−metaValueToPaths x = [metaValueToString x]
272+metaValueToPaths (MetaList xs) = map (T.unpack . metaValueToString) xs
273+metaValueToPaths x = [T.unpack $ metaValueToString x]
275274
276−getList :: TS.Text -> Meta -> (MetaValue -> a) -> [a]
275+getList :: T.Text -> Meta -> (MetaValue -> a) -> [a]
277276getList s meta handleMetaValue =
278277 case lookupMeta s meta of
279278 Just (MetaList xs) -> map handleMetaValue xs
@@ -297,7 +296,7 @@ getTitle meta = getList "title" meta handleMetaValue
297296 , titleType = metaValueToString <$> M.lookup "type" m }
298297 handleMetaValue mv = Title (metaValueToString mv) Nothing Nothing
299298
300−getCreator :: TS.Text -> Meta -> [Creator]
299+getCreator :: T.Text -> Meta -> [Creator]
301300getCreator s meta = getList s meta handleMetaValue
302301 where handleMetaValue (MetaMap m) =
303302 Creator{ creatorText = maybe "" metaValueToString $ M.lookup "text" m
@@ -305,7 +304,7 @@ getCreator s meta = getList s meta handleMetaValue
305304 , creatorRole = metaValueToString <$> M.lookup "role" m }
306305 handleMetaValue mv = Creator (metaValueToString mv) Nothing Nothing
307306
308−getDate :: TS.Text -> Meta -> [Date]
307+getDate :: T.Text -> Meta -> [Date]
309308getDate s meta = getList s meta handleMetaValue
310309 where handleMetaValue (MetaMap m) =
311310 Date{ dateText = fromMaybe "" $
@@ -314,7 +313,7 @@ getDate s meta = getList s meta handleMetaValue
314313 handleMetaValue mv = Date { dateText = fromMaybe "" $ normalizeDate' $ metaValueToString mv
315314 , dateEvent = Nothing }
316315
317−simpleList :: TS.Text -> Meta -> [String]
316+simpleList :: T.Text -> Meta -> [Text]
318317simpleList s meta =
319318 case lookupMeta s meta of
320319 Just (MetaList xs) -> map metaValueToString xs
@@ -339,7 +338,7 @@ metadataFromMeta opts meta = EPUBMetadata{
339338 , epubCoverage = coverage
340339 , epubRights = rights
341340 , epubBelongsToCollection = belongsToCollection
342− , epubGroupPosition = groupPosition
341+ , epubGroupPosition = groupPosition
343342 , epubCoverImage = coverImage
344343 , epubStylesheets = stylesheets
345344 , epubPageDirection = pageDirection
@@ -363,31 +362,30 @@ metadataFromMeta opts meta = EPUBMetadata{
363362 coverage = metaValueToString <$> lookupMeta "coverage" meta
364363 rights = metaValueToString <$> lookupMeta "rights" meta
365364 belongsToCollection = metaValueToString <$> lookupMeta "belongs-to-collection" meta
366− groupPosition = metaValueToString <$> lookupMeta "group-position" meta
367− coverImage =
368− (TS.unpack <$> lookupContext "epub-cover-image"
369− (writerVariables opts))
365+ groupPosition = metaValueToString <$> lookupMeta "group-position" meta
366+ coverImage = T.unpack <$>
367+ lookupContext "epub-cover-image" (writerVariables opts)
370368 `mplus` (metaValueToString <$> lookupMeta "cover-image" meta)
371369 mCss = lookupMeta "css" meta <|> lookupMeta "stylesheet" meta
372370 stylesheets = maybe [] metaValueToPaths mCss ++
373371 case lookupContext "css" (writerVariables opts) of
374− Just xs -> map TS.unpack xs
372+ Just xs -> map T.unpack xs
375373 Nothing ->
376374 case lookupContext "css" (writerVariables opts) of
377− Just x -> [TS.unpack x]
375+ Just x -> [T.unpack x]
378376 Nothing -> []
379− pageDirection = case map toLower . metaValueToString <$>
377+ pageDirection = case T.toLower . metaValueToString <$>
380378 lookupMeta "page-progression-direction" meta of
381379 Just "ltr" -> Just LTR
382380 Just "rtl" -> Just RTL
383381 _ -> Nothing
384382 ibooksFields = case lookupMeta "ibooks" meta of
385383 Just (MetaMap mp)
386− -> M.toList $ M.mapKeys TS.unpack $ M.map metaValueToString mp
384+ -> M.toList $ M.map metaValueToString mp
387385 _ -> []
388386 calibreFields = case lookupMeta "calibre" meta of
389387 Just (MetaMap mp)
390− -> M.toList $ M.mapKeys TS.unpack $ M.map metaValueToString mp
388+ -> M.toList $ M.map metaValueToString mp
391389 _ -> []
392390
393391-- | Produce an EPUB2 file from a Pandoc document.
@@ -413,9 +411,11 @@ writeEPUB :: PandocMonad m
413411writeEPUB epubVersion opts doc = do
414412 let epubSubdir = writerEpubSubdirectory opts
415413 -- sanity check on epubSubdir
416− unless (TS.all (\c -> isAscii c && isAlphaNum c) epubSubdir) $
414+ unless (T.all (\c -> isAscii c && isAlphaNum c) epubSubdir) $
417415 throwError $ PandocEpubSubdirectoryError epubSubdir
418− let initState = EPUBState { stMediaPaths = [], stMediaNextId = 0, stEpubSubdir = TS.unpack epubSubdir }
416+ let initState = EPUBState { stMediaPaths = []
417+ , stMediaNextId = 0
418+ , stEpubSubdir = T.unpack epubSubdir }
419419 evalStateT (pandocToEPUB epubVersion opts doc) initState
420420
421421pandocToEPUB :: PandocMonad m
@@ -439,7 +439,7 @@ pandocToEPUB version opts doc = do
439439 [] -> case epubTitle metadata of
440440 [] -> "UNTITLED"
441441 (x:_) -> titleText x
442− x -> TS.unpack $ stringify x
442+ x -> stringify x
443443
444444 -- stylesheet
445445 stylesheets <- case epubStylesheets metadata of
@@ -461,7 +461,8 @@ pandocToEPUB version opts doc = do
461461 (ListVal $ map
462462 (\e -> toVal' $
463463 (if useprefix then "../" else "") <>
464− makeRelative epubSubdir (eRelativePath e))
464+ T.pack
465+ (makeRelative epubSubdir (eRelativePath e)))
465466 stylesheetEntries)
466467 mempty
467468
@@ -490,18 +491,19 @@ pandocToEPUB version opts doc = do
490491 case imageSize opts' (B.toStrict imgContent) of
491492 Right sz -> return $ sizeInPixels sz
492493 Left err' -> (0, 0) <$ report
493− (CouldNotDetermineImageSize (TS.pack img) err')
494+ (CouldNotDetermineImageSize (T.pack img) err')
494495 cpContent <- lift $ writeHtml
495496 opts'{ writerVariables =
496497 Context (M.fromList [
497498 ("coverpage", toVal' "true"),
498499 ("pagetitle", toVal $
499− escapeStringForXML $ TS.pack plainTitle),
500− ("cover-image", toVal' coverImageName),
500+ escapeStringForXML plainTitle),
501+ ("cover-image",
502+ toVal' $ T.pack coverImageName),
501503 ("cover-image-width", toVal' $
502− show coverImageWidth),
504+ tshow coverImageWidth),
503505 ("cover-image-height", toVal' $
504− show coverImageHeight)]) <>
506+ tshow coverImageHeight)]) <>
505507 cssvars True <> vars }
506508 (Pandoc meta [])
507509 coverEntry <- mkEntry "text/cover.xhtml" cpContent
@@ -517,7 +519,7 @@ pandocToEPUB version opts doc = do
517519 ("titlepage", toVal' "true"),
518520 ("body-type", toVal' "frontmatter"),
519521 ("pagetitle", toVal $
520− escapeStringForXML $ TS.pack plainTitle)])
522+ escapeStringForXML plainTitle)])
521523 <> cssvars True <> vars }
522524 (Pandoc meta [])
523525 tpEntry <- mkEntry "text/title_page.xhtml" tpContent
@@ -526,7 +528,7 @@ pandocToEPUB version opts doc = do
526528 let matchingGlob f = do
527529 xs <- lift $ P.glob f
528530 when (null xs) $
529− report $ CouldNotFetchResource (TS.pack f) "glob did not match any font files"
531+ report $ CouldNotFetchResource (T.pack f) "glob did not match any font files"
530532 return xs
531533 let mkFontEntry f = mkEntry ("fonts/" ++ takeFileName f) =<<
532534 lift (P.readFileLazy f)
@@ -573,13 +575,13 @@ pandocToEPUB version opts doc = do
573575
574576 let chapters' = secsToChapters secs
575577
576− let extractLinkURL' :: Int -> Inline -> [(TS.Text, TS.Text)]
578+ let extractLinkURL' :: Int -> Inline -> [(T.Text, T.Text)]
577579 extractLinkURL' num (Span (ident, _, _) _)
578− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
580+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
579581 extractLinkURL' num (Link (ident, _, _) _ _)
580− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
582+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
581583 extractLinkURL' num (Image (ident, _, _) _ _)
582− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
584+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
583585 extractLinkURL' num (RawInline fmt raw)
584586 | isHtmlFormat fmt
585587 = foldr (\tag ->
@@ -587,18 +589,18 @@ pandocToEPUB version opts doc = do
587589 TagOpen{} ->
588590 case fromAttrib "id" tag of
589591 "" -> id
590− x -> ((x, TS.pack (showChapter num) <> "#" <> x):)
592+ x -> ((x, showChapter num <> "#" <> x):)
591593 _ -> id)
592594 [] (parseTags raw)
593595 extractLinkURL' _ _ = []
594596
595− let extractLinkURL :: Int -> Block -> [(TS.Text, TS.Text)]
597+ let extractLinkURL :: Int -> Block -> [(T.Text, T.Text)]
596598 extractLinkURL num (Div (ident, _, _) _)
597− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
599+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
598600 extractLinkURL num (Header _ (ident, _, _) _)
599− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
601+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
600602 extractLinkURL num (Table (ident,_,_) _ _ _ _ _)
601− | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
603+ | not (T.null ident) = [(ident, showChapter num <> "#" <> ident)]
602604 extractLinkURL num (RawBlock fmt raw)
603605 | isHtmlFormat fmt
604606 = foldr (\tag ->
@@ -606,7 +608,7 @@ pandocToEPUB version opts doc = do
606608 TagOpen{} ->
607609 case fromAttrib "id" tag of
608610 "" -> id
609− x -> ((x, TS.pack (showChapter num) <> "#" <> x):)
611+ x -> ((x, showChapter num <> "#" <> x):)
610612 _ -> id)
611613 [] (parseTags raw)
612614 extractLinkURL num b = query (extractLinkURL' num) b
@@ -617,7 +619,7 @@ pandocToEPUB version opts doc = do
617619
618620 let fixInternalReferences :: Inline -> Inline
619621 fixInternalReferences (Link attr lab (src, tit))
620− | Just ('#', xs) <- TS.uncons src = case lookup xs reftable of
622+ | Just ('#', xs) <- T.uncons src = case lookup xs reftable of
621623 Just ys -> Link attr lab (ys, tit)
622624 Nothing -> Link attr lab (src, tit)
623625 fixInternalReferences x = x
@@ -630,7 +632,7 @@ pandocToEPUB version opts doc = do
630632 chapters'
631633
632634 let chapToEntry num (Chapter bs) =
633− mkEntry ("text/" ++ showChapter num) =<<
635+ mkEntry ("text/" ++ T.unpack (showChapter num)) =<<
634636 writeHtml opts'{ writerVariables =
635637 Context (M.fromList
636638 [("body-type", toVal' bodyType),
@@ -677,12 +679,12 @@ pandocToEPUB version opts doc = do
677679 let chapterNode ent = unode "item" !
678680 ([("id", toId $ makeRelative epubSubdir
679681 $ eRelativePath ent),
680− ("href", makeRelative epubSubdir
682+ ("href", T.pack $ makeRelative epubSubdir
681683 $ eRelativePath ent),
682684 ("media-type", "application/xhtml+xml")]
683685 ++ case props ent of
684686 [] -> []
685− xs -> [("properties", unwords xs)])
687+ xs -> [("properties", T.unwords xs)])
686688 $ ()
687689
688690 let chapterRefNode ent = unode "itemref" !
@@ -691,17 +693,17 @@ pandocToEPUB version opts doc = do
691693 let pictureNode ent = unode "item" !
692694 [("id", toId $ makeRelative epubSubdir
693695 $ eRelativePath ent),
694− ("href", makeRelative epubSubdir
696+ ("href", T.pack $ makeRelative epubSubdir
695697 $ eRelativePath ent),
696698 ("media-type",
697− maybe "application/octet-stream" TS.unpack
699+ fromMaybe "application/octet-stream"
698700 $ mediaTypeOf $ eRelativePath ent)] $ ()
699701 let fontNode ent = unode "item" !
700702 [("id", toId $ makeRelative epubSubdir
701703 $ eRelativePath ent),
702− ("href", makeRelative epubSubdir
704+ ("href", T.pack $ makeRelative epubSubdir
703705 $ eRelativePath ent),
704− ("media-type", maybe "" TS.unpack $
706+ ("media-type", fromMaybe "" $
705707 getMimeType $ eRelativePath ent)] $ ()
706708
707709 let tocTitle = maybe plainTitle
@@ -710,7 +712,7 @@ pandocToEPUB version opts doc = do
710712 (x:_) -> return $ identifierText x -- use first identifier as UUID
711713 [] -> throwError $ PandocShouldNeverHappenError "epubIdentifier is null" -- shouldn't happen
712714 currentTime <- lift P.getTimestamp
713− let contentsData = UTF8.fromStringLazy $ ppTopElement $
715+ let contentsData = UTF8.fromTextLazy $ TL.fromStrict $ ppTopElement $
714716 unode "package" !
715717 ([("version", case version of
716718 EPUB2 -> "2.0"
@@ -728,7 +730,8 @@ pandocToEPUB version opts doc = do
728730 ,("media-type","application/xhtml+xml")] ++
729731 [("properties","nav") | epub3 ]) $ ()
730732 ] ++
731− [ unode "item" ! [("id","stylesheet" ++ show n), ("href",fp)
733+ [ unode "item" ! [("id","stylesheet" <> tshow n)
734+ , ("href", T.pack fp)
732735 ,("media-type","text/css")] $ () |
733736 (n :: Int, fp) <- zip [1..] (map
734737 (makeRelative epubSubdir . eRelativePath)
@@ -773,7 +776,7 @@ pandocToEPUB version opts doc = do
773776 let tocLevel = writerTOCDepth opts
774777
775778 let navPointNode :: PandocMonad m
776− => (Int -> [Inline] -> TS.Text -> [Element] -> Element)
779+ => (Int -> [Inline] -> T.Text -> [Element] -> Element)
777780 -> Block -> StateT Int m [Element]
778781 navPointNode formatter (Div (ident,_,_)
779782 (Header lvl (_,_,kvs) ils : children)) =
@@ -783,7 +786,7 @@ pandocToEPUB version opts doc = do
783786 n <- get
784787 modify (+1)
785788 let num = fromMaybe "" $ lookup "number" kvs
786− let tit = if writerNumberSections opts && not (TS.null num)
789+ let tit = if writerNumberSections opts && not (T.null num)
787790 then Span ("", ["section-header-number"], [])
788791 [Str num] : Space : ils
789792 else ils
@@ -797,21 +800,21 @@ pandocToEPUB version opts doc = do
797800 concat <$> mapM (navPointNode formatter) bs
798801 navPointNode _ _ = return []
799802
800− let navMapFormatter :: Int -> [Inline] -> TS.Text -> [Element] -> Element
803+ let navMapFormatter :: Int -> [Inline] -> T.Text -> [Element] -> Element
801804 navMapFormatter n tit src subs = unode "navPoint" !
802− [("id", "navPoint-" ++ show n)] $
803− [ unode "navLabel" $ unode "text" $ TS.unpack $ stringify tit
804− , unode "content" ! [("src", "text/" <> TS.unpack src)] $ ()
805+ [("id", "navPoint-" <> tshow n)] $
806+ [ unode "navLabel" $ unode "text" $ stringify tit
807+ , unode "content" ! [("src", "text/" <> src)] $ ()
805808 ] ++ subs
806809
807810 let tpNode = unode "navPoint" ! [("id", "navPoint-0")] $
808− [ unode "navLabel" $ unode "text" (TS.unpack $ stringify $ docTitle' meta)
811+ [ unode "navLabel" $ unode "text" (stringify $ docTitle' meta)
809812 , unode "content" ! [("src", "text/title_page.xhtml")]
810813 $ () ]
811814
812815 navMap <- lift $ evalStateT
813816 (concat <$> mapM (navPointNode navMapFormatter) secs) 1
814− let tocData = UTF8.fromStringLazy $ ppTopElement $
817+ let tocData = B.fromStrict $ UTF8.fromText $ ppTopElement $
815818 unode "ncx" ! [("version","2005-1")
816819 ,("xmlns","http://www.daisy.org/z3986/2005/ncx/")] $
817820 [ unode "head" $
@@ -833,11 +836,11 @@ pandocToEPUB version opts doc = do
833836 ]
834837 tocEntry <- mkEntry "toc.ncx" tocData
835838
836− let navXhtmlFormatter :: Int -> [Inline] -> TS.Text -> [Element] -> Element
839+ let navXhtmlFormatter :: Int -> [Inline] -> T.Text -> [Element] -> Element
837840 navXhtmlFormatter n tit src subs = unode "li" !
838− [("id", "toc-li-" ++ show n)] $
841+ [("id", "toc-li-" <> tshow n)] $
839842 (unode "a" !
840− [("href", "text/" <> TS.unpack src)]
843+ [("href", "text/" <> src)]
841844 $ titElements)
842845 : case subs of
843846 [] -> []
@@ -850,7 +853,7 @@ pandocToEPUB version opts doc = do
850853 , writerVariables =
851854 Context (M.fromList
852855 [("pagetitle", toVal $
853− escapeStringForXML $ TS.pack plainTitle)])
856+ escapeStringForXML plainTitle)])
854857 <> writerVariables opts}
855858 (Pandoc nullMeta
856859 [Plain $ walk clean tit])) of
@@ -865,7 +868,7 @@ pandocToEPUB version opts doc = do
865868 tocBlocks <- lift $ evalStateT
866869 (concat <$> mapM (navPointNode navXhtmlFormatter) secs) 1
867870 let navBlocks = [RawBlock (Format "html")
868− $ TS.pack $ showElement $ -- prettyprinting introduces bad spaces
871+ $ showElement $ -- prettyprinting introduces bad spaces
869872 unode navtag ! ([("epub:type","toc") | epub3] ++
870873 [("id","toc")]) $
871874 [ unode "h1" ! [("id","toc-title")] $ tocTitle
@@ -875,21 +878,21 @@ pandocToEPUB version opts doc = do
875878 [ unode "a" ! [("href",
876879 "text/title_page.xhtml")
877880 ,("epub:type", "titlepage")] $
878− ("Title Page" :: String) ] :
881+ ("Title Page" :: Text) ] :
879882 [ unode "li"
880883 [ unode "a" ! [("href", "text/cover.xhtml")
881884 ,("epub:type", "cover")] $
882− ("Cover" :: String)] |
885+ ("Cover" :: Text)] |
883886 isJust (epubCoverImage metadata)
884887 ] ++
885888 [ unode "li"
886889 [ unode "a" ! [("href", "#toc")
887890 ,("epub:type", "toc")] $
888− ("Table of Contents" :: String)
891+ ("Table of Contents" :: Text)
889892 ] | writerTableOfContents opts
890893 ]
891894 else []
892− let landmarks = [RawBlock (Format "html") $ TS.pack $ ppElement $
895+ let landmarks = [RawBlock (Format "html") $ ppElement $
893896 unode "nav" ! [("epub:type","landmarks")
894897 ,("id","landmarks")
895898 ,("hidden","hidden")] $
@@ -910,22 +913,22 @@ pandocToEPUB version opts doc = do
910913 UTF8.fromStringLazy "application/epub+zip"
911914
912915 -- container.xml
913− let containerData = UTF8.fromStringLazy $ ppTopElement $
916+ let containerData = B.fromStrict $ UTF8.fromText $ ppTopElement $
914917 unode "container" ! [("version","1.0")
915918 ,("xmlns","urn:oasis:names:tc:opendocument:xmlns:container")] $
916919 unode "rootfiles" $
917920 unode "rootfile" ! [("full-path",
918921 (if null epubSubdir
919922 then ""
920− else epubSubdir ++ "/") ++ "content.opf")
923+ else T.pack epubSubdir <> "/") <> "content.opf")
921924 ,("media-type","application/oebps-package+xml")] $ ()
922925 containerEntry <- mkEntry "META-INF/container.xml" containerData
923926
924927 -- com.apple.ibooks.display-options.xml
925− let apple = UTF8.fromStringLazy $ ppTopElement $
928+ let apple = B.fromStrict $ UTF8.fromText $ ppTopElement $
926929 unode "display_options" $
927930 unode "platform" ! [("name","*")] $
928− unode "option" ! [("name","specified-fonts")] $ ("true" :: String)
931+ unode "option" ! [("name","specified-fonts")] $ ("true" :: Text)
929932 appleEntry <- mkEntry "META-INF/com.apple.ibooks.display-options.xml" apple
930933
931934 -- construct archive
@@ -947,7 +950,8 @@ metadataElement version md currentTime =
947950 ++ publisherNodes ++ sourceNodes ++ relationNodes
948951 ++ coverageNodes ++ rightsNodes ++ coverImageNodes
949952 ++ modifiedNodes ++ belongsToCollectionNodes
950− withIds base f = concat . zipWith f (map (\x -> base ++ ('-' : show x))
953+ withIds base f = concat . zipWith f (map (\x -> base <>
954+ T.cons '-' (tshow x))
951955 ([1..] :: [Int]))
952956 identifierNodes = withIds "epub-id" toIdentifierNode $
953957 epubIdentifier md
@@ -961,9 +965,9 @@ metadataElement version md currentTime =
961965 (x:_) -> [dcNode "date" ! [("id","epub-date")]
962966 $ dateText x]
963967 ibooksNodes = map ibooksNode (epubIbooksFields md)
964− ibooksNode (k, v) = unode "meta" ! [("property", "ibooks:" ++ k)] $ v
968+ ibooksNode (k, v) = unode "meta" ! [("property", "ibooks:" <> k)] $ v
965969 calibreNodes = map calibreNode (epubCalibreFields md)
966− calibreNode (k, v) = unode "meta" ! [("name", "calibre:" ++ k),
970+ calibreNode (k, v) = unode "meta" ! [("name", "calibre:" <> k),
967971 ("content", v)] $ ()
968972 languageNodes = [dcTag "language" $ epubLanguage md]
969973 creatorNodes = withIds "epub-creator" (toCreatorNode "creator") $
@@ -989,12 +993,12 @@ metadataElement version md currentTime =
989993 maybe []
990994 (\belongsToCollection -> (unode "meta" ! [("property", "belongs-to-collection"), ("id", "epub-id-1")] $ belongsToCollection )
991995 :
992− [unode "meta" ! [("refines", "#epub-id-1"), ("property", "collection-type")] $ ("series" :: String) ])
996+ [unode "meta" ! [("refines", "#epub-id-1"), ("property", "collection-type")] $ ("series" :: Text) ])
993997 (epubBelongsToCollection md)++
994998 maybe []
995999 (\groupPosition -> [unode "meta" ! [("refines", "#epub-id-1"), ("property", "group-position")] $ groupPosition ])
9961000 (epubGroupPosition md)
997− dcTag n s = unode ("dc:" ++ n) s
1001+ dcTag n s = unode ("dc:" <> n) s
9981002 dcTag' n s = [dcTag n s]
9991003 toIdentifierNode id' (Identifier txt scheme)
10001004 | version == EPUB2 = [dcNode "identifier" !
@@ -1002,7 +1006,7 @@ metadataElement version md currentTime =
10021006 txt]
10031007 | otherwise = (dcNode "identifier" ! [("id",id')] $ txt) :
10041008 maybe [] ((\x -> [unode "meta" !
1005− [ ("refines",'#':id')
1009+ [ ("refines","#" <> id')
10061010 , ("property","identifier-type")
10071011 , ("scheme","onix:codelist5")
10081012 ]
@@ -1018,10 +1022,10 @@ metadataElement version md currentTime =
10181022 (creatorRole creator >>= toRelator)) $ creatorText creator]
10191023 | otherwise = [dcNode s ! [("id",id')] $ creatorText creator] ++
10201024 maybe [] (\x -> [unode "meta" !
1021− [("refines",'#':id'),("property","file-as")] $ x])
1025+ [("refines","#" <> id'),("property","file-as")] $ x])
10221026 (creatorFileAs creator) ++
10231027 maybe [] (\x -> [unode "meta" !
1024− [("refines",'#':id'),("property","role"),
1028+ [("refines","#" <> id'),("property","role"),
10251029 ("scheme","marc:relators")] $ x])
10261030 (creatorRole creator >>= toRelator)
10271031 toTitleNode id' title
@@ -1033,16 +1037,16 @@ metadataElement version md currentTime =
10331037 | otherwise = [dcNode "title" ! [("id",id')] $ titleText title]
10341038 ++
10351039 maybe [] (\x -> [unode "meta" !
1036− [("refines",'#':id'),("property","file-as")] $ x])
1040+ [("refines","#" <> id'),("property","file-as")] $ x])
10371041 (titleFileAs title) ++
10381042 maybe [] (\x -> [unode "meta" !
1039− [("refines",'#':id'),("property","title-type")] $ x])
1043+ [("refines","#" <> id'),("property","title-type")] $ x])
10401044 (titleType title)
10411045 toDateNode id' date = [dcNode "date" !
10421046 (("id",id') :
10431047 maybe [] (\x -> [("opf:event",x)]) (dateEvent date)) $
10441048 dateText date]
1045− schemeToOnix :: String -> String
1049+ schemeToOnix :: Text -> Text
10461050 schemeToOnix "ISBN-10" = "02"
10471051 schemeToOnix "GTIN-13" = "03"
10481052 schemeToOnix "UPC" = "04"
@@ -1060,48 +1064,48 @@ metadataElement version md currentTime =
10601064 schemeToOnix "OLCC" = "28"
10611065 schemeToOnix _ = "01"
10621066
1063−showDateTimeISO8601 :: UTCTime -> String
1064−showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ"
1067+showDateTimeISO8601 :: UTCTime -> Text
1068+showDateTimeISO8601 = T.pack . formatTime defaultTimeLocale "%FT%TZ"
10651069
10661070transformTag :: PandocMonad m
1067− => Tag TS.Text
1068− -> E m (Tag TS.Text)
1071+ => Tag T.Text
1072+ -> E m (Tag T.Text)
10691073transformTag tag@(TagOpen name attr)
10701074 | name `elem` ["video", "source", "img", "audio"] &&
10711075 isNothing (lookup "data-external" attr) = do
10721076 let src = fromAttrib "src" tag
10731077 let poster = fromAttrib "poster" tag
1074− newsrc <- modifyMediaRef $ TS.unpack src
1075− newposter <- modifyMediaRef $ TS.unpack poster
1078+ newsrc <- modifyMediaRef $ T.unpack src
1079+ newposter <- modifyMediaRef $ T.unpack poster
10761080 let attr' = filter (\(x,_) -> x /= "src" && x /= "poster") attr ++
1077− [("src", "../" <> newsrc) | not (TS.null newsrc)] ++
1078− [("poster", "../" <> newposter) | not (TS.null newposter)]
1081+ [("src", "../" <> newsrc) | not (T.null newsrc)] ++
1082+ [("poster", "../" <> newposter) | not (T.null newposter)]
10791083 return $ TagOpen name attr'
10801084transformTag tag = return tag
10811085
10821086modifyMediaRef :: PandocMonad m
10831087 => FilePath
1084− -> E m TS.Text
1088+ -> E m T.Text
10851089modifyMediaRef "" = return ""
10861090modifyMediaRef oldsrc = do
10871091 media <- gets stMediaPaths
10881092 case lookup oldsrc media of
1089− Just (n,_) -> return $ TS.pack n
1093+ Just (n,_) -> return $ T.pack n
10901094 Nothing -> catchError
1091− (do (img, mbMime) <- P.fetchItem $ TS.pack oldsrc
1092− let ext = maybe (takeExtension (takeWhile (/='?') oldsrc)) TS.unpack
1095+ (do (img, mbMime) <- P.fetchItem $ T.pack oldsrc
1096+ let ext = maybe (takeExtension (takeWhile (/='?') oldsrc)) T.unpack
10931097 (("." <>) <$> (mbMime >>= extensionFromMimeType))
10941098 newName <- getMediaNextNewName ext
10951099 let newPath = "media/" ++ newName
10961100 entry <- mkEntry newPath (B.fromChunks . (:[]) $ img)
10971101 modify $ \st -> st{ stMediaPaths =
10981102 (oldsrc, (newPath, Just entry)):media}
1099− return $ TS.pack newPath)
1103+ return $ T.pack newPath)
11001104 (\e -> do
1101− report $ CouldNotFetchResource (TS.pack oldsrc) (tshow e)
1102− return $ TS.pack oldsrc)
1105+ report $ CouldNotFetchResource (T.pack oldsrc) (tshow e)
1106+ return $ T.pack oldsrc)
11031107
1104−getMediaNextNewName :: PandocMonad m => String -> E m String
1108+getMediaNextNewName :: PandocMonad m => FilePath -> E m FilePath
11051109getMediaNextNewName ext = do
11061110 nextId <- gets stMediaNextId
11071111 modify $ \st -> st { stMediaNextId = nextId + 1 }
@@ -1128,11 +1132,11 @@ transformInline :: PandocMonad m
11281132 -> Inline
11291133 -> E m Inline
11301134transformInline _opts (Image attr lab (src,tit)) = do
1131− newsrc <- modifyMediaRef $ TS.unpack src
1135+ newsrc <- modifyMediaRef $ T.unpack src
11321136 return $ Image attr lab ("../" <> newsrc, tit)
11331137transformInline opts x@(Math t m)
11341138 | WebTeX url <- writerHTMLMathMethod opts = do
1135− newsrc <- modifyMediaRef (TS.unpack url <> urlEncode (TS.unpack m))
1139+ newsrc <- modifyMediaRef (T.unpack url <> urlEncode (T.unpack m))
11361140 let mathclass = if t == DisplayMath then "display" else "inline"
11371141 return $ Span ("",["math",mathclass],[])
11381142 [Image nullAttr [x] ("../" <> newsrc, "")]
@@ -1143,40 +1147,26 @@ transformInline _opts (RawInline fmt raw)
11431147 return $ RawInline fmt (renderTags' tags')
11441148transformInline _ x = return x
11451149
1146−(!) :: (t -> Element) -> [(String, String)] -> t -> Element
1150+(!) :: (t -> Element) -> [(Text, Text)] -> t -> Element
11471151(!) f attrs n = add_attrs (map (\(k,v) -> Attr (unqual k) v) attrs) (f n)
11481152
1149−-- | Version of 'ppTopElement' that specifies UTF-8 encoding.
1150−ppTopElement :: Element -> String
1151−ppTopElement = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++) . unEntity . ppElement
1152− -- unEntity removes numeric entities introduced by ppElement
1153− -- (kindlegen seems to choke on these).
1154− where unEntity [] = ""
1155− unEntity ('&':'#':xs) =
1156− let (ds,ys) = break (==';') xs
1157− rest = drop 1 ys
1158− in case safeRead (TS.pack $ "'\\" <> ds <> "'") of
1159− Just x -> x : unEntity rest
1160− Nothing -> '&':'#':unEntity xs
1161− unEntity (x:xs) = x : unEntity xs
1162−
11631153mediaTypeOf :: FilePath -> Maybe MimeType
11641154mediaTypeOf x =
11651155 let mediaPrefixes = ["image", "video", "audio"] in
11661156 case getMimeType x of
1167− Just y | any (`TS.isPrefixOf` y) mediaPrefixes -> Just y
1157+ Just y | any (`T.isPrefixOf` y) mediaPrefixes -> Just y
11681158 _ -> Nothing
11691159
11701160-- Returns filename for chapter number.
1171−showChapter :: Int -> String
1172−showChapter = printf "ch%03d.xhtml"
1161+showChapter :: Int -> Text
1162+showChapter = T.pack . printf "ch%03d.xhtml"
11731163
11741164-- Add identifiers to any headers without them.
11751165addIdentifiers :: WriterOptions -> [Block] -> [Block]
11761166addIdentifiers opts bs = evalState (mapM go bs) Set.empty
11771167 where go (Header n (ident,classes,kvs) ils) = do
11781168 ids <- get
1179− let ident' = if TS.null ident
1169+ let ident' = if T.null ident
11801170 then uniqueIdent (writerExtensions opts) ils ids
11811171 else ident
11821172 modify $ Set.insert ident'
@@ -1184,27 +1174,27 @@ addIdentifiers opts bs = evalState (mapM go bs) Set.empty
11841174 go x = return x
11851175
11861176-- Variant of normalizeDate that allows partial dates: YYYY, YYYY-MM
1187−normalizeDate' :: String -> Maybe String
1188−normalizeDate' = fmap TS.unpack . go . trim . TS.pack
1177+normalizeDate' :: Text -> Maybe Text
1178+normalizeDate' = go . T.strip
11891179 where
11901180 go xs
1191− | TS.length xs == 4 -- YYY
1192− , TS.all isDigit xs = Just xs
1193− | (y, s) <- TS.splitAt 4 xs -- YYY-MM
1194− , Just ('-', m) <- TS.uncons s
1195− , TS.length m == 2
1196− , TS.all isDigit y && TS.all isDigit m = Just xs
1181+ | T.length xs == 4 -- YYY
1182+ , T.all isDigit xs = Just xs
1183+ | (y, s) <- T.splitAt 4 xs -- YYY-MM
1184+ , Just ('-', m) <- T.uncons s
1185+ , T.length m == 2
1186+ , T.all isDigit y && T.all isDigit m = Just xs
11971187 | otherwise = normalizeDate xs
11981188
1199−toRelator :: String -> Maybe String
1189+toRelator :: Text -> Maybe Text
12001190toRelator x
12011191 | x `elem` relators = Just x
1202− | otherwise = lookup (map toLower x) relatorMap
1192+ | otherwise = lookup (T.toLower x) relatorMap
12031193
1204−relators :: [String]
1194+relators :: [Text]
12051195relators = map snd relatorMap
12061196
1207−relatorMap :: [(String, String)]
1197+relatorMap :: [(Text, Text)]
12081198relatorMap =
12091199 [("abridger", "abr")
12101200 ,("actor", "act")